diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-base.patch b/kernel/tools/perf/files/patches/aufs6/aufs6-base.patch similarity index 59% rename from kernel/tools/perf/files/patches/aufs5/aufs5-base.patch rename to kernel/tools/perf/files/patches/aufs6/aufs6-base.patch index b37e855f41..24983178a6 100644 --- a/kernel/tools/perf/files/patches/aufs5/aufs5-base.patch +++ b/kernel/tools/perf/files/patches/aufs6/aufs6-base.patch @@ -1,13 +1,13 @@ SPDX-License-Identifier: GPL-2.0 -aufs5.15.41 base patch +aufs6.12 base patch diff --git a/MAINTAINERS b/MAINTAINERS -index c8103e57a70b..e1b9eaca78fd 100644 +index b878ddc99f94e..8489754030b99 100644 --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -3122,6 +3122,19 @@ F: include/uapi/linux/audit.h - F: kernel/audit* +@@ -3666,6 +3666,19 @@ F: kernel/audit* F: lib/*audit.c + K: \baudit_[a-z_0-9]\+\b +AUFS (advanced multi layered unification filesystem) FILESYSTEM +M: "J. R. Okajima" @@ -22,21 +22,23 @@ index c8103e57a70b..e1b9eaca78fd 100644 +F: fs/aufs/ +F: include/uapi/linux/aufs_type.h + - AUXILIARY DISPLAY DRIVERS - M: Miguel Ojeda - S: Maintained + AUXILIARY BUS DRIVER + M: Greg Kroah-Hartman + R: Dave Ertman diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index 8cba10aafadb..7a9e40b97831 100644 +index 78a7bb28defe4..479480f25a6c0 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; +@@ -661,6 +661,26 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + goto done; } +/* + * for AUFS + * no get/put for file. + */ ++/* Just to make the compiler silence, declare it */ ++struct file *loop_backing_file(struct super_block *sb); +struct file *loop_backing_file(struct super_block *sb) +{ + struct file *ret; @@ -55,10 +57,20 @@ index 8cba10aafadb..7a9e40b97831 100644 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 +index 0f6b16ba30d08..1ab11cad60e8c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c -@@ -1320,7 +1320,7 @@ enum d_walk_ret { +@@ -1223,6 +1223,9 @@ enum d_walk_ret { + D_WALK_SKIP, + }; + ++/* AUFS calls d_walk(). Just to make the compiler silence, declare it */ ++void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *)); + /** + * d_walk - walk the dentry tree + * @parent: start of walk +@@ -1231,7 +1234,7 @@ enum d_walk_ret { * * The @enter() callbacks are called with d_lock held. */ @@ -66,21 +78,21 @@ index cf871a81f4fd..bc5095b734f5 100644 +void d_walk(struct dentry *parent, void *data, enum d_walk_ret (*enter)(void *, struct dentry *)) { - struct dentry *this_parent; + struct dentry *this_parent, *dentry; diff --git a/fs/fcntl.c b/fs/fcntl.c -index 9c6c6a3e2de5..02382fa9bd34 100644 +index 22dd9dcce7ecc..460791727fd9c 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c -@@ -33,7 +33,7 @@ +@@ -37,7 +37,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) +-static int setfl(int fd, struct file * filp, unsigned int arg) ++int setfl(int fd, struct file * filp, unsigned int 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) +@@ -67,6 +67,8 @@ static int setfl(int fd, struct file * filp, unsigned int arg) if (filp->f_op->check_flags) error = filp->f_op->check_flags(arg); @@ -90,10 +102,10 @@ index 9c6c6a3e2de5..02382fa9bd34 100644 return error; diff --git a/fs/namespace.c b/fs/namespace.c -index b696543adab8..c45740054bc7 100644 +index d26f5e6d2ca35..85739e2d64c00 100644 --- a/fs/namespace.c +++ b/fs/namespace.c -@@ -808,6 +808,12 @@ static inline int check_mnt(struct mount *mnt) +@@ -966,6 +966,12 @@ static inline int check_mnt(struct mount *mnt) return mnt->mnt_ns == current->nsproxy->mnt_ns; } @@ -107,74 +119,43 @@ index b696543adab8..c45740054bc7 100644 * vfsmount lock must be held for write */ diff --git a/fs/splice.c b/fs/splice.c -index 5dbce4dcc1a7..3e6ba363b777 100644 +index 06232d7e505f6..b15fd6073b6d3 100644 --- a/fs/splice.c +++ b/fs/splice.c -@@ -759,8 +759,8 @@ static int warn_unsupported(struct file *file, const char *op) +@@ -933,7 +933,7 @@ 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) +-static ssize_t do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ssize_t 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 +index 3559446279c15..51b64b2ad82c4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -1381,6 +1381,7 @@ extern void fasync_free(struct fasync_struct *); +@@ -1160,6 +1160,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 int setfl(int fd, struct file *filp, unsigned int 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 int f_setown(struct file *filp, int who, 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); +@@ -2082,6 +2083,7 @@ struct file_operations { + int (*lock) (struct file *, int, struct file_lock *); 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 +index 217f7abf2cbfa..0e17b8c23f105 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, +@@ -210,6 +210,8 @@ static inline int lockdep_match_key(struct lockdep_map *lock, return lock->key == key; } @@ -184,10 +165,10 @@ index 9fe165beb0f9..e47f7e15eeaf 100644 * Acquire a lock. * diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h -index 8f882f5881e8..6b9808f09843 100644 +index 70b366b648160..08cfdabb2721f 100644 --- a/include/linux/mnt_namespace.h +++ b/include/linux/mnt_namespace.h -@@ -7,12 +7,15 @@ struct mnt_namespace; +@@ -10,6 +10,7 @@ struct mnt_namespace; struct fs_struct; struct user_namespace; struct ns_common; @@ -195,7 +176,8 @@ index 8f882f5881e8..6b9808f09843 100644 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); +@@ -17,6 +18,8 @@ extern void put_mnt_ns(struct mnt_namespace *ns); + DEFINE_FREE(put_mnt_ns, struct mnt_namespace *, if (!IS_ERR_OR_NULL(_T)) put_mnt_ns(_T)) extern struct ns_common *from_mnt_ns(struct mnt_namespace *); +extern int is_current_mnt_ns(struct vfsmount *mnt); @@ -204,25 +186,22 @@ index 8f882f5881e8..6b9808f09843 100644 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 +index 9dec4861d09f6..14583d8468640 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h -@@ -93,4 +93,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); +@@ -108,4 +108,7 @@ 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); ++extern ssize_t do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); #endif diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c -index a30702b847ba..ce380d0abdf0 100644 +index 536bd471557f5..34b378cf7a95f 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c -@@ -187,7 +187,7 @@ unsigned long max_lock_class_idx; +@@ -218,7 +218,7 @@ unsigned long max_lock_class_idx; struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); @@ -231,7 +210,7 @@ index a30702b847ba..ce380d0abdf0 100644 { unsigned int class_idx = hlock->class_idx; -@@ -208,6 +208,7 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock) +@@ -239,6 +239,7 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock) */ return lock_classes + class_idx; } diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-kbuild.patch b/kernel/tools/perf/files/patches/aufs6/aufs6-kbuild.patch similarity index 63% rename from kernel/tools/perf/files/patches/aufs5/aufs5-kbuild.patch rename to kernel/tools/perf/files/patches/aufs6/aufs6-kbuild.patch index aa8869f06c..70c96059b0 100644 --- a/kernel/tools/perf/files/patches/aufs5/aufs5-kbuild.patch +++ b/kernel/tools/perf/files/patches/aufs6/aufs6-kbuild.patch @@ -1,11 +1,11 @@ SPDX-License-Identifier: GPL-2.0 -aufs5.15.41 kbuild patch +aufs6.12 kbuild patch diff --git a/fs/Kconfig b/fs/Kconfig -index a6313a969bc5..aca4b89d41a1 100644 +index aae170fc27952..d5bb584649f50 100644 --- a/fs/Kconfig +++ b/fs/Kconfig -@@ -312,6 +312,7 @@ source "fs/sysv/Kconfig" +@@ -341,6 +341,7 @@ source "fs/sysv/Kconfig" source "fs/ufs/Kconfig" source "fs/erofs/Kconfig" source "fs/vboxsf/Kconfig" @@ -14,11 +14,11 @@ index a6313a969bc5..aca4b89d41a1 100644 endif # MISC_FILESYSTEMS diff --git a/fs/Makefile b/fs/Makefile -index 84c5e4cdfee5..b4fcdad8412e 100644 +index 61679fd587b7e..b2539712b80d0 100644 --- a/fs/Makefile +++ b/fs/Makefile -@@ -138,3 +138,4 @@ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ - obj-$(CONFIG_EROFS_FS) += erofs/ +@@ -130,3 +130,4 @@ obj-$(CONFIG_EROFS_FS) += erofs/ obj-$(CONFIG_VBOXSF_FS) += vboxsf/ obj-$(CONFIG_ZONEFS_FS) += zonefs/ + obj-$(CONFIG_BPF_LSM) += bpf_fs_kfuncs.o +obj-$(CONFIG_AUFS_FS) += aufs/ diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-loopback.patch b/kernel/tools/perf/files/patches/aufs6/aufs6-loopback.patch similarity index 73% rename from kernel/tools/perf/files/patches/aufs5/aufs5-loopback.patch rename to kernel/tools/perf/files/patches/aufs6/aufs6-loopback.patch index 753437f378..82c527f131 100644 --- a/kernel/tools/perf/files/patches/aufs5/aufs5-loopback.patch +++ b/kernel/tools/perf/files/patches/aufs6/aufs6-loopback.patch @@ -1,11 +1,20 @@ SPDX-License-Identifier: GPL-2.0 -aufs5.15.41 loopback patch +aufs6.12 loopback patch diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index 7a9e40b97831..5ed06240cc9c 100644 +index 479480f25a6c0..ba3477c30e294 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) +@@ -54,7 +54,7 @@ struct loop_device { + int lo_flags; + char lo_file_name[LO_NAME_SIZE]; + +- struct file * lo_backing_file; ++ struct file *lo_backing_file, *lo_backing_virt_file; + struct block_device *lo_device; + + gfp_t old_gfp_mask; +@@ -526,6 +526,15 @@ static inline void loop_update_dio(struct loop_device *lo) lo->use_dio); } @@ -21,7 +30,7 @@ index 7a9e40b97831..5ed06240cc9c 100644 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, +@@ -583,6 +592,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, { struct file *file = fget(arg); struct file *old_file; @@ -29,7 +38,7 @@ index 7a9e40b97831..5ed06240cc9c 100644 int error; bool partscan; bool is_loop; -@@ -749,11 +759,19 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, +@@ -606,11 +616,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; @@ -49,7 +58,7 @@ index 7a9e40b97831..5ed06240cc9c 100644 error = -EINVAL; -@@ -766,6 +784,7 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, +@@ -623,6 +641,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; @@ -57,7 +66,7 @@ index 7a9e40b97831..5ed06240cc9c 100644 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, +@@ -645,6 +664,8 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, * dependency. */ fput(old_file); @@ -65,25 +74,25 @@ index 7a9e40b97831..5ed06240cc9c 100644 + 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, + +@@ -658,6 +679,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; + goto done; } -@@ -1201,6 +1224,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode, +@@ -1039,6 +1062,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_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, + loff_t size; +@@ -1052,6 +1076,13 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode, /* This is safe, since we have a reference from open(). */ __module_get(THIS_MODULE); @@ -97,7 +106,7 @@ index 7a9e40b97831..5ed06240cc9c 100644 /* * 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, +@@ -1108,6 +1139,7 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode, lo->use_dio = lo->lo_flags & LO_FLAGS_DIRECT_IO; lo->lo_device = bdev; lo->lo_backing_file = file; @@ -105,7 +114,7 @@ index 7a9e40b97831..5ed06240cc9c 100644 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, +@@ -1150,6 +1182,8 @@ static int loop_configure(struct loop_device *lo, blk_mode_t mode, bd_abort_claiming(bdev, loop_configure); out_putf: fput(file); @@ -114,49 +123,34 @@ index 7a9e40b97831..5ed06240cc9c 100644 /* 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) +@@ -1159,11 +1193,13 @@ static void __loop_clr_fd(struct loop_device *lo) { - struct file *filp = NULL; + struct queue_limits lim; + struct file *filp; + 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); + filp = lo->lo_backing_file; 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) + lo->lo_device = NULL; +@@ -1225,6 +1261,8 @@ static void __loop_clr_fd(struct loop_device *lo) + * fput can take open_mutex which is usually taken before lo_mutex. */ - if (filp) - fput(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; - + static int loop_clr_fd(struct loop_device *lo) diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c -index 99ceca144044..e49dfe855032 100644 +index db7e9fcf1056a..6d202136d29af 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) +@@ -317,7 +317,7 @@ static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) if (IS_ERR(h_file)) goto out; @@ -166,7 +160,7 @@ index 99ceca144044..e49dfe855032 100644 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 +index 69dea4cda00c0..92a74affb2208 100644 --- a/fs/aufs/loop.c +++ b/fs/aufs/loop.c @@ -133,3 +133,19 @@ void au_loopback_fin(void) @@ -190,7 +184,7 @@ index 74347bd75b38..5ef888a1d53f 100644 + return f; +} diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h -index 7293bee427f9..3345c098d0d4 100644 +index 519efba31c700..ac701381da792 100644 --- a/fs/aufs/loop.h +++ b/fs/aufs/loop.h @@ -26,6 +26,8 @@ void au_warn_loopback(struct super_block *h_sb); @@ -212,7 +206,7 @@ index 7293bee427f9..3345c098d0d4 100644 #endif /* __KERNEL__ */ diff --git a/fs/aufs/super.c b/fs/aufs/super.c -index 90043afec51c..0835f6da42d9 100644 +index 9c30cba527421..8161108d0f6d5 100644 --- a/fs/aufs/super.c +++ b/fs/aufs/super.c @@ -758,7 +758,10 @@ const struct super_operations aufs_sop = { @@ -228,13 +222,14 @@ index 90043afec51c..0835f6da42d9 100644 /* ---------------------------------------------------------------------- */ diff --git a/include/linux/fs.h b/include/linux/fs.h -index e60d8ad85400..2ac5317f9b79 100644 +index 51b64b2ad82c4..8c3ff295b020b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -2226,6 +2226,10 @@ struct super_operations { - struct shrink_control *); +@@ -2248,6 +2248,11 @@ struct super_operations { long (*free_cached_objects)(struct super_block *, struct shrink_control *); + void (*shutdown)(struct super_block *sb); ++ +#if IS_ENABLED(CONFIG_BLK_DEV_LOOP) || IS_ENABLED(CONFIG_BLK_DEV_LOOP_MODULE) + /* and aufs */ + struct file *(*real_loop)(struct file *); diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-mmap.patch b/kernel/tools/perf/files/patches/aufs6/aufs6-mmap.patch similarity index 64% rename from kernel/tools/perf/files/patches/aufs5/aufs5-mmap.patch rename to kernel/tools/perf/files/patches/aufs6/aufs6-mmap.patch index 05ee1b401b..879079c95c 100644 --- a/kernel/tools/perf/files/patches/aufs5/aufs5-mmap.patch +++ b/kernel/tools/perf/files/patches/aufs6/aufs6-mmap.patch @@ -1,24 +1,24 @@ SPDX-License-Identifier: GPL-2.0 -aufs5.15.41 mmap patch +aufs6.12 mmap patch diff --git a/fs/proc/base.c b/fs/proc/base.c -index 1f394095eb88..93f2479ef319 100644 +index b31283d81c52e..644bd3d84cf76 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) +@@ -2270,7 +2270,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 = *file_user_path(vma->vm_file); + *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 +index c6e7ebc637562..d7ccfd9097646 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) +@@ -39,7 +39,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) file = region->vm_file; if (file) { @@ -31,35 +31,43 @@ index 13452b32e2bd..38acccfef9d4 100644 ino = inode->i_ino; } diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c -index 79ca4d69dfd6..3d3067c8d868 100644 +index 7eb010de39fe2..0c576103f7f15 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; +@@ -264,7 +264,8 @@ static void get_vma_name(struct vm_area_struct *vma, + *name_fmt = "[anon_shmem:%s]"; + *name = anon_name->name; + } else { +- *path = file_user_path(vma->vm_file); ++ struct file *f = vma_pr_or_file(vma); ++ *path = file_user_path(f); + } + return; + } +@@ -333,7 +334,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) + dev_t dev = 0; + + if (vma->vm_file) { +- const struct inode *inode = file_user_inode(vma->vm_file); ++ const struct inode *inode ++ = file_inode(vma_pr_or_file(vma)); - 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) +@@ -3008,7 +3010,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]; + struct mempolicy *pol; diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c -index a6d21fc0033c..02c2de31196e 100644 +index bce6745330003..b12b5a75c799c 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) +@@ -137,7 +137,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) file = vma->vm_file; if (file) { @@ -72,14 +80,14 @@ index a6d21fc0033c..02c2de31196e 100644 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 04345ff97f8c..4ab9bb75c894 100644 +index 61fff5d34ed53..94b66987b4bb0 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); - } +@@ -2469,6 +2469,43 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, + static inline struct vm_area_struct *vma_lookup(struct mm_struct *mm, + unsigned long addr); -+#if IS_ENABLED(CONFIG_AUFS_FS) ++#if 1 /* 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); @@ -120,172 +128,148 @@ index 04345ff97f8c..4ab9bb75c894 100644 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 +index 6e3bdf8e38bca..c70247dc71022 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h -@@ -294,6 +294,9 @@ struct vm_region { +@@ -572,6 +572,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) ++#if 1 /* 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 { +@@ -747,6 +750,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) ++#if 1 /* 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 + #ifdef CONFIG_ANON_VMA_NAME diff --git a/kernel/fork.c b/kernel/fork.c -index 89475c994ca9..82f46f8f4090 100644 +index 22f43721d031d..03abd72b3353d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c -@@ -573,7 +573,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, +@@ -730,7 +730,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) + if (vma_is_shared_maywrite(tmp)) mapping_allow_writable(mapping); diff --git a/mm/Makefile b/mm/Makefile -index fc60a40ce954..d45773672730 100644 +index d5639b0361663..bb57f616f0325 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 +@@ -145,3 +145,4 @@ obj-$(CONFIG_GENERIC_IOREMAP) += ioremap.o + obj-$(CONFIG_SHRINKER_DEBUG) += shrinker_debug.o + obj-$(CONFIG_EXECMEM) += execmem.o + obj-$(CONFIG_TMPFS_QUOTA) += shmem_quota.o ++obj-y += prfile.o diff --git a/mm/filemap.c b/mm/filemap.c -index 00e391e75880..d8b52d814319 100644 +index 56fa431c52af7..d55fe4e7bcfd1 100644 --- a/mm/filemap.c +++ b/mm/filemap.c -@@ -3353,7 +3353,7 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) +@@ -3707,7 +3707,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); + folio_lock(folio); + if (folio->mapping != mapping) { + folio_unlock(folio); diff --git a/mm/mmap.c b/mm/mmap.c -index 6bb553ed5c55..3f9d6d155171 100644 +index 79d541f1502b2..2dc64f6dc0181 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; +@@ -1484,7 +1484,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, + * and cause general protection fault + * ultimately. + */ +- fput(vma->vm_file); ++ vma_fput(vma); + vm_area_free(vma); + vma = merge; + /* Update vm_flags to pick up the change. */ +@@ -1654,6 +1654,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, unsigned long ret = -EINVAL; struct file *file; -+#if IS_ENABLED(CONFIG_AUFS_FS) -+ struct file *prfile; -+#endif + vm_flags_t vm_flags; ++ struct file *prfile = NULL; /* aufs */ - pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", + pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/mm/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; +@@ -1696,14 +1697,18 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, -+#if IS_ENABLED(CONFIG_AUFS_FS) + /* Save vm_flags used to calculate prot and flags, and recheck later. */ + vm_flags = vma->vm_flags; +- file = get_file(vma->vm_file); + vma_get_file(vma); + file = vma->vm_file; ++#if 1 /* IS_ENABLED(CONFIG_AUFS_FS) */ + prfile = vma->vm_prfile; -+ ret = do_mmap(vma->vm_file, start, size, -+ prot, flags, pgoff, &populate, NULL); ++#endif + + mmap_read_unlock(mm); + + /* Call outside mmap_lock to be consistent with other callers. */ + ret = security_mmap_file(file, prot, flags); + if (ret) { +- fput(file); ++ vma_fput(vma); + return ret; + } + +@@ -1711,7 +1716,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + + /* OK security check passed, take write lock + let it rip. */ + if (mmap_write_lock_killable(mm)) { +- fput(file); ++ vma_fput(vma); + return -EINTR; + } + +@@ -1753,9 +1758,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + + ret = do_mmap(vma->vm_file, start, size, + prot, flags, 0, pgoff, &populate, NULL); ++#if 1 /* IS_ENABLED(CONFIG_AUFS_FS) */ + 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) ++ if (prfile) + get_file(prfile); + } ++#endif ++ + out: + mmap_write_unlock(mm); + /* + * two fput()s instead of vma_fput(vma), + * coz vma may not be available anymore. + */ -+ fput(file); + 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); + mm_populate(ret, populate); + if (!IS_ERR_VALUE(ret)) diff --git a/mm/nommu.c b/mm/nommu.c -index 02d2427b8f9e..a7419302ab4e 100644 +index 9cb6e99215e2b..5add36afa9786 100644 --- a/mm/nommu.c +++ b/mm/nommu.c -@@ -523,7 +523,7 @@ static void __put_nommu_region(struct vm_region *region) +@@ -512,7 +512,7 @@ static void __put_nommu_region(struct vm_region *region) up_write(&nommu_region_sem); if (region->vm_file) @@ -294,16 +278,16 @@ index 02d2427b8f9e..a7419302ab4e 100644 /* 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); +@@ -591,7 +591,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) + { + vma_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, +@@ -1123,7 +1123,7 @@ unsigned long do_mmap(struct file *file, goto error_just_free; } } @@ -312,9 +296,9 @@ index 02d2427b8f9e..a7419302ab4e 100644 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); +@@ -1209,10 +1209,10 @@ unsigned long do_mmap(struct file *file, error: + vma_iter_free(&vmi); if (region->vm_file) - fput(region->vm_file); + vmr_fput(region); @@ -327,7 +311,7 @@ index 02d2427b8f9e..a7419302ab4e 100644 diff --git a/mm/prfile.c b/mm/prfile.c new file mode 100644 -index 000000000000..511543ab1b41 +index 0000000000000..b034d160a18f4 --- /dev/null +++ b/mm/prfile.c @@ -0,0 +1,86 @@ @@ -339,7 +323,7 @@ index 000000000000..511543ab1b41 + * + * See Documentation/filesystems/aufs/design/06mmap.txt + * -+ * Copyright (c) 2014-2021 Junjro R. Okajima ++ * Copyright (c) 2014-2025 Junjro R. Okajima + * Copyright (c) 2014 Ian Campbell + */ + @@ -417,3 +401,52 @@ index 000000000000..511543ab1b41 + fput(pr); +} +#endif /* !CONFIG_MMU */ +diff --git a/mm/vma.c b/mm/vma.c +index 7621384d64cf5..3bb41fe6ac48e 100644 +--- a/mm/vma.c ++++ b/mm/vma.c +@@ -248,7 +248,7 @@ static void vma_complete(struct vma_prepare *vp, struct vma_iterator *vmi, + if (vp->file) { + uprobe_munmap(vp->remove, vp->remove->vm_start, + vp->remove->vm_end); +- fput(vp->file); ++ vma_fput(vp->vma); + } + if (vp->remove->anon_vma) + anon_vma_merge(vp->vma, vp->remove); +@@ -328,7 +328,7 @@ void remove_vma(struct vm_area_struct *vma, bool unreachable) + might_sleep(); + vma_close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + mpol_put(vma_policy(vma)); + if (unreachable) + __vm_area_free(vma); +@@ -405,7 +405,7 @@ static int __split_vma(struct vma_iterator *vmi, 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); +@@ -1671,7 +1671,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); + if (vma_link(mm, new_vma)) +@@ -1684,7 +1684,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, + vma_close(new_vma); + + if (new_vma->vm_file) +- fput(new_vma->vm_file); ++ vma_fput(new_vma); + + unlink_anon_vmas(new_vma); + out_free_mempol: diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5-standalone.patch b/kernel/tools/perf/files/patches/aufs6/aufs6-standalone.patch similarity index 51% rename from kernel/tools/perf/files/patches/aufs5/aufs5-standalone.patch rename to kernel/tools/perf/files/patches/aufs6/aufs6-standalone.patch index 54fcb65bd3..828406cc5b 100644 --- a/kernel/tools/perf/files/patches/aufs5/aufs5-standalone.patch +++ b/kernel/tools/perf/files/patches/aufs6/aufs6-standalone.patch @@ -1,11 +1,11 @@ SPDX-License-Identifier: GPL-2.0 -aufs5.15.41 standalone patch +aufs6.12 standalone patch diff --git a/fs/dcache.c b/fs/dcache.c -index bc5095b734f5..9508bd57a3bc 100644 +index 1ab11cad60e8c..3a01c42c6639e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c -@@ -1425,6 +1425,7 @@ void d_walk(struct dentry *parent, void *data, +@@ -1333,6 +1333,7 @@ void d_walk(struct dentry *parent, void *data, seq = 1; goto again; } @@ -13,7 +13,7 @@ index bc5095b734f5..9508bd57a3bc 100644 struct check_mount { struct vfsmount *mnt; -@@ -2970,6 +2971,7 @@ void d_exchange(struct dentry *dentry1, struct dentry *dentry2) +@@ -2899,6 +2900,7 @@ void d_exchange(struct dentry *dentry1, struct dentry *dentry2) write_sequnlock(&rename_lock); } @@ -22,10 +22,10 @@ index bc5095b734f5..9508bd57a3bc 100644 /** * d_ancestor - search for an ancestor diff --git a/fs/exec.c b/fs/exec.c -index 29e865c59854..3ea36fa14622 100644 +index 6c53920795c2e..22e10087e34fa 100644 --- a/fs/exec.c +++ b/fs/exec.c -@@ -111,6 +111,7 @@ bool path_noexec(const struct path *path) +@@ -114,6 +114,7 @@ bool path_noexec(const struct path *path) return (path->mnt->mnt_flags & MNT_NOEXEC) || (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); } @@ -34,22 +34,22 @@ index 29e865c59854..3ea36fa14622 100644 #ifdef CONFIG_USELIB /* diff --git a/fs/fcntl.c b/fs/fcntl.c -index 02382fa9bd34..3418c60b9014 100644 +index 460791727fd9c..75ab59a3df36f 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c -@@ -86,6 +86,7 @@ int setfl(int fd, struct file *filp, unsigned long arg) +@@ -90,6 +90,7 @@ int setfl(int fd, struct file * filp, unsigned int arg) out: return error; } +EXPORT_SYMBOL_GPL(setfl); - static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, - int force) + /* + * Allocate an file->f_owner struct if it doesn't exist, handling racing diff --git a/fs/file_table.c b/fs/file_table.c -index e8c9016703ad..5e7a880830fb 100644 +index eed5ffad9997c..2f6bead424786 100644 --- a/fs/file_table.c +++ b/fs/file_table.c -@@ -161,6 +161,7 @@ struct file *alloc_empty_file(int flags, const struct cred *cred) +@@ -228,6 +228,7 @@ struct file *alloc_empty_file(int flags, const struct cred *cred) } return ERR_PTR(-ENFILE); } @@ -58,18 +58,10 @@ index e8c9016703ad..5e7a880830fb 100644 /* * 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 +index 85739e2d64c00..8aa96de6c151e 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) +@@ -971,6 +971,7 @@ int is_current_mnt_ns(struct vfsmount *mnt) { return check_mnt(real_mount(mnt)); } @@ -77,7 +69,23 @@ index c45740054bc7..d3d750635610 100644 /* * vfsmount lock must be held for write -@@ -2011,6 +2013,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, +@@ -2200,6 +2201,7 @@ struct vfsmount *collect_mounts(const struct path *path) + return ERR_CAST(tree); + return &tree->mnt; + } ++EXPORT_SYMBOL_GPL(collect_mounts); + + static void free_mnt_ns(struct mnt_namespace *); + static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *, bool); +@@ -2230,6 +2232,7 @@ void drop_collected_mounts(struct vfsmount *mnt) + unlock_mount_hash(); + namespace_unlock(); + } ++EXPORT_SYMBOL_GPL(drop_collected_mounts); + + bool has_locked_children(struct mount *mnt, struct dentry *dentry) + { +@@ -2301,6 +2304,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, } return 0; } @@ -86,7 +94,7 @@ index c45740054bc7..d3d750635610 100644 static void lock_mnt_tree(struct mount *mnt) { diff --git a/fs/notify/group.c b/fs/notify/group.c -index fb89c351295d..460ad19c2570 100644 +index 18446b7b0d495..09138e0b8a6a5 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -100,6 +100,7 @@ void fsnotify_get_group(struct fsnotify_group *group) @@ -98,10 +106,10 @@ index fb89c351295d..460ad19c2570 100644 /* * 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 +index 5da4df2f9b18a..6024098fc6444 100644 --- a/fs/open.c +++ b/fs/open.c -@@ -65,6 +65,7 @@ int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry, +@@ -66,6 +66,7 @@ int do_truncate(struct mnt_idmap *idmap, struct dentry *dentry, inode_unlock(dentry->d_inode); return ret; } @@ -110,10 +118,10 @@ index e0df1536eb69..81b2d7c83add 100644 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 +index 64dc24afdb3a7..ec1fd6aab1759 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) +@@ -576,6 +576,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) inc_syscr(current); return ret; } @@ -121,7 +129,7 @@ index af057c57bdc6..76017f8331fb 100644 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_ +@@ -691,6 +692,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ file_end_write(file); return ret; } @@ -130,30 +138,22 @@ index af057c57bdc6..76017f8331fb 100644 /* 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 +index b15fd6073b6d3..0fdb86c3813e2 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, +@@ -940,6 +940,7 @@ ssize_t 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 + * Indicate to the caller that there was a premature EOF when reading from the diff --git a/fs/xattr.c b/fs/xattr.c -index 5c8c5175b385..ff7e9ff774b7 100644 +index 05ec7e7d9e87e..e07ffa052dfb4 100644 --- a/fs/xattr.c +++ b/fs/xattr.c -@@ -384,6 +384,7 @@ vfs_getxattr_alloc(struct user_namespace *mnt_userns, struct dentry *dentry, +@@ -405,6 +405,7 @@ vfs_getxattr_alloc(struct mnt_idmap *idmap, struct dentry *dentry, *xattr_value = value; return error; } @@ -162,10 +162,10 @@ index 5c8c5175b385..ff7e9ff774b7 100644 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 +index 34b378cf7a95f..df6a751298b32 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) +@@ -239,6 +239,7 @@ inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) */ return lock_classes + class_idx; } @@ -174,79 +174,79 @@ index ce380d0abdf0..409c7d1a6803 100644 #ifdef CONFIG_LOCK_STAT diff --git a/kernel/task_work.c b/kernel/task_work.c -index 1698fbe6f0e1..081b05acadf8 100644 +index c969f1f26be58..68eb672f425d9 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c -@@ -167,3 +167,4 @@ void task_work_run(void) +@@ -242,3 +242,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 +index c5981e558bc26..045dd716e3400 100644 --- a/security/security.c +++ b/security/security.c -@@ -1160,6 +1160,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) +@@ -1944,6 +1944,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) return 0; - return call_int_hook(path_rmdir, 0, dir, dentry); + return call_int_hook(path_rmdir, 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, + /** + * security_path_unlink() - Check if removing a hard link is allowed +@@ -1979,6 +1980,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); + return call_int_hook(path_symlink, 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, + /** + * security_path_link - Check if creating a hard link is allowed +@@ -1997,6 +1999,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); + return call_int_hook(path_link, 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) + /** + * security_path_rename() - Check if renaming a file is allowed +@@ -2058,6 +2061,7 @@ int security_path_chmod(const struct path *path, umode_t mode) 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); + return call_int_hook(path_chmod, 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) + /** + * security_path_chown() - Check if changing the file's owner/group is allowed +@@ -2075,6 +2079,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); + return call_int_hook(path_chown, 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) + /** + * security_path_chroot() - Check if changing the root directory is allowed +@@ -2319,6 +2324,7 @@ int security_inode_permission(struct inode *inode, int mask) return 0; - return call_int_hook(inode_permission, 0, inode, mask); + return call_int_hook(inode_permission, inode, mask); } +EXPORT_SYMBOL_GPL(security_inode_permission); - int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + /** + * security_inode_setattr() - Check if setting file attributes is allowed +@@ -2840,6 +2846,7 @@ int security_file_permission(struct file *file, int mask) { -@@ -1522,6 +1529,7 @@ int security_file_permission(struct file *file, int mask) - - return fsnotify_perm(file, mask); + return call_int_hook(file_permission, file, mask); } +EXPORT_SYMBOL_GPL(security_file_permission); - int security_file_alloc(struct file *file) + /** + * security_file_alloc() - Allocate and init a file's LSM blob +@@ -3144,6 +3151,7 @@ int security_file_truncate(struct file *file) { + return call_int_hook(file_truncate, file); + } ++EXPORT_SYMBOL_GPL(security_file_truncate); + + /** + * security_task_alloc() - Allocate a task's LSM blob diff --git a/kernel/tools/perf/files/patches/aufs5/aufs5.15.41-20220620.patch b/kernel/tools/perf/files/patches/aufs6/aufs6.12-20250414.patch similarity index 94% rename from kernel/tools/perf/files/patches/aufs5/aufs5.15.41-20220620.patch rename to kernel/tools/perf/files/patches/aufs6/aufs6.12-20250414.patch index ab0613211c..d0af9e9652 100644 --- a/kernel/tools/perf/files/patches/aufs5/aufs5.15.41-20220620.patch +++ b/kernel/tools/perf/files/patches/aufs6/aufs6.12-20250414.patch @@ -1,6 +1,6 @@ -diff -Naur null/Documentation/ABI/testing/debugfs-aufs linux-5.15.41/Documentation/ABI/testing/debugfs-aufs +diff -Naur null/Documentation/ABI/testing/debugfs-aufs linux-6.12.30/Documentation/ABI/testing/debugfs-aufs --- /dev/null -+++ linux-5.15.41/Documentation/ABI/testing/debugfs-aufs 2022-09-06 12:51:51.030710012 +0300 ++++ linux-6.12.30/Documentation/ABI/testing/debugfs-aufs 2025-05-27 19:28:00.097257513 +0300 @@ -0,0 +1,55 @@ +What: /debug/aufs/si_/ +Date: March 2009 @@ -57,9 +57,9 @@ diff -Naur null/Documentation/ABI/testing/debugfs-aufs linux-5.15.41/Documentati + 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.41/Documentation/ABI/testing/sysfs-aufs +diff -Naur null/Documentation/ABI/testing/sysfs-aufs linux-6.12.30/Documentation/ABI/testing/sysfs-aufs --- /dev/null -+++ linux-5.15.41/Documentation/ABI/testing/sysfs-aufs 2022-09-06 12:51:51.030710012 +0300 ++++ linux-6.12.30/Documentation/ABI/testing/sysfs-aufs 2025-05-27 19:28:00.097257513 +0300 @@ -0,0 +1,31 @@ +What: /sys/fs/aufs/si_/ +Date: March 2009 @@ -92,23 +92,23 @@ diff -Naur null/Documentation/ABI/testing/sysfs-aufs linux-5.15.41/Documentation + 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.41/Documentation/filesystems/aufs/design/01intro.txt +diff -Naur null/Documentation/filesystems/aufs/design/01intro.txt linux-6.12.30/Documentation/filesystems/aufs/design/01intro.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/01intro.txt 2022-09-06 12:51:51.031709999 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/01intro.txt 2025-05-27 19:28:00.097257513 +0300 @@ -0,0 +1,171 @@ + -+# Copyright (C) 2005-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2005-2025 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 . + @@ -267,23 +267,23 @@ diff -Naur null/Documentation/filesystems/aufs/design/01intro.txt linux-5.15.41/ +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.41/Documentation/filesystems/aufs/design/02struct.txt +diff -Naur null/Documentation/filesystems/aufs/design/02struct.txt linux-6.12.30/Documentation/filesystems/aufs/design/02struct.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/02struct.txt 2022-09-06 12:51:51.031709999 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/02struct.txt 2025-05-27 19:28:00.097257513 +0300 @@ -0,0 +1,258 @@ + -+# Copyright (C) 2005-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2005-2025 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 . + @@ -529,23 +529,23 @@ diff -Naur null/Documentation/filesystems/aufs/design/02struct.txt linux-5.15.41 +- etc. + +For this purpose, use "aumvdown" command in aufs-util.git. -diff -Naur null/Documentation/filesystems/aufs/design/03atomic_open.txt linux-5.15.41/Documentation/filesystems/aufs/design/03atomic_open.txt +diff -Naur null/Documentation/filesystems/aufs/design/03atomic_open.txt linux-6.12.30/Documentation/filesystems/aufs/design/03atomic_open.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/03atomic_open.txt 2022-09-06 12:51:51.031709999 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/03atomic_open.txt 2025-05-27 19:28:00.097257513 +0300 @@ -0,0 +1,85 @@ + -+# Copyright (C) 2015-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2015-2025 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 . + @@ -618,23 +618,23 @@ diff -Naur null/Documentation/filesystems/aufs/design/03atomic_open.txt linux-5. + ->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.41/Documentation/filesystems/aufs/design/03lookup.txt +diff -Naur null/Documentation/filesystems/aufs/design/03lookup.txt linux-6.12.30/Documentation/filesystems/aufs/design/03lookup.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/03lookup.txt 2022-09-06 12:51:51.031709999 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/03lookup.txt 2025-05-27 19:28:00.097257513 +0300 @@ -0,0 +1,113 @@ + -+# Copyright (C) 2005-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2005-2025 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 . + @@ -735,23 +735,23 @@ diff -Naur null/Documentation/filesystems/aufs/design/03lookup.txt linux-5.15.41 + 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.41/Documentation/filesystems/aufs/design/04branch.txt +diff -Naur null/Documentation/filesystems/aufs/design/04branch.txt linux-6.12.30/Documentation/filesystems/aufs/design/04branch.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/04branch.txt 2022-09-06 12:51:51.031709999 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/04branch.txt 2025-05-27 19:28:00.098257501 +0300 @@ -0,0 +1,74 @@ + -+# Copyright (C) 2005-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2005-2025 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 . + @@ -813,23 +813,23 @@ diff -Naur null/Documentation/filesystems/aufs/design/04branch.txt linux-5.15.41 + - 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.41/Documentation/filesystems/aufs/design/05wbr_policy.txt +diff -Naur null/Documentation/filesystems/aufs/design/05wbr_policy.txt linux-6.12.30/Documentation/filesystems/aufs/design/05wbr_policy.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/05wbr_policy.txt 2022-09-06 12:51:51.032709987 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/05wbr_policy.txt 2025-05-27 19:28:00.098257501 +0300 @@ -0,0 +1,64 @@ + -+# Copyright (C) 2005-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2005-2025 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 . + @@ -881,12 +881,25 @@ diff -Naur null/Documentation/filesystems/aufs/design/05wbr_policy.txt linux-5.1 + 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.41/Documentation/filesystems/aufs/design/06dirren.dot +diff -Naur null/Documentation/filesystems/aufs/design/06dirren.dot linux-6.12.30/Documentation/filesystems/aufs/design/06dirren.dot --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/06dirren.dot 2022-09-06 12:51:51.032709987 +0300 -@@ -0,0 +1,31 @@ ++++ linux-6.12.30/Documentation/filesystems/aufs/design/06dirren.dot 2025-05-27 19:28:00.098257501 +0300 +@@ -0,0 +1,44 @@ + +// to view this graph, run dot(1) command in GRAPHVIZ. ++// ++// 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 . + +digraph G { +node [shape=box]; @@ -916,12 +929,12 @@ diff -Naur null/Documentation/filesystems/aufs/design/06dirren.dot linux-5.15.41 + +aufs_lookup -> whinfo [label="load/remove"]; +} -diff -Naur null/Documentation/filesystems/aufs/design/06dirren.txt linux-5.15.41/Documentation/filesystems/aufs/design/06dirren.txt +diff -Naur null/Documentation/filesystems/aufs/design/06dirren.txt linux-6.12.30/Documentation/filesystems/aufs/design/06dirren.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/06dirren.txt 2022-09-06 12:51:51.032709987 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/06dirren.txt 2025-05-27 19:28:00.098257501 +0300 @@ -0,0 +1,102 @@ + -+# Copyright (C) 2017-2021 Junjiro R. Okajima ++# Copyright (C) 2017-2025 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 @@ -1022,27 +1035,25 @@ diff -Naur null/Documentation/filesystems/aufs/design/06dirren.txt linux-5.15.41 +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.41/Documentation/filesystems/aufs/design/06fhsm.txt +diff -Naur null/Documentation/filesystems/aufs/design/06fhsm.txt linux-6.12.30/Documentation/filesystems/aufs/design/06fhsm.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/06fhsm.txt 2022-09-06 12:51:51.032709987 +0300 -@@ -0,0 +1,120 @@ ++++ linux-6.12.30/Documentation/filesystems/aufs/design/06fhsm.txt 2025-05-27 19:28:00.098257501 +0300 +@@ -0,0 +1,118 @@ + -+# Copyright (C) 2011-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2011-2025 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 -+ ++# along with this program. If not, see . + +File-based Hierarchical Storage Management (FHSM) +---------------------------------------------------------------------- @@ -1146,23 +1157,23 @@ diff -Naur null/Documentation/filesystems/aufs/design/06fhsm.txt linux-5.15.41/D + +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.41/Documentation/filesystems/aufs/design/06mmap.txt +diff -Naur null/Documentation/filesystems/aufs/design/06mmap.txt linux-6.12.30/Documentation/filesystems/aufs/design/06mmap.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/06mmap.txt 2022-09-06 12:51:51.032709987 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/06mmap.txt 2025-05-27 19:28:00.098257501 +0300 @@ -0,0 +1,72 @@ + -+# Copyright (C) 2005-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2005-2025 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 . + @@ -1222,12 +1233,12 @@ diff -Naur null/Documentation/filesystems/aufs/design/06mmap.txt linux-5.15.41/D + 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.41/Documentation/filesystems/aufs/design/06xattr.txt +diff -Naur null/Documentation/filesystems/aufs/design/06xattr.txt linux-6.12.30/Documentation/filesystems/aufs/design/06xattr.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/06xattr.txt 2022-09-06 12:51:51.032709987 +0300 -@@ -0,0 +1,96 @@ ++++ linux-6.12.30/Documentation/filesystems/aufs/design/06xattr.txt 2025-05-27 19:28:00.098257501 +0300 +@@ -0,0 +1,94 @@ + -+# Copyright (C) 2014-2021 Junjiro R. Okajima ++# Copyright (C) 2014-2025 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 @@ -1240,9 +1251,7 @@ diff -Naur null/Documentation/filesystems/aufs/design/06xattr.txt linux-5.15.41/ +# 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 -+ ++# along with this program. If not, see . + +Listing XATTR/EA and getting the value +---------------------------------------------------------------------- @@ -1322,23 +1331,23 @@ diff -Naur null/Documentation/filesystems/aufs/design/06xattr.txt linux-5.15.41/ +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.41/Documentation/filesystems/aufs/design/07export.txt +diff -Naur null/Documentation/filesystems/aufs/design/07export.txt linux-6.12.30/Documentation/filesystems/aufs/design/07export.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/07export.txt 2022-09-06 12:51:51.032709987 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/07export.txt 2025-05-27 19:28:00.098257501 +0300 @@ -0,0 +1,58 @@ + -+# Copyright (C) 2005-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2005-2025 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 . + @@ -1384,23 +1393,23 @@ diff -Naur null/Documentation/filesystems/aufs/design/07export.txt linux-5.15.41 + 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.41/Documentation/filesystems/aufs/design/08shwh.txt +diff -Naur null/Documentation/filesystems/aufs/design/08shwh.txt linux-6.12.30/Documentation/filesystems/aufs/design/08shwh.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/08shwh.txt 2022-09-06 12:51:51.032709987 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/08shwh.txt 2025-05-27 19:28:00.098257501 +0300 @@ -0,0 +1,52 @@ + -+# Copyright (C) 2005-2021 Junjiro R. Okajima -+# ++# Copyright (C) 2005-2025 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 . + @@ -1440,12 +1449,12 @@ diff -Naur null/Documentation/filesystems/aufs/design/08shwh.txt linux-5.15.41/D + +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.41/Documentation/filesystems/aufs/design/10dynop.txt +diff -Naur null/Documentation/filesystems/aufs/design/10dynop.txt linux-6.12.30/Documentation/filesystems/aufs/design/10dynop.txt --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/design/10dynop.txt 2022-09-06 12:51:51.032709987 +0300 ++++ linux-6.12.30/Documentation/filesystems/aufs/design/10dynop.txt 2025-05-27 19:28:00.098257501 +0300 @@ -0,0 +1,47 @@ + -+# Copyright (C) 2010-2021 Junjiro R. Okajima ++# Copyright (C) 2010-2025 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 @@ -1491,12 +1500,12 @@ diff -Naur null/Documentation/filesystems/aufs/design/10dynop.txt linux-5.15.41/ +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.41/Documentation/filesystems/aufs/README +diff -Naur null/Documentation/filesystems/aufs/README linux-6.12.30/Documentation/filesystems/aufs/README --- /dev/null -+++ linux-5.15.41/Documentation/filesystems/aufs/README 2022-09-06 12:51:51.031709999 +0300 -@@ -0,0 +1,397 @@ ++++ linux-6.12.30/Documentation/filesystems/aufs/README 2025-05-27 19:28:00.097257513 +0300 +@@ -0,0 +1,409 @@ + -+Aufs5 -- advanced multi layered unification filesystem version 5.x ++Aufs6 -- advanced multi layered unification filesystem version 6.x +http://aufs.sf.net +Junjiro R. Okajima + @@ -1512,13 +1521,19 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio +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, ++Aufs6 supports linux-v6.0 and later, try aufs6.0 branch in ++aufs-linux.git or aufs-standalone.git. ++If you want older kernel version support, ++- for linux-v5.x series, try aufs-linux.git or aufs-standalone.git +- 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: the name of aufs5-linux.git and aufs5-standalone.git on github ++ were changed. Now they are aufs-linux.git and ++ aufs-standalone.git and they contain aufs5 and later branches. ++ +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. @@ -1577,7 +1592,7 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio +- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. +- and more... + -+Currently these features are dropped temporary from aufs5. ++Currently these features are dropped temporary from aufs6. +See design/08plan.txt in detail. +- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs + (robr) @@ -1595,64 +1610,63 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio + +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. ++There are three GIT trees for aufs6, aufs-linux.git, ++aufs-standalone.git, and aufs-util.git. ++While the aufs-util is always necessary, you need either of aufs-linux ++or aufs-standalone. + -+The aufs5-linux tree includes the whole linux mainline GIT tree, ++The aufs-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. ++build aufs6 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 ++aufs-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 ++On the other hand, the aufs-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. ++You will find GIT branches whose name is in form of "aufs6.x" where "x" ++represents the linux kernel version, "linux-6.x". For instance, ++"aufs6.0" is for linux-6.0. For latest "linux-6.x-rcN", use ++"aufs6.x-rcN" branch. + -+o aufs5-linux tree ++o aufs-linux tree +$ git clone --reference /your/linux/git/tree \ -+ git://github.com/sfjro/aufs5-linux.git aufs5-linux.git ++ git://github.com/sfjro/aufs-linux.git aufs-linux.git +- if you don't have linux GIT tree, then remove "--reference ..." -+$ cd aufs5-linux.git -+$ git checkout origin/aufs5.0 ++$ cd aufs-linux.git ++$ git checkout origin/aufs6.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 ++$ git remote add aufs git://github.com/sfjro/aufs-linux.git ++$ git fetch aufs ++$ git checkout -b my6.0 v6.0 +$ (add your local change...) -+$ git pull aufs5 aufs5.0 -+- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch. ++$ git pull aufs aufs6.0 ++- now you have v6.0 + your_changes + aufs6.0 in you my6.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 ++ aufs6.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 6.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-standalone tree ++$ git clone git://github.com/sfjro/aufs-standalone.git aufs-standalone.git ++$ cd aufs-standalone.git ++$ git checkout origin/aufs6.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 ++$ git checkout origin/aufs6.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 ++Note: The 6.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '6.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. @@ -1664,8 +1678,8 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio +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" ++If you are using "linux-6.10" and the "aufs6.10" branch ++does not exist in aufs-util repository, then "aufs6.9", "aufs6.8" +or something numerically smaller is the branch for your kernel. + +Also you can view all branches by @@ -1676,7 +1690,7 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio +---------------------------------------- +Make sure you have git-checkout'ed the correct branch. + -+For aufs5-linux tree, ++For aufs-linux tree, +- enable CONFIG_AUFS_FS. +- set other aufs configurations if necessary. +- for aufs5.13 and later @@ -1689,16 +1703,18 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio + CONFIG_LOCKDEP_BITS=21 + CONFIG_LOCKDEP_CHAINS_BITS=21 + CONFIG_LOCKDEP_STACK_TRACE_BITS=24 ++ Also you will need to expand some constant values in LOCKDEP. Refer ++ to lockdep-debug.patch in aufs-standalone.git. + -+For aufs5-standalone tree, ++For aufs-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. ++- apply ./aufs6-kbuild.patch to your kernel source files. ++- apply ./aufs6-base.patch too. ++- apply ./aufs6-mmap.patch too. ++- apply ./aufs6-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs-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 @@ -1712,9 +1728,9 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio + +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. ++- apply ./aufs6-base.patch to your kernel source files. ++- apply ./aufs6-mmap.patch too. ++- apply ./aufs6-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 @@ -1730,7 +1746,7 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio + 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 ++- no need to apply aufs6-kbuild.patch, nor copying source files to your + kernel source tree. + +Note: The header file aufs_type.h is necessary to build aufs-util @@ -1750,9 +1766,9 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio + 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 ++There several other patches in aufs-standalone.git. They are all +optional. When you meet some problems, they will help you. -+- aufs5-loopback.patch ++- aufs6-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". @@ -1766,6 +1782,10 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio + 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. ++- lockdep-debug.patch ++ Similar to some kernel configurations for LOCKDEP (see the top of ++ this section), you will need expand some constants in LOCKDEP for ++ aufs if you enable CONFIG_LOCKDEP. + + +4. Usage @@ -1874,7 +1894,8 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio +James Burry made a donation (2016/12). +Carsten Rose made a donation (2018/9). +Porteus Kiosk made a donation (2018/10). -+Enya Quetzalli Gomez Rodriguez made a donation (2022/5). ++huronOS team: Enya Quetzalli made donations (2022/5, 2023/5, 8 and 2024/8). ++Vasily Mikhaylichenko made a donation (2023/5 and 2024/5). + +Thank you very much. +Donations are always, including future donations, very important and @@ -1892,15 +1913,15 @@ diff -Naur null/Documentation/filesystems/aufs/README linux-5.15.41/Documentatio +# Local variables: ; +# mode: text; +# End: ; -diff -Naur null/fs/aufs/aufs.h linux-5.15.41/fs/aufs/aufs.h +diff -Naur null/fs/aufs/aufs.h linux-6.12.30/fs/aufs/aufs.h --- /dev/null -+++ linux-5.15.41/fs/aufs/aufs.h 2022-09-06 12:51:51.034709962 +0300 ++++ linux-6.12.30/fs/aufs/aufs.h 2025-05-27 19:28:00.099257488 +0300 @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -1958,15 +1979,15 @@ diff -Naur null/fs/aufs/aufs.h linux-5.15.41/fs/aufs/aufs.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_H__ */ -diff -Naur null/fs/aufs/branch.c linux-5.15.41/fs/aufs/branch.c +diff -Naur null/fs/aufs/branch.c linux-6.12.30/fs/aufs/branch.c --- /dev/null -+++ linux-5.15.41/fs/aufs/branch.c 2022-09-06 12:51:51.034709962 +0300 ++++ linux-6.12.30/fs/aufs/branch.c 2025-05-27 19:28:00.100257476 +0300 @@ -0,0 +1,1427 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -2207,7 +2228,7 @@ diff -Naur null/fs/aufs/branch.c linux-5.15.41/fs/aufs/branch.c + + inode = d_inode(add->path.dentry); + err = -ENOENT; -+ if (unlikely(!inode->i_nlink)) { ++ if (unlikely(!vfsub_inode_nlink(inode, AU_I_UNKNOWN))) { + pr_err("no existence %s\n", add->pathname); + goto out; + } @@ -2457,14 +2478,14 @@ diff -Naur null/fs/aufs/branch.c linux-5.15.41/fs/aufs/branch.c + bbot = au_sbbot(sb); + amount = bbot + 1 - bindex; + h_dentry = au_br_dentry(br); -+ au_sbilist_lock(); ++ au_sbilist_write_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(); ++ au_sbilist_write_unlock(); +} + +int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) @@ -2942,11 +2963,11 @@ diff -Naur null/fs/aufs/branch.c linux-5.15.41/fs/aufs/branch.c + h_inode = au_igrab(hinode->hi_inode); + au_hiput(hinode); + -+ au_sbilist_lock(); ++ au_sbilist_write_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(); ++ au_sbilist_write_unlock(); + + /* ignore an error */ + au_dr_br_fin(sb, br); /* always, regardless the mount option */ @@ -3257,7 +3278,7 @@ diff -Naur null/fs/aufs/branch.c linux-5.15.41/fs/aufs/branch.c + if (hf->f_mode & FMODE_READ) + i_readcount_inc(h_inode); + put_write_access(h_inode); -+ __mnt_drop_write(hf->f_path.mnt); ++ mnt_put_write_access(hf->f_path.mnt); + } + } + @@ -3389,15 +3410,15 @@ diff -Naur null/fs/aufs/branch.c linux-5.15.41/fs/aufs/branch.c + + return err; +} -diff -Naur null/fs/aufs/branch.h linux-5.15.41/fs/aufs/branch.h +diff -Naur null/fs/aufs/branch.h linux-6.12.30/fs/aufs/branch.h --- /dev/null -+++ linux-5.15.41/fs/aufs/branch.h 2022-09-06 12:51:51.034709962 +0300 ++++ linux-6.12.30/fs/aufs/branch.h 2025-05-27 19:28:00.100257476 +0300 @@ -0,0 +1,375 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -3541,9 +3562,9 @@ diff -Naur null/fs/aufs/branch.h linux-5.15.41/fs/aufs/branch.h + return br->br_path.dentry; +} + -+static inline struct user_namespace *au_br_userns(struct au_branch *br) ++static inline struct mnt_idmap *au_br_idmap(struct au_branch *br) +{ -+ return mnt_user_ns(br->br_path.mnt); ++ return mnt_idmap(br->br_path.mnt); +} + +static inline struct super_block *au_br_sb(struct au_branch *br) @@ -3705,9 +3726,9 @@ diff -Naur null/fs/aufs/branch.h linux-5.15.41/fs/aufs/branch.h +} + +static inline -+struct user_namespace *au_sbr_userns(struct super_block *sb, aufs_bindex_t bindex) ++struct mnt_idmap *au_sbr_idmap(struct super_block *sb, aufs_bindex_t bindex) +{ -+ return au_br_userns(au_sbr(sb, bindex)); ++ return au_br_idmap(au_sbr(sb, bindex)); +} + +static inline @@ -3768,9 +3789,9 @@ diff -Naur null/fs/aufs/branch.h linux-5.15.41/fs/aufs/branch.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_BRANCH_H__ */ -diff -Naur null/fs/aufs/conf.mk linux-5.15.41/fs/aufs/conf.mk +diff -Naur null/fs/aufs/conf.mk linux-6.12.30/fs/aufs/conf.mk --- /dev/null -+++ linux-5.15.41/fs/aufs/conf.mk 2022-09-06 12:51:51.035709949 +0300 ++++ linux-6.12.30/fs/aufs/conf.mk 2025-05-27 19:28:00.100257476 +0300 @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0 + @@ -3812,15 +3833,15 @@ diff -Naur null/fs/aufs/conf.mk linux-5.15.41/fs/aufs/conf.mk +${obj}/sysfs.o: ${AuConfName} + +-include ${srctree}/${src}/conf_priv.mk -diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c +diff -Naur null/fs/aufs/cpup.c linux-6.12.30/fs/aufs/cpup.c --- /dev/null -+++ linux-5.15.41/fs/aufs/cpup.c 2022-09-06 12:51:51.035709949 +0300 -@@ -0,0 +1,1459 @@ ++++ linux-6.12.30/fs/aufs/cpup.c 2025-05-27 19:28:00.100257476 +0300 +@@ -0,0 +1,1458 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -3887,7 +3908,7 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause + * the incorrect link count. + */ -+ set_nlink(inode, h_inode->i_nlink); ++ vfsub_set_nlink(inode, vfsub_inode_nlink(h_inode, AU_I_BRANCH)); + + /* + * fewer nlink makes find(1) noisy, but larger nlink doesn't. @@ -3931,8 +3952,7 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + + 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); ++ 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); @@ -3951,8 +3971,8 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + 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; ++ dt->dt_atime = inode_get_atime(h_inode); ++ dt->dt_mtime = inode_get_mtime(h_inode); + /* smp_mb(); */ +} + @@ -4018,8 +4038,8 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + } 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; ++ ia.ia_atime = inode_get_atime(h_isrc); ++ ia.ia_mtime = inode_get_mtime(h_isrc); + if (h_idst->i_mode != h_isrc->i_mode + && !S_ISLNK(h_idst->i_mode)) { + ia.ia_valid |= ATTR_MODE; @@ -4361,7 +4381,7 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + goto out; + } + h_src_attr->valid = 1; -+ if (!au_test_nfs(h_src_inode->i_sb)) { ++ if (!au_test_fs_unlock_for_open(h_src_inode->i_sb)) { + err = au_cp_regular(cpg); + inode_unlock_shared(h_src_inode); + } else { @@ -4407,23 +4427,23 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + * 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) ++static int au_reset_acl(struct path *h_path, umode_t mode) +{ + int err; + struct dentry *h_dentry; -+ struct inode *h_inode; -+ struct user_namespace *h_userns; ++ /* struct inode *h_inode; */ ++ struct mnt_idmap *h_idmap; + -+ h_userns = mnt_user_ns(h_path->mnt); ++ h_idmap = mnt_idmap(h_path->mnt); + h_dentry = h_path->dentry; -+ h_inode = d_inode(h_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); ++ err = vfsub_remove_acl(h_idmap, 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); ++ err = vfsub_acl_chmod(h_idmap, h_dentry, mode); + + AuTraceErr(err); + return err; @@ -4434,11 +4454,11 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c +{ + int err; + struct inode *dir, *inode; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + -+ h_userns = mnt_user_ns(h_path->mnt); -+ err = vfsub_removexattr(h_userns, h_path->dentry, -+ XATTR_NAME_POSIX_ACL_DEFAULT); ++ h_idmap = mnt_idmap(h_path->mnt); ++ err = vfsub_remove_acl(h_idmap, h_path->dentry, ++ XATTR_NAME_POSIX_ACL_DEFAULT); + AuTraceErr(err); + if (err == -EOPNOTSUPP) + err = 0; @@ -4529,13 +4549,13 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + err = -EIO; + } + if (!err) -+ err = au_reset_acl(h_dir, &h_path, mode); ++ err = au_reset_acl(&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 ++ && (vfsub_inode_nlink(h_inode, AU_I_BRANCH) == 1 + || (h_inode->i_state & I_LINKABLE)) + /* todo: unnecessary? */ + /* && d_inode(cpg->dentry)->i_nlink == 1 */ @@ -4662,7 +4682,7 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + goto out_parent; + } + -+ if (dst_inode->i_nlink) { ++ if (vfsub_inode_nlink(dst_inode, AU_I_BRANCH)) { + const int do_dt = au_ftest_cpup(cpg->flags, DTIME); + + h_src = au_plink_lkup(inode, cpg->bdst); @@ -4747,7 +4767,7 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + + src_inode = d_inode(h_src); + if (!isdir -+ && (src_inode->i_nlink > 1 ++ && (vfsub_inode_nlink(src_inode, AU_I_BRANCH) > 1 + || src_inode->i_state & I_LINKABLE) + && plink) + au_plink_append(inode, cpg->bdst, h_dst); @@ -4917,7 +4937,7 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + struct dentry *dentry, *parent; + struct file *h_file; + struct inode *h_dir; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + dentry = cpg->dentry; + h_file = NULL; @@ -4931,8 +4951,8 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + + 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) ++ h_idmap = au_sbr_idmap(dentry->d_sb, cpg->bdst); ++ if (!au_test_h_perm_sio(h_idmap, h_dir, MAY_EXEC | MAY_WRITE) + && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) + err = au_cpup_simple(cpg); + else { @@ -5102,7 +5122,7 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + struct inode *dir, *h_dir, *h_tmpdir; + struct au_wbr *wbr; + struct au_pin wh_pin, *pin_orig; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + dentry = cpg->dentry; + bdst = cpg->bdst; @@ -5113,7 +5133,7 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + h_dir = au_igrab(au_h_iptr(dir, bdst)); + h_tmpdir = h_dir; + pin_orig = NULL; -+ if (!h_dir->i_nlink) { ++ if (!vfsub_inode_nlink(h_dir, AU_I_BRANCH)) { + wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; + h_orph = wbr->wbr_orph; + @@ -5131,8 +5151,8 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + 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) ++ h_idmap = au_sbr_idmap(dentry->d_sb, bdst); ++ if (!au_test_h_perm_sio(h_idmap, h_tmpdir, MAY_EXEC | MAY_WRITE) + && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) + err = au_cpup_wh(cpg, file); + else { @@ -5275,15 +5295,15 @@ diff -Naur null/fs/aufs/cpup.c linux-5.15.41/fs/aufs/cpup.c + dput(parent); + return err; +} -diff -Naur null/fs/aufs/cpup.h linux-5.15.41/fs/aufs/cpup.h +diff -Naur null/fs/aufs/cpup.h linux-6.12.30/fs/aufs/cpup.h --- /dev/null -+++ linux-5.15.41/fs/aufs/cpup.h 2022-09-06 12:51:51.035709949 +0300 -@@ -0,0 +1,100 @@ ++++ linux-6.12.30/fs/aufs/cpup.h 2025-05-27 19:28:00.100257476 +0300 +@@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -5307,6 +5327,7 @@ diff -Naur null/fs/aufs/cpup.h linux-5.15.41/fs/aufs/cpup.h +#ifdef __KERNEL__ + +#include ++#include + +struct inode; +struct file; @@ -5330,15 +5351,15 @@ diff -Naur null/fs/aufs/cpup.h linux-5.15.41/fs/aufs/cpup.h +}; + +/* cpup flags */ -+#define AuCpup_DTIME 1 /* do dtime_store/revert */ -+#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, ++#define AuCpup_DTIME BIT(0) /* do dtime_store/revert */ ++#define AuCpup_KEEPLINO BIT(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 ++#define AuCpup_RENAME BIT(2) /* rename after cpup */ ++#define AuCpup_HOPEN BIT(3) /* call h_open_pre/post() in + cpup */ -+#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the ++#define AuCpup_OVERWRITE BIT(4) /* allow overwriting the + existing entry */ -+#define AuCpup_RWDST (1 << 5) /* force write target even if ++#define AuCpup_RWDST BIT(5) /* force write target even if + the branch is marked as RO */ + +#ifndef CONFIG_AUFS_BR_HFSPLUS @@ -5379,15 +5400,15 @@ diff -Naur null/fs/aufs/cpup.h linux-5.15.41/fs/aufs/cpup.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_CPUP_H__ */ -diff -Naur null/fs/aufs/dbgaufs.c linux-5.15.41/fs/aufs/dbgaufs.c +diff -Naur null/fs/aufs/dbgaufs.c linux-6.12.30/fs/aufs/dbgaufs.c --- /dev/null -+++ linux-5.15.41/fs/aufs/dbgaufs.c 2022-09-06 12:51:51.035709949 +0300 ++++ linux-6.12.30/fs/aufs/dbgaufs.c 2025-05-27 19:28:00.100257476 +0300 @@ -0,0 +1,526 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -5549,7 +5570,7 @@ diff -Naur null/fs/aufs/dbgaufs.c linux-5.15.41/fs/aufs/dbgaufs.c + } else { +#define str "1\n0\n0\n" + p->n = sizeof(str) - 1; -+ strcpy(p->a, str); ++ strscpy(p->a, str, sizeof(str)); +#undef str + } + si_read_unlock(sb); @@ -5909,15 +5930,15 @@ diff -Naur null/fs/aufs/dbgaufs.c linux-5.15.41/fs/aufs/dbgaufs.c + err = 0; + return err; +} -diff -Naur null/fs/aufs/dbgaufs.h linux-5.15.41/fs/aufs/dbgaufs.h +diff -Naur null/fs/aufs/dbgaufs.h linux-6.12.30/fs/aufs/dbgaufs.h --- /dev/null -+++ linux-5.15.41/fs/aufs/dbgaufs.h 2022-09-06 12:51:51.035709949 +0300 ++++ linux-6.12.30/fs/aufs/dbgaufs.h 2025-05-27 19:28:00.100257476 +0300 @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -5966,15 +5987,15 @@ diff -Naur null/fs/aufs/dbgaufs.h linux-5.15.41/fs/aufs/dbgaufs.h + +#endif /* __KERNEL__ */ +#endif /* __DBGAUFS_H__ */ -diff -Naur null/fs/aufs/dcsub.c linux-5.15.41/fs/aufs/dcsub.c +diff -Naur null/fs/aufs/dcsub.c linux-6.12.30/fs/aufs/dcsub.c --- /dev/null -+++ linux-5.15.41/fs/aufs/dcsub.c 2022-09-06 12:51:51.035709949 +0300 ++++ linux-6.12.30/fs/aufs/dcsub.c 2025-05-27 19:28:00.100257476 +0300 @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -6195,15 +6216,15 @@ diff -Naur null/fs/aufs/dcsub.c linux-5.15.41/fs/aufs/dcsub.c + + return path_is_under(path + 0, path + 1); +} -diff -Naur null/fs/aufs/dcsub.h linux-5.15.41/fs/aufs/dcsub.h +diff -Naur null/fs/aufs/dcsub.h linux-6.12.30/fs/aufs/dcsub.h --- /dev/null -+++ linux-5.15.41/fs/aufs/dcsub.h 2022-09-06 12:51:51.035709949 +0300 -@@ -0,0 +1,137 @@ ++++ linux-6.12.30/fs/aufs/dcsub.h 2025-05-27 19:28:00.100257476 +0300 +@@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -6228,6 +6249,7 @@ diff -Naur null/fs/aufs/dcsub.h linux-5.15.41/fs/aufs/dcsub.h + +#include +#include ++#include "vfsub.h" + +struct au_dpage { + int ndentry; @@ -6268,7 +6290,8 @@ diff -Naur null/fs/aufs/dcsub.h linux-5.15.41/fs/aufs/dcsub.h + err = 0; + if (unlikely(d_unhashed(d) + || d_is_negative(d) -+ || !inode->i_nlink)) ++ /* to support both aufs and branches */ ++ || !vfsub_inode_nlink(inode, AU_I_UNKNOWN))) + err = -ENOENT; + return err; +} @@ -6298,7 +6321,7 @@ diff -Naur null/fs/aufs/dcsub.h linux-5.15.41/fs/aufs/dcsub.h + inode = d_inode(d); + if (unlikely(d_unlinked(d) + || d_is_negative(d) -+ || !inode->i_nlink)) ++ || !vfsub_inode_nlink(inode, AU_I_UNKNOWN))) + err = -ENOENT; + } + return err; @@ -6336,15 +6359,15 @@ diff -Naur null/fs/aufs/dcsub.h linux-5.15.41/fs/aufs/dcsub.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DCSUB_H__ */ -diff -Naur null/fs/aufs/debug.c linux-5.15.41/fs/aufs/debug.c +diff -Naur null/fs/aufs/debug.c linux-6.12.30/fs/aufs/debug.c --- /dev/null -+++ linux-5.15.41/fs/aufs/debug.c 2022-09-06 12:51:51.036709937 +0300 -@@ -0,0 +1,444 @@ ++++ linux-6.12.30/fs/aufs/debug.c 2025-05-27 19:28:00.101257463 +0300 +@@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -6454,6 +6477,7 @@ diff -Naur null/fs/aufs/debug.c linux-5.15.41/fs/aufs/debug.c +{ + char *n = NULL; + int l = 0; ++ struct timespec64 ctime; + + if (!inode || IS_ERR(inode)) { + dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); @@ -6468,13 +6492,16 @@ diff -Naur null/fs/aufs/debug.c linux-5.15.41/fs/aufs/debug.c + 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", ++ ctime = inode_get_ctime(inode); ++ dpri("i%d: %p, i%lu, %s, cnt %d, nl %u?, 0%o, sz %llu, blk %llu," ++ " acl %p, def_acl %p," ++ " hn %d, ct %lld, np %lu, st 0x%x, 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_acl, inode->i_default_acl, ++ hn, (long long)timespec64_to_ns(&ctime) & 0x0ffff, + inode->i_mapping ? inode->i_mapping->nrpages : 0, + inode->i_state, inode->i_flags, inode_peek_iversion(inode), + inode->i_generation, @@ -6590,9 +6617,9 @@ diff -Naur null/fs/aufs/debug.c linux-5.15.41/fs/aufs/debug.c + && 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", ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, pos %llu%s\n", + bindex, file->f_mode, file->f_flags, (long)file_count(file), -+ file->f_version, file->f_pos, a); ++ file->f_pos, a); + if (!IS_ERR_OR_NULL(file->f_path.dentry)) + do_pri_dentry(bindex, file->f_path.dentry); + return 0; @@ -6784,15 +6811,15 @@ diff -Naur null/fs/aufs/debug.c linux-5.15.41/fs/aufs/debug.c + + return 0; +} -diff -Naur null/fs/aufs/debug.h linux-5.15.41/fs/aufs/debug.h +diff -Naur null/fs/aufs/debug.h linux-6.12.30/fs/aufs/debug.h --- /dev/null -+++ linux-5.15.41/fs/aufs/debug.h 2022-09-06 12:51:51.036709937 +0300 ++++ linux-6.12.30/fs/aufs/debug.h 2025-05-27 19:28:00.101257463 +0300 @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -6839,7 +6866,7 @@ diff -Naur null/fs/aufs/debug.h linux-5.15.41/fs/aufs/debug.h + return atomic_read(&aufs_debug) > 0; +} +#else -+#define AuDebugOn(a) do {} while (0) ++AuStubVoid(AuDebugOn, bool expr __maybe_unused) +AuStubVoid(au_debug_on, void) +AuStubVoid(au_debug_off, void) +AuStubInt0(au_debug_test, void) @@ -6898,14 +6925,14 @@ diff -Naur null/fs/aufs/debug.h linux-5.15.41/fs/aufs/debug.h +/* ---------------------------------------------------------------------- */ + +struct dentry; ++struct inode; ++struct au_nhash; ++struct au_vdir; +#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); @@ -6981,14 +7008,14 @@ diff -Naur null/fs/aufs/debug.h linux-5.15.41/fs/aufs/debug.h +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) ++AuStubVoid(AuDbgWhlist, struct au_nhash *whlist) ++AuStubVoid(AuDbgVdir, struct au_vdir *vdir) ++AuStubVoid(AuDbgInode, struct inode *inode) ++AuStubVoid(AuDbgDAlias, struct inode *inode) ++AuStubVoid(AuDbgDentry, struct dentry *dentry) ++AuStubVoid(AuDbgFile, struct file *filp) ++AuStubVoid(AuDbgSb, struct super_block *sb) ++AuStubVoid(AuDbgSym, void *addr) +#endif /* CONFIG_AUFS_DEBUG */ + +/* ---------------------------------------------------------------------- */ @@ -7014,15 +7041,15 @@ diff -Naur null/fs/aufs/debug.h linux-5.15.41/fs/aufs/debug.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DEBUG_H__ */ -diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c +diff -Naur null/fs/aufs/dentry.c linux-6.12.30/fs/aufs/dentry.c --- /dev/null -+++ linux-5.15.41/fs/aufs/dentry.c 2022-09-06 12:51:51.036709937 +0300 -@@ -0,0 +1,1168 @@ ++++ linux-6.12.30/fs/aufs/dentry.c 2025-05-27 19:28:00.101257463 +0300 +@@ -0,0 +1,1176 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -7054,7 +7081,7 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + struct dentry *h_dentry; + struct inode *h_inode; + struct au_branch *br; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + struct path h_path; + int wh_found, opq; + unsigned char wh_able; @@ -7066,10 +7093,10 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + 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); ++ h_idmap = au_br_idmap(br); + wh_able = !!au_br_whable(br->br_perm); + if (wh_able) -+ wh_found = au_wh_test(h_userns, &h_path, &args->whname, ++ wh_found = au_wh_test(h_idmap, &h_path, &args->whname, + ignore_perm); + h_dentry = ERR_PTR(wh_found); + if (!wh_found) @@ -7087,7 +7114,7 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + 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); ++ h_dentry = au_sio_lkup_one(h_idmap, args->name, &h_path); + if (IS_ERR(h_dentry)) { + if (PTR_ERR(h_dentry) == -ENAMETOOLONG + && !allow_neg) @@ -7123,7 +7150,7 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + + h_path.dentry = h_dentry; + inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); -+ opq = au_diropq_test(h_userns, &h_path); ++ opq = au_diropq_test(h_idmap, &h_path); + inode_unlock_shared(h_inode); + if (opq > 0) + au_set_dbdiropq(dentry, bindex); @@ -7268,13 +7295,13 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + return err; +} + -+struct dentry *au_sio_lkup_one(struct user_namespace *userns, struct qstr *name, ++struct dentry *au_sio_lkup_one(struct mnt_idmap *idmap, 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)) ++ if (!au_test_h_perm_sio(idmap, d_inode(ppath->dentry), MAY_EXEC)) + dentry = vfsub_lkup_one(name, ppath); + else { + struct vfsub_lkup_one_args args = { @@ -7299,18 +7326,18 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + int err; + struct dentry *parent, *h_dentry; + struct au_branch *br; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + 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); ++ h_idmap = au_br_idmap(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); ++ h_dentry = au_sio_lkup_one(h_idmap, &dentry->d_name, &h_ppath); + err = PTR_ERR(h_dentry); + if (IS_ERR(h_dentry)) + goto out; @@ -7526,10 +7553,11 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + 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); ++ if (vfsub_inode_nlink(inode, AU_I_AUFS) ++ && !d_unhashed(dentry)) ++ vfsub_drop_nlink(inode); + } else { -+ clear_nlink(inode); ++ vfsub_clear_nlink(inode); + /* stop next lookup */ + inode->i_flags |= S_DEAD; + } @@ -7884,7 +7912,7 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c +{ + int err; + umode_t mode, h_mode; -+ aufs_bindex_t bindex, btail, btop, ibs, ibe; ++ aufs_bindex_t bindex, btail, btop, ibs, ibe, bwh; + unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; + struct inode *h_inode, *h_cached_inode; + struct dentry *h_dentry; @@ -7909,17 +7937,23 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + */ + if (do_udba && inode) { + mode = (inode->i_mode & S_IFMT); -+ plus = (inode->i_nlink > 0); ++ plus = (vfsub_inode_nlink(inode, AU_I_AUFS) > 0); + ibs = au_ibtop(inode); + ibe = au_ibbot(inode); + } + + btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ if (0 <= bwh && bwh < btop) ++ btop = bwh; + 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 ++ && (bindex == bwh && inode)) ++ h_dentry = au_hi_wh(inode, bindex); + if (!h_dentry) + continue; + @@ -7928,6 +7962,7 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + spin_lock(&h_dentry->d_lock); + h_name = &h_dentry->d_name; + if (unlikely(do_udba ++ && bindex != bwh + && !is_root + && ((!h_nfs + && (unhashed != !!d_unhashed(h_dentry) @@ -7968,9 +8003,9 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + h_plus = plus; + h_mode = mode; + h_cached_inode = h_inode; -+ if (h_inode) { ++ if (h_inode && bindex != bwh) { + h_mode = (h_inode->i_mode & S_IFMT); -+ h_plus = (h_inode->i_nlink > 0); ++ h_plus = (vfsub_inode_nlink(h_inode, AU_I_BRANCH) > 0); + } + if (inode && ibs <= bindex && bindex <= ibe) + h_cached_inode = au_h_iptr(inode, bindex); @@ -8126,7 +8161,7 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c + if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) + && inode + && !(inode->i_state && I_LINKABLE) -+ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ && (IS_DEADDIR(inode) || !vfsub_inode_nlink(inode, AU_I_AUFS))) { + AuTraceErr(err); + goto out_inval; + } @@ -8186,15 +8221,15 @@ diff -Naur null/fs/aufs/dentry.c linux-5.15.41/fs/aufs/dentry.c +const struct dentry_operations aufs_dop_noreval = { + .d_release = aufs_d_release +}; -diff -Naur null/fs/aufs/dentry.h linux-5.15.41/fs/aufs/dentry.h +diff -Naur null/fs/aufs/dentry.h linux-6.12.30/fs/aufs/dentry.h --- /dev/null -+++ linux-5.15.41/fs/aufs/dentry.h 2022-09-06 12:51:51.036709937 +0300 -@@ -0,0 +1,269 @@ ++++ linux-6.12.30/fs/aufs/dentry.h 2025-05-27 19:28:00.101257463 +0300 +@@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -8233,15 +8268,16 @@ diff -Naur null/fs/aufs/dentry.h linux-5.15.41/fs/aufs/dentry.h + 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 file *di_htmpfile; + 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 AuLkup_ALLOW_NEG BIT(0) ++#define AuLkup_IGNORE_PERM BIT(1) ++#define AuLkup_DIRREN BIT(2) +#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) +#define au_fset_lkup(flags, name) \ + do { (flags) |= AuLkup_##name; } while (0) @@ -8265,7 +8301,7 @@ diff -Naur null/fs/aufs/dentry.h linux-5.15.41/fs/aufs/dentry.h +/* 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 dentry *au_sio_lkup_one(struct mnt_idmap *idmap, 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); @@ -8459,15 +8495,15 @@ diff -Naur null/fs/aufs/dentry.h linux-5.15.41/fs/aufs/dentry.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DENTRY_H__ */ -diff -Naur null/fs/aufs/dinfo.c linux-5.15.41/fs/aufs/dinfo.c +diff -Naur null/fs/aufs/dinfo.c linux-6.12.30/fs/aufs/dinfo.c --- /dev/null -+++ linux-5.15.41/fs/aufs/dinfo.c 2022-09-06 12:51:51.037709924 +0300 -@@ -0,0 +1,554 @@ ++++ linux-6.12.30/fs/aufs/dinfo.c 2025-05-27 19:28:00.101257463 +0300 +@@ -0,0 +1,555 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -8516,6 +8552,7 @@ diff -Naur null/fs/aufs/dinfo.c linux-5.15.41/fs/aufs/dinfo.c + dinfo->di_tmpfile = 0; + for (i = 0; i < nbr; i++) + dinfo->di_hdentry[i].hd_id = -1; ++ dinfo->di_htmpfile = NULL; + goto out; + } + @@ -9017,15 +9054,15 @@ diff -Naur null/fs/aufs/dinfo.c linux-5.15.41/fs/aufs/dinfo.c + return bindex; + return -1; +} -diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c +diff -Naur null/fs/aufs/dir.c linux-6.12.30/fs/aufs/dir.c --- /dev/null -+++ linux-5.15.41/fs/aufs/dir.c 2022-09-06 12:51:51.037709924 +0300 ++++ linux-6.12.30/fs/aufs/dir.c 2025-05-27 19:28:00.101257463 +0300 @@ -0,0 +1,765 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -9049,32 +9086,32 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + +void au_add_nlink(struct inode *dir, struct inode *h_dir) +{ -+ unsigned int nlink; ++ unsigned int nlink, h_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 = vfsub_inode_nlink(dir, AU_I_AUFS); ++ h_nlink = vfsub_inode_nlink(h_dir, AU_I_BRANCH); ++ nlink += h_nlink - 2; ++ if (h_nlink < 2) + nlink += 2; -+ smp_mb(); /* for i_nlink */ + /* 0 can happen in revaliding */ -+ set_nlink(dir, nlink); ++ vfsub_set_nlink(dir, nlink); +} + +void au_sub_nlink(struct inode *dir, struct inode *h_dir) +{ -+ unsigned int nlink; ++ unsigned int nlink, h_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 = vfsub_inode_nlink(dir, AU_I_AUFS); ++ h_nlink = vfsub_inode_nlink(h_dir, AU_I_BRANCH); ++ nlink -= h_nlink - 2; ++ if (h_nlink < 2) + nlink -= 2; -+ smp_mb(); /* for i_nlink */ + /* nlink == 0 means the branch-fs is broken */ -+ set_nlink(dir, nlink); ++ vfsub_set_nlink(dir, nlink); +} + +loff_t au_dir_size(struct file *file, struct dentry *dentry) @@ -9130,6 +9167,7 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + struct au_dir_ts_arg *a = arg; + struct au_dtime dt; + struct path h_path; ++ struct timespec64 ts; + struct inode *dir, *h_dir; + struct super_block *sb; + struct au_branch *br; @@ -9167,8 +9205,9 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + 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) { ++ ts = inode_get_mtime(h_dir); ++ if (vfsub_inode_nlink(h_dir, AU_I_BRANCH) ++ && timespec64_compare(&ts, &dt.dt_mtime) < 0) { + dt.dt_h_path = h_path; + au_dtime_revert(&dt); + } @@ -9283,7 +9322,6 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + 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); @@ -9550,9 +9588,9 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + +/* ---------------------------------------------------------------------- */ + -+#define AuTestEmpty_WHONLY 1 -+#define AuTestEmpty_CALLED (1 << 1) -+#define AuTestEmpty_SHWH (1 << 2) ++#define AuTestEmpty_WHONLY BIT(0) ++#define AuTestEmpty_CALLED BIT(1) ++#define AuTestEmpty_SHWH BIT(2) +#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) +#define au_fset_testempty(flags, name) \ + do { (flags) |= AuTestEmpty_##name; } while (0) @@ -9572,9 +9610,9 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + 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) ++static bool 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); @@ -9583,8 +9621,7 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + arg->err = 0; + au_fset_testempty(arg->flags, CALLED); + /* smp_mb(); */ -+ if (name[0] == '.' -+ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ if (is_dot_dotdot(name, namelen)) + goto out; /* success */ + + if (namelen <= AUFS_WH_PFX_LEN @@ -9605,7 +9642,7 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c +out: + /* smp_mb(); */ + AuTraceErr(arg->err); -+ return arg->err; ++ return !arg->err; +} + +static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) @@ -9623,7 +9660,7 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + + err = 0; + if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) -+ && !file_inode(h_file)->i_nlink) ++ && !vfsub_inode_nlink(file_inode(h_file), AU_I_BRANCH)) + goto out_put; + + do { @@ -9660,14 +9697,14 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + int err, wkq_err; + struct dentry *h_dentry; + struct inode *h_inode; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + -+ h_userns = au_sbr_userns(dentry->d_sb, arg->bindex); ++ h_idmap = au_sbr_idmap(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); ++ err = au_test_h_perm_sio(h_idmap, h_inode, MAY_EXEC | MAY_READ); + inode_unlock_shared(h_inode); + if (!err) + err = do_test_empty(dentry, arg); @@ -9786,15 +9823,15 @@ diff -Naur null/fs/aufs/dir.c linux-5.15.41/fs/aufs/dir.c + .flush = aufs_flush_dir, + .fsync = aufs_fsync_dir +}; -diff -Naur null/fs/aufs/dir.h linux-5.15.41/fs/aufs/dir.h +diff -Naur null/fs/aufs/dir.h linux-6.12.30/fs/aufs/dir.h --- /dev/null -+++ linux-5.15.41/fs/aufs/dir.h 2022-09-06 12:51:51.037709924 +0300 ++++ linux-6.12.30/fs/aufs/dir.h 2025-05-27 19:28:00.101257463 +0300 @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -9924,15 +9961,15 @@ diff -Naur null/fs/aufs/dir.h linux-5.15.41/fs/aufs/dir.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DIR_H__ */ -diff -Naur null/fs/aufs/dirren.c linux-5.15.41/fs/aufs/dirren.c +diff -Naur null/fs/aufs/dirren.c linux-6.12.30/fs/aufs/dirren.c --- /dev/null -+++ linux-5.15.41/fs/aufs/dirren.c 2022-09-06 12:51:51.037709924 +0300 ++++ linux-6.12.30/fs/aufs/dirren.c 2025-05-27 19:28:00.101257463 +0300 @@ -0,0 +1,1315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ * Copyright (C) 2017-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -10665,7 +10702,7 @@ diff -Naur null/fs/aufs/dirren.c linux-5.15.41/fs/aufs/dirren.c + + memset(w, 0, sizeof(*w)); + w->allocated = roundup_pow_of_two(sizeof(*w->fdata) + 40); -+ strcpy(w->whname, AUFS_WH_DR_INFO_PFX); ++ strscpy(w->whname, AUFS_WH_DR_INFO_PFX, sizeof(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; @@ -11243,15 +11280,15 @@ diff -Naur null/fs/aufs/dirren.c linux-5.15.41/fs/aufs/dirren.c +out: + return err; +} -diff -Naur null/fs/aufs/dirren.h linux-5.15.41/fs/aufs/dirren.h +diff -Naur null/fs/aufs/dirren.h linux-6.12.30/fs/aufs/dirren.h --- /dev/null -+++ linux-5.15.41/fs/aufs/dirren.h 2022-09-06 12:51:51.037709924 +0300 ++++ linux-6.12.30/fs/aufs/dirren.h 2025-05-27 19:28:00.102257451 +0300 @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ * Copyright (C) 2017-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -11387,15 +11424,15 @@ diff -Naur null/fs/aufs/dirren.h linux-5.15.41/fs/aufs/dirren.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DIRREN_H__ */ -diff -Naur null/fs/aufs/dynop.c linux-5.15.41/fs/aufs/dynop.c +diff -Naur null/fs/aufs/dynop.c linux-6.12.30/fs/aufs/dynop.c --- /dev/null -+++ linux-5.15.41/fs/aufs/dynop.c 2022-09-06 12:51:51.037709924 +0300 -@@ -0,0 +1,368 @@ ++++ linux-6.12.30/fs/aufs/dynop.c 2025-05-27 19:28:00.102257451 +0300 +@@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ * Copyright (C) 2010-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -11415,7 +11452,7 @@ diff -Naur null/fs/aufs/dynop.c linux-5.15.41/fs/aufs/dynop.c + +#include "aufs.h" + -+#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) ++#define DyPrSym(key) AuDbgSym((void*)(key->dk_op.dy_hop)) + +/* + * How large will these lists be? @@ -11530,12 +11567,11 @@ diff -Naur null/fs/aufs/dynop.c linux-5.15.41/fs/aufs/dynop.c + +#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) + ++#define DyDbgDeclare(cnt) unsigned int cnt __maybe_unused = 0 +#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) ++AuStubVoid(DyDbgInc, unsigned int cnt __maybe_unused); +#endif + +#define DySet(func, dst, src, h_op, h_sb) do { \ @@ -11569,28 +11605,26 @@ diff -Naur null/fs/aufs/dynop.c linux-5.15.41/fs/aufs/dynop.c + AuDbg("%s\n", au_sbtype(h_sb)); + + DySetAop(writepage); -+ DySetAopForce(readpage); /* force */ ++ DySetAopForce(read_folio); /* force */ + DySetAop(writepages); -+ DySetAop(set_page_dirty); -+ DySetAop(readpages); ++ DySetAop(dirty_folio); ++ DySetAop(invalidate_folio); + DySetAop(readahead); + DySetAop(write_begin); + DySetAop(write_end); + DySetAop(bmap); -+ DySetAop(invalidatepage); -+ DySetAop(releasepage); -+ DySetAop(freepage); ++ DySetAop(release_folio); ++ DySetAop(free_folio); + /* 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(migrate_folio); ++ DySetAop(launder_folio); + DySetAop(is_partially_uptodate); + DySetAop(is_dirty_writeback); -+ DySetAop(error_remove_page); ++ DySetAop(error_remove_folio); + DySetAop(swap_activate); + DySetAop(swap_deactivate); ++ DySetAop(swap_rw); + + DyDbgSize(cnt, *h_aop); +} @@ -11759,15 +11793,15 @@ diff -Naur null/fs/aufs/dynop.c linux-5.15.41/fs/aufs/dynop.c + for (i = 0; i < AuDyLast; i++) + WARN_ON(!hlist_bl_empty(dynop + i)); +} -diff -Naur null/fs/aufs/dynop.h linux-5.15.41/fs/aufs/dynop.h +diff -Naur null/fs/aufs/dynop.h linux-6.12.30/fs/aufs/dynop.h --- /dev/null -+++ linux-5.15.41/fs/aufs/dynop.h 2022-09-06 12:51:51.038709912 +0300 ++++ linux-6.12.30/fs/aufs/dynop.h 2025-05-27 19:28:00.102257451 +0300 @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ * Copyright (C) 2010-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -11840,15 +11874,15 @@ diff -Naur null/fs/aufs/dynop.h linux-5.15.41/fs/aufs/dynop.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_DYNOP_H__ */ -diff -Naur null/fs/aufs/export.c linux-5.15.41/fs/aufs/export.c +diff -Naur null/fs/aufs/export.c linux-6.12.30/fs/aufs/export.c --- /dev/null -+++ linux-5.15.41/fs/aufs/export.c 2022-09-06 12:51:51.038709912 +0300 -@@ -0,0 +1,830 @@ ++++ linux-6.12.30/fs/aufs/export.c 2025-05-27 19:28:00.102257451 +0300 +@@ -0,0 +1,846 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -12140,17 +12174,33 @@ diff -Naur null/fs/aufs/export.c linux-5.15.41/fs/aufs/export.c +{ + int err; + struct path root; ++ struct vfsmount *mnt; + struct au_compare_mnt_args args = { + .sb = sb + }; + + get_fs_root(current->fs, &root); ++ /* ++ * as long as this sb is alive, this temporary unlock is safe. ++ * Really? ++ */ ++ si_read_unlock(sb); ++ mnt = collect_mounts(&root); ++ if (IS_ERR(mnt)) { ++ args.mnt = mnt; ++ goto out; ++ } ++ + rcu_read_lock(); -+ err = iterate_mounts(au_compare_mnt, &args, root.mnt); ++ err = iterate_mounts(au_compare_mnt, &args, mnt); + rcu_read_unlock(); -+ path_put(&root); ++ drop_collected_mounts(mnt); + AuDebugOn(!err); ++ ++out: ++ si_noflush_read_lock(sb); + AuDebugOn(!args.mnt); ++ path_put(&root); + return args.mnt; +} + @@ -12192,7 +12242,7 @@ diff -Naur null/fs/aufs/export.c linux-5.15.41/fs/aufs/export.c + int namelen; +}; + -+static int ++static bool +find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, + loff_t offset, u64 ino, unsigned int d_type) +{ @@ -12201,12 +12251,12 @@ diff -Naur null/fs/aufs/export.c linux-5.15.41/fs/aufs/export.c + + a->called++; + if (a->ino != ino) -+ return 0; ++ return true; + + memcpy(a->name, name, namelen); + a->namelen = namelen; + a->found = 1; -+ return 1; ++ return false; +} + +static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, @@ -12674,15 +12724,15 @@ diff -Naur null/fs/aufs/export.c linux-5.15.41/fs/aufs/export.c + BUILD_BUG_ON(sizeof(u) != sizeof(int)); + atomic_set(&sbinfo->si_xigen_next, u); +} -diff -Naur null/fs/aufs/fhsm.c linux-5.15.41/fs/aufs/fhsm.c +diff -Naur null/fs/aufs/fhsm.c linux-6.12.30/fs/aufs/fhsm.c --- /dev/null -+++ linux-5.15.41/fs/aufs/fhsm.c 2022-09-06 12:51:51.038709912 +0300 -@@ -0,0 +1,427 @@ ++++ linux-6.12.30/fs/aufs/fhsm.c 2025-05-27 19:28:00.102257451 +0300 +@@ -0,0 +1,426 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2011-2021 Junjiro R. Okajima ++ * Copyright (C) 2011-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -12693,8 +12743,7 @@ diff -Naur null/fs/aufs/fhsm.c linux-5.15.41/fs/aufs/fhsm.c + * 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 ++ * along with this program. If not, see . + */ + +/* @@ -13105,15 +13154,15 @@ diff -Naur null/fs/aufs/fhsm.c linux-5.15.41/fs/aufs/fhsm.c + if (u != AUFS_FHSM_CACHE_DEF_SEC) + seq_printf(seq, ",fhsm_sec=%u", u); +} -diff -Naur null/fs/aufs/file.c linux-5.15.41/fs/aufs/file.c +diff -Naur null/fs/aufs/file.c linux-6.12.30/fs/aufs/file.c --- /dev/null -+++ linux-5.15.41/fs/aufs/file.c 2022-09-06 12:51:51.039709899 +0300 -@@ -0,0 +1,863 @@ ++++ linux-6.12.30/fs/aufs/file.c 2025-05-27 19:28:00.102257451 +0300 +@@ -0,0 +1,858 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -13197,18 +13246,15 @@ diff -Naur null/fs/aufs/file.c linux-5.15.41/fs/aufs/file.c + au_lcnt_inc(&br->br_nfiles); + h_path.dentry = h_dentry; + h_path.mnt = au_br_mnt(br); ++ /* ++ * vfs::backing_file_open() looks promising since it can get rid of ++ * mm::vm_prfile approach from my mind. ++ * but I keep current approach for a while. ++ */ + 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 */ + @@ -13355,18 +13401,20 @@ diff -Naur null/fs/aufs/file.c linux-5.15.41/fs/aufs/file.c + 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 { ++ if (!aopen) { ++ err = args->open(file, vfsub_file_flags(file), ++ au_di(dentry)->di_htmpfile); ++ di_write_unlock(dentry); ++ } else { ++ di_downgrade_lock(dentry, AuLock_IR); + lockdep_off(); + err = args->open(file, vfsub_file_flags(file), + args->h_file); + lockdep_on(); ++ di_read_unlock(dentry, AuLock_IR); + } + } -+ di_read_unlock(dentry, AuLock_IR); + + finfo = au_fi(file); + if (!err) { @@ -13441,6 +13489,7 @@ diff -Naur null/fs/aufs/file.c linux-5.15.41/fs/aufs/file.c + au_set_fbtop(file, btop); + au_set_h_fptr(file, btop, h_file); + au_update_figen(file); ++ file->f_mode |= h_file->f_mode & FMODE_CAN_ODIRECT; + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + @@ -13509,7 +13558,7 @@ diff -Naur null/fs/aufs/file.c linux-5.15.41/fs/aufs/file.c + err = au_reopen_wh(file, bcpup, hi_wh); + + if (!err -+ && (inode->i_nlink > 1 ++ && (vfsub_inode_nlink(inode, AU_I_AUFS) > 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)); @@ -13889,9 +13938,9 @@ diff -Naur null/fs/aufs/file.c linux-5.15.41/fs/aufs/file.c + +/* cf. aufs_nopage() */ +/* for madvise(2) */ -+static int aufs_readpage(struct file *file __maybe_unused, struct page *page) ++static int aufs_read_folio(struct file *file __maybe_unused, struct folio *folio) +{ -+ unlock_page(page); ++ folio_unlock(folio); + return 0; +} + @@ -13902,85 +13951,80 @@ diff -Naur null/fs/aufs/file.c linux-5.15.41/fs/aufs/file.c +/* 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) ++ loff_t pos, unsigned len, ++ struct folio **foliop, 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) ++ struct folio *folio, 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) ++static bool aufs_dirty_folio(struct address_space *mapping, struct folio *folio) ++{ AuUnsupport(); return true; } ++static void aufs_invalidate_folio(struct folio *folio, size_t offset, size_t len) +{ AuUnsupport(); } -+static int aufs_releasepage(struct page *page, gfp_t gfp) -+{ AuUnsupport(); return 0; } ++static bool aufs_release_folio(struct folio *folio, gfp_t gfp) ++{ AuUnsupport(); return true; } +#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) ++static int aufs_migrate_folio(struct address_space *mapping, struct folio *dst, ++ struct folio *src, enum migrate_mode mode) +{ AuUnsupport(); return 0; } +#endif -+static bool aufs_isolate_page(struct page *page, isolate_mode_t mode) ++static int aufs_launder_folio(struct folio *folio) ++{ AuUnsupport(); return 0; } ++static bool aufs_is_partially_uptodate(struct folio *folio, size_t from, ++ size_t count) +{ 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, ++static void aufs_is_dirty_writeback(struct folio *folio, bool *dirty, + bool *writeback) +{ AuUnsupport(); } -+static int aufs_error_remove_page(struct address_space *mapping, -+ struct page *page) ++static int aufs_error_remove_folio(struct address_space *mapping, ++ struct folio *folio) +{ 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(); } ++static int aufs_swap_rw(struct kiocb *iocb, struct iov_iter *iter) ++{ AuUnsupport(); return 0; } +#endif /* CONFIG_AUFS_DEBUG */ + +const struct address_space_operations aufs_aop = { -+ .readpage = aufs_readpage, ++ .read_folio = aufs_read_folio, + .direct_IO = aufs_direct_IO, +#ifdef CONFIG_AUFS_DEBUG + .writepage = aufs_writepage, + /* no writepages, because of writepage */ -+ .set_page_dirty = aufs_set_page_dirty, ++ .dirty_folio = aufs_dirty_folio, + /* 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, ++ .invalidate_folio = aufs_invalidate_folio, ++ .release_folio = aufs_release_folio, + /* is fallback_migrate_page ok? */ -+ /* .migratepage = aufs_migratepage, */ -+ .isolate_page = aufs_isolate_page, -+ .putback_page = aufs_putback_page, -+ .launder_page = aufs_launder_page, ++ /* .migrate_folio = aufs_migrate_folio, */ ++ .launder_folio = aufs_launder_folio, + .is_partially_uptodate = aufs_is_partially_uptodate, + .is_dirty_writeback = aufs_is_dirty_writeback, -+ .error_remove_page = aufs_error_remove_page, ++ .error_remove_folio = aufs_error_remove_folio, + .swap_activate = aufs_swap_activate, -+ .swap_deactivate = aufs_swap_deactivate ++ .swap_deactivate = aufs_swap_deactivate, ++ .swap_rw = aufs_swap_rw +#endif /* CONFIG_AUFS_DEBUG */ +}; -diff -Naur null/fs/aufs/file.h linux-5.15.41/fs/aufs/file.h +diff -Naur null/fs/aufs/file.h linux-6.12.30/fs/aufs/file.h --- /dev/null -+++ linux-5.15.41/fs/aufs/file.h 2022-09-06 12:51:51.039709899 +0300 ++++ linux-6.12.30/fs/aufs/file.h 2025-05-27 19:28:00.102257451 +0300 @@ -0,0 +1,342 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -14280,7 +14324,7 @@ diff -Naur null/fs/aufs/file.h linux-5.15.41/fs/aufs/file.h +} + +#ifdef CONFIG_MMU -+#define AuDbgVmRegion(file, vma) do {} while (0) ++AuStubVoid(AuDbgVmRegion, struct file *file, struct vm_area_struct *vma) + +static inline void au_vm_file_reset(struct vm_area_struct *vma, + struct file *file) @@ -14318,15 +14362,15 @@ diff -Naur null/fs/aufs/file.h linux-5.15.41/fs/aufs/file.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_FILE_H__ */ -diff -Naur null/fs/aufs/finfo.c linux-5.15.41/fs/aufs/finfo.c +diff -Naur null/fs/aufs/finfo.c linux-6.12.30/fs/aufs/finfo.c --- /dev/null -+++ linux-5.15.41/fs/aufs/finfo.c 2022-09-06 12:51:51.039709899 +0300 -@@ -0,0 +1,149 @@ ++++ linux-6.12.30/fs/aufs/finfo.c 2025-05-27 19:28:00.102257451 +0300 +@@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -14348,8 +14392,6 @@ diff -Naur null/fs/aufs/finfo.c linux-5.15.41/fs/aufs/finfo.c + +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); @@ -14471,15 +14513,15 @@ diff -Naur null/fs/aufs/finfo.c linux-5.15.41/fs/aufs/finfo.c +out: + return err; +} -diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c +diff -Naur null/fs/aufs/f_op.c linux-6.12.30/fs/aufs/f_op.c --- /dev/null -+++ linux-5.15.41/fs/aufs/f_op.c 2022-09-06 12:51:51.038709912 +0300 -@@ -0,0 +1,771 @@ ++++ linux-6.12.30/fs/aufs/f_op.c 2025-05-27 19:28:00.102257451 +0300 +@@ -0,0 +1,782 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -14538,16 +14580,22 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + /* 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); ++ if (flags & __O_TMPFILE) { ++ AuDebugOn(!h_file); ++ AuDebugOn(h_file != au_di(dentry)->di_htmpfile); ++ au_di(dentry)->di_htmpfile = NULL; ++ ++ if (!(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); ++ file->f_mode |= h_file->f_mode & FMODE_CAN_ODIRECT; + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + @@ -14695,6 +14743,7 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + if (do_ready) + au_unpin(&pin); + di_read_unlock(dentry, /*flags*/0); ++ vfsub_file_start_write(h_file); + +out_fi: + fi_write_unlock(file); @@ -14707,6 +14756,7 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c +{ + struct inode *h_inode; + ++ vfsub_file_end_write(h_file); + au_cpup_attr_timesizes(inode); + AuDebugOn(au_ibtop(inode) != wpre->btop); + h_inode = file_inode(h_file); @@ -14768,7 +14818,12 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + } else + /* currently there is no such fs */ + WARN_ON_ONCE(1); -+ kio->ki_filp = file; ++ if (!is_sync_kiocb(kio)) { ++ /* do not restore ki_filp */ ++ fput(file); ++ get_file(h_file); ++ } else ++ kio->ki_filp = file; + +out: + return err; @@ -14826,7 +14881,12 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + err = PTR_ERR(h_file); + if (IS_ERR(h_file)) + goto out; -+ ++ if (!is_sync_kiocb(kio)) { ++ /* .vs. sb_start_write() in aio_write() */ ++ if (S_ISREG(inode->i_mode)) ++ __sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE); ++ file_end_write(file); ++ } + err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); + au_write_post(inode, h_file, &wpre, err); + @@ -14863,7 +14923,7 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + if (IS_ERR(h_file)) + goto out; + -+ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ err = vfsub_splice_read(h_file, ppos, pipe, len, flags); + /* todo: necessary? */ + /* file->f_ra = h_file->f_ra; */ + au_read_post(inode, h_file); @@ -14920,6 +14980,10 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + lockdep_off(); + err = vfs_fallocate(h_file, mode, offset, len); + lockdep_on(); ++ /* ++ * we don't need to call file_modifed() here since au_write_post() ++ * is equivalent and copies-up all timestamps and permission bits. ++ */ + au_write_post(inode, h_file, &wpre, /*written*/1); + +out: @@ -15204,16 +15268,6 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + +/* ---------------------------------------------------------------------- */ + -+/* 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, + @@ -15235,7 +15289,6 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + .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, @@ -15246,15 +15299,15 @@ diff -Naur null/fs/aufs/f_op.c linux-5.15.41/fs/aufs/f_op.c + .fallocate = aufs_fallocate, + .copy_file_range = aufs_copy_file_range +}; -diff -Naur null/fs/aufs/fsctx.c linux-5.15.41/fs/aufs/fsctx.c +diff -Naur null/fs/aufs/fsctx.c linux-6.12.30/fs/aufs/fsctx.c --- /dev/null -+++ linux-5.15.41/fs/aufs/fsctx.c 2022-09-06 12:51:51.039709899 +0300 -@@ -0,0 +1,1242 @@ ++++ linux-6.12.30/fs/aufs/fsctx.c 2025-05-27 19:28:00.103257438 +0300 +@@ -0,0 +1,1244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2022 Junjiro R. Okajima ++ * Copyright (C) 2022-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -15312,6 +15365,8 @@ diff -Naur null/fs/aufs/fsctx.c linux-5.15.41/fs/aufs/fsctx.c + + root = fc->root; + sb = root->d_sb; ++ root = sb->s_root; /* "bind"-mount may give us non-root */ ++ AuDebugOn(!IS_ROOT(root)); + err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (!err) { + di_write_lock_child(root); @@ -15345,7 +15400,8 @@ diff -Naur null/fs/aufs/fsctx.c linux-5.15.41/fs/aufs/fsctx.c +out: + inode_unlock(inode); + err = cvt_err(err); -+ AuTraceErr(err); ++ if (unlikely(err)) ++ pr_err("remount err %d\n", err); + + return err; +} @@ -15369,8 +15425,7 @@ diff -Naur null/fs/aufs/fsctx.c linux-5.15.41/fs/aufs/fsctx.c + 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_flags |= SB_NOATIME | SB_NODIRATIME | SB_I_VERSION; + sb->s_op = &aufs_sop; + sb->s_d_op = &aufs_dop; + sb->s_magic = AUFS_SUPER_MAGIC; @@ -16492,15 +16547,15 @@ diff -Naur null/fs/aufs/fsctx.c linux-5.15.41/fs/aufs/fsctx.c + AuTraceErr(err); + return err; +} -diff -Naur null/fs/aufs/fstype.h linux-5.15.41/fs/aufs/fstype.h +diff -Naur null/fs/aufs/fstype.h linux-6.12.30/fs/aufs/fstype.h --- /dev/null -+++ linux-5.15.41/fs/aufs/fstype.h 2022-09-06 12:51:51.039709899 +0300 -@@ -0,0 +1,401 @@ ++++ linux-6.12.30/fs/aufs/fstype.h 2025-05-27 19:28:00.103257438 +0300 +@@ -0,0 +1,419 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -16745,6 +16800,15 @@ diff -Naur null/fs/aufs/fstype.h linux-5.15.41/fs/aufs/fstype.h +#endif +} + ++static inline int au_test_f2fs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_F2FS_FS) ++ return sb->s_magic == F2FS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ +/* ---------------------------------------------------------------------- */ +/* + * they can't be an aufs branch. @@ -16895,17 +16959,26 @@ diff -Naur null/fs/aufs/fstype.h linux-5.15.41/fs/aufs/fstype.h + && !nfs_server_capable(inode, NFS_CAP_ACLS); +} + ++/* ++ * filesystems which requires inode-lock in open. ++ */ ++static inline int au_test_fs_unlock_for_open(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_f2fs(sb); ++} ++ +#endif /* __KERNEL__ */ +#endif /* __AUFS_FSTYPE_H__ */ -diff -Naur null/fs/aufs/hbl.h linux-5.15.41/fs/aufs/hbl.h +diff -Naur null/fs/aufs/hbl.h linux-6.12.30/fs/aufs/hbl.h --- /dev/null -+++ linux-5.15.41/fs/aufs/hbl.h 2022-09-06 12:51:51.039709899 +0300 ++++ linux-6.12.30/fs/aufs/hbl.h 2025-05-27 19:28:00.103257438 +0300 @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2017-2021 Junjiro R. Okajima ++ * Copyright (C) 2017-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -16966,15 +17039,15 @@ diff -Naur null/fs/aufs/hbl.h linux-5.15.41/fs/aufs/hbl.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_HBL_H__ */ -diff -Naur null/fs/aufs/hfsnotify.c linux-5.15.41/fs/aufs/hfsnotify.c +diff -Naur null/fs/aufs/hfsnotify.c linux-6.12.30/fs/aufs/hfsnotify.c --- /dev/null -+++ linux-5.15.41/fs/aufs/hfsnotify.c 2022-09-06 12:51:51.040709887 +0300 -@@ -0,0 +1,288 @@ ++++ linux-6.12.30/fs/aufs/hfsnotify.c 2025-05-27 19:28:00.103257438 +0300 +@@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -17142,7 +17215,8 @@ diff -Naur null/fs/aufs/hfsnotify.c linux-5.15.41/fs/aufs/hfsnotify.c + struct inode *h_dir, *h_inode; + struct fsnotify_mark *inode_mark; + -+ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ AuDebugOn(!(data_type == FSNOTIFY_EVENT_INODE ++ || data_type == FSNOTIFY_EVENT_DENTRY)); + + err = 0; + /* if FS_UNMOUNT happens, there must be another bug */ @@ -17154,11 +17228,11 @@ diff -Naur null/fs/aufs/hfsnotify.c linux-5.15.41/fs/aufs/hfsnotify.c + 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)) { ++ if (1 || file_name.len != sizeof(AUFS_XINO_FNAME) - 1 ++ || strncmp(file_name.name, AUFS_XINO_FNAME, file_name.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); ++ AuLNPair(file_name), h_inode ? h_inode->i_ino : 0); + /* WARN_ON(1); */ + } + au_debug_off(); @@ -17210,7 +17284,8 @@ diff -Naur null/fs/aufs/hfsnotify.c linux-5.15.41/fs/aufs/hfsnotify.c + goto out; + + err = 0; -+ group = fsnotify_alloc_group(&au_hfsn_ops); ++ group = fsnotify_alloc_group(&au_hfsn_ops, ++ /*flags - not for userspace*/0); + if (IS_ERR(group)) { + err = PTR_ERR(group); + pr_err("fsnotify_alloc_group() failed, %d\n", err); @@ -17258,15 +17333,15 @@ diff -Naur null/fs/aufs/hfsnotify.c linux-5.15.41/fs/aufs/hfsnotify.c + .fin_br = au_hfsn_fin_br, + .init_br = au_hfsn_init_br +}; -diff -Naur null/fs/aufs/hfsplus.c linux-5.15.41/fs/aufs/hfsplus.c +diff -Naur null/fs/aufs/hfsplus.c linux-6.12.30/fs/aufs/hfsplus.c --- /dev/null -+++ linux-5.15.41/fs/aufs/hfsplus.c 2022-09-06 12:51:51.040709887 +0300 ++++ linux-6.12.30/fs/aufs/hfsplus.c 2025-05-27 19:28:00.103257438 +0300 @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ * Copyright (C) 2010-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -17322,15 +17397,15 @@ diff -Naur null/fs/aufs/hfsplus.c linux-5.15.41/fs/aufs/hfsplus.c + au_lcnt_dec(&br->br_nfiles); + } +} -diff -Naur null/fs/aufs/hnotify.c linux-5.15.41/fs/aufs/hnotify.c +diff -Naur null/fs/aufs/hnotify.c linux-6.12.30/fs/aufs/hnotify.c --- /dev/null -+++ linux-5.15.41/fs/aufs/hnotify.c 2022-09-06 12:51:51.040709887 +0300 ++++ linux-6.12.30/fs/aufs/hnotify.c 2025-05-27 19:28:00.103257438 +0300 @@ -0,0 +1,715 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -17600,12 +17675,12 @@ diff -Naur null/fs/aufs/hnotify.c linux-5.15.41/fs/aufs/hnotify.c +/* ---------------------------------------------------------------------- */ + +/* 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 AuHnJob_XINO0 BIT(0) ++#define AuHnJob_GEN BIT(1) ++#define AuHnJob_DIRENT BIT(2) ++#define AuHnJob_ISDIR BIT(3) ++#define AuHnJob_TRYXINO0 BIT(4) ++#define AuHnJob_MNTPNT BIT(5) +#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) +#define au_fset_hnjob(flags, name) \ + do { (flags) |= AuHnJob_##name; } while (0) @@ -17647,7 +17722,7 @@ diff -Naur null/fs/aufs/hnotify.c linux-5.15.41/fs/aufs/hnotify.c + && a->inode + && a->h_inode) { + inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); -+ if (!a->h_inode->i_nlink ++ if (!vfsub_inode_nlink(a->h_inode, AU_I_BRANCH) + && !(a->h_inode->i_state & I_LINKABLE)) + hn_xino(a->inode, a->h_inode); /* ignore this error */ + inode_unlock_shared(a->h_inode); @@ -17698,7 +17773,7 @@ diff -Naur null/fs/aufs/hnotify.c linux-5.15.41/fs/aufs/hnotify.c + + dentry = NULL; + spin_lock(&parent->d_lock); -+ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ hlist_for_each_entry(d, &parent->d_children, d_sib) { + /* AuDbg("%pd\n", d); */ + spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); + dname = &d->d_name; @@ -17961,7 +18036,7 @@ diff -Naur null/fs/aufs/hnotify.c linux-5.15.41/fs/aufs/hnotify.c + + /* NFS fires the event for silly-renamed one from kworker */ + f = 0; -+ if (!dir->i_nlink ++ if (!vfsub_inode_nlink(dir, AU_I_AUFS) + || (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); @@ -18041,15 +18116,15 @@ diff -Naur null/fs/aufs/hnotify.c linux-5.15.41/fs/aufs/hnotify.c + if (au_cache[AuCache_HNOTIFY]) + au_hn_destroy_cache(); +} -diff -Naur null/fs/aufs/iinfo.c linux-5.15.41/fs/aufs/iinfo.c +diff -Naur null/fs/aufs/iinfo.c linux-6.12.30/fs/aufs/iinfo.c --- /dev/null -+++ linux-5.15.41/fs/aufs/iinfo.c 2022-09-06 12:51:51.041709874 +0300 -@@ -0,0 +1,286 @@ ++++ linux-6.12.30/fs/aufs/iinfo.c 2025-05-27 19:28:00.104257426 +0300 +@@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -18194,7 +18269,7 @@ diff -Naur null/fs/aufs/iinfo.c linux-5.15.41/fs/aufs/iinfo.c + + h_i = au_hinode(iinfo, bindex)->hi_inode; + if (h_i -+ && !h_i->i_nlink ++ && !vfsub_inode_nlink(h_i, AU_I_BRANCH) + && !(h_i->i_state & I_LINKABLE)) + au_set_h_iptr(inode, bindex, NULL, 0); + } @@ -18227,6 +18302,7 @@ diff -Naur null/fs/aufs/iinfo.c linux-5.15.41/fs/aufs/iinfo.c + spin_lock_init(&iinfo->ii_generation.ig_spin); + au_rw_init(&iinfo->ii_rwsem); + inode_init_once(&c->vfs_inode); ++ spin_lock_init(&c->nlink_spin); +} + +void au_hinode_init(struct au_hinode *hinode) @@ -18294,7 +18370,7 @@ diff -Naur null/fs/aufs/iinfo.c linux-5.15.41/fs/aufs/iinfo.c + struct au_hinode *hi; + struct super_block *sb; + aufs_bindex_t bindex, bbot; -+ const unsigned char unlinked = !inode->i_nlink; ++ const unsigned char unlinked = !vfsub_inode_nlink(inode, AU_I_AUFS); + + AuDebugOn(au_is_bad_inode(inode)); + @@ -18331,15 +18407,15 @@ diff -Naur null/fs/aufs/iinfo.c linux-5.15.41/fs/aufs/iinfo.c + au_kfree_rcu(iinfo->ii_hinode); + AuRwDestroy(&iinfo->ii_rwsem); +} -diff -Naur null/fs/aufs/inode.c linux-5.15.41/fs/aufs/inode.c +diff -Naur null/fs/aufs/inode.c linux-6.12.30/fs/aufs/inode.c --- /dev/null -+++ linux-5.15.41/fs/aufs/inode.c 2022-09-06 12:51:51.041709874 +0300 -@@ -0,0 +1,531 @@ ++++ linux-6.12.30/fs/aufs/inode.c 2025-05-27 19:28:00.104257426 +0300 +@@ -0,0 +1,532 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -18611,7 +18687,7 @@ diff -Naur null/fs/aufs/inode.c linux-5.15.41/fs/aufs/inode.c + } + au_cpup_attr_all(inode, /*force*/1); + /* -+ * to force calling aufs_get_acl() every time, ++ * to force calling aufs_get_inode_acl() every time, + * do not call cache_no_acl() for aufs inode. + */ + @@ -18639,7 +18715,7 @@ diff -Naur null/fs/aufs/inode.c linux-5.15.41/fs/aufs/inode.c + * it can happen by UDBA and the obsoleted inode number. + */ + err = -EIO; -+ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ if (unlikely(inode->i_ino == d_parent_ino(dentry))) + goto out; + + err = 1; @@ -18721,7 +18797,7 @@ diff -Naur null/fs/aufs/inode.c linux-5.15.41/fs/aufs/inode.c + 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; ++ hlinked = !d_is_dir(h_dentry) && vfsub_inode_nlink(h_inode, AU_I_BRANCH) > 1; + +new_ino: + /* @@ -18754,7 +18830,7 @@ diff -Naur null/fs/aufs/inode.c linux-5.15.41/fs/aufs/inode.c + if (IS_ERR(inode)) + goto out_xinondir; + -+ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ AuDbg("%x, 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); @@ -18774,7 +18850,8 @@ diff -Naur null/fs/aufs/inode.c linux-5.15.41/fs/aufs/inode.c + 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) { ++ } else if (!must_new && !IS_DEADDIR(inode) ++ && vfsub_inode_nlink(inode, AU_I_AUFS)) { + /* + * horrible race condition between lookup, readdir and copyup + * (or something). @@ -18849,32 +18926,32 @@ diff -Naur null/fs/aufs/inode.c linux-5.15.41/fs/aufs/inode.c + return err; +} + -+int au_test_h_perm(struct user_namespace *h_userns, struct inode *h_inode, ++int au_test_h_perm(struct mnt_idmap *h_idmap, struct inode *h_inode, + int mask) +{ + if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) + return 0; -+ return inode_permission(h_userns, h_inode, mask); ++ return inode_permission(h_idmap, h_inode, mask); +} + -+int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode, ++int au_test_h_perm_sio(struct mnt_idmap *h_idmap, 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); ++ return au_test_h_perm(h_idmap, h_inode, mask); +} -diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h +diff -Naur null/fs/aufs/inode.h linux-6.12.30/fs/aufs/inode.h --- /dev/null -+++ linux-5.15.41/fs/aufs/inode.h 2022-09-06 12:51:51.042709862 +0300 -@@ -0,0 +1,705 @@ ++++ linux-6.12.30/fs/aufs/inode.h 2025-05-27 19:28:00.105257413 +0300 +@@ -0,0 +1,727 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -18898,6 +18975,7 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h +#ifdef __KERNEL__ + +#include ++#include "fstype.h" +#include "rwsem.h" + +struct vfsmount; @@ -18952,13 +19030,14 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h +struct au_icntnr { + struct au_iinfo iinfo; + struct inode vfs_inode; ++ spinlock_t nlink_spin; /* protects vfs_inode.i_nlink */ + 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 AuPin_DI_LOCKED BIT(0) ++#define AuPin_MNT_WRITE BIT(1) +#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) +#define au_fset_pin(flags, name) \ + do { (flags) |= AuPin_##name; } while (0) @@ -18997,6 +19076,24 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h + return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); +} + ++static inline void au_nlink_lock(struct inode *inode) ++{ ++ spinlock_t *spin; ++ ++ AuDebugOn(!au_test_aufs(inode->i_sb)); ++ AuDebugOn(is_bad_inode(inode)); ++ spin = &(container_of(inode, struct au_icntnr, vfs_inode)->nlink_spin); ++ spin_lock(spin); ++} ++ ++static inline void au_nlink_unlock(struct inode *inode) ++{ ++ spinlock_t *spin; ++ ++ spin = &(container_of(inode, struct au_icntnr, vfs_inode)->nlink_spin); ++ spin_unlock(spin); ++} ++ +/* ---------------------------------------------------------------------- */ + +/* inode.c */ @@ -19009,9 +19106,9 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h +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 au_test_h_perm(struct mnt_idmap *h_idmap, struct inode *h_inode, + int mask); -+int au_test_h_perm_sio(struct user_namespace *h_userns, struct inode *h_inode, ++int au_test_h_perm_sio(struct mnt_idmap *h_idmap, struct inode *h_inode, + int mask); + +static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, @@ -19035,9 +19132,9 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h + 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 AuWrDir_ADD_ENTRY BIT(0) ++#define AuWrDir_ISDIR BIT(1) ++#define AuWrDir_TMPFILE BIT(2) +#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) +#define au_fset_wrdir(flags, name) \ + do { (flags) |= AuWrDir_##name; } while (0) @@ -19087,20 +19184,20 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h +/* 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, ++int aufs_mknod(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode, dev_t dev); -+int aufs_symlink(struct user_namespace *userns, struct inode *dir, ++int aufs_symlink(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, const char *symname); -+int aufs_create(struct user_namespace *userns, struct inode *dir, ++int aufs_create(struct mnt_idmap *idmap, 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_tmpfile(struct mnt_idmap *idmap, struct inode *dir, ++ struct file *file, 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, ++int aufs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode); + +/* i_op_del.c */ @@ -19112,7 +19209,7 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h + +/* i_op_ren.c */ +int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); -+int aufs_rename(struct user_namespace *userns, ++int aufs_rename(struct mnt_idmap *idmap, + struct inode *_src_dir, struct dentry *_src_dentry, + struct inode *_dst_dir, struct dentry *_dst_dentry, + unsigned int _flags); @@ -19125,8 +19222,8 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h +unsigned int au_hi_flags(struct inode *inode, int isdir); + +/* hinode flags */ -+#define AuHi_XINO 1 -+#define AuHi_HNOTIFY (1 << 1) ++#define AuHi_XINO BIT(0) ++#define AuHi_HNOTIFY BIT(1) +#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) +#define au_fset_hi(flags, name) \ + do { (flags) |= AuHi_##name; } while (0) @@ -19196,8 +19293,10 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h +#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 *aufs_get_inode_acl(struct inode *inode, int type, bool rcu); ++struct posix_acl *aufs_get_acl(struct mnt_idmap *idmap, ++ struct dentry *dentry, int type); ++int aufs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, + struct posix_acl *acl, int type); +#endif + @@ -19575,15 +19674,15 @@ diff -Naur null/fs/aufs/inode.h linux-5.15.41/fs/aufs/inode.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_INODE_H__ */ -diff -Naur null/fs/aufs/ioctl.c linux-5.15.41/fs/aufs/ioctl.c +diff -Naur null/fs/aufs/ioctl.c linux-6.12.30/fs/aufs/ioctl.c --- /dev/null -+++ linux-5.15.41/fs/aufs/ioctl.c 2022-09-06 12:51:51.042709862 +0300 ++++ linux-6.12.30/fs/aufs/ioctl.c 2025-05-27 19:28:00.105257413 +0300 @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -19799,15 +19898,15 @@ diff -Naur null/fs/aufs/ioctl.c linux-5.15.41/fs/aufs/ioctl.c + return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif -diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c +diff -Naur null/fs/aufs/i_op_add.c linux-6.12.30/fs/aufs/i_op_add.c --- /dev/null -+++ linux-5.15.41/fs/aufs/i_op_add.c 2022-09-06 12:51:51.041709874 +0300 -@@ -0,0 +1,941 @@ ++++ linux-6.12.30/fs/aufs/i_op_add.c 2025-05-27 19:28:00.104257426 +0300 +@@ -0,0 +1,971 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -19928,7 +20027,7 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + if (unlikely(d_is_negative(h_dentry))) + goto out; + h_inode = d_inode(h_dentry); -+ if (unlikely(!h_inode->i_nlink)) ++ if (unlikely(!vfsub_inode_nlink(h_inode, AU_I_BRANCH))) + goto out; + + h_mode = h_inode->i_mode; @@ -20171,7 +20270,7 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + return err; +} + -+int aufs_mknod(struct user_namespace *userns, struct inode *dir, ++int aufs_mknod(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode, dev_t dev) +{ + struct simple_arg arg = { @@ -20184,7 +20283,7 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + return add_simple(dir, dentry, &arg); +} + -+int aufs_symlink(struct user_namespace *userns, struct inode *dir, ++int aufs_symlink(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, const char *symname) +{ + struct simple_arg arg = { @@ -20194,7 +20293,7 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + return add_simple(dir, dentry, &arg); +} + -+int aufs_create(struct user_namespace *userns, struct inode *dir, ++int aufs_create(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode, bool want_excl) +{ + struct simple_arg arg = { @@ -20222,16 +20321,19 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + return add_simple(dir, dentry, &arg); +} + -+int aufs_tmpfile(struct user_namespace *userns, struct inode *dir, -+ struct dentry *dentry, umode_t mode) ++int aufs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, ++ struct file *file, umode_t mode) +{ + int err; + aufs_bindex_t bindex; ++ struct path h_ppath; + struct super_block *sb; -+ struct dentry *parent, *h_parent, *h_dentry; ++ struct au_branch *br; ++ struct dentry *dentry, *parent, *h_parent, *h_dentry; + struct inode *h_dir, *inode; + struct vfsmount *h_mnt; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; ++ struct file *h_file; + struct au_wr_dir_args wr_dir_args = { + .force_btgt = -1, + .flags = AuWrDir_TMPFILE @@ -20240,11 +20342,13 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + /* copy-up may happen */ + inode_lock(dir); + ++ h_file = NULL; + sb = dir->i_sb; + err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); + if (unlikely(err)) + goto out; + ++ dentry = file->f_path.dentry; + err = au_di_init(dentry); + if (unlikely(err)) + goto out_si; @@ -20273,19 +20377,25 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + if (unlikely(!h_dir->i_op->tmpfile)) + goto out_parent; + -+ h_mnt = au_sbr_mnt(sb, bindex); ++ br = au_sbr(sb, bindex); ++ h_mnt = au_br_mnt(br); + err = vfsub_mnt_want_write(h_mnt); + if (unlikely(err)) + goto out_parent; + -+ h_userns = mnt_user_ns(h_mnt); ++ h_idmap = mnt_idmap(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); ++ h_ppath.mnt = h_mnt; ++ h_ppath.dentry = h_parent; ++ h_file = kernel_tmpfile_open(h_idmap, &h_ppath, mode, /*open_flag*/0, ++ current_cred()); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ h_file = NULL; + goto out_mnt; + } + ++ h_dentry = h_file->f_path.dentry; + au_set_dbtop(dentry, bindex); + au_set_dbbot(dentry, bindex); + au_set_h_dptr(dentry, bindex, dget(h_dentry)); @@ -20295,32 +20405,51 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + 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); ++ goto out_h_file; + } -+ dput(h_dentry); + ++ vfsub_inode_nlink_init(inode, 1); ++ d_tmpfile(file, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ get_file(h_file); ++ au_di(dentry)->di_htmpfile = h_file; ++ ++ /* update without i_mutex */ ++ if (au_ibtop(dir) == au_dbtop(dentry)) ++ au_cpup_attr_timesizes(dir); ++ ++out_h_file: ++ fput(h_file); +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; -+ } ++ if (!err) ++ goto out_si; ++ if (h_file) ++ fput(h_file); ++ au_di(dentry)->di_htmpfile = NULL; ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; +out_si: + si_read_unlock(sb); ++ if (!err && h_file) { ++ /* finally... */ ++ err = finish_open_simple(file, err); ++ if (!err) ++ au_lcnt_inc(&br->br_nfiles); ++ else { ++ fput(h_file); ++ au_di(dentry)->di_htmpfile = NULL; ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++ } +out: + inode_unlock(dir); ++ AuTraceErr(err); + return err; +} + @@ -20384,7 +20513,7 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + 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) { ++ if (!h_inode || !vfsub_inode_nlink(h_inode, AU_I_BRANCH)) { + /* copyup src_dentry as the name of dentry. */ + bbot = au_dbbot(dentry); + if (bbot < a->bsrc) @@ -20597,8 +20726,8 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + + au_dir_ts(dir, a->bdst); + inode_inc_iversion(dir); -+ inc_nlink(inode); -+ inode->i_ctime = dir->i_ctime; ++ vfsub_inc_nlink(inode); ++ inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); + d_instantiate(dentry, au_igrab(inode)); + if (d_unhashed(a->h_path.dentry)) + /* some filesystem calls d_drop() */ @@ -20636,7 +20765,7 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + return err; +} + -+int aufs_mkdir(struct user_namespace *userns, struct inode *dir, ++int aufs_mkdir(struct mnt_idmap *idmap, struct inode *dir, + struct dentry *dentry, umode_t mode) +{ + int err, rerr; @@ -20702,7 +20831,7 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c + + err = epilog(dir, bindex, wh_dentry, dentry); + if (!err) { -+ inc_nlink(dir); ++ vfsub_inc_nlink(dir); + goto out_unpin; /* success */ + } + @@ -20744,15 +20873,15 @@ diff -Naur null/fs/aufs/i_op_add.c linux-5.15.41/fs/aufs/i_op_add.c +out: + return err; +} -diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c +diff -Naur null/fs/aufs/i_op.c linux-6.12.30/fs/aufs/i_op.c --- /dev/null -+++ linux-5.15.41/fs/aufs/i_op.c 2022-09-06 12:51:51.040709887 +0300 -@@ -0,0 +1,1512 @@ ++++ linux-6.12.30/fs/aufs/i_op.c 2025-05-27 19:28:00.104257426 +0300 +@@ -0,0 +1,1526 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -20771,6 +20900,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + */ + +#include ++#include +#include +#include +#include @@ -20781,7 +20911,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c +{ + int err; + const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + err = -EPERM; + if (write_mask && IS_IMMUTABLE(h_inode)) @@ -20801,21 +20931,22 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + * - 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); ++ h_idmap = mnt_idmap(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); ++ /* AuDbg("get_inode_acl %ps\n", ++ h_inode->i_op->get_inode_acl); */ ++ err = generic_permission(h_idmap, h_inode, mask); + if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) -+ err = h_inode->i_op->permission(h_userns, h_inode, ++ err = h_inode->i_op->permission(h_idmap, h_inode, + mask); + AuTraceErr(err); + } else { + /* AuLabel(h_inode->permission); */ -+ err = h_inode->i_op->permission(h_userns, h_inode, mask); ++ err = h_inode->i_op->permission(h_idmap, h_inode, mask); + AuTraceErr(err); + } + @@ -20828,7 +20959,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + return err; +} + -+static int aufs_permission(struct user_namespace *userns, struct inode *inode, ++static int aufs_permission(struct mnt_idmap *idmap, struct inode *inode, + int mask) +{ + int err; @@ -21376,7 +21507,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + continue; + if (d_is_positive(h_d[i])) { + h_i = d_inode(h_d[i]); -+ err = !h_i->i_nlink; ++ err = !vfsub_inode_nlink(h_i, AU_I_BRANCH); + } + } + @@ -21386,7 +21517,13 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + +static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) +{ ++ AuRwMustWriteLock(&p->hdir->hi_inode->i_rwsem); ++#ifndef CONFIG_PREEMPT_RT + atomic_long_set(&p->hdir->hi_inode->i_rwsem.owner, (long)task); ++#else ++ p->hdir->hi_inode->i_rwsem.rwbase.rtmutex.owner = task; ++ smp_mb(); /* advertise the owner */ ++#endif +} + +void au_pin_hdir_acquire_nest(struct au_pin *p) @@ -21677,7 +21814,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + return err; +} + -+static int aufs_setattr(struct user_namespace *userns, struct dentry *dentry, ++static int aufs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, + struct iattr *ia) +{ + int err; @@ -21685,12 +21822,12 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + struct super_block *sb; + struct file *file; + struct au_icpup_args *a; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + inode = d_inode(dentry); + IMustLock(inode); + -+ err = setattr_prepare(userns, dentry, ia); ++ err = setattr_prepare(idmap, dentry, ia); + if (unlikely(err)) + goto out; + @@ -21784,8 +21921,8 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + * 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); ++ h_idmap = mnt_idmap(a->h_path.mnt); ++ err = vfsub_acl_chmod(h_idmap, a->h_path.dentry, ia->ia_mode); + } + if (!err) + au_cpup_attr_changeable(inode); @@ -21848,7 +21985,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + struct super_block *sb; + struct au_icpup_args *a; + struct inode *h_inode; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + IMustLock(inode); + @@ -21867,13 +22004,13 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + 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); ++ h_idmap = mnt_idmap(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, ++ err = vfsub_setxattr(h_idmap, h_path.dentry, + arg->u.set.name, arg->u.set.value, + arg->u.set.size, arg->u.set.flags); + break; @@ -21882,7 +22019,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + 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, ++ err = h_inode->i_op->set_acl(h_idmap, h_path.dentry, + arg->u.acl_set.acl, + arg->u.acl_set.type); + } @@ -21915,18 +22052,17 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + /* 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; ++ inode_set_atime_to_ts(inode, st->atime); ++ inode_set_mtime_to_ts(inode, st->mtime); ++ inode_set_ctime_to_ts(inode, st->ctime); + + au_cpup_attr_nlink(inode, /*force*/0); + if (S_ISDIR(inode->i_mode)) { -+ n = inode->i_nlink; ++ n = vfsub_inode_nlink(inode, AU_I_AUFS); + n -= nlink; + n += st->nlink; -+ smp_mb(); /* for i_nlink */ + /* 0 can happen */ -+ set_nlink(inode, n); ++ vfsub_set_nlink(inode, n); + } + + spin_lock(&inode->i_lock); @@ -22016,7 +22152,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + return err; +} + -+static int aufs_getattr(struct user_namespace *userns, const struct path *path, ++static int aufs_getattr(struct mnt_idmap *idmap, const struct path *path, + struct kstat *st, u32 request, unsigned int query) +{ + int err; @@ -22041,20 +22177,25 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + goto out_fill; /* pretending success */ + + positive = d_is_positive(h_path.dentry); -+ if (positive) ++ if (positive) { + /* no vfsub version */ -+ err = vfs_getattr(&h_path, st, request, query); ++ if (query & AT_GETATTR_NOSEC) ++ err = vfs_getattr_nosec(&h_path, st, request, query); ++ else ++ err = vfs_getattr(&h_path, st, request, query); ++ } + if (!err) { + if (positive) + au_refresh_iattr(inode, st, -+ d_inode(h_path.dentry)->i_nlink); ++ vfsub_inode_nlink(d_inode(h_path.dentry), ++ AU_I_BRANCH)); + goto out_fill; /* success */ + } + AuTraceErr(err); + goto out_di; + +out_fill: -+ generic_fillattr(userns, inode, st); ++ generic_fillattr(idmap, request, inode, st); +out_di: + di_read_unlock(dentry, AuLock_IR); +out_si: @@ -22136,8 +22277,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + 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) ++static int aufs_update_time(struct inode *inode, int flags) +{ + int err; + aufs_bindex_t bindex; @@ -22161,7 +22301,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + h_mnt = au_sbr_mnt(sb, bindex); + err = vfsub_mnt_want_write(h_mnt); + if (!err) { -+ err = vfsub_update_time(h_inode, ts, flags); ++ err = vfsub_update_time(h_inode, flags); + vfsub_mnt_drop_write(h_mnt); + } + } else if (au_is_special(h_inode)) { @@ -22200,6 +22340,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + [AuIop_SYMLINK] = { + .permission = aufs_permission, +#ifdef CONFIG_FS_POSIX_ACL ++ .get_inode_acl = aufs_get_inode_acl, + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, /* unsupport for symlink? */ +#endif @@ -22211,7 +22352,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + .listxattr = aufs_listxattr, +#endif + -+ .get_link = aufs_get_link, ++ .get_link = aufs_get_link + + /* .update_time = aufs_update_time */ + }, @@ -22228,6 +22369,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + + .permission = aufs_permission, +#ifdef CONFIG_FS_POSIX_ACL ++ .get_inode_acl = aufs_get_inode_acl, + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, +#endif @@ -22246,6 +22388,7 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + [AuIop_OTHER] = { + .permission = aufs_permission, +#ifdef CONFIG_FS_POSIX_ACL ++ .get_inode_acl = aufs_get_inode_acl, + .get_acl = aufs_get_acl, + .set_acl = aufs_set_acl, +#endif @@ -22260,15 +22403,15 @@ diff -Naur null/fs/aufs/i_op.c linux-5.15.41/fs/aufs/i_op.c + .update_time = aufs_update_time + } +}; -diff -Naur null/fs/aufs/i_op_del.c linux-5.15.41/fs/aufs/i_op_del.c +diff -Naur null/fs/aufs/i_op_del.c linux-6.12.30/fs/aufs/i_op_del.c --- /dev/null -+++ linux-5.15.41/fs/aufs/i_op_del.c 2022-09-06 12:51:51.041709874 +0300 -@@ -0,0 +1,522 @@ ++++ linux-6.12.30/fs/aufs/i_op_del.c 2025-05-27 19:28:00.104257426 +0300 +@@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -22363,7 +22506,7 @@ diff -Naur null/fs/aufs/i_op_del.c linux-5.15.41/fs/aufs/i_op_del.c + struct path h_ppath; + struct super_block *sb; + struct au_branch *br; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + h_dentry = au_h_dptr(dentry, bindex); + if (d_really_is_positive(dentry)) { @@ -22371,7 +22514,7 @@ diff -Naur null/fs/aufs/i_op_del.c linux-5.15.41/fs/aufs/i_op_del.c + if (unlikely(d_is_negative(h_dentry))) + goto out; + h_inode = d_inode(h_dentry); -+ if (unlikely(!h_inode->i_nlink)) ++ if (unlikely(!vfsub_inode_nlink(h_inode, AU_I_BRANCH))) + goto out; + + h_mode = h_inode->i_mode; @@ -22403,15 +22546,15 @@ diff -Naur null/fs/aufs/i_op_del.c linux-5.15.41/fs/aufs/i_op_del.c + err = -EACCES; + sb = dentry->d_sb; + br = au_sbr(sb, bindex); -+ h_userns = au_br_userns(br); ++ h_idmap = au_br_idmap(br); + if (unlikely(!au_opt_test(au_mntflags(sb), DIRPERM1) -+ && au_test_h_perm(h_userns, d_inode(h_parent), ++ && au_test_h_perm(h_idmap, 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); ++ h_latest = au_sio_lkup_one(h_idmap, &dentry->d_name, &h_ppath); + err = -EIO; + if (IS_ERR(h_latest)) + goto out; @@ -22543,7 +22686,7 @@ diff -Naur null/fs/aufs/i_op_del.c linux-5.15.41/fs/aufs/i_op_del.c + + inode = d_inode(dentry); + d_drop(dentry); -+ inode->i_ctime = dir->i_ctime; ++ inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); + + au_dir_ts(dir, bindex); + inode_inc_iversion(dir); @@ -22579,7 +22722,7 @@ diff -Naur null/fs/aufs/i_op_del.c linux-5.15.41/fs/aufs/i_op_del.c +{ + int err; + aufs_bindex_t bwh, bindex, btop; -+ struct inode *inode, *h_dir, *delegated; ++ struct inode *inode, *h_dir, *delegated, *h_inode; + struct dentry *parent, *wh_dentry; + /* to reduce stack size */ + struct { @@ -22645,10 +22788,11 @@ diff -Naur null/fs/aufs/i_op_del.c linux-5.15.41/fs/aufs/i_op_del.c + if (bindex == btop) { + vfsub_update_h_iattr(&a->h_path, /*did*/NULL); + /*ignore*/ -+ inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ h_inode = d_inode(a->h_path.dentry); ++ inode_set_ctime_to_ts(inode, inode_get_ctime(h_inode)); + } else + /* todo: this timestamp may be reverted later */ -+ inode->i_ctime = h_dir->i_ctime; ++ inode_set_ctime_to_ts(inode, inode_get_ctime(h_dir)); + goto out_unpin; /* success */ + } + @@ -22786,15 +22930,15 @@ diff -Naur null/fs/aufs/i_op_del.c linux-5.15.41/fs/aufs/i_op_del.c + AuTraceErr(err); + return err; +} -diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c +diff -Naur null/fs/aufs/i_op_ren.c linux-6.12.30/fs/aufs/i_op_ren.c --- /dev/null -+++ linux-5.15.41/fs/aufs/i_op_ren.c 2022-09-06 12:51:51.041709874 +0300 -@@ -0,0 +1,1257 @@ ++++ linux-6.12.30/fs/aufs/i_op_ren.c 2025-05-27 19:28:00.104257426 +0300 +@@ -0,0 +1,1264 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -22819,18 +22963,18 @@ diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c +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 AuRen_ISDIR_SRC BIT(0) ++#define AuRen_ISDIR_DST BIT(1) ++#define AuRen_ISSAMEDIR BIT(2) ++#define AuRen_WHSRC BIT(3) ++#define AuRen_WHDST BIT(4) ++#define AuRen_MNT_WRITE BIT(5) ++#define AuRen_DT_DSTDIR BIT(6) ++#define AuRen_DIROPQ_SRC BIT(7) ++#define AuRen_DIROPQ_DST BIT(8) ++#define AuRen_DIRREN BIT(9) ++#define AuRen_DROPPED_SRC BIT(10) ++#define AuRen_DROPPED_DST BIT(11) +#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) +#define au_fset_ren(flags, name) \ + do { (flags) |= AuRen_##name; } while (0) @@ -23158,6 +23302,7 @@ diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c +{ + int err; + struct dentry *d, *h_d; ++ struct inode *h_inode; + + if (!a->exchange) { + /* prepare workqueue args for asynchronous rmdir */ @@ -23235,12 +23380,14 @@ diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c + 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; ++ h_inode = d_inode(a->h_path.dentry); ++ inode_set_ctime_to_ts(a->dst_inode, inode_get_ctime(h_inode)); + } + 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; ++ h_inode = d_inode(a->h_path.dentry); ++ inode_set_ctime_to_ts(a->src_inode, inode_get_ctime(h_inode)); + + if (!a->exchange) { + /* remove whiteout for dentry */ @@ -23440,7 +23587,7 @@ diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c + if (unlikely(d_is_negative(a->dst_h_dentry))) + goto out; + h_inode = d_inode(a->dst_h_dentry); -+ if (h_inode->i_nlink) ++ if (vfsub_inode_nlink(h_inode, AU_I_BRANCH)) + err = au_may_del(a->dst_dentry, a->btgt, + a->dst_h_parent, isdir); + } @@ -23522,6 +23669,10 @@ diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c + } + a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, + a->dst_h_parent, a->dst_hdir); ++ if (IS_ERR(a->h_trap)) { ++ err = PTR_ERR(a->h_trap); ++ goto out; ++ } + 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))) @@ -23751,7 +23902,7 @@ diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c + +/* ---------------------------------------------------------------------- */ + -+int aufs_rename(struct user_namespace *userns, ++int aufs_rename(struct mnt_idmap *idmap, + struct inode *_src_dir, struct dentry *_src_dentry, + struct inode *_dst_dir, struct dentry *_dst_dentry, + unsigned int _flags) @@ -23833,7 +23984,7 @@ diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c + * 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)) ++ if (unlikely(!vfsub_inode_nlink(a->dst_inode, AU_I_AUFS))) + goto out_unlock; + if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) { + err = au_d_hashed_positive(a->dst_dentry); @@ -24047,10 +24198,10 @@ diff -Naur null/fs/aufs/i_op_ren.c linux-5.15.41/fs/aufs/i_op_ren.c + AuTraceErr(err); + return err; +} -diff -Naur null/fs/aufs/Kconfig linux-5.15.41/fs/aufs/Kconfig +diff -Naur null/fs/aufs/Kconfig linux-6.12.30/fs/aufs/Kconfig --- /dev/null -+++ linux-5.15.41/fs/aufs/Kconfig 2022-09-06 12:51:51.034709962 +0300 -@@ -0,0 +1,199 @@ ++++ linux-6.12.30/fs/aufs/Kconfig 2025-05-27 19:28:00.099257488 +0300 +@@ -0,0 +1,201 @@ +# SPDX-License-Identifier: GPL-2.0 +config AUFS_FS + tristate "Aufs (Advanced multi layered unification filesystem) support" @@ -24115,13 +24266,15 @@ diff -Naur null/fs/aufs/Kconfig linux-5.15.41/fs/aufs/Kconfig + It will have a negative impact to the performance. + See detail in aufs.5. + ++if AUFS_HNOTIFY +choice -+ prompt "method" if AUFS_HNOTIFY ++ prompt "method" + default AUFS_HFSNOTIFY +config AUFS_HFSNOTIFY + bool "fsnotify" + select FSNOTIFY +endchoice ++endif + +config AUFS_EXPORT + bool "NFS-exportable aufs" @@ -24250,15 +24403,15 @@ diff -Naur null/fs/aufs/Kconfig linux-5.15.41/fs/aufs/Kconfig + Automatic configuration for internal use. + When aufs supports Magic SysRq, enabled automatically. +endif -diff -Naur null/fs/aufs/lcnt.h linux-5.15.41/fs/aufs/lcnt.h +diff -Naur null/fs/aufs/lcnt.h linux-6.12.30/fs/aufs/lcnt.h --- /dev/null -+++ linux-5.15.41/fs/aufs/lcnt.h 2022-09-06 12:51:51.042709862 +0300 ++++ linux-6.12.30/fs/aufs/lcnt.h 2025-05-27 19:28:00.105257413 +0300 @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2018-2021 Junjiro R. Okajima ++ * Copyright (C) 2018-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -24435,20 +24588,20 @@ diff -Naur null/fs/aufs/lcnt.h linux-5.15.41/fs/aufs/lcnt.h + AuDbg("%s = %ld\n", #val, l); \ +} while (0) +#else -+#define AuLCntZero(val) do {} while (0) ++AuStubVoid(AuLCntZero, long val __maybe_unused); +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_LCNT_H__ */ -diff -Naur null/fs/aufs/loop.c linux-5.15.41/fs/aufs/loop.c +diff -Naur null/fs/aufs/loop.c linux-6.12.30/fs/aufs/loop.c --- /dev/null -+++ linux-5.15.41/fs/aufs/loop.c 2022-09-06 12:51:51.042709862 +0300 ++++ linux-6.12.30/fs/aufs/loop.c 2025-05-27 19:28:00.105257413 +0300 @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -24592,15 +24745,15 @@ diff -Naur null/fs/aufs/loop.c linux-5.15.41/fs/aufs/loop.c + symbol_put(loop_backing_file); + au_kfree_try_rcu(au_warn_loopback_array); +} -diff -Naur null/fs/aufs/loop.h linux-5.15.41/fs/aufs/loop.h +diff -Naur null/fs/aufs/loop.h linux-6.12.30/fs/aufs/loop.h --- /dev/null -+++ linux-5.15.41/fs/aufs/loop.h 2022-09-06 12:51:51.042709862 +0300 ++++ linux-6.12.30/fs/aufs/loop.h 2025-05-27 19:28:00.105257413 +0300 @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -24651,9 +24804,9 @@ diff -Naur null/fs/aufs/loop.h linux-5.15.41/fs/aufs/loop.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_LOOP_H__ */ -diff -Naur null/fs/aufs/magic.mk linux-5.15.41/fs/aufs/magic.mk +diff -Naur null/fs/aufs/magic.mk linux-6.12.30/fs/aufs/magic.mk --- /dev/null -+++ linux-5.15.41/fs/aufs/magic.mk 2022-09-06 12:51:51.042709862 +0300 ++++ linux-6.12.30/fs/aufs/magic.mk 2025-05-27 19:28:00.105257413 +0300 @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0 + @@ -24686,9 +24839,9 @@ diff -Naur null/fs/aufs/magic.mk linux-5.15.41/fs/aufs/magic.mk +ifdef CONFIG_HFSPLUS_FS +ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b +endif -diff -Naur null/fs/aufs/Makefile linux-5.15.41/fs/aufs/Makefile +diff -Naur null/fs/aufs/Makefile linux-6.12.30/fs/aufs/Makefile --- /dev/null -+++ linux-5.15.41/fs/aufs/Makefile 2022-09-06 12:51:51.034709962 +0300 ++++ linux-6.12.30/fs/aufs/Makefile 2025-05-27 19:28:00.099257488 +0300 @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0 + @@ -24736,15 +24889,15 @@ diff -Naur null/fs/aufs/Makefile linux-5.15.41/fs/aufs/Makefile +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.41/fs/aufs/module.c +diff -Naur null/fs/aufs/module.c linux-6.12.30/fs/aufs/module.c --- /dev/null -+++ linux-5.15.41/fs/aufs/module.c 2022-09-06 12:51:51.042709862 +0300 -@@ -0,0 +1,273 @@ ++++ linux-6.12.30/fs/aufs/module.c 2025-05-27 19:28:00.105257413 +0300 +@@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -24875,7 +25028,8 @@ diff -Naur null/fs/aufs/module.c linux-5.15.41/fs/aufs/module.c + * iterate_supers_type() doesn't protect us from + * remounting (branch management) + */ -+struct hlist_bl_head au_sbilist; ++struct au_rwsem au_sbilist_lock; ++struct hlist_head au_sbilist; +#endif + +/* @@ -25009,19 +25163,20 @@ diff -Naur null/fs/aufs/module.c linux-5.15.41/fs/aufs/module.c + dbgaufs_fin(); + sysaufs_fin(); + au_dy_fin(); ++ au_sbilist_fin(); +} + +module_init(aufs_init); +module_exit(aufs_exit); -diff -Naur null/fs/aufs/module.h linux-5.15.41/fs/aufs/module.h +diff -Naur null/fs/aufs/module.h linux-6.12.30/fs/aufs/module.h --- /dev/null -+++ linux-5.15.41/fs/aufs/module.h 2022-09-06 12:51:51.042709862 +0300 -@@ -0,0 +1,166 @@ ++++ linux-6.12.30/fs/aufs/module.h 2025-05-27 19:28:00.105257413 +0300 +@@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -25148,15 +25303,17 @@ diff -Naur null/fs/aufs/module.h linux-5.15.41/fs/aufs/module.h + +extern struct kmem_cache *au_cache[AuCache_Last]; + -+#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++#define AuCacheFlags SLAB_RECLAIM_ACCOUNT +#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) \ ++#define AuCacheFuncAlloc(name, index) \ + static inline struct au_##name *au_cache_alloc_##name(void) \ -+ { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ ++ { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } ++ ++#define AuCacheFuncs(name, index) \ + static inline void au_cache_free_##name##_norcu(struct au_##name *p) \ + { kmem_cache_free(au_cache[AuCache_##index], p); } \ + \ @@ -25173,25 +25330,37 @@ diff -Naur null/fs/aufs/module.h linux-5.15.41/fs/aufs/module.h + au_cache_free_##name##_rcu(p); } + +AuCacheFuncs(dinfo, DINFO); ++AuCacheFuncAlloc(dinfo, DINFO); ++ +AuCacheFuncs(icntnr, ICNTNR); ++static inline struct au_icntnr *au_cache_alloc_icntnr(struct super_block *sb) ++{ return alloc_inode_sb(sb, au_cache[AuCache_ICNTNR], GFP_NOFS); } ++ +AuCacheFuncs(finfo, FINFO); ++AuCacheFuncAlloc(finfo, FINFO); ++ +AuCacheFuncs(vdir, VDIR); ++AuCacheFuncAlloc(vdir, VDIR); ++ +AuCacheFuncs(vdir_dehstr, DEHSTR); ++AuCacheFuncAlloc(vdir_dehstr, DEHSTR); ++ +#ifdef CONFIG_AUFS_HNOTIFY +AuCacheFuncs(hnotify, HNOTIFY); ++AuCacheFuncAlloc(hnotify, HNOTIFY); +#endif + +#endif /* __KERNEL__ */ +#endif /* __AUFS_MODULE_H__ */ -diff -Naur null/fs/aufs/mvdown.c linux-5.15.41/fs/aufs/mvdown.c +diff -Naur null/fs/aufs/mvdown.c linux-6.12.30/fs/aufs/mvdown.c --- /dev/null -+++ linux-5.15.41/fs/aufs/mvdown.c 2022-09-06 12:51:51.043709849 +0300 -@@ -0,0 +1,706 @@ ++++ linux-6.12.30/fs/aufs/mvdown.c 2025-05-27 19:28:00.105257413 +0300 +@@ -0,0 +1,714 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2011-2021 Junjiro R. Okajima ++ * Copyright (C) 2011-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -25363,6 +25532,13 @@ diff -Naur null/fs/aufs/mvdown.c linux-5.15.41/fs/aufs/mvdown.c + 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 (IS_ERR(h_trap)) { ++ err = PTR_ERR(h_trap); ++ 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; ++ } + if (h_trap) { + err = (h_trap != a->mvd_h_src_parent); + if (err) @@ -25589,15 +25765,16 @@ diff -Naur null/fs/aufs/mvdown.c linux-5.15.41/fs/aufs/mvdown.c + && 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) ++ && vfsub_inode_nlink(a->inode, AU_I_AUFS) == 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, ++ atomic_read(&a->inode->i_count), ++ vfsub_inode_nlink(a->inode, AU_I_AUFS), ++ vfsub_inode_nlink(a->mvd_h_src_inode, AU_I_BRANCH), + plinked, plinked ? au_plink_test(a->inode) : 0); + +out: @@ -25893,15 +26070,15 @@ diff -Naur null/fs/aufs/mvdown.c linux-5.15.41/fs/aufs/mvdown.c + AuTraceErr(err); + return err; +} -diff -Naur null/fs/aufs/opts.c linux-5.15.41/fs/aufs/opts.c +diff -Naur null/fs/aufs/opts.c linux-6.12.30/fs/aufs/opts.c --- /dev/null -+++ linux-5.15.41/fs/aufs/opts.c 2022-09-06 12:51:51.043709849 +0300 -@@ -0,0 +1,1032 @@ ++++ linux-6.12.30/fs/aufs/opts.c 2025-05-27 19:28:00.105257413 +0300 +@@ -0,0 +1,1030 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -26408,10 +26585,8 @@ diff -Naur null/fs/aufs/opts.c linux-5.15.41/fs/aufs/opts.c + 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); -+ } ++ } else ++ pr_warn_once("ignored nodio\n"); + break; + + case Opt_fhsm_sec: @@ -26570,8 +26745,8 @@ diff -Naur null/fs/aufs/opts.c linux-5.15.41/fs/aufs/opts.c + case Opt_prepend: + opt->add.bindex = 0; + fallthrough; -+ add: /* indented label */ + case Opt_add: ++ add: /* indented label */ + err = au_br_add(sb, &opt->add, + au_ftest_opts(opts->flags, REMOUNT)); + if (!err) { @@ -26929,15 +27104,15 @@ diff -Naur null/fs/aufs/opts.c linux-5.15.41/fs/aufs/opts.c +{ + return au_mntflags(sb) & AuOptMask_UDBA; +} -diff -Naur null/fs/aufs/opts.h linux-5.15.41/fs/aufs/opts.h +diff -Naur null/fs/aufs/opts.h linux-6.12.30/fs/aufs/opts.h --- /dev/null -+++ linux-5.15.41/fs/aufs/opts.h 2022-09-06 12:51:51.043709849 +0300 -@@ -0,0 +1,263 @@ ++++ linux-6.12.30/fs/aufs/opts.h 2025-05-27 19:28:00.105257413 +0300 +@@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -26992,23 +27167,23 @@ diff -Naur null/fs/aufs/opts.h linux-5.15.41/fs/aufs/opts.h +/* ---------------------------------------------------------------------- */ + +/* mount flags */ -+#define AuOpt_XINO 1 /* external inode number bitmap ++#define AuOpt_XINO BIT(0) /* 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 ++#define AuOpt_TRUNC_XINO BIT(1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE BIT(2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL BIT(3) ++#define AuOpt_UDBA_HNOTIFY BIT(4) ++#define AuOpt_SHWH BIT(5) /* show whiteout */ ++#define AuOpt_PLINK BIT(6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 BIT(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 */ ++#define AuOpt_ALWAYS_DIROPQ BIT(8) /* policy to creating diropq */ ++#define AuOpt_SUM BIT(9) /* summation for statfs(2) */ ++#define AuOpt_SUM_W BIT(10) /* unimplemented */ ++#define AuOpt_WARN_PERM BIT(11) /* warn when add-branch */ ++#define AuOpt_VERBOSE BIT(12) /* print the cause of error */ ++#define AuOpt_DIO BIT(13) /* direct io */ ++#define AuOpt_DIRREN BIT(14) /* directory rename */ + +#ifndef CONFIG_AUFS_HNOTIFY +#undef AuOpt_UDBA_HNOTIFY @@ -27027,7 +27202,8 @@ diff -Naur null/fs/aufs/opts.h linux-5.15.41/fs/aufs/opts.h + | AuOpt_UDBA_REVAL \ + | AuOpt_PLINK \ + /* | AuOpt_DIRPERM1 */ \ -+ | AuOpt_WARN_PERM) ++ | AuOpt_WARN_PERM \ ++ | AuOpt_DIO) +#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ + | AuOpt_UDBA_REVAL \ + | AuOpt_UDBA_HNOTIFY) @@ -27142,12 +27318,12 @@ diff -Naur null/fs/aufs/opts.h linux-5.15.41/fs/aufs/opts.h +}; + +/* 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 AuOpts_REMOUNT BIT(0) ++#define AuOpts_REFRESH BIT(1) ++#define AuOpts_TRUNC_XIB BIT(2) ++#define AuOpts_REFRESH_DYAOP BIT(3) ++#define AuOpts_REFRESH_IDOP BIT(4) ++#define AuOpts_DR_FLUSHED BIT(5) +#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) +#define au_fset_opts(flags, name) \ + do { (flags) |= AuOpts_##name; } while (0) @@ -27196,15 +27372,15 @@ diff -Naur null/fs/aufs/opts.h linux-5.15.41/fs/aufs/opts.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_OPTS_H__ */ -diff -Naur null/fs/aufs/plink.c linux-5.15.41/fs/aufs/plink.c +diff -Naur null/fs/aufs/plink.c linux-6.12.30/fs/aufs/plink.c --- /dev/null -+++ linux-5.15.41/fs/aufs/plink.c 2022-09-06 12:51:51.043709849 +0300 ++++ linux-6.12.30/fs/aufs/plink.c 2025-05-27 19:28:00.106257401 +0300 @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -27716,15 +27892,15 @@ diff -Naur null/fs/aufs/plink.c linux-5.15.41/fs/aufs/plink.c + } + } +} -diff -Naur null/fs/aufs/poll.c linux-5.15.41/fs/aufs/poll.c +diff -Naur null/fs/aufs/poll.c linux-6.12.30/fs/aufs/poll.c --- /dev/null -+++ linux-5.15.41/fs/aufs/poll.c 2022-09-06 12:51:51.044709837 +0300 ++++ linux-6.12.30/fs/aufs/poll.c 2025-05-27 19:28:00.106257401 +0300 @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -27771,15 +27947,15 @@ diff -Naur null/fs/aufs/poll.c linux-5.15.41/fs/aufs/poll.c + AuDbg("mask 0x%x\n", mask); + return mask; +} -diff -Naur null/fs/aufs/posix_acl.c linux-5.15.41/fs/aufs/posix_acl.c +diff -Naur null/fs/aufs/posix_acl.c linux-6.12.30/fs/aufs/posix_acl.c --- /dev/null -+++ linux-5.15.41/fs/aufs/posix_acl.c 2022-09-06 12:51:51.044709837 +0300 -@@ -0,0 +1,111 @@ ++++ linux-6.12.30/fs/aufs/posix_acl.c 2025-05-27 19:28:00.106257401 +0300 +@@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2014-2021 Junjiro R. Okajima ++ * Copyright (C) 2014-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -27800,7 +27976,7 @@ diff -Naur null/fs/aufs/posix_acl.c linux-5.15.41/fs/aufs/posix_acl.c +#include +#include "aufs.h" + -+struct posix_acl *aufs_get_acl(struct inode *inode, int type, bool rcu) ++struct posix_acl *aufs_get_inode_acl(struct inode *inode, int type, bool rcu) +{ + struct posix_acl *acl; + int err; @@ -27830,7 +28006,7 @@ diff -Naur null/fs/aufs/posix_acl.c linux-5.15.41/fs/aufs/posix_acl.c + } + + /* always topmost only */ -+ acl = get_acl(h_inode, type); ++ acl = get_inode_acl(h_inode, type); + if (IS_ERR(acl)) + forget_cached_acl(inode, type); + else @@ -27845,12 +28021,24 @@ diff -Naur null/fs/aufs/posix_acl.c linux-5.15.41/fs/aufs/posix_acl.c + return acl; +} + -+int aufs_set_acl(struct user_namespace *userns, struct inode *inode, ++struct posix_acl *aufs_get_acl(struct mnt_idmap *idmap, ++ struct dentry *dentry, int type) ++{ ++ struct posix_acl *acl; ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ acl = aufs_get_inode_acl(inode, type, /*rcu*/false); ++ ++ return acl; ++} ++ ++int aufs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, + struct posix_acl *acl, int type) +{ + int err; + ssize_t ssz; -+ struct dentry *dentry; ++ struct inode *inode; + struct au_sxattr arg = { + .type = AU_ACL_SET, + .u.acl_set = { @@ -27859,42 +28047,27 @@ diff -Naur null/fs/aufs/posix_acl.c linux-5.15.41/fs/aufs/posix_acl.c + }, + }; + ++ inode = d_inode(dentry); + 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.41/fs/aufs/procfs.c +diff -Naur null/fs/aufs/procfs.c linux-6.12.30/fs/aufs/procfs.c --- /dev/null -+++ linux-5.15.41/fs/aufs/procfs.c 2022-09-06 12:51:51.044709837 +0300 -@@ -0,0 +1,170 @@ ++++ linux-6.12.30/fs/aufs/procfs.c 2025-05-27 19:28:00.106257401 +0300 +@@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2010-2021 Junjiro R. Okajima ++ * Copyright (C) 2010-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -27942,22 +28115,20 @@ diff -Naur null/fs/aufs/procfs.c linux-5.15.41/fs/aufs/procfs.c + 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) ++ au_sbilist_read_lock(); ++ hlist_for_each_entry(sbinfo, &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); ++ au_sbilist_read_unlock(); + + err = -EINVAL; + if (unlikely(!sb)) @@ -28060,15 +28231,15 @@ diff -Naur null/fs/aufs/procfs.c linux-5.15.41/fs/aufs/procfs.c +out: + return err; +} -diff -Naur null/fs/aufs/rdu.c linux-5.15.41/fs/aufs/rdu.c +diff -Naur null/fs/aufs/rdu.c linux-6.12.30/fs/aufs/rdu.c --- /dev/null -+++ linux-5.15.41/fs/aufs/rdu.c 2022-09-06 12:51:51.044709837 +0300 ++++ linux-6.12.30/fs/aufs/rdu.c 2025-05-27 19:28:00.106257401 +0300 @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -28092,9 +28263,9 @@ diff -Naur null/fs/aufs/rdu.c linux-5.15.41/fs/aufs/rdu.c +#include "aufs.h" + +/* bits for struct aufs_rdu.flags */ -+#define AuRdu_CALLED 1 -+#define AuRdu_CONT (1 << 1) -+#define AuRdu_FULL (1 << 2) ++#define AuRdu_CALLED BIT(0) ++#define AuRdu_CONT BIT(1) ++#define AuRdu_FULL BIT(2) +#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) +#define au_fset_rdu(flags, name) \ + do { (flags) |= AuRdu_##name; } while (0) @@ -28111,8 +28282,8 @@ diff -Naur null/fs/aufs/rdu.c linux-5.15.41/fs/aufs/rdu.c + 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) ++static bool 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); @@ -28153,7 +28324,7 @@ diff -Naur null/fs/aufs/rdu.c linux-5.15.41/fs/aufs/rdu.c + +out: + /* AuTraceErr(err); */ -+ return err; ++ return !err; +} + +static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) @@ -28216,7 +28387,7 @@ diff -Naur null/fs/aufs/rdu.c linux-5.15.41/fs/aufs/rdu.c + arg.end += rdu->sz; + + err = -ENOTDIR; -+ if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared)) ++ if (unlikely(!file->f_op->iterate_shared)) + goto out; + + err = security_file_permission(file, MAY_READ); @@ -28448,15 +28619,15 @@ diff -Naur null/fs/aufs/rdu.c linux-5.15.41/fs/aufs/rdu.c + return err; +} +#endif -diff -Naur null/fs/aufs/rwsem.h linux-5.15.41/fs/aufs/rwsem.h +diff -Naur null/fs/aufs/rwsem.h linux-6.12.30/fs/aufs/rwsem.h --- /dev/null -+++ linux-5.15.41/fs/aufs/rwsem.h 2022-09-06 12:51:51.044709837 +0300 -@@ -0,0 +1,85 @@ ++++ linux-6.12.30/fs/aufs/rwsem.h 2025-05-27 19:28:00.106257401 +0300 +@@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -28485,7 +28656,11 @@ diff -Naur null/fs/aufs/rwsem.h linux-5.15.41/fs/aufs/rwsem.h +#define au_rwsem rw_semaphore + +/* to debug easier, do not make them inlined functions */ ++#ifndef CONFIG_PREEMPT_RT +#define AuRwMustNoWaiters(rw) AuDebugOn(rwsem_is_contended(rw)) ++#else ++AuStubVoid(AuRwMustNoWaiters, struct rw_semaphore *rw) ++#endif + +#ifdef CONFIG_LOCKDEP +/* rwsem_is_locked() is unusable */ @@ -28506,10 +28681,10 @@ diff -Naur null/fs/aufs/rwsem.h linux-5.15.41/fs/aufs/rwsem.h + && 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) ++AuStubVoid(AuRwMustReadLock, struct rw_semaphore *rw) ++AuStubVoid(AuRwMustWriteLock, struct rw_semaphore *rw) ++AuStubVoid(AuRwMustAnyLock, struct rw_semaphore *rw) ++AuStubVoid(AuRwDestroy, struct rw_semaphore *rw) +#endif + +#define au_rw_init(rw) init_rwsem(rw) @@ -28537,15 +28712,15 @@ diff -Naur null/fs/aufs/rwsem.h linux-5.15.41/fs/aufs/rwsem.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_RWSEM_H__ */ -diff -Naur null/fs/aufs/sbinfo.c linux-5.15.41/fs/aufs/sbinfo.c +diff -Naur null/fs/aufs/sbinfo.c linux-6.12.30/fs/aufs/sbinfo.c --- /dev/null -+++ linux-5.15.41/fs/aufs/sbinfo.c 2022-09-06 12:51:51.044709837 +0300 ++++ linux-6.12.30/fs/aufs/sbinfo.c 2025-05-27 19:28:00.106257401 +0300 @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -28857,15 +29032,15 @@ diff -Naur null/fs/aufs/sbinfo.c linux-5.15.41/fs/aufs/sbinfo.c + di_write_unlock2(d1, d2); + si_read_unlock(d1->d_sb); +} -diff -Naur null/fs/aufs/super.c linux-5.15.41/fs/aufs/super.c +diff -Naur null/fs/aufs/super.c linux-6.12.30/fs/aufs/super.c --- /dev/null -+++ linux-5.15.41/fs/aufs/super.c 2022-09-06 12:51:51.044709837 +0300 ++++ linux-6.12.30/fs/aufs/super.c 2025-05-27 19:28:00.106257401 +0300 @@ -0,0 +1,871 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -28897,7 +29072,7 @@ diff -Naur null/fs/aufs/super.c linux-5.15.41/fs/aufs/super.c +{ + struct au_icntnr *c; + -+ c = au_cache_alloc_icntnr(); ++ c = au_cache_alloc_icntnr(sb); + if (c) { + au_icntnr_init(c); + inode_set_iversion(&c->vfs_inode, 1); /* sigen(sb); */ @@ -28980,7 +29155,7 @@ diff -Naur null/fs/aufs/super.c linux-5.15.41/fs/aufs/super.c + return err; +} + -+static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat, ++static void au_gen_fmt(char *fmt, int len, const char *pat, + const char *append) +{ + char *p; @@ -28989,7 +29164,7 @@ diff -Naur null/fs/aufs/super.c linux-5.15.41/fs/aufs/super.c + while (*pat != ':') + *p++ = *pat++; + *p++ = *pat++; -+ strcpy(p, append); ++ strscpy(p, append, len - (p - fmt)); + AuDebugOn(strlen(fmt) >= len); +} + @@ -29654,7 +29829,7 @@ diff -Naur null/fs/aufs/super.c linux-5.15.41/fs/aufs/super.c + 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); ++ vfsub_inode_nlink_init(inode, 2); + unlock_new_inode(inode); + + root = d_make_root(inode); @@ -29732,15 +29907,15 @@ diff -Naur null/fs/aufs/super.c linux-5.15.41/fs/aufs/super.c + /* no need to __module_get() and module_put(). */ + .owner = THIS_MODULE, +}; -diff -Naur null/fs/aufs/super.h linux-5.15.41/fs/aufs/super.h +diff -Naur null/fs/aufs/super.h linux-6.12.30/fs/aufs/super.h --- /dev/null -+++ linux-5.15.41/fs/aufs/super.h 2022-09-06 12:51:51.045709824 +0300 -@@ -0,0 +1,592 @@ ++++ linux-6.12.30/fs/aufs/super.h 2025-05-27 19:28:00.106257401 +0300 +@@ -0,0 +1,618 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -29775,8 +29950,8 @@ diff -Naur null/fs/aufs/super.h linux-5.15.41/fs/aufs/super.h + int (*copyup)(struct dentry *dentry); +}; + -+#define AuWbr_DIR 1 /* target is a dir */ -+#define AuWbr_PARENT (1 << 1) /* always require a parent */ ++#define AuWbr_DIR BIT(0) /* target is a dir */ ++#define AuWbr_PARENT BIT(1) /* always require a parent */ + +#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) +#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } @@ -29934,7 +30109,7 @@ diff -Naur null/fs/aufs/super.h linux-5.15.41/fs/aufs/super.h +#endif + +#ifdef CONFIG_AUFS_SBILIST -+ struct hlist_bl_node si_list; ++ struct hlist_node si_list; +#endif + + /* dirty, necessary for unmounting, sysfs and sysrq */ @@ -29947,9 +30122,9 @@ diff -Naur null/fs/aufs/super.h linux-5.15.41/fs/aufs/super.h + * 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 */ ++#define AuSi_FAILED_REFRESH_DIR BIT(0) ++#define AuSi_FHSM BIT(1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL BIT(2) /* disable all d_revalidate */ + +#ifndef CONFIG_AUFS_FHSM +#undef AuSi_FHSM @@ -29981,15 +30156,15 @@ diff -Naur null/fs/aufs/super.h linux-5.15.41/fs/aufs/super.h + ((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 */ ++#define AuLock_DW BIT(0) /* write-lock dentry */ ++#define AuLock_IR BIT(1) /* read-lock inode */ ++#define AuLock_IW BIT(2) /* write-lock inode */ ++#define AuLock_FLUSH BIT(3) /* wait for 'nowait' tasks */ ++#define AuLock_DIRS BIT(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 AuLock_NOPLM BIT(5) /* return err in plm mode */ ++#define AuLock_NOPLMW BIT(6) /* wait for plm mode ends */ ++#define AuLock_GEN BIT(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) @@ -30114,45 +30289,71 @@ diff -Naur null/fs/aufs/super.h linux-5.15.41/fs/aufs/super.h + +#ifdef CONFIG_AUFS_SBILIST +/* module.c */ -+extern struct hlist_bl_head au_sbilist; ++extern struct au_rwsem au_sbilist_lock; ++extern struct hlist_head au_sbilist; + +static inline void au_sbilist_init(void) +{ -+ INIT_HLIST_BL_HEAD(&au_sbilist); ++ au_rw_init(&au_sbilist_lock); ++ INIT_HLIST_HEAD(&au_sbilist); ++} ++ ++static inline void au_sbilist_fin(void) ++{ ++ AuRwDestroy(&au_sbilist_lock); +} + +static inline void au_sbilist_add(struct super_block *sb) +{ -+ au_hbl_add(&au_sbi(sb)->si_list, &au_sbilist); ++ au_rw_write_lock(&au_sbilist_lock); ++ hlist_add_head(&au_sbi(sb)->si_list, &au_sbilist); ++ au_rw_write_unlock(&au_sbilist_lock); +} + +static inline void au_sbilist_del(struct super_block *sb) +{ -+ au_hbl_del(&au_sbi(sb)->si_list, &au_sbilist); ++ au_rw_write_lock(&au_sbilist_lock); ++ hlist_del(&au_sbi(sb)->si_list); ++ au_rw_write_unlock(&au_sbilist_lock); +} + +#ifdef CONFIG_AUFS_MAGIC_SYSRQ -+static inline void au_sbilist_lock(void) ++static inline void au_sbilist_write_lock(void) +{ -+ hlist_bl_lock(&au_sbilist); ++ au_rw_write_lock(&au_sbilist_lock); +} + -+static inline void au_sbilist_unlock(void) ++static inline void au_sbilist_write_unlock(void) +{ -+ hlist_bl_unlock(&au_sbilist); ++ au_rw_write_unlock(&au_sbilist_lock); ++} ++ ++static inline void au_sbilist_read_lock(void) ++{ ++ au_rw_read_lock(&au_sbilist_lock); ++} ++ ++static inline void au_sbilist_read_unlock(void) ++{ ++ au_rw_read_unlock(&au_sbilist_lock); +} +#define AuGFP_SBILIST GFP_ATOMIC +#else -+AuStubVoid(au_sbilist_lock, void) -+AuStubVoid(au_sbilist_unlock, void) ++AuStubVoid(au_sbilist_write_lock, void) ++AuStubVoid(au_sbilist_write_unlock, void) ++AuStubVoid(au_sbilist_read_lock, void) ++AuStubVoid(au_sbilist_read_unlock, void) +#define AuGFP_SBILIST GFP_NOFS +#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ +#else +AuStubVoid(au_sbilist_init, void) ++AuStubVoid(au_sbilist_fin, 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) ++AuStubVoid(au_sbilist_write_lock, void) ++AuStubVoid(au_sbilist_write_unlock, void) ++AuStubVoid(au_sbilist_read_lock, void) ++AuStubVoid(au_sbilist_read_unlock, void) +#define AuGFP_SBILIST GFP_NOFS +#endif + @@ -30328,15 +30529,15 @@ diff -Naur null/fs/aufs/super.h linux-5.15.41/fs/aufs/super.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_SUPER_H__ */ -diff -Naur null/fs/aufs/sysaufs.c linux-5.15.41/fs/aufs/sysaufs.c +diff -Naur null/fs/aufs/sysaufs.c linux-6.12.30/fs/aufs/sysaufs.c --- /dev/null -+++ linux-5.15.41/fs/aufs/sysaufs.c 2022-09-06 12:51:51.045709824 +0300 -@@ -0,0 +1,93 @@ ++++ linux-6.12.30/fs/aufs/sysaufs.c 2025-05-27 19:28:00.106257401 +0300 +@@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -30371,15 +30572,16 @@ diff -Naur null/fs/aufs/sysaufs.c linux-5.15.41/fs/aufs/sysaufs.c + &sysaufs_si_attr_xi_path.attr, + NULL, +}; ++ATTRIBUTE_GROUPS(sysaufs_si); + +static const struct sysfs_ops au_sbi_ops = { + .show = sysaufs_si_show +}; + -+static struct kobj_type au_sbi_ktype = { ++static const struct kobj_type au_sbi_ktype = { + .release = au_si_free, + .sysfs_ops = &au_sbi_ops, -+ .default_attrs = sysaufs_si_attrs ++ .default_groups = sysaufs_si_groups +}; + +/* ---------------------------------------------------------------------- */ @@ -30425,15 +30627,15 @@ diff -Naur null/fs/aufs/sysaufs.c linux-5.15.41/fs/aufs/sysaufs.c +out: + return err; +} -diff -Naur null/fs/aufs/sysaufs.h linux-5.15.41/fs/aufs/sysaufs.h +diff -Naur null/fs/aufs/sysaufs.h linux-6.12.30/fs/aufs/sysaufs.h --- /dev/null -+++ linux-5.15.41/fs/aufs/sysaufs.h 2022-09-06 12:51:51.045709824 +0300 ++++ linux-6.12.30/fs/aufs/sysaufs.h 2025-05-27 19:28:00.106257401 +0300 @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -30531,15 +30733,15 @@ diff -Naur null/fs/aufs/sysaufs.h linux-5.15.41/fs/aufs/sysaufs.h + +#endif /* __KERNEL__ */ +#endif /* __SYSAUFS_H__ */ -diff -Naur null/fs/aufs/sysfs.c linux-5.15.41/fs/aufs/sysfs.c +diff -Naur null/fs/aufs/sysfs.c linux-6.12.30/fs/aufs/sysfs.c --- /dev/null -+++ linux-5.15.41/fs/aufs/sysfs.c 2022-09-06 12:51:51.045709824 +0300 ++++ linux-6.12.30/fs/aufs/sysfs.c 2025-05-27 19:28:00.106257401 +0300 @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -30909,15 +31111,15 @@ diff -Naur null/fs/aufs/sysfs.c linux-5.15.41/fs/aufs/sysfs.c + } + } +} -diff -Naur null/fs/aufs/sysrq.c linux-5.15.41/fs/aufs/sysrq.c +diff -Naur null/fs/aufs/sysrq.c linux-6.12.30/fs/aufs/sysrq.c --- /dev/null -+++ linux-5.15.41/fs/aufs/sysrq.c 2022-09-06 12:51:51.045709824 +0300 -@@ -0,0 +1,149 @@ ++++ linux-6.12.30/fs/aufs/sysrq.c 2025-05-27 19:28:00.106257401 +0300 +@@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -31018,17 +31220,25 @@ diff -Naur null/fs/aufs/sysrq.c linux-5.15.41/fs/aufs/sysrq.c +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) ++static void au_sysrq_work_fn(struct work_struct *wk __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) ++ au_sbilist_read_lock(); ++ hlist_for_each_entry(sbinfo, &au_sbilist, si_list) + sysrq_sb(sbinfo->si_sb); -+ au_sbilist_unlock(); -+ lockdep_on(); ++ au_sbilist_read_unlock(); ++ ++ module_put(THIS_MODULE); ++} ++ ++static DECLARE_WORK(au_sysrq_work, au_sysrq_work_fn); ++ ++static void au_sysrq(u8 key __maybe_unused) ++{ ++ /* au_wkq is too much here */ ++ __module_get(THIS_MODULE); ++ schedule_work(&au_sysrq_work); +} + +static struct sysrq_key_op au_sysrq_op = { @@ -31062,15 +31272,15 @@ diff -Naur null/fs/aufs/sysrq.c linux-5.15.41/fs/aufs/sysrq.c + if (unlikely(err)) + pr_err("err %d (ignored)\n", err); +} -diff -Naur null/fs/aufs/vdir.c linux-5.15.41/fs/aufs/vdir.c +diff -Naur null/fs/aufs/vdir.c linux-6.12.30/fs/aufs/vdir.c --- /dev/null -+++ linux-5.15.41/fs/aufs/vdir.c 2022-09-06 12:51:51.045709824 +0300 ++++ linux-6.12.30/fs/aufs/vdir.c 2025-05-27 19:28:00.107257388 +0300 @@ -0,0 +1,896 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -31495,9 +31705,9 @@ diff -Naur null/fs/aufs/vdir.c linux-5.15.41/fs/aufs/vdir.c + +/* ---------------------------------------------------------------------- */ + -+#define AuFillVdir_CALLED 1 -+#define AuFillVdir_WHABLE (1 << 1) -+#define AuFillVdir_SHWH (1 << 2) ++#define AuFillVdir_CALLED BIT(0) ++#define AuFillVdir_WHABLE BIT(1) ++#define AuFillVdir_SHWH BIT(2) +#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) +#define au_fset_fillvdir(flags, name) \ + do { (flags) |= AuFillVdir_##name; } while (0) @@ -31520,7 +31730,7 @@ diff -Naur null/fs/aufs/vdir.c linux-5.15.41/fs/aufs/vdir.c + int err; +}; + -+static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, ++static bool fillvdir(struct dir_context *ctx, const char *__name, int nlen, + loff_t offset __maybe_unused, u64 h_ino, + unsigned int d_type) +{ @@ -31571,7 +31781,7 @@ diff -Naur null/fs/aufs/vdir.c linux-5.15.41/fs/aufs/vdir.c + arg->vdir->vd_jiffy = jiffies; + /* smp_mb(); */ + AuTraceErr(arg->err); -+ return arg->err; ++ return !arg->err; +} + +static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, @@ -31821,6 +32031,7 @@ diff -Naur null/fs/aufs/vdir.c linux-5.15.41/fs/aufs/vdir.c + goto out; + + allocated = NULL; ++ inode = file_inode(file); + vdir_cache = au_fvdir_cache(file); + if (!vdir_cache) { + vdir_cache = alloc_vdir(file); @@ -31828,7 +32039,8 @@ diff -Naur null/fs/aufs/vdir.c linux-5.15.41/fs/aufs/vdir.c + if (IS_ERR(vdir_cache)) + goto out; + allocated = vdir_cache; -+ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ } else if (!file->f_pos ++ && vdir_cache->vd_version != inode_query_iversion(inode)) { + /* test file->f_pos here instead of ctx->pos */ + err = reinit_vdir(vdir_cache); + if (unlikely(err)) @@ -31836,10 +32048,8 @@ diff -Naur null/fs/aufs/vdir.c linux-5.15.41/fs/aufs/vdir.c + } 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) @@ -31962,15 +32172,15 @@ diff -Naur null/fs/aufs/vdir.c linux-5.15.41/fs/aufs/vdir.c + /* smp_mb(); */ + return 0; +} -diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +diff -Naur null/fs/aufs/vfsub.c linux-6.12.30/fs/aufs/vfsub.c --- /dev/null -+++ linux-5.15.41/fs/aufs/vfsub.c 2022-09-06 12:51:51.045709824 +0300 -@@ -0,0 +1,918 @@ ++++ linux-6.12.30/fs/aufs/vfsub.c 2025-05-27 19:28:00.107257388 +0300 +@@ -0,0 +1,966 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -32019,6 +32229,53 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + +/* ---------------------------------------------------------------------- */ + ++unsigned int vfsub_inode_nlink_aufs(struct inode *inode) ++{ ++ unsigned int nlink; ++ ++ au_nlink_lock(inode); ++ nlink = inode->i_nlink; ++ au_nlink_unlock(inode); ++ ++ return nlink; ++} ++ ++void vfsub_inc_nlink(struct inode *inode) ++{ ++ au_nlink_lock(inode); ++ inc_nlink(inode); ++ au_nlink_unlock(inode); ++} ++ ++void vfsub_drop_nlink(struct inode *inode) ++{ ++ au_nlink_lock(inode); ++ AuDebugOn(!inode->i_nlink); ++ drop_nlink(inode); ++ au_nlink_unlock(inode); ++} ++ ++void vfsub_clear_nlink(struct inode *inode) ++{ ++ au_nlink_lock(inode); ++ /* it can happen */ ++ /* AuDebugOn(!inode->i_nlink); */ ++ clear_nlink(inode); ++ au_nlink_unlock(inode); ++} ++ ++void vfsub_set_nlink(struct inode *inode, unsigned int nlink) ++{ ++ /* ++ * stop setting the value equal to the current one, in order to stop ++ * a useless warning from vfs:destroy_inode() about sb->s_remove_count. ++ */ ++ au_nlink_lock(inode); ++ if (nlink != inode->i_nlink) ++ set_nlink(inode, nlink); ++ au_nlink_unlock(inode); ++} ++ +int vfsub_update_h_iattr(struct path *h_path, int *did) +{ + int err; @@ -32115,8 +32372,6 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + + /* 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 @@ -32192,10 +32447,13 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + lockdep_off(); + d = lock_rename(d1, d2); + lockdep_on(); ++ if (IS_ERR(d)) ++ goto out; + au_hn_suspend(hdir1); + if (hdir1 != hdir2) + au_hn_suspend(hdir2); + ++out: + return d; +} + @@ -32216,7 +32474,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +{ + int err; + struct dentry *d; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + + IMustLock(dir); + @@ -32226,10 +32484,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + path->dentry = d; + if (unlikely(err)) + goto out; -+ userns = mnt_user_ns(path->mnt); ++ idmap = mnt_idmap(path->mnt); + + lockdep_off(); -+ err = vfs_create(userns, dir, path->dentry, mode, want_excl); ++ err = vfs_create(idmap, dir, path->dentry, mode, want_excl); + lockdep_on(); + if (!err) { + struct path tmp = *path; @@ -32251,7 +32509,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +{ + int err; + struct dentry *d; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + + IMustLock(dir); + @@ -32261,10 +32519,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + path->dentry = d; + if (unlikely(err)) + goto out; -+ userns = mnt_user_ns(path->mnt); ++ idmap = mnt_idmap(path->mnt); + + lockdep_off(); -+ err = vfs_symlink(userns, dir, path->dentry, symname); ++ err = vfs_symlink(idmap, dir, path->dentry, symname); + lockdep_on(); + if (!err) { + struct path tmp = *path; @@ -32286,7 +32544,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +{ + int err; + struct dentry *d; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + + IMustLock(dir); + @@ -32296,10 +32554,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + path->dentry = d; + if (unlikely(err)) + goto out; -+ userns = mnt_user_ns(path->mnt); ++ idmap = mnt_idmap(path->mnt); + + lockdep_off(); -+ err = vfs_mknod(userns, dir, path->dentry, mode, dev); ++ err = vfs_mknod(idmap, dir, path->dentry, mode, dev); + lockdep_on(); + if (!err) { + struct path tmp = *path; @@ -32322,7 +32580,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + 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) ++ || vfsub_inode_nlink(inode, AU_I_BRANCH) < link_max) + return 0; + return -EMLINK; +} @@ -32332,7 +32590,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +{ + int err; + struct dentry *d; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + + IMustLock(dir); + @@ -32347,10 +32605,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + path->dentry = d; + if (unlikely(err)) + goto out; -+ userns = mnt_user_ns(path->mnt); ++ idmap = mnt_idmap(path->mnt); + + lockdep_off(); -+ err = vfs_link(src_dentry, userns, dir, path->dentry, delegated_inode); ++ err = vfs_link(src_dentry, idmap, dir, path->dentry, delegated_inode); + lockdep_on(); + if (!err) { + struct path tmp = *path; @@ -32393,10 +32651,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + if (unlikely(err)) + goto out; + -+ rd.old_mnt_userns = mnt_user_ns(path->mnt); ++ rd.old_mnt_idmap = mnt_idmap(path->mnt); + rd.old_dir = src_dir; + rd.old_dentry = src_dentry; -+ rd.new_mnt_userns = rd.old_mnt_userns; ++ rd.new_mnt_idmap = rd.old_mnt_idmap; + rd.new_dir = dir; + rd.new_dentry = path->dentry; + rd.delegated_inode = delegated_inode; @@ -32426,7 +32684,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +{ + int err; + struct dentry *d; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + + IMustLock(dir); + @@ -32436,10 +32694,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + path->dentry = d; + if (unlikely(err)) + goto out; -+ userns = mnt_user_ns(path->mnt); ++ idmap = mnt_idmap(path->mnt); + + lockdep_off(); -+ err = vfs_mkdir(userns, dir, path->dentry, mode); ++ err = vfs_mkdir(idmap, dir, path->dentry, mode); + lockdep_on(); + if (!err) { + struct path tmp = *path; @@ -32461,7 +32719,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +{ + int err; + struct dentry *d; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + + IMustLock(dir); + @@ -32471,10 +32729,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + path->dentry = d; + if (unlikely(err)) + goto out; -+ userns = mnt_user_ns(path->mnt); ++ idmap = mnt_idmap(path->mnt); + + lockdep_off(); -+ err = vfs_rmdir(userns, dir, path->dentry); ++ err = vfs_rmdir(idmap, dir, path->dentry); + lockdep_on(); + if (!err) { + struct path tmp = { @@ -32579,14 +32837,14 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + return err; +} + -+long vfsub_splice_to(struct file *in, loff_t *ppos, -+ struct pipe_inode_info *pipe, size_t len, -+ unsigned int flags) ++ssize_t vfsub_splice_read(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) +{ -+ long err; ++ ssize_t err; + + lockdep_off(); -+ err = do_splice_to(in, ppos, pipe, len, flags); ++ err = vfs_splice_read(in, ppos, pipe, len, flags); + lockdep_on(); + file_accessed(in); + if (err >= 0) @@ -32594,10 +32852,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + return err; +} + -+long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, -+ loff_t *ppos, size_t len, unsigned int flags) ++ssize_t vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) +{ -+ long err; ++ ssize_t err; + + lockdep_off(); + err = do_splice_from(pipe, out, ppos, len, flags); @@ -32632,7 +32890,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + int err; + struct inode *h_inode; + struct super_block *h_sb; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + if (!h_file) { + err = vfsub_truncate(h_path, length); @@ -32644,11 +32902,11 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + lockdep_off(); + sb_start_write(h_sb); + lockdep_on(); -+ err = security_path_truncate(h_path); ++ err = security_file_truncate(h_file); + if (!err) { -+ h_userns = mnt_user_ns(h_path->mnt); ++ h_idmap = mnt_idmap(h_path->mnt); + lockdep_off(); -+ err = do_truncate(h_userns, h_path->dentry, length, attr, ++ err = do_truncate(h_idmap, h_path->dentry, length, attr, + h_file); + lockdep_on(); + } @@ -32678,10 +32936,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) +{ + int err, do_sio, wkq_err; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + -+ userns = mnt_user_ns(path->mnt); -+ do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE); ++ idmap = mnt_idmap(path->mnt); ++ do_sio = au_test_h_perm_sio(idmap, dir, MAY_EXEC | MAY_WRITE); + if (!do_sio) { + lockdep_off(); + err = vfsub_mkdir(dir, path, mode); @@ -32716,10 +32974,10 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +int vfsub_sio_rmdir(struct inode *dir, struct path *path) +{ + int err, do_sio, wkq_err; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + -+ userns = mnt_user_ns(path->mnt); -+ do_sio = au_test_h_perm_sio(userns, dir, MAY_EXEC | MAY_WRITE); ++ idmap = mnt_idmap(path->mnt); ++ do_sio = au_test_h_perm_sio(idmap, dir, MAY_EXEC | MAY_WRITE); + if (!do_sio) { + lockdep_off(); + err = vfsub_rmdir(dir, path); @@ -32751,16 +33009,16 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c +{ + struct notify_change_args *a = args; + struct inode *h_inode; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + + 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); ++ idmap = mnt_idmap(a->path->mnt); + lockdep_off(); -+ *a->errp = notify_change(userns, a->path->dentry, a->ia, ++ *a->errp = notify_change(idmap, a->path->dentry, a->ia, + a->delegated_inode); + lockdep_on(); + if (!*a->errp) @@ -32817,7 +33075,7 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + struct unlink_args *a = args; + struct dentry *d = a->path->dentry; + struct inode *h_inode; -+ struct user_namespace *userns; ++ struct mnt_idmap *idmap; + const int stop_sillyrename = (au_test_nfs(d->d_sb) + && au_dcount(d) == 1); + @@ -32837,9 +33095,9 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + ihold(h_inode); + } + -+ userns = mnt_user_ns(a->path->mnt); ++ idmap = mnt_idmap(a->path->mnt); + lockdep_off(); -+ *a->errp = vfs_unlink(userns, a->dir, d, a->delegated_inode); ++ *a->errp = vfs_unlink(idmap, a->dir, d, a->delegated_inode); + lockdep_on(); + if (!*a->errp) { + struct path tmp = { @@ -32884,15 +33142,15 @@ diff -Naur null/fs/aufs/vfsub.c linux-5.15.41/fs/aufs/vfsub.c + + return err; +} -diff -Naur null/fs/aufs/vfsub.h linux-5.15.41/fs/aufs/vfsub.h +diff -Naur null/fs/aufs/vfsub.h linux-6.12.30/fs/aufs/vfsub.h --- /dev/null -+++ linux-5.15.41/fs/aufs/vfsub.h 2022-09-06 12:51:51.046709812 +0300 -@@ -0,0 +1,358 @@ ++++ linux-6.12.30/fs/aufs/vfsub.h 2025-05-27 19:28:00.107257388 +0300 +@@ -0,0 +1,441 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -32920,10 +33178,10 @@ diff -Naur null/fs/aufs/vfsub.h linux-5.15.41/fs/aufs/vfsub.h +#include +#include +#include "debug.h" ++#include "fstype.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 *); + +/* ---------------------------------------------------------------------- */ @@ -32947,17 +33205,55 @@ diff -Naur null/fs/aufs/vfsub.h linux-5.15.41/fs/aufs/vfsub.h + +/* ---------------------------------------------------------------------- */ + -+static inline void vfsub_drop_nlink(struct inode *inode) ++unsigned int vfsub_inode_nlink_aufs(struct inode *inode); ++ ++enum au_inode_type { ++ AU_I_AUFS, ++ AU_I_BRANCH, ++ AU_I_UNKNOWN ++}; ++ ++static inline unsigned int vfsub_inode_nlink(struct inode *inode, ++ enum au_inode_type type) +{ -+ AuDebugOn(!inode->i_nlink); -+ drop_nlink(inode); ++ unsigned int nlink; ++ ++ switch (type) { ++ case AU_I_AUFS: ++ nlink = vfsub_inode_nlink_aufs(inode); ++ break; ++ case AU_I_BRANCH: /* aufs cannot be a branch of another aufs mount */ ++ AuDebugOn(au_test_aufs(inode->i_sb)); ++ nlink = inode->i_nlink; ++ break; ++ case AU_I_UNKNOWN: ++ if (au_test_aufs(inode->i_sb)) ++ nlink = vfsub_inode_nlink_aufs(inode); ++ else ++ nlink = inode->i_nlink; ++ break; ++ }; ++ ++ return nlink; ++} ++ ++void vfsub_inc_nlink(struct inode *inode); ++void vfsub_drop_nlink(struct inode *inode); ++void vfsub_clear_nlink(struct inode *inode); ++void vfsub_set_nlink(struct inode *inode, unsigned int nlink); ++ ++static inline void vfsub_inode_nlink_init(struct inode *inode, ++ unsigned int nlink) ++{ ++ /* to ignore sb->s_remove_count, do not use set_nlink() */ ++ inode->__i_nlink = nlink; +} + +static inline void vfsub_dead_dir(struct inode *inode) +{ + AuDebugOn(!S_ISDIR(inode->i_mode)); + inode->i_flags |= S_DEAD; -+ clear_nlink(inode); ++ vfsub_clear_nlink(inode); +} + +static inline int vfsub_native_ro(struct inode *inode) @@ -33039,6 +33335,20 @@ diff -Naur null/fs/aufs/vfsub.h linux-5.15.41/fs/aufs/vfsub.h +} +#endif + ++static inline void vfsub_file_start_write(struct file *file) ++{ ++ lockdep_off(); ++ file_start_write(file); ++ lockdep_on(); ++} ++ ++static inline void vfsub_file_end_write(struct file *file) ++{ ++ lockdep_off(); ++ file_end_write(file); ++ lockdep_on(); ++} ++ +/* ---------------------------------------------------------------------- */ + +struct au_hinode; @@ -33116,34 +33426,33 @@ diff -Naur null/fs/aufs/vfsub.h linux-5.15.41/fs/aufs/vfsub.h +} +#endif + -+static inline int vfsub_update_time(struct inode *h_inode, -+ struct timespec64 *ts, int flags) ++static inline int vfsub_update_time(struct inode *h_inode, int flags) +{ -+ return inode_update_time(h_inode, ts, flags); ++ return inode_update_time(h_inode, 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) ++static inline int vfsub_acl_chmod(struct mnt_idmap *h_idmap, ++ struct dentry *h_dentry, umode_t h_mode) +{ + int err; + -+ err = posix_acl_chmod(h_userns, h_inode, h_mode); ++ err = posix_acl_chmod(h_idmap, h_dentry, 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); ++AuStubInt0(vfsub_acl_chmod, struct mnt_idmap *h_idmap, ++ struct dentry *h_dentry, 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); ++ssize_t vfsub_splice_read(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++ssize_t 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) +{ @@ -33219,42 +33528,74 @@ diff -Naur null/fs/aufs/vfsub.h linux-5.15.41/fs/aufs/vfsub.h + +/* ---------------------------------------------------------------------- */ + -+static inline int vfsub_setxattr(struct user_namespace *userns, ++static inline int vfsub_setxattr(struct mnt_idmap *idmap, + 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); ++ err = vfs_setxattr(idmap, dentry, name, value, size, flags); + lockdep_on(); + + return err; +} + -+static inline int vfsub_removexattr(struct user_namespace *userns, ++static inline int vfsub_removexattr(struct mnt_idmap *idmap, + struct dentry *dentry, const char *name) +{ + int err; + + lockdep_off(); -+ err = vfs_removexattr(userns, dentry, name); ++ err = vfs_removexattr(idmap, dentry, name); + lockdep_on(); + + return err; +} + ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_set_acl(struct mnt_idmap *idmap, ++ struct dentry *dentry, const char *name, ++ struct posix_acl *acl) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_set_acl(idmap, dentry, name, acl); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_remove_acl(struct mnt_idmap *idmap, ++ struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_remove_acl(idmap, dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++#else ++AuStubInt0(vfsub_set_acl, struct mnt_idmap *idmap, struct dentry *dentry, ++ const char *name, struct posix_acl *acl); ++AuStubInt0(vfsub_remove_acl, struct mnt_idmap *idmap, ++ struct dentry *dentry, const char *name); ++#endif ++ +#endif /* __KERNEL__ */ +#endif /* __AUFS_VFSUB_H__ */ -diff -Naur null/fs/aufs/wbr_policy.c linux-5.15.41/fs/aufs/wbr_policy.c +diff -Naur null/fs/aufs/wbr_policy.c linux-6.12.30/fs/aufs/wbr_policy.c --- /dev/null -+++ linux-5.15.41/fs/aufs/wbr_policy.c 2022-09-06 12:51:51.046709812 +0300 ++++ linux-6.12.30/fs/aufs/wbr_policy.c 2025-05-27 19:28:00.107257388 +0300 @@ -0,0 +1,830 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -33303,10 +33644,10 @@ diff -Naur null/fs/aufs/wbr_policy.c linux-5.15.41/fs/aufs/wbr_policy.c + return err; +} + -+#define AuCpdown_PARENT_OPQ 1 -+#define AuCpdown_WHED (1 << 1) -+#define AuCpdown_MADE_DIR (1 << 2) -+#define AuCpdown_DIROPQ (1 << 3) ++#define AuCpdown_PARENT_OPQ BIT(0) ++#define AuCpdown_WHED BIT(1) ++#define AuCpdown_MADE_DIR BIT(2) ++#define AuCpdown_DIROPQ BIT(3) +#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) +#define au_fset_cpdown(flags, name) \ + do { (flags) |= AuCpdown_##name; } while (0) @@ -34080,15 +34421,15 @@ diff -Naur null/fs/aufs/wbr_policy.c linux-5.15.41/fs/aufs/wbr_policy.c + .fin = au_wbr_create_fin_mfs + } +}; -diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c +diff -Naur null/fs/aufs/whout.c linux-6.12.30/fs/aufs/whout.c --- /dev/null -+++ linux-5.15.41/fs/aufs/whout.c 2022-09-06 12:51:51.046709812 +0300 ++++ linux-6.12.30/fs/aufs/whout.c 2025-05-27 19:28:00.107257388 +0300 @@ -0,0 +1,1072 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -34150,7 +34491,7 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + * 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, ++int au_wh_test(struct mnt_idmap *h_idmap, struct path *h_ppath, + struct qstr *wh_name, int try_sio) +{ + int err; @@ -34159,7 +34500,7 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + 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); ++ wh_dentry = au_sio_lkup_one(h_idmap, wh_name, h_ppath); + err = PTR_ERR(wh_dentry); + if (IS_ERR(wh_dentry)) { + if (err == -ENAMETOOLONG) @@ -34188,14 +34529,14 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c +/* + * test if the @h_path->dentry sets opaque or not. + */ -+int au_diropq_test(struct user_namespace *h_userns, struct path *h_path) ++int au_diropq_test(struct mnt_idmap *h_idmap, 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)); ++ err = au_wh_test(h_idmap, h_path, &diropq_name, ++ au_test_h_perm_sio(h_idmap, h_dir, MAY_EXEC)); + return err; +} + @@ -34213,7 +34554,7 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + static unsigned short cnt; + struct qstr qs; + struct path h_ppath; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); + @@ -34239,11 +34580,11 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + + h_ppath.dentry = h_parent; + h_ppath.mnt = au_br_mnt(br); -+ h_userns = au_br_userns(br); ++ h_idmap = au_br_idmap(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); ++ dentry = au_sio_lkup_one(h_idmap, &qs, &h_ppath); + if (IS_ERR(dentry) || d_is_negative(dentry)) + goto out_name; + dput(dentry); @@ -34840,11 +35181,11 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + unsigned int flags) +{ + struct dentry *diropq, *h_dentry; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + -+ h_userns = au_sbr_userns(dentry->d_sb, bindex); ++ h_idmap = au_sbr_idmap(dentry->d_sb, bindex); + h_dentry = au_h_dptr(dentry, bindex); -+ if (!au_test_h_perm_sio(h_userns, d_inode(h_dentry), ++ if (!au_test_h_perm_sio(h_idmap, d_inode(h_dentry), + MAY_EXEC | MAY_WRITE)) + diropq = do_diropq(dentry, bindex, flags); + else { @@ -35033,7 +35374,7 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + struct path wh_path; + struct inode *wh_inode, *h_dir; + struct au_branch *br; -+ struct user_namespace *h_userns; ++ struct mnt_idmap *h_idmap; + + h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ + IMustLock(h_dir); @@ -35041,7 +35382,7 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + 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); ++ h_idmap = au_br_idmap(br); + wh_inode = d_inode(wh_dentry); + inode_lock_nested(wh_inode, AuLsc_I_CHILD); + @@ -35049,7 +35390,7 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + * 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)) ++ if (!au_test_h_perm_sio(h_idmap, wh_inode, MAY_EXEC | MAY_WRITE)) + err = del_wh_children(&wh_path, whlist, bindex); + else { + int wkq_err; @@ -35067,10 +35408,10 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + inode_unlock(wh_inode); + + if (!err) { -+ h_nlink = h_dir->i_nlink; ++ h_nlink = vfsub_inode_nlink(h_dir, AU_I_BRANCH); + err = vfsub_rmdir(h_dir, &wh_path); + /* some fs doesn't change the parent nlink in some cases */ -+ h_nlink -= h_dir->i_nlink; ++ h_nlink -= vfsub_inode_nlink(h_dir, AU_I_BRANCH); + } + + if (!err) { @@ -35156,15 +35497,15 @@ diff -Naur null/fs/aufs/whout.c linux-5.15.41/fs/aufs/whout.c + au_whtmp_rmdir_free(args); + } +} -diff -Naur null/fs/aufs/whout.h linux-5.15.41/fs/aufs/whout.h +diff -Naur null/fs/aufs/whout.h linux-6.12.30/fs/aufs/whout.h --- /dev/null -+++ linux-5.15.41/fs/aufs/whout.h 2022-09-06 12:51:51.046709812 +0300 ++++ linux-6.12.30/fs/aufs/whout.h 2025-05-27 19:28:00.107257388 +0300 @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -35191,9 +35532,9 @@ diff -Naur null/fs/aufs/whout.h linux-5.15.41/fs/aufs/whout.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, ++int au_wh_test(struct mnt_idmap *h_idmap, struct path *h_ppath, + struct qstr *wh_name, int try_sio); -+int au_diropq_test(struct user_namespace *h_userns, struct path *h_path); ++int au_diropq_test(struct mnt_idmap *h_idmap, struct path *h_path); +struct au_branch; +struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, + struct qstr *prefix); @@ -35247,15 +35588,15 @@ diff -Naur null/fs/aufs/whout.h linux-5.15.41/fs/aufs/whout.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WHOUT_H__ */ -diff -Naur null/fs/aufs/wkq.c linux-5.15.41/fs/aufs/wkq.c +diff -Naur null/fs/aufs/wkq.c linux-6.12.30/fs/aufs/wkq.c --- /dev/null -+++ linux-5.15.41/fs/aufs/wkq.c 2022-09-06 12:51:51.046709812 +0300 -@@ -0,0 +1,372 @@ ++++ linux-6.12.30/fs/aufs/wkq.c 2025-05-27 19:28:00.107257388 +0300 +@@ -0,0 +1,370 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -35484,8 +35825,6 @@ diff -Naur null/fs/aufs/wkq.c linux-5.15.41/fs/aufs/wkq.c +/* + * 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); @@ -35532,7 +35871,7 @@ diff -Naur null/fs/aufs/wkq.c linux-5.15.41/fs/aufs/wkq.c +int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) +{ + int err; -+ AuWkqCompDeclare(comp); ++ struct completion *comp = NULL; + struct au_wkinfo wkinfo = { + .flags = flags, + .func = func, @@ -35623,15 +35962,15 @@ diff -Naur null/fs/aufs/wkq.c linux-5.15.41/fs/aufs/wkq.c + + return err; +} -diff -Naur null/fs/aufs/wkq.h linux-5.15.41/fs/aufs/wkq.h +diff -Naur null/fs/aufs/wkq.h linux-6.12.30/fs/aufs/wkq.h --- /dev/null -+++ linux-5.15.41/fs/aufs/wkq.h 2022-09-06 12:51:51.047709799 +0300 ++++ linux-6.12.30/fs/aufs/wkq.h 2025-05-27 19:28:00.108257376 +0300 @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -35674,8 +36013,8 @@ diff -Naur null/fs/aufs/wkq.h linux-5.15.41/fs/aufs/wkq.h +typedef void (*au_wkq_func_t)(void *args); + +/* wkq flags */ -+#define AuWkq_WAIT 1 -+#define AuWkq_NEST (1 << 1) ++#define AuWkq_WAIT BIT(0) ++#define AuWkq_NEST BIT(1) +#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) +#define au_fset_wkq(flags, name) \ + do { (flags) |= AuWkq_##name; } while (0) @@ -35716,15 +36055,15 @@ diff -Naur null/fs/aufs/wkq.h linux-5.15.41/fs/aufs/wkq.h + +#endif /* __KERNEL__ */ +#endif /* __AUFS_WKQ_H__ */ -diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c +diff -Naur null/fs/aufs/xattr.c linux-6.12.30/fs/aufs/xattr.c --- /dev/null -+++ linux-5.15.41/fs/aufs/xattr.c 2022-09-06 12:51:51.047709799 +0300 -@@ -0,0 +1,368 @@ ++++ linux-6.12.30/fs/aufs/xattr.c 2025-05-27 19:28:00.108257376 +0300 +@@ -0,0 +1,360 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2014-2021 Junjiro R. Okajima ++ * Copyright (C) 2014-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -35743,7 +36082,6 @@ diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c + */ + +#include -+#include +#include +#include "aufs.h" + @@ -35790,39 +36128,57 @@ diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c + char *name, char **buf, unsigned int ignore_flags, + unsigned int verbose) +{ -+ int err; ++ int err, is_acl; + ssize_t ssz; + struct inode *h_idst; + struct dentry *h_dst_dentry, *h_src_dentry; -+ struct user_namespace *h_dst_userns, *h_src_userns; ++ struct mnt_idmap *h_dst_idmap, *h_src_idmap; ++ struct posix_acl *acl; + -+ h_src_userns = mnt_user_ns(h_src->mnt); ++ is_acl = !!is_posix_acl_xattr(name); ++ h_src_idmap = mnt_idmap(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; ++ if (is_acl) { ++ acl = vfs_get_acl(h_src_idmap, h_src_dentry, name); ++ AuDebugOn(!acl); ++ if (IS_ERR(acl)) { ++ err = PTR_ERR(acl); ++ if (err == -ENODATA) ++ err = 0; ++ else if (err == -EOPNOTSUPP ++ && au_test_nfs_noacl(d_inode(h_src_dentry))) ++ err = 0; ++ else if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ } else { ++ ssz = vfs_getxattr_alloc(h_src_idmap, h_src_dentry, name, buf, ++ 0, GFP_NOFS); ++ if (unlikely(ssz <= 0)) { ++ err = ssz; ++ if (err == -ENODATA) ++ err = 0; ++ else if (err == -EOPNOTSUPP ++ && (ignore_flags & au_xattr_out_of_list)) ++ err = 0; ++ else 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_idmap = mnt_idmap(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); ++ if (is_acl) { ++ err = vfsub_set_acl(h_dst_idmap, h_dst_dentry, name, acl); ++ posix_acl_release(acl); ++ } else ++ err = vfsub_setxattr(h_dst_idmap, h_dst_dentry, name, *buf, ++ ssz, /*flags*/0); + inode_lock_nested(h_idst, AuLsc_I_CHILD2); + if (unlikely(err)) { + if (verbose || au_debug_test()) @@ -35837,7 +36193,7 @@ diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c +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; ++ int err, unlocked; + ssize_t ssz; + struct dentry *h_dst_dentry, *h_src_dentry; + struct inode *h_isrc, *h_idst; @@ -35885,33 +36241,12 @@ diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c + err = 0; + e = p + ssz; + value = NULL; -+ acl_access = 0; -+ acl_default = 0; ++ ignore_flags |= au_xattr_out_of_list; + 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: @@ -35988,7 +36323,7 @@ diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c + break; + case AU_XATTR_GET: + AuDebugOn(d_is_negative(h_path.dentry)); -+ err = vfs_getxattr(mnt_user_ns(h_path.mnt), h_path.dentry, ++ err = vfs_getxattr(mnt_idmap(h_path.mnt), h_path.dentry, + arg->u.get.name, arg->u.get.value, + arg->u.get.size); + break; @@ -36060,7 +36395,7 @@ diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c +} + +static int au_xattr_set(const struct xattr_handler *handler, -+ struct user_namespace *userns, ++ struct mnt_idmap *idmap, + struct dentry *dentry, struct inode *inode, + const char *name, const void *value, size_t size, + int flags) @@ -36076,10 +36411,6 @@ diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c +}; + +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 +}; @@ -36088,15 +36419,15 @@ diff -Naur null/fs/aufs/xattr.c linux-5.15.41/fs/aufs/xattr.c +{ + sb->s_xattr = au_xattr_handlers; +} -diff -Naur null/fs/aufs/xino.c linux-5.15.41/fs/aufs/xino.c +diff -Naur null/fs/aufs/xino.c linux-6.12.30/fs/aufs/xino.c --- /dev/null -+++ linux-5.15.41/fs/aufs/xino.c 2022-09-06 12:51:51.047709799 +0300 ++++ linux-6.12.30/fs/aufs/xino.c 2025-05-27 19:28:00.108257376 +0300 @@ -0,0 +1,1926 @@ +// SPDX-License-Identifier: GPL-2.0 +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -36291,7 +36622,7 @@ diff -Naur null/fs/aufs/xino.c linux-5.15.41/fs/aufs/xino.c + h_dir = d_inode(h_parent); + inode = file_inode(file); + /* no delegation since it is just created */ -+ if (inode->i_nlink) ++ if (vfsub_inode_nlink(inode, AU_I_BRANCH)) + err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, + /*force*/0); + inode_unlock(h_dir); @@ -36353,7 +36684,7 @@ diff -Naur null/fs/aufs/xino.c linux-5.15.41/fs/aufs/xino.c + } + + /* 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); ++ err = vfs_create(mnt_idmap(base->mnt), dir, path.dentry, 0666, NULL); + if (unlikely(err)) { + file = ERR_PTR(err); + pr_err("%pd create err %d\n", dentry, err); @@ -37192,7 +37523,7 @@ diff -Naur null/fs/aufs/xino.c linux-5.15.41/fs/aufs/xino.c + struct super_block *sb; + struct au_sbinfo *sbinfo; + -+ AuDebugOn(inode->i_nlink); ++ AuDebugOn(vfsub_inode_nlink(inode, AU_I_AUFS)); + + sb = inode->i_sb; + xib_calc_bit(inode->i_ino, &pindex, &bit); @@ -37881,7 +38212,7 @@ diff -Naur null/fs/aufs/xino.c linux-5.15.41/fs/aufs/xino.c + for (; bindex <= bbot; bindex++, hi++) { + h_inode = hi->hi_inode; + if (!h_inode -+ || (!unlinked && h_inode->i_nlink)) ++ || (!unlinked && vfsub_inode_nlink(h_inode, AU_I_BRANCH))) + continue; + + /* inode may not be revalidated */ @@ -38018,15 +38349,15 @@ diff -Naur null/fs/aufs/xino.c linux-5.15.41/fs/aufs/xino.c +out: + return err; +} -diff -Naur null/include/uapi/linux/aufs_type.h linux-5.15.41/include/uapi/linux/aufs_type.h +diff -Naur null/include/uapi/linux/aufs_type.h linux-6.12.30/include/uapi/linux/aufs_type.h --- /dev/null -+++ linux-5.15.41/include/uapi/linux/aufs_type.h 2022-09-06 12:51:51.048709787 +0300 ++++ linux-6.12.30/include/uapi/linux/aufs_type.h 2025-05-27 19:28:00.108257376 +0300 @@ -0,0 +1,452 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* -+ * Copyright (C) 2005-2021 Junjiro R. Okajima ++ * Copyright (C) 2005-2025 Junjiro R. Okajima + * -+ * This program, aufs is free software; you can redistribute it and/or modify ++ * 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. @@ -38064,7 +38395,7 @@ diff -Naur null/include/uapi/linux/aufs_type.h linux-5.15.41/include/uapi/linux/ +#include +#endif /* __KERNEL__ */ + -+#define AUFS_VERSION "5.15.41-20220620" ++#define AUFS_VERSION "6.12-20250414" + +/* todo? move this to linux-2.6.19/include/magic.h */ +#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') diff --git a/kernel/tools/perf/files/patches/aufs6/lockdep-debug.patch b/kernel/tools/perf/files/patches/aufs6/lockdep-debug.patch new file mode 100644 index 0000000000..81033ab74c --- /dev/null +++ b/kernel/tools/perf/files/patches/aufs6/lockdep-debug.patch @@ -0,0 +1,16 @@ +SPDX-License-Identifier: GPL-2.0 +aufs6.12 lockdep patch + +diff --git a/include/linux/lockdep_types.h b/include/linux/lockdep_types.h +index 9f361d3ab9d95..57efd6ffe7a44 100644 +--- a/include/linux/lockdep_types.h ++++ b/include/linux/lockdep_types.h +@@ -12,7 +12,7 @@ + + #include + +-#define MAX_LOCKDEP_SUBCLASSES 8UL ++#define MAX_LOCKDEP_SUBCLASSES (8UL + 4) + + enum lockdep_wait_type { + LD_WAIT_INV = 0, /* not checked, catch all */ diff --git a/kernel/tools/perf/files/patches/aufs5/tmpfs-idr.patch b/kernel/tools/perf/files/patches/aufs6/tmpfs-idr.patch similarity index 62% rename from kernel/tools/perf/files/patches/aufs5/tmpfs-idr.patch rename to kernel/tools/perf/files/patches/aufs6/tmpfs-idr.patch index f4313145bf..40cf01c2f3 100644 --- a/kernel/tools/perf/files/patches/aufs5/tmpfs-idr.patch +++ b/kernel/tools/perf/files/patches/aufs6/tmpfs-idr.patch @@ -1,10 +1,10 @@ SPDX-License-Identifier: GPL-2.0 diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h -index 166158b6e917..0e9606171432 100644 +index 515a9a6a3c6f..9de809dac3be 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h -@@ -28,10 +28,13 @@ struct shmem_inode_info { +@@ -55,10 +55,13 @@ struct shmem_quota_limits { }; struct shmem_sb_info { @@ -14,17 +14,17 @@ index 166158b6e917..0e9606171432 100644 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 */ +- unsigned long free_ispace; /* How much ispace left for allocation */ + int max_inodes; /* How many inodes are allowed */ -+ int free_inodes; /* How many are left for allocation */ ++ unsigned long free_ispace; /* 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 342d1bc72867..460e4c54483f 100644 +index 568bb290bdce..f8869230f782 100644 --- a/mm/shmem.c +++ b/mm/shmem.c -@@ -108,7 +108,7 @@ struct shmem_falloc { +@@ -112,7 +112,7 @@ struct shmem_falloc { struct shmem_options { unsigned long long blocks; @@ -33,7 +33,7 @@ index 342d1bc72867..460e4c54483f 100644 struct mempolicy *mpol; kuid_t uid; kgid_t gid; -@@ -128,11 +128,14 @@ static unsigned long shmem_default_max_blocks(void) +@@ -144,12 +144,14 @@ static unsigned long shmem_default_max_blocks(void) return totalram_pages() / 2; } @@ -43,52 +43,53 @@ index 342d1bc72867..460e4c54483f 100644 unsigned long nr_pages = totalram_pages(); + unsigned long ul; -- return min(nr_pages - totalhigh_pages(), nr_pages / 2); +- return min3(nr_pages - totalhigh_pages(), nr_pages / 2, +- ULONG_MAX / BOGO_INODE_SIZE); + 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) +@@ -1291,6 +1293,11 @@ static void shmem_evict_inode(struct inode *inode) + } - simple_xattrs_free(&info->xattrs); - WARN_ON(inode->i_blocks); + simple_xattrs_free(&info->xattrs, sbinfo->max_inodes ? &freed : NULL); + 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); + shmem_free_inode(inode->i_sb, freed); + WARN_ON(inode->i_blocks); clear_inode(inode); - } -@@ -2336,6 +2344,25 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode - break; - } +@@ -2854,6 +2861,25 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap, + 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 ++ 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); -@@ -3252,8 +3279,7 @@ static struct dentry *shmem_get_parent(struct dentry *child) + lockdep_annotate_inode_mutex_key(inode); + return inode; + } +@@ -4098,8 +4124,7 @@ static struct dentry *shmem_get_parent(struct dentry *child) static int shmem_match(struct inode *ino, void *vfh) { __u32 *fh = vfh; @@ -98,7 +99,7 @@ index 342d1bc72867..460e4c54483f 100644 return ino->i_ino == inum && fh[0] == ino->i_generation; } -@@ -3273,14 +3299,11 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, +@@ -4118,14 +4143,11 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, struct dentry *dentry = NULL; u64 inum; @@ -116,7 +117,7 @@ index 342d1bc72867..460e4c54483f 100644 if (inode) { dentry = shmem_find_alias(inode); iput(inode); -@@ -3292,30 +3315,15 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb, +@@ -4137,30 +4159,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) { @@ -150,53 +151,48 @@ index 342d1bc72867..460e4c54483f 100644 return 1; } -@@ -3394,7 +3402,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) +@@ -4259,7 +4266,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) +- if (*rest || ctx->inodes > ULONG_MAX / BOGO_INODE_SIZE) ++ if (*rest || ctx->inodes < 2 || ctx->inodes > INT_MAX) goto bad_value; ctx->seen |= SHMEM_SEEN_INODES; break; -@@ -3504,7 +3512,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; - -@@ -3573,7 +3581,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root) - seq_printf(seq, ",size=%luk", - sbinfo->max_blocks << (PAGE_SHIFT - 10)); +@@ -4541,7 +4548,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root) + if (sbinfo->max_blocks != shmem_default_max_blocks()) + seq_printf(seq, ",size=%luk", K(sbinfo->max_blocks)); 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)) -@@ -3620,6 +3628,8 @@ static void shmem_put_super(struct super_block *sb) - { - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - +@@ -4613,6 +4620,8 @@ static void shmem_put_super(struct super_block *sb) + #ifdef CONFIG_TMPFS_QUOTA + shmem_disable_quotas(sb); + #endif + if (!sbinfo->idr_nouse) + idr_destroy(&sbinfo->idr); free_percpu(sbinfo->ino_batch); percpu_counter_destroy(&sbinfo->used_blocks); mpol_put(sbinfo->mpol); -@@ -3662,6 +3672,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc) +@@ -4657,9 +4666,11 @@ 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; + sbinfo->max_inodes = ctx->inodes; +- sbinfo->free_ispace = sbinfo->max_inodes * BOGO_INODE_SIZE; ++ sbinfo->free_ispace = (unsigned long)sbinfo->max_inodes * BOGO_INODE_SIZE; if (sb->s_flags & SB_KERNMOUNT) { -@@ -3779,6 +3791,15 @@ static void shmem_destroy_inodecache(void) - kmem_cache_destroy(shmem_inode_cachep); + sbinfo->ino_batch = alloc_percpu(ino_t); + if (!sbinfo->ino_batch) +@@ -4804,6 +4815,15 @@ static int shmem_error_remove_folio(struct address_space *mapping, + return 0; } +static __init void shmem_no_idr(struct super_block *sb) @@ -208,10 +204,10 @@ index 342d1bc72867..460e4c54483f 100644 + idr_destroy(&sbinfo->idr); +} + - const struct address_space_operations shmem_aops = { + static const struct address_space_operations shmem_aops = { .writepage = shmem_writepage, - .set_page_dirty = __set_page_dirty_no_writeback, -@@ -3920,6 +3941,7 @@ int __init shmem_init(void) + .dirty_folio = noop_dirty_folio, +@@ -4968,6 +4988,7 @@ void __init shmem_init(void) pr_err("Could not kern_mount tmpfs\n"); goto out1; } diff --git a/kernel/tools/perf/files/patches/aufs5/vfs-ino.patch b/kernel/tools/perf/files/patches/aufs6/vfs-ino.patch similarity index 75% rename from kernel/tools/perf/files/patches/aufs5/vfs-ino.patch rename to kernel/tools/perf/files/patches/aufs6/vfs-ino.patch index 992d86c106..6ff72c1a42 100644 --- a/kernel/tools/perf/files/patches/aufs5/vfs-ino.patch +++ b/kernel/tools/perf/files/patches/aufs6/vfs-ino.patch @@ -1,10 +1,10 @@ SPDX-License-Identifier: GPL-2.0 diff --git a/fs/inode.c b/fs/inode.c -index 9abc88d7959c..82b13641423c 100644 +index 8dabb224f941..4f03eaa25cc2 100644 --- a/fs/inode.c +++ b/fs/inode.c -@@ -904,6 +904,8 @@ unsigned int get_next_ino(void) +@@ -1070,6 +1070,8 @@ unsigned int get_next_ino(void) unsigned int *p = &get_cpu_var(last_ino); unsigned int res = *p; @@ -13,7 +13,7 @@ index 9abc88d7959c..82b13641423c 100644 #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) +@@ -1082,7 +1084,7 @@ unsigned int get_next_ino(void) res++; /* get_next_ino should not provide a 0 inode number */ if (unlikely(!res)) diff --git a/kernel/tools/perf/files/patches/linux/patch-5.15.81.xz b/kernel/tools/perf/files/patches/linux/patch-5.15.81.xz deleted file mode 100644 index ece5544ea1..0000000000 Binary files a/kernel/tools/perf/files/patches/linux/patch-5.15.81.xz and /dev/null differ diff --git a/kernel/tools/perf/files/patches/linux/patch-6.12.54.xz b/kernel/tools/perf/files/patches/linux/patch-6.12.54.xz new file mode 100644 index 0000000000..eea7560b90 Binary files /dev/null and b/kernel/tools/perf/files/patches/linux/patch-6.12.54.xz differ diff --git a/kernel/tools/perf/files/patches/linux/patch-6.12.58.xz b/kernel/tools/perf/files/patches/linux/patch-6.12.58.xz new file mode 100644 index 0000000000..55e26dbe8c Binary files /dev/null and b/kernel/tools/perf/files/patches/linux/patch-6.12.58.xz differ diff --git a/kernel/tools/perf/files/patches/mageia/0001-Pull-device-0x0821-from-list-of-device-supported-by-.patch b/kernel/tools/perf/files/patches/mageia/0001-Pull-device-0x0821-from-list-of-device-supported-by-.patch new file mode 100644 index 0000000000..d519e9f8fb --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0001-Pull-device-0x0821-from-list-of-device-supported-by-.patch @@ -0,0 +1,28 @@ +From cfa62868adc134623104a759902a95bc71790614 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Giuseppe=20Ghib=C3=B2?= +Date: Sat, 16 Dec 2023 19:50:53 +0100 +Subject: [PATCH] Pull device 0x0821 from list of device supported by rtl8812au + drivers + +The Realtek device with ID 0x0821 seems better supported by upstream rtl8821ae +kernel module (see bug https://bugs.mageia.org/show_bug.cgi?id=31965). + +--- + drivers/staging/rtl8812au/os_dep/linux/usb_intf.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +index be0f654f0..c019fa82b 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +@@ -185,7 +185,6 @@ static struct usb_device_id rtw_usb_id_tbl[] = { + #ifdef CONFIG_RTL8821A + /*=== Realtek demoboard ===*/ + {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0811), .driver_info = RTL8821}, /* Default ID */ +- {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0821), .driver_info = RTL8821}, /* Default ID */ + {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8822), .driver_info = RTL8821}, /* Default ID */ + {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xA811) , .driver_info = RTL8821},/* Default ID */ + {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0820, 0xff, 0xff, 0xff), .driver_info = RTL8821}, /* 8821AU */ +-- +2.41.0 + diff --git a/kernel/tools/perf/files/patches/mageia/0001-rtl8812au-add-missed-prototypes.patch b/kernel/tools/perf/files/patches/mageia/0001-rtl8812au-add-missed-prototypes.patch new file mode 100644 index 0000000000..40392f5135 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0001-rtl8812au-add-missed-prototypes.patch @@ -0,0 +1,6262 @@ +From 292797fe6f0fda6ab984e68d07eb97d85daa4837 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Giuseppe=20Ghib=C3=B2?= +Date: Wed, 20 Nov 2024 22:23:47 +0100 +Subject: [PATCH] rtl8812au: add missed prototypes + +--- + .../staging/rtl8812au/core/efuse/rtw_efuse.c | 12 ++ + drivers/staging/rtl8812au/core/rtw_ap.c | 4 + + drivers/staging/rtl8812au/core/rtw_br_ext.c | 4 + + drivers/staging/rtl8812au/core/rtw_chplan.c | 3 +- + drivers/staging/rtl8812au/core/rtw_cmd.c | 12 ++ + .../staging/rtl8812au/core/rtw_ieee80211.c | 4 + + drivers/staging/rtl8812au/core/rtw_mi.c | 2 + + drivers/staging/rtl8812au/core/rtw_mlme.c | 5 + + drivers/staging/rtl8812au/core/rtw_mlme_ext.c | 30 ++++- + drivers/staging/rtl8812au/core/rtw_mp.c | 4 + + drivers/staging/rtl8812au/core/rtw_odm.c | 3 + + drivers/staging/rtl8812au/core/rtw_p2p.c | 12 ++ + drivers/staging/rtl8812au/core/rtw_pwrctrl.c | 2 + + drivers/staging/rtl8812au/core/rtw_recv.c | 27 ++++ + drivers/staging/rtl8812au/core/rtw_rf.c | 2 + + drivers/staging/rtl8812au/core/rtw_sreset.c | 3 + + drivers/staging/rtl8812au/core/rtw_sta_mgt.c | 4 + + drivers/staging/rtl8812au/core/rtw_vht.c | 3 + + .../staging/rtl8812au/core/rtw_wlan_util.c | 7 ++ + drivers/staging/rtl8812au/core/rtw_xmit.c | 5 + + drivers/staging/rtl8812au/hal/hal_com.c | 14 +++ + .../staging/rtl8812au/hal/hal_com_phycfg.c | 83 +++++++++++++ + drivers/staging/rtl8812au/hal/hal_dm.c | 7 +- + drivers/staging/rtl8812au/hal/hal_intf.c | 2 + + drivers/staging/rtl8812au/hal/hal_mp.c | 15 +++ + .../staging/rtl8812au/hal/led/hal_usb_led.c | 109 +++++++++++++++++ + .../rtl8812au/hal/phydm/halrf/halphyrf_ce.c | 3 + + .../staging/rtl8812au/hal/phydm/halrf/halrf.c | 4 + + .../rtl8812au/hal/phydm/halrf/halrf_debug.c | 3 + + .../rtl8812au/hal/phydm/halrf/halrf_kfree.c | 26 ++++ + .../hal/phydm/halrf/halrf_powertracking_ce.c | 2 + + .../hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c | 23 ++++ + .../hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c | 9 ++ + .../phydm/halrf/rtl8814a/halrf_iqk_8814a.c | 67 +++++++++- + .../phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c | 69 +++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm.c | 15 +++ + .../rtl8812au/hal/phydm/phydm_adaptivity.c | 11 ++ + .../rtl8812au/hal/phydm/phydm_adc_sampling.c | 5 + + .../staging/rtl8812au/hal/phydm/phydm_api.c | 16 +++ + .../rtl8812au/hal/phydm/phydm_beamforming.c | 107 ++++++++++++++++ + .../rtl8812au/hal/phydm/phydm_cck_pd.c | 5 + + .../staging/rtl8812au/hal/phydm/phydm_ccx.c | 24 ++++ + .../rtl8812au/hal/phydm/phydm_cfotracking.c | 3 + + .../staging/rtl8812au/hal/phydm/phydm_debug.c | 41 +++++++ + .../staging/rtl8812au/hal/phydm/phydm_dig.c | 23 ++++ + .../rtl8812au/hal/phydm/phydm_interface.c | 1 + + .../rtl8812au/hal/phydm/phydm_noisemonitor.c | 5 + + .../rtl8812au/hal/phydm/phydm_phystatus.c | 29 +++++ + .../rtl8812au/hal/phydm/phydm_rainfo.c | 16 +++ + .../rtl8812au/hal/phydm/phydm_rssi_monitor.c | 2 + + .../hal/phydm/rtl8821a/phydm_rtl8821a.c | 8 ++ + .../rtl8812au/hal/phydm/txbf/halcomtxbf.c | 16 +++ + .../rtl8812au/hal/phydm/txbf/haltxbf8814a.c | 4 + + .../rtl8812au/hal/phydm/txbf/haltxbfjaguar.c | 8 ++ + .../rtl8812au/hal/rtl8812a/rtl8812a_cmd.c | 13 ++ + .../hal/rtl8812a/rtl8812a_hal_init.c | 89 ++++++++++++++ + .../rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c | 74 +++++++++++ + .../rtl8812au/hal/rtl8812a/usb/usb_halinit.c | 65 +++++++++- + .../hal/rtl8812a/usb/usb_ops_linux.c | 1 + + .../rtl8812au/hal/rtl8814a/rtl8814a_cmd.c | 15 +++ + .../hal/rtl8814a/rtl8814a_hal_init.c | 115 ++++++++++++++++++ + .../rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c | 67 +++++++++- + .../rtl8812au/hal/rtl8814a/usb/usb_halinit.c | 58 ++++++++- + .../hal/rtl8814a/usb/usb_ops_linux.c | 1 + + .../rtl8812au/os_dep/linux/ioctl_cfg80211.c | 12 ++ + .../rtl8812au/os_dep/linux/ioctl_linux.c | 2 + + .../staging/rtl8812au/os_dep/linux/os_intfs.c | 18 ++- + .../rtl8812au/os_dep/linux/rtw_android.c | 11 ++ + .../staging/rtl8812au/os_dep/linux/rtw_proc.c | 13 ++ + .../staging/rtl8812au/os_dep/linux/usb_intf.c | 1 + + .../rtl8812au/os_dep/linux/usb_ops_linux.c | 1 + + .../rtl8812au/os_dep/linux/xmit_linux.c | 1 + + .../staging/rtl8812au/os_dep/osdep_service.c | 1 + + .../staging/rtl8812au/platform/platform_ops.c | 2 + + 74 files changed, 1467 insertions(+), 16 deletions(-) + +diff --git a/drivers/staging/rtl8812au/core/efuse/rtw_efuse.c b/drivers/staging/rtl8812au/core/efuse/rtw_efuse.c +index cca02619e..6587eb7fe 100644 +--- a/drivers/staging/rtl8812au/core/efuse/rtw_efuse.c ++++ b/drivers/staging/rtl8812au/core/efuse/rtw_efuse.c +@@ -793,6 +793,9 @@ void rtw_efuse_analyze(PADAPTER padapter, u8 Type, u8 Fake) + rtw_mfree((u8 *)eFuseWord, EFUSE_MAX_SECTION_NUM * (EFUSE_MAX_WORD_UNIT * 2)); + } + ++VOID efuse_PreUpdateAction( ++ PADAPTER pAdapter, ++ pu4Byte BackupRegs); + VOID efuse_PreUpdateAction( + PADAPTER pAdapter, + pu4Byte BackupRegs) +@@ -822,6 +825,9 @@ VOID efuse_PreUpdateAction( + } + + ++VOID efuse_PostUpdateAction( ++ PADAPTER pAdapter, ++ pu4Byte BackupRegs); + VOID efuse_PostUpdateAction( + PADAPTER pAdapter, + pu4Byte BackupRegs) +@@ -2214,6 +2220,12 @@ Efuse_PgPacketWrite(IN PADAPTER pAdapter, + } + + ++int ++Efuse_PgPacketWrite_BT(IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *data, ++ IN BOOLEAN bPseudoTest); + int + Efuse_PgPacketWrite_BT(IN PADAPTER pAdapter, + IN u8 offset, +diff --git a/drivers/staging/rtl8812au/core/rtw_ap.c b/drivers/staging/rtl8812au/core/rtw_ap.c +index 1912448ba..7c3cc03e8 100644 +--- a/drivers/staging/rtl8812au/core/rtw_ap.c ++++ b/drivers/staging/rtl8812au/core/rtw_ap.c +@@ -940,6 +940,7 @@ void rtw_update_bmc_sta_tx_rate(_adapter *adapter) + } + #endif + ++void rtw_init_bmc_sta_tx_rate(_adapter *padapter, struct sta_info *psta); + void rtw_init_bmc_sta_tx_rate(_adapter *padapter, struct sta_info *psta) + { + #ifdef CONFIG_BMC_TX_LOW_RATE +@@ -1027,6 +1028,7 @@ void update_bmc_sta(_adapter *padapter) + } + + #if defined(CONFIG_80211N_HT) && defined(CONFIG_BEAMFORMING) ++void update_sta_info_apmode_ht_bf_cap(_adapter *padapter, struct sta_info *psta); + void update_sta_info_apmode_ht_bf_cap(_adapter *padapter, struct sta_info *psta) + { + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); +@@ -2856,6 +2858,7 @@ int rtw_ap_set_wep_key(_adapter *padapter, u8 *key, u8 keylen, int keyid, u8 set + return rtw_ap_set_key(padapter, key, alg, keyid, set_tx); + } + ++u8 rtw_ap_bmc_frames_hdl(_adapter *padapter); + u8 rtw_ap_bmc_frames_hdl(_adapter *padapter) + { + #define HIQ_XMIT_COUNTS (6) +@@ -4182,6 +4185,7 @@ void start_ap_mode(_adapter *padapter) + + } + ++void rtw_ap_bcmc_sta_flush(_adapter *padapter); + void rtw_ap_bcmc_sta_flush(_adapter *padapter) + { + #ifdef CONFIG_CONCURRENT_MODE +diff --git a/drivers/staging/rtl8812au/core/rtw_br_ext.c b/drivers/staging/rtl8812au/core/rtw_br_ext.c +index c80474e8b..955a50912 100644 +--- a/drivers/staging/rtl8812au/core/rtw_br_ext.c ++++ b/drivers/staging/rtl8812au/core/rtw_br_ext.c +@@ -668,6 +668,7 @@ void nat25_db_cleanup(_adapter *priv) + } + + ++void nat25_db_expire(_adapter *priv); + void nat25_db_expire(_adapter *priv) + { + int i; +@@ -784,6 +785,7 @@ static int checkIPMcAndReplace(_adapter *priv, struct sk_buff *skb, unsigned int + } + #endif + ++int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method); + int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method) + { + unsigned short protocol; +@@ -1193,6 +1195,7 @@ int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method) + } + + ++int nat25_handle_frame(_adapter *priv, struct sk_buff *skb); + int nat25_handle_frame(_adapter *priv, struct sk_buff *skb) + { + #ifdef BR_EXT_DEBUG +@@ -1324,6 +1327,7 @@ struct dhcpMessage { + u_int8_t options[308]; /* 312 - cookie */ + }; + ++void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb); + void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb) + { + if (skb == NULL) +diff --git a/drivers/staging/rtl8812au/core/rtw_chplan.c b/drivers/staging/rtl8812au/core/rtw_chplan.c +index 34263a5fd..afefe957a 100644 +--- a/drivers/staging/rtl8812au/core/rtw_chplan.c ++++ b/drivers/staging/rtl8812au/core/rtw_chplan.c +@@ -404,7 +404,8 @@ bool rtw_chplan_is_empty(u8 id) + return _FALSE; + } + +-bool rtw_regsty_is_excl_chs(struct registry_priv *regsty, u8 ch) ++bool rtw_regsty_is_excl_chs(struct registry_priv *regsty, u8 ch); ++bool rtw_regsty_is_excl_chs(struct registry_priv *regsty, u8 ch) + { + int i; + +diff --git a/drivers/staging/rtl8812au/core/rtw_cmd.c b/drivers/staging/rtl8812au/core/rtw_cmd.c +index ca4e35b9b..62bd059c6 100644 +--- a/drivers/staging/rtl8812au/core/rtw_cmd.c ++++ b/drivers/staging/rtl8812au/core/rtw_cmd.c +@@ -2018,6 +2018,7 @@ u8 rtw_reset_securitypriv_cmd(_adapter *padapter) + + } + ++void free_assoc_resources_hdl(_adapter *padapter, u8 lock_scanned_queue); + void free_assoc_resources_hdl(_adapter *padapter, u8 lock_scanned_queue) + { + rtw_free_assoc_resources(padapter, lock_scanned_queue); +@@ -2177,6 +2178,7 @@ u8 rtw_set_chbw_cmd(_adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 flags) + return res; + } + ++u8 _rtw_set_chplan_cmd(_adapter *adapter, int flags, u8 chplan, const struct country_chplan *country_ent, u8 swconfig); + u8 _rtw_set_chplan_cmd(_adapter *adapter, int flags, u8 chplan, const struct country_chplan *country_ent, u8 swconfig) + { + struct cmd_obj *cmdobj; +@@ -2444,6 +2446,7 @@ u8 rtw_periodic_tsf_update_end_cmd(_adapter *adapter) + exit: + return res; + } ++u8 rtw_ssmps_wk_hdl(_adapter *adapter, struct ssmps_cmd_parm *ssmp_param); + u8 rtw_ssmps_wk_hdl(_adapter *adapter, struct ssmps_cmd_parm *ssmp_param) + { + u8 res = _SUCCESS; +@@ -3232,6 +3235,7 @@ void rtw_iface_dynamic_chk_wk_hdl(_adapter *padapter) + #endif + + } ++void rtw_dynamic_chk_wk_hdl(_adapter *padapter); + void rtw_dynamic_chk_wk_hdl(_adapter *padapter) + { + rtw_mi_dynamic_chk_wk_hdl(padapter); +@@ -3609,6 +3613,7 @@ u8 rtw_antenna_select_cmd(_adapter *padapter, u8 antenna, u8 enqueue) + } + #endif + ++void rtw_dm_ra_mask_hdl(_adapter *padapter, struct sta_info *psta); + void rtw_dm_ra_mask_hdl(_adapter *padapter, struct sta_info *psta) + { + if (psta) +@@ -3651,12 +3656,14 @@ u8 rtw_dm_ra_mask_wk_cmd(_adapter *padapter, u8 *psta) + + } + ++void power_saving_wk_hdl(_adapter *padapter); + void power_saving_wk_hdl(_adapter *padapter) + { + rtw_ps_processor(padapter); + } + + /* add for CONFIG_IEEE80211W, none 11w can use it */ ++void reset_securitypriv_hdl(_adapter *padapter); + void reset_securitypriv_hdl(_adapter *padapter) + { + rtw_reset_securitypriv(padapter); +@@ -4903,6 +4910,7 @@ inline u8 rtw_customer_str_write_cmd(_adapter *adapter, const u8 *cstr) + } + #endif /* CONFIG_RTW_CUSTOMER_STR */ + ++u8 rtw_c2h_wk_cmd(PADAPTER padapter, u8 *pbuf, u16 length, u8 type); + u8 rtw_c2h_wk_cmd(PADAPTER padapter, u8 *pbuf, u16 length, u8 type) + { + struct cmd_obj *ph2c; +@@ -5021,6 +5029,7 @@ s32 c2h_evt_hdl(_adapter *adapter, u8 *c2h_evt, c2h_id_filter filter) + } + #endif /* CONFIG_FW_C2H_REG */ + ++u8 session_tracker_cmd(_adapter *adapter, u8 cmd, struct sta_info *sta, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port); + u8 session_tracker_cmd(_adapter *adapter, u8 cmd, struct sta_info *sta, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port) + { + struct cmd_priv *cmdpriv = &adapter->cmdpriv; +@@ -5087,6 +5096,7 @@ inline u8 session_tracker_del_cmd(_adapter *adapter, struct sta_info *sta, u8 *l + return session_tracker_cmd(adapter, ST_CMD_DEL, sta, local_naddr, local_port, remote_naddr, remote_port); + } + ++void session_tracker_chk_for_sta(_adapter *adapter, struct sta_info *sta); + void session_tracker_chk_for_sta(_adapter *adapter, struct sta_info *sta) + { + struct st_ctl_t *st_ctl = &sta->st_ctl; +@@ -5169,6 +5179,7 @@ void session_tracker_chk_for_sta(_adapter *adapter, struct sta_info *sta) + return; + } + ++void session_tracker_chk_for_adapter(_adapter *adapter); + void session_tracker_chk_for_adapter(_adapter *adapter) + { + struct sta_priv *stapriv = &adapter->stapriv; +@@ -5201,6 +5212,7 @@ void session_tracker_chk_for_adapter(_adapter *adapter) + #endif + } + ++void session_tracker_cmd_hdl(_adapter *adapter, struct st_cmd_parm *parm); + void session_tracker_cmd_hdl(_adapter *adapter, struct st_cmd_parm *parm) + { + u8 cmd = parm->cmd; +diff --git a/drivers/staging/rtl8812au/core/rtw_ieee80211.c b/drivers/staging/rtl8812au/core/rtw_ieee80211.c +index 01bf7ffb4..ddfe0b921 100644 +--- a/drivers/staging/rtl8812au/core/rtw_ieee80211.c ++++ b/drivers/staging/rtl8812au/core/rtw_ieee80211.c +@@ -672,6 +672,7 @@ int rtw_get_wpa2_cipher_suite(u8 *s) + return 0; + } + ++u32 rtw_get_akm_suite_bitmap(u8 *s); + u32 rtw_get_akm_suite_bitmap(u8 *s) + { + if (_rtw_memcmp(s, WLAN_AKM_8021X, RSN_SELECTOR_LEN) == _TRUE) +@@ -1666,6 +1667,7 @@ void dump_ht_cap_ie_content(void *sel, const u8 *buf, u32 buf_len) + , HT_SUP_MCS_SET_ARG(HT_CAP_ELE_SUP_MCS_SET(buf))); + } + ++void dump_ht_cap_ie(void *sel, const u8 *ie, u32 ie_len); + void dump_ht_cap_ie(void *sel, const u8 *ie, u32 ie_len) + { + const u8 *ht_cap_ie; +@@ -1685,6 +1687,7 @@ const char *const _ht_sc_offset_str[] = { + "SCB", + }; + ++void dump_ht_op_ie_content(void *sel, const u8 *buf, u32 buf_len); + void dump_ht_op_ie_content(void *sel, const u8 *buf, u32 buf_len) + { + if (buf_len != HT_OP_IE_LEN) { +@@ -1699,6 +1702,7 @@ void dump_ht_op_ie_content(void *sel, const u8 *buf, u32 buf_len) + ); + } + ++void dump_ht_op_ie(void *sel, const u8 *ie, u32 ie_len); + void dump_ht_op_ie(void *sel, const u8 *ie, u32 ie_len) + { + const u8 *ht_op_ie; +diff --git a/drivers/staging/rtl8812au/core/rtw_mi.c b/drivers/staging/rtl8812au/core/rtw_mi.c +index 2a9added7..409c9d2ca 100644 +--- a/drivers/staging/rtl8812au/core/rtw_mi.c ++++ b/drivers/staging/rtl8812au/core/rtw_mi.c +@@ -883,6 +883,7 @@ void rtw_mi_buddy_xmit_tasklet_schedule(_adapter *padapter) + } + #endif + ++u8 _rtw_mi_busy_traffic_check(_adapter *padapter, void *data); + u8 _rtw_mi_busy_traffic_check(_adapter *padapter, void *data) + { + u32 passtime; +@@ -1342,6 +1343,7 @@ _adapter *rtw_get_iface_by_hwport(_adapter *padapter, u8 hw_port) + /*#define CONFIG_SKB_ALLOCATED*/ + #define DBG_SKB_PROCESS + #ifdef DBG_SKB_PROCESS ++void rtw_dbg_skb_process(_adapter *padapter, union recv_frame *precvframe, union recv_frame *pcloneframe); + void rtw_dbg_skb_process(_adapter *padapter, union recv_frame *precvframe, union recv_frame *pcloneframe) + { + _pkt *pkt_copy, *pkt_org; +diff --git a/drivers/staging/rtl8812au/core/rtw_mlme.c b/drivers/staging/rtl8812au/core/rtw_mlme.c +index 573358826..daeb92407 100644 +--- a/drivers/staging/rtl8812au/core/rtw_mlme.c ++++ b/drivers/staging/rtl8812au/core/rtw_mlme.c +@@ -20,6 +20,7 @@ extern void indicate_wx_scan_complete_event(_adapter *padapter); + extern u8 rtw_do_join(_adapter *padapter); + + ++void rtw_init_mlme_timer(_adapter *padapter); + void rtw_init_mlme_timer(_adapter *padapter) + { + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +@@ -37,6 +38,7 @@ void rtw_init_mlme_timer(_adapter *padapter) + #endif + } + ++sint _rtw_init_mlme_priv(_adapter *padapter); + sint _rtw_init_mlme_priv(_adapter *padapter) + { + sint i; +@@ -295,6 +297,7 @@ int rtw_mlme_update_wfd_ie_data(struct mlme_priv *mlme, u8 type, u8 *ie, u32 ie_ + } + #endif /* defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211) */ + ++void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv); + void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) + { + _adapter *adapter = mlme_to_adapter(pmlmepriv); +@@ -314,6 +317,7 @@ void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) + return; + } + ++sint _rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork); + sint _rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork) + { + _irqL irqL; +@@ -1633,6 +1637,7 @@ static void free_scanqueue(struct mlme_priv *pmlmepriv) + + } + ++void rtw_reset_rx_info(_adapter *adapter); + void rtw_reset_rx_info(_adapter *adapter) + { + struct recv_priv *precvpriv = &adapter->recvpriv; +diff --git a/drivers/staging/rtl8812au/core/rtw_mlme_ext.c b/drivers/staging/rtl8812au/core/rtw_mlme_ext.c +index 527e06dd5..0d79cde59 100644 +--- a/drivers/staging/rtl8812au/core/rtw_mlme_ext.c ++++ b/drivers/staging/rtl8812au/core/rtw_mlme_ext.c +@@ -1106,6 +1106,7 @@ static void init_mlme_ext_priv_value(_adapter *padapter) + #endif /* ROKU_PRIVATE */ + } + ++void init_mlme_ext_timer(_adapter *padapter); + void init_mlme_ext_timer(_adapter *padapter) + { + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +@@ -1380,6 +1381,7 @@ void mgt_dispatcher(_adapter *padapter, union recv_frame *precv_frame) + } + + #ifdef CONFIG_P2P ++u32 p2p_listen_state_process(_adapter *padapter, unsigned char *da); + u32 p2p_listen_state_process(_adapter *padapter, unsigned char *da) + { + bool response = _TRUE; +@@ -3081,7 +3083,8 @@ unsigned int OnAtim(_adapter *padapter, union recv_frame *precv_frame) + return _SUCCESS; + } + +-unsigned int on_action_spct_ch_switch(_adapter *padapter, struct sta_info *psta, u8 *ies, uint ies_len) ++unsigned int on_action_spct_ch_switch(_adapter *padapter, struct sta_info *psta, u8 *ies, uint ies_len); ++unsigned int on_action_spct_ch_switch(_adapter *padapter, struct sta_info *psta, u8 *ies, uint ies_len) + { + unsigned int ret = _FAIL; + struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv; +@@ -4134,6 +4137,7 @@ void issue_p2p_GO_request(_adapter *padapter, u8 *raddr) + } + + ++void issue_p2p_GO_response(_adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result); + void issue_p2p_GO_response(_adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result) + { + struct p2p_channels *ch_list = &(adapter_to_rfctl(padapter)->channel_list); +@@ -4556,6 +4560,7 @@ void issue_p2p_GO_response(_adapter *padapter, u8 *raddr, u8 *frame_body, uint l + + } + ++void issue_p2p_GO_confirm(_adapter *padapter, u8 *raddr, u8 result); + void issue_p2p_GO_confirm(_adapter *padapter, u8 *raddr, u8 result) + { + +@@ -5434,6 +5439,7 @@ void issue_p2p_provision_request(_adapter *padapter, u8 *pssid, u8 ussidlen, u8 + } + + ++u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo); + u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo) + { + u8 i, match_result = 0; +@@ -5786,6 +5792,7 @@ void issue_probersp_p2p(_adapter *padapter, unsigned char *da) + + } + ++int _issue_probereq_p2p(_adapter *padapter, u8 *da, int wait_ack); + int _issue_probereq_p2p(_adapter *padapter, u8 *da, int wait_ack) + { + int ret = _FAIL; +@@ -6163,6 +6170,7 @@ int issue_probereq_p2p_ex(_adapter *adapter, u8 *da, int try_cnt, int wait_ms) + + #endif /* CONFIG_P2P */ + ++s32 rtw_action_public_decache(union recv_frame *rframe, u8 token_offset); + s32 rtw_action_public_decache(union recv_frame *rframe, u8 token_offset) + { + _adapter *adapter = rframe->u.hdr.adapter; +@@ -6188,7 +6196,8 @@ s32 rtw_action_public_decache(union recv_frame *rframe, u8 token_offset) + return _SUCCESS; + } + +-unsigned int on_action_public_p2p(union recv_frame *precv_frame) ++unsigned int on_action_public_p2p(union recv_frame *precv_frame); ++unsigned int on_action_public_p2p(union recv_frame *precv_frame) + { + _adapter *padapter = precv_frame->u.hdr.adapter; + u8 *pframe = precv_frame->u.hdr.rx_data; +@@ -6564,6 +6573,7 @@ unsigned int on_action_public_p2p(union recv_frame *precv_frame) + return _SUCCESS; + } + ++unsigned int on_action_public_vendor(union recv_frame *precv_frame); + unsigned int on_action_public_vendor(union recv_frame *precv_frame) + { + unsigned int ret = _FAIL; +@@ -6594,6 +6604,7 @@ unsigned int on_action_public_vendor(union recv_frame *precv_frame) + return ret; + } + ++unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action); + unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action) + { + unsigned int ret = _FAIL; +@@ -7462,6 +7473,7 @@ unsigned int DoReserved(_adapter *padapter, union recv_frame *precv_frame) + return _SUCCESS; + } + ++struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once); + struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once) + { + struct xmit_frame *pmgntframe; +@@ -7762,6 +7774,7 @@ s32 dump_mgntframe_and_wait_ack(_adapter *padapter, struct xmit_frame *pmgntfram + } + + ++int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode); + int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) + { + u8 *ssid_ie; +@@ -8399,6 +8412,7 @@ void issue_probersp(_adapter *padapter, unsigned char *da, u8 is_valid_p2p_probe + + } + ++int _issue_probereq(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da, u8 ch, bool append_wps, int wait_ack); + int _issue_probereq(_adapter *padapter, const NDIS_802_11_SSID *pssid, const u8 *da, u8 ch, bool append_wps, int wait_ack) + { + int ret = _FAIL; +@@ -10560,6 +10574,7 @@ void issue_action_BSSCoexistPacket(_adapter *padapter) + } + + /* Spatial Multiplexing Powersave (SMPS) action frame */ ++int _issue_action_SM_PS(_adapter *padapter , unsigned char *raddr , u8 NewMimoPsMode , u8 wait_ack); + int _issue_action_SM_PS(_adapter *padapter , unsigned char *raddr , u8 NewMimoPsMode , u8 wait_ack) + { + +@@ -12591,6 +12606,7 @@ When station does not receive any packet in MAX_CONTINUAL_NORXPACKET_COUNT*2 sec + recipient station will teardown the block ack by issuing DELBA frame. + + *********************************************************************/ ++void rtw_delba_check(_adapter *padapter, struct sta_info *psta, u8 from_timer); + void rtw_delba_check(_adapter *padapter, struct sta_info *psta, u8 from_timer) + { + int i = 0; +@@ -12629,6 +12645,7 @@ void rtw_delba_check(_adapter *padapter, struct sta_info *psta, u8 from_timer) + } + } + ++u8 chk_ap_is_alive(_adapter *padapter, struct sta_info *psta); + u8 chk_ap_is_alive(_adapter *padapter, struct sta_info *psta) + { + u8 ret = _FALSE; +@@ -12669,6 +12686,7 @@ u8 chk_ap_is_alive(_adapter *padapter, struct sta_info *psta) + return ret; + } + ++u8 chk_adhoc_peer_is_alive(struct sta_info *psta); + u8 chk_adhoc_peer_is_alive(struct sta_info *psta) + { + u8 ret = _TRUE; +@@ -13210,6 +13228,7 @@ void addba_timer_hdl(void *ctx) + } + + #ifdef CONFIG_IEEE80211W ++void report_sta_timeout_event(_adapter *padapter, u8 *MacAddr, unsigned short reason); + void report_sta_timeout_event(_adapter *padapter, u8 *MacAddr, unsigned short reason) + { + struct cmd_obj *pcmd_obj; +@@ -13267,6 +13286,7 @@ void report_sta_timeout_event(_adapter *padapter, u8 *MacAddr, unsigned short re + return; + } + ++void clnt_sa_query_timeout(_adapter *padapter); + void clnt_sa_query_timeout(_adapter *padapter) + { + struct mlme_ext_priv *mlmeext = &(padapter->mlmeextpriv); +@@ -14253,6 +14273,7 @@ static bool scan_abort_hdl(_adapter *adapter) + return ret; + } + ++u8 rtw_scan_sparse(_adapter *adapter, struct rtw_ieee80211_channel *ch, u8 ch_num); + u8 rtw_scan_sparse(_adapter *adapter, struct rtw_ieee80211_channel *ch, u8 ch_num) + { + /* interval larger than this is treated as backgroud scan */ +@@ -14357,6 +14378,7 @@ u8 rtw_scan_sparse(_adapter *adapter, struct rtw_ieee80211_channel *ch, u8 ch_nu + } + + #ifdef CONFIG_SCAN_BACKOP ++u8 rtw_scan_backop_decision(_adapter *adapter); + u8 rtw_scan_backop_decision(_adapter *adapter) + { + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; +@@ -14772,6 +14794,7 @@ void site_survey(_adapter *padapter, u8 survey_channel, RT_SCAN_TYPE ScanType) + return; + } + ++void survey_done_set_ch_bw(_adapter *padapter); + void survey_done_set_ch_bw(_adapter *padapter) + { + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +@@ -14842,6 +14865,7 @@ void survey_done_set_ch_bw(_adapter *padapter) + * + * Returns: 0: no ps announcement is doing. 1: ps announcement is doing + */ ++u8 rtw_ps_annc(_adapter *adapter, bool ps); + u8 rtw_ps_annc(_adapter *adapter, bool ps) + { + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); +@@ -14931,6 +14955,7 @@ void rtw_back_opch(_adapter *adapter) + _exit_critical_mutex(&rfctl->offch_mutex, NULL); + } + ++void sitesurvey_set_igi(_adapter *adapter); + void sitesurvey_set_igi(_adapter *adapter) + { + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; +@@ -14991,6 +15016,7 @@ void sitesurvey_set_igi(_adapter *adapter) + break; + } + } ++void sitesurvey_set_msr(_adapter *adapter, bool enter); + void sitesurvey_set_msr(_adapter *adapter, bool enter) + { + u8 network_type; +diff --git a/drivers/staging/rtl8812au/core/rtw_mp.c b/drivers/staging/rtl8812au/core/rtw_mp.c +index bb7f78a4c..8d4966e32 100644 +--- a/drivers/staging/rtl8812au/core/rtw_mp.c ++++ b/drivers/staging/rtl8812au/core/rtw_mp.c +@@ -362,6 +362,7 @@ static VOID PHY_SetRFPathSwitch_default( + } + #endif + ++void mpt_InitHWConfig(PADAPTER Adapter); + void mpt_InitHWConfig(PADAPTER Adapter) + { + PHAL_DATA_TYPE hal; +@@ -1187,6 +1188,7 @@ int SetTxPower(PADAPTER pAdapter) + return _TRUE; + } + ++void SetTxAGCOffset(PADAPTER pAdapter, u32 ulTxAGCOffset); + void SetTxAGCOffset(PADAPTER pAdapter, u32 ulTxAGCOffset) + { + u32 TxAGCOffset_B, TxAGCOffset_C, TxAGCOffset_D, tmpAGC; +@@ -1483,6 +1485,7 @@ void fill_tx_desc_8188e(PADAPTER padapter) + #endif + + #if defined(CONFIG_RTL8814A) ++void fill_tx_desc_8814a(PADAPTER padapter); + void fill_tx_desc_8814a(PADAPTER padapter) + { + struct mp_priv *pmp_priv = &padapter->mppriv; +@@ -1541,6 +1544,7 @@ void fill_tx_desc_8814a(PADAPTER padapter) + #endif + + #if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) ++void fill_tx_desc_8812a(PADAPTER padapter); + void fill_tx_desc_8812a(PADAPTER padapter) + { + struct mp_priv *pmp_priv = &padapter->mppriv; +diff --git a/drivers/staging/rtl8812au/core/rtw_odm.c b/drivers/staging/rtl8812au/core/rtw_odm.c +index 4e1151d51..336dd9236 100644 +--- a/drivers/staging/rtl8812au/core/rtw_odm.c ++++ b/drivers/staging/rtl8812au/core/rtw_odm.c +@@ -64,6 +64,7 @@ void rtw_odm_init_ic_type(_adapter *adapter) + odm_cmn_info_init(odm, ODM_CMNINFO_IC_TYPE, ic_type); + } + ++void rtw_odm_adaptivity_ver_msg(void *sel, _adapter *adapter); + void rtw_odm_adaptivity_ver_msg(void *sel, _adapter *adapter) + { + RTW_PRINT_SEL(sel, "ADAPTIVITY_VERSION "ADAPTIVITY_VERSION"\n"); +@@ -72,6 +73,7 @@ void rtw_odm_adaptivity_ver_msg(void *sel, _adapter *adapter) + #define RTW_ADAPTIVITY_EN_DISABLE 0 + #define RTW_ADAPTIVITY_EN_ENABLE 1 + ++void rtw_odm_adaptivity_en_msg(void *sel, _adapter *adapter); + void rtw_odm_adaptivity_en_msg(void *sel, _adapter *adapter) + { + struct registry_priv *regsty = &adapter->registrypriv; +@@ -89,6 +91,7 @@ void rtw_odm_adaptivity_en_msg(void *sel, _adapter *adapter) + #define RTW_ADAPTIVITY_MODE_NORMAL 0 + #define RTW_ADAPTIVITY_MODE_CARRIER_SENSE 1 + ++void rtw_odm_adaptivity_mode_msg(void *sel, _adapter *adapter); + void rtw_odm_adaptivity_mode_msg(void *sel, _adapter *adapter) + { + struct registry_priv *regsty = &adapter->registrypriv; +diff --git a/drivers/staging/rtl8812au/core/rtw_p2p.c b/drivers/staging/rtl8812au/core/rtw_p2p.c +index f66fa7155..167dd067f 100644 +--- a/drivers/staging/rtl8812au/core/rtw_p2p.c ++++ b/drivers/staging/rtl8812au/core/rtw_p2p.c +@@ -18,6 +18,7 @@ + + #ifdef CONFIG_P2P + ++int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt); + int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt) + { + int found = 0, i = 0; +@@ -31,6 +32,7 @@ int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt) + return found ; + } + ++int is_any_client_associated(_adapter *padapter); + int is_any_client_associated(_adapter *padapter) + { + return padapter->stapriv.asoc_list_cnt ? _TRUE : _FALSE; +@@ -2551,6 +2553,7 @@ u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe) + return _TRUE; + } + ++u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list); + u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list) + { + u8 i = 0, j = 0; +@@ -2573,6 +2576,7 @@ u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 + return ch_no; + } + ++u8 rtw_p2p_ch_inclusion(_adapter *adapter, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned); + u8 rtw_p2p_ch_inclusion(_adapter *adapter, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned) + { + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); +@@ -3068,6 +3072,7 @@ u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint le + return _TRUE; + } + ++void find_phase_handler(_adapter *padapter); + void find_phase_handler(_adapter *padapter) + { + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +@@ -3093,6 +3098,7 @@ void find_phase_handler(_adapter *padapter) + + void p2p_concurrent_handler(_adapter *padapter); + ++void restore_p2p_state_handler(_adapter *padapter); + void restore_p2p_state_handler(_adapter *padapter) + { + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +@@ -3126,6 +3132,7 @@ void restore_p2p_state_handler(_adapter *padapter) + } + } + ++void pre_tx_invitereq_handler(_adapter *padapter); + void pre_tx_invitereq_handler(_adapter *padapter) + { + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +@@ -3138,6 +3145,7 @@ void pre_tx_invitereq_handler(_adapter *padapter) + + } + ++void pre_tx_provdisc_handler(_adapter *padapter); + void pre_tx_provdisc_handler(_adapter *padapter) + { + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +@@ -3150,6 +3158,7 @@ void pre_tx_provdisc_handler(_adapter *padapter) + + } + ++void pre_tx_negoreq_handler(_adapter *padapter); + void pre_tx_negoreq_handler(_adapter *padapter) + { + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +@@ -3737,6 +3746,7 @@ static void rtw_cfg80211_adjust_p2pie_channel(_adapter *padapter, const u8 *fram + #endif + + #ifdef CONFIG_WFD ++u32 rtw_xframe_build_wfd_ie(struct xmit_frame *xframe); + u32 rtw_xframe_build_wfd_ie(struct xmit_frame *xframe) + { + _adapter *adapter = xframe->padapter; +@@ -3815,6 +3825,7 @@ u32 rtw_xframe_build_wfd_ie(struct xmit_frame *xframe) + } + #endif /* CONFIG_WFD */ + ++bool rtw_xframe_del_wfd_ie(struct xmit_frame *xframe); + bool rtw_xframe_del_wfd_ie(struct xmit_frame *xframe) + { + #define DBG_XFRAME_DEL_WFD_IE 0 +@@ -3939,6 +3950,7 @@ u8 *dump_p2p_attr_ch_list(u8 *p2p_ie, uint p2p_ielen, u8 *buf, u32 buf_len) + /* + * return _TRUE if requester is GO, _FALSE if responder is GO + */ ++bool rtw_p2p_nego_intent_compare(u8 req, u8 resp); + bool rtw_p2p_nego_intent_compare(u8 req, u8 resp) + { + if (req >> 1 == resp >> 1) +diff --git a/drivers/staging/rtl8812au/core/rtw_pwrctrl.c b/drivers/staging/rtl8812au/core/rtw_pwrctrl.c +index 34e10dc0a..44d702868 100644 +--- a/drivers/staging/rtl8812au/core/rtw_pwrctrl.c ++++ b/drivers/staging/rtl8812au/core/rtw_pwrctrl.c +@@ -194,6 +194,7 @@ int ips_leave(_adapter *padapter) + int rtw_hw_resume(_adapter *padapter); + #endif + ++bool rtw_pwr_unassociated_idle(_adapter *adapter); + bool rtw_pwr_unassociated_idle(_adapter *adapter) + { + u8 i; +@@ -400,6 +401,7 @@ void rtw_ps_processor(_adapter *padapter) + return; + } + ++void pwr_state_check_handler(void *ctx); + void pwr_state_check_handler(void *ctx) + { + _adapter *padapter = (_adapter *)ctx; +diff --git a/drivers/staging/rtl8812au/core/rtw_recv.c b/drivers/staging/rtl8812au/core/rtw_recv.c +index 3c180740b..ed2bf605c 100644 +--- a/drivers/staging/rtl8812au/core/rtw_recv.c ++++ b/drivers/staging/rtl8812au/core/rtw_recv.c +@@ -851,6 +851,7 @@ sint recv_bcast_pn_decache(union recv_frame *precv_frame) + return _SUCCESS; + } + ++sint recv_decache(union recv_frame *precv_frame); + sint recv_decache(union recv_frame *precv_frame) + { + struct sta_info *psta = precv_frame->u.hdr.psta; +@@ -906,6 +907,7 @@ sint recv_decache(union recv_frame *precv_frame) + return _SUCCESS; + } + ++void process_pwrbit_data(_adapter *padapter, union recv_frame *precv_frame, struct sta_info *psta); + void process_pwrbit_data(_adapter *padapter, union recv_frame *precv_frame, struct sta_info *psta) + { + #ifdef CONFIG_AP_MODE +@@ -934,6 +936,7 @@ void process_pwrbit_data(_adapter *padapter, union recv_frame *precv_frame, stru + #endif + } + ++void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame, struct sta_info *psta); + void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame, struct sta_info *psta) + { + #ifdef CONFIG_AP_MODE +@@ -1167,6 +1170,11 @@ void count_rx_stats(_adapter *padapter, union recv_frame *prframe, struct sta_in + + } + ++sint sta2sta_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info **psta ++); + sint sta2sta_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, +@@ -1346,6 +1354,10 @@ sint sta2sta_data_frame( + + } + ++sint ap2sta_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info **psta); + sint ap2sta_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, +@@ -1486,6 +1498,10 @@ sint ap2sta_data_frame( + + } + ++sint sta2ap_data_frame( ++ _adapter *adapter, ++ union recv_frame *precv_frame, ++ struct sta_info **psta); + sint sta2ap_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, +@@ -1960,6 +1976,7 @@ static sint validate_mgmt_protect(_adapter *adapter, union recv_frame *precv_fra + + union recv_frame *recvframe_chk_defrag(PADAPTER padapter, union recv_frame *precv_frame); + ++sint validate_recv_mgnt_frame(PADAPTER padapter, union recv_frame *precv_frame); + sint validate_recv_mgnt_frame(PADAPTER padapter, union recv_frame *precv_frame) + { + struct sta_info *psta = precv_frame->u.hdr.psta +@@ -2051,6 +2068,7 @@ sint validate_recv_mgnt_frame(PADAPTER padapter, union recv_frame *precv_frame) + + } + ++sint validate_recv_data_frame(_adapter *adapter, union recv_frame *precv_frame); + sint validate_recv_data_frame(_adapter *adapter, union recv_frame *precv_frame) + { + u8 bretry, a4_shift; +@@ -2408,6 +2426,7 @@ sint validate_recv_frame(_adapter *adapter, union recv_frame *precv_frame) + + /* remove the wlanhdr and add the eth_hdr */ + #if 1 ++sint wlanhdr_to_ethhdr(union recv_frame *precvframe); + sint wlanhdr_to_ethhdr(union recv_frame *precvframe) + { + sint rmv_len; +@@ -3013,6 +3032,7 @@ static void recv_fwd_pkt_hdl(_adapter *adapter, _pkt *pkt + } + #endif /* CONFIG_RTW_MESH */ + ++int amsdu_to_msdu(_adapter *padapter, union recv_frame *prframe); + int amsdu_to_msdu(_adapter *padapter, union recv_frame *prframe) + { + struct rx_pkt_attrib *rattrib = &prframe->u.hdr.attrib; +@@ -3649,6 +3669,7 @@ static void recv_set_iseq_after_mpdu_process(union recv_frame *rframe, u16 seq_n + } + + #ifdef CONFIG_MP_INCLUDED ++int validate_mp_recv_frame(_adapter *adapter, union recv_frame *precv_frame); + int validate_mp_recv_frame(_adapter *adapter, union recv_frame *precv_frame) + { + int ret = _SUCCESS; +@@ -3785,6 +3806,7 @@ static sint MPwlanhdr_to_ethhdr(union recv_frame *precvframe) + } + + ++int mp_recv_frame(_adapter *padapter, union recv_frame *rframe); + int mp_recv_frame(_adapter *padapter, union recv_frame *rframe) + { + int ret = _SUCCESS; +@@ -4290,6 +4312,7 @@ static sint fill_radiotap_hdr(_adapter *padapter, union recv_frame *precvframe, + + } + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) ++int recv_frame_monitor(_adapter *padapter, union recv_frame *rframe); + int recv_frame_monitor(_adapter *padapter, union recv_frame *rframe) + { + int ret = _SUCCESS; +@@ -4336,6 +4359,7 @@ int recv_frame_monitor(_adapter *padapter, union recv_frame *rframe) + return ret; + } + #endif ++int recv_func_prehandle(_adapter *padapter, union recv_frame *rframe); + int recv_func_prehandle(_adapter *padapter, union recv_frame *rframe) + { + int ret = _SUCCESS; +@@ -4373,6 +4397,7 @@ int recv_func_prehandle(_adapter *padapter, union recv_frame *rframe) + } + + /*#define DBG_RX_BMC_FRAME*/ ++int recv_func_posthandle(_adapter *padapter, union recv_frame *prframe); + int recv_func_posthandle(_adapter *padapter, union recv_frame *prframe) + { + int ret = _SUCCESS; +@@ -4481,6 +4506,7 @@ int recv_func_posthandle(_adapter *padapter, union recv_frame *prframe) + return ret; + } + ++int recv_func(_adapter *padapter, union recv_frame *rframe); + int recv_func(_adapter *padapter, union recv_frame *rframe) + { + int ret; +@@ -4794,6 +4820,7 @@ static void rx_process_link_qual(_adapter *padapter, union recv_frame *prframe) + #endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + } + ++void rx_process_phy_info(_adapter *padapter, union recv_frame *rframe); + void rx_process_phy_info(_adapter *padapter, union recv_frame *rframe) + { + /* Check RSSI */ +diff --git a/drivers/staging/rtl8812au/core/rtw_rf.c b/drivers/staging/rtl8812au/core/rtw_rf.c +index 6d827c364..eb884c3ce 100644 +--- a/drivers/staging/rtl8812au/core/rtw_rf.c ++++ b/drivers/staging/rtl8812au/core/rtw_rf.c +@@ -588,6 +588,7 @@ const char *const _regd_str[] = { + }; + + #if CONFIG_TXPWR_LIMIT ++void _dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl); + void _dump_regd_exc_list(void *sel, struct rf_ctl_t *rfctl) + { + struct regd_exc_ent *ent; +@@ -1219,6 +1220,7 @@ int rtw_ch_to_bb_gain_sel(int ch) + return sel; + } + ++s8 rtw_rf_get_kfree_tx_gain_offset(_adapter *padapter, u8 path, u8 ch); + s8 rtw_rf_get_kfree_tx_gain_offset(_adapter *padapter, u8 path, u8 ch) + { + s8 kfree_offset = 0; +diff --git a/drivers/staging/rtl8812au/core/rtw_sreset.c b/drivers/staging/rtl8812au/core/rtw_sreset.c +index 03dba20f3..d3d4447b3 100644 +--- a/drivers/staging/rtl8812au/core/rtw_sreset.c ++++ b/drivers/staging/rtl8812au/core/rtw_sreset.c +@@ -101,6 +101,7 @@ bool sreset_inprogress(_adapter *padapter) + #endif + } + ++void sreset_restore_security_station(_adapter *padapter); + void sreset_restore_security_station(_adapter *padapter) + { + struct mlme_priv *mlmepriv = &padapter->mlmepriv; +@@ -137,6 +138,7 @@ void sreset_restore_security_station(_adapter *padapter) + } + } + ++void sreset_restore_network_station(_adapter *padapter); + void sreset_restore_network_station(_adapter *padapter) + { + struct mlme_priv *mlmepriv = &padapter->mlmepriv; +@@ -195,6 +197,7 @@ void sreset_restore_network_station(_adapter *padapter) + } + + ++void sreset_restore_network_status(_adapter *padapter); + void sreset_restore_network_status(_adapter *padapter) + { + struct mlme_priv *mlmepriv = &padapter->mlmepriv; +diff --git a/drivers/staging/rtl8812au/core/rtw_sta_mgt.c b/drivers/staging/rtl8812au/core/rtw_sta_mgt.c +index ddcd1f70b..b42102142 100644 +--- a/drivers/staging/rtl8812au/core/rtw_sta_mgt.c ++++ b/drivers/staging/rtl8812au/core/rtw_sta_mgt.c +@@ -16,6 +16,7 @@ + + #include + ++bool test_st_match_rule(_adapter *adapter, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port); + bool test_st_match_rule(_adapter *adapter, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port) + { + if (ntohs(*((u16 *)local_port)) == 5001 || ntohs(*((u16 *)remote_port)) == 5001) +@@ -365,6 +366,7 @@ static void _rtw_free_sta_recv_priv_lock(struct sta_recv_priv *psta_recvpriv) + + } + ++void rtw_mfree_stainfo(struct sta_info *psta); + void rtw_mfree_stainfo(struct sta_info *psta) + { + +@@ -376,6 +378,7 @@ void rtw_mfree_stainfo(struct sta_info *psta) + } + + /* this function is used to free the memory of lock || sema for all stainfos */ ++void rtw_mfree_all_stainfo(struct sta_priv *pstapriv); + void rtw_mfree_all_stainfo(struct sta_priv *pstapriv) + { + _irqL irqL; +@@ -1044,6 +1047,7 @@ const char *const _acl_mode_str[RTW_ACL_MODE_MAX] = { + "DENY_UNLESS_LISTED", + }; + ++u8 _rtw_access_ctrl(_adapter *adapter, u8 period, const u8 *mac_addr); + u8 _rtw_access_ctrl(_adapter *adapter, u8 period, const u8 *mac_addr) + { + u8 res = _TRUE; +diff --git a/drivers/staging/rtl8812au/core/rtw_vht.c b/drivers/staging/rtl8812au/core/rtw_vht.c +index 9a7608c8e..382813830 100644 +--- a/drivers/staging/rtl8812au/core/rtw_vht.c ++++ b/drivers/staging/rtl8812au/core/rtw_vht.c +@@ -39,6 +39,7 @@ const char *const _vht_sup_ch_width_set_str[] = { + "BW-RSVD", + }; + ++void dump_vht_cap_ie_content(void *sel, const u8 *buf, u32 buf_len); + void dump_vht_cap_ie_content(void *sel, const u8 *buf, u32 buf_len) + { + if (buf_len != VHT_CAP_IE_LEN) { +@@ -79,6 +80,7 @@ const char *const _vht_op_ch_width_str[] = { + "BW-RSVD", + }; + ++void dump_vht_op_ie_content(void *sel, const u8 *buf, u32 buf_len); + void dump_vht_op_ie_content(void *sel, const u8 *buf, u32 buf_len) + { + if (buf_len != VHT_OP_IE_LEN) { +@@ -359,6 +361,7 @@ u64 rtw_vht_mcs_map_to_bitmap(u8 *mcs_map, u8 nss) + } + + #ifdef CONFIG_BEAMFORMING ++void update_sta_vht_info_apmode_bf_cap(_adapter *padapter, struct sta_info *psta); + void update_sta_vht_info_apmode_bf_cap(_adapter *padapter, struct sta_info *psta) + { + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); +diff --git a/drivers/staging/rtl8812au/core/rtw_wlan_util.c b/drivers/staging/rtl8812au/core/rtw_wlan_util.c +index 817245957..a427c7c51 100644 +--- a/drivers/staging/rtl8812au/core/rtw_wlan_util.c ++++ b/drivers/staging/rtl8812au/core/rtw_wlan_util.c +@@ -1011,6 +1011,7 @@ inline bool rtw_sec_camid_is_drv_forbid(struct cam_ctl_t *cam_ctl, u8 id) + return 1; + } + ++bool _rtw_sec_camid_is_used(struct cam_ctl_t *cam_ctl, u8 id); + bool _rtw_sec_camid_is_used(struct cam_ctl_t *cam_ctl, u8 id) + { + bool ret = _FALSE; +@@ -1099,6 +1100,7 @@ inline bool rtw_camid_is_gk(_adapter *adapter, u8 cam_id) + return ret; + } + ++bool cam_cache_chk(_adapter *adapter, u8 id, u8 *addr, s16 kid, s8 gk); + bool cam_cache_chk(_adapter *adapter, u8 id, u8 *addr, s16 kid, s8 gk) + { + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); +@@ -1117,6 +1119,7 @@ bool cam_cache_chk(_adapter *adapter, u8 id, u8 *addr, s16 kid, s8 gk) + return ret; + } + ++s16 _rtw_camid_search(_adapter *adapter, u8 *addr, s16 kid, s8 gk); + s16 _rtw_camid_search(_adapter *adapter, u8 *addr, s16 kid, s8 gk) + { + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); +@@ -1157,6 +1160,7 @@ s16 rtw_camid_search(_adapter *adapter, u8 *addr, s16 kid, s8 gk) + return cam_id; + } + ++s16 rtw_get_camid(_adapter *adapter, u8 *addr, s16 kid, u8 gk); + s16 rtw_get_camid(_adapter *adapter, u8 *addr, s16 kid, u8 gk) + { + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); +@@ -1276,6 +1280,7 @@ s16 rtw_camid_alloc(_adapter *adapter, struct sta_info *sta, u8 kid, u8 gk, bool + return cam_id; + } + ++void rtw_camid_set(_adapter *adapter, u8 cam_id); + void rtw_camid_set(_adapter *adapter, u8 cam_id) + { + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); +@@ -1359,6 +1364,7 @@ inline void rtw_sec_cam_swap(_adapter *adapter, u8 cam_id_a, u8 cam_id_b) + } + } + ++s16 rtw_get_empty_cam_entry(_adapter *adapter, u8 start_camid); + s16 rtw_get_empty_cam_entry(_adapter *adapter, u8 start_camid) + { + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); +@@ -2232,6 +2238,7 @@ void update_ldpc_stbc_cap(struct sta_info *psta) + #endif /* CONFIG_80211N_HT */ + } + ++int check_ielen(u8 *start, uint len); + int check_ielen(u8 *start, uint len) + { + int left = len; +diff --git a/drivers/staging/rtl8812au/core/rtw_xmit.c b/drivers/staging/rtl8812au/core/rtw_xmit.c +index 8504dba09..0b97e5099 100644 +--- a/drivers/staging/rtl8812au/core/rtw_xmit.c ++++ b/drivers/staging/rtl8812au/core/rtw_xmit.c +@@ -56,6 +56,7 @@ void rtw_init_xmit_block(_adapter *padapter) + dvobj->xmit_block = XMIT_BLOCK_NONE; + + } ++void rtw_free_xmit_block(_adapter *padapter); + void rtw_free_xmit_block(_adapter *padapter) + { + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); +@@ -505,6 +506,7 @@ void rtw_get_adapter_tx_rate_bmp_by_bw(_adapter *adapter, u8 bw, u16 *r_bmp_cck_ + *r_bmp_vht = bmp_vht; + } + ++void rtw_get_shared_macid_tx_rate_bmp_by_bw(struct dvobj_priv *dvobj, u8 bw, u16 *r_bmp_cck_ofdm, u32 *r_bmp_ht, u32 *r_bmp_vht); + void rtw_get_shared_macid_tx_rate_bmp_by_bw(struct dvobj_priv *dvobj, u8 bw, u16 *r_bmp_cck_ofdm, u32 *r_bmp_ht, u32 *r_bmp_vht) + { + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); +@@ -3476,6 +3478,7 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) + return _SUCCESS; + } + ++void rtw_init_xmitframe(struct xmit_frame *pxframe); + void rtw_init_xmitframe(struct xmit_frame *pxframe) + { + if (pxframe != NULL) { /* default value setting */ +@@ -4146,6 +4149,7 @@ void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry) + } + + #ifdef CONFIG_BR_EXT ++int rtw_br_client_tx(_adapter *padapter, struct sk_buff **pskb); + int rtw_br_client_tx(_adapter *padapter, struct sk_buff **pskb) + { + struct sk_buff *skb = *pskb; +@@ -6040,6 +6044,7 @@ int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg) + return ret; + } + ++bool rtw_sctx_chk_waring_status(int status); + bool rtw_sctx_chk_waring_status(int status) + { + switch (status) { +diff --git a/drivers/staging/rtl8812au/hal/hal_com.c b/drivers/staging/rtl8812au/hal/hal_com.c +index b3b1e16c8..a230ea6e5 100644 +--- a/drivers/staging/rtl8812au/hal/hal_com.c ++++ b/drivers/staging/rtl8812au/hal/hal_com.c +@@ -2021,6 +2021,7 @@ void rtw_hal_update_sta_wset(_adapter *adapter, struct sta_info *psta) + psta->cmn.support_wireless_set = w_set; + } + ++void rtw_hal_update_sta_mimo_type(_adapter *adapter, struct sta_info *psta); + void rtw_hal_update_sta_mimo_type(_adapter *adapter, struct sta_info *psta) + { + s8 tx_nss, rx_nss; +@@ -2054,6 +2055,7 @@ void rtw_hal_update_sta_mimo_type(_adapter *adapter, struct sta_info *psta) + psta->cmn.mac_id, tx_nss, rx_nss); + } + ++void rtw_hal_update_sta_smps_cap(_adapter *adapter, struct sta_info *psta); + void rtw_hal_update_sta_smps_cap(_adapter *adapter, struct sta_info *psta) + { + /*Spatial Multiplexing Power Save*/ +@@ -2092,6 +2094,7 @@ u8 rtw_get_mgntframe_raid(_adapter *adapter, unsigned char network_type) + return raid; + } + ++void rtw_hal_update_sta_rate_mask(PADAPTER padapter, struct sta_info *psta); + void rtw_hal_update_sta_rate_mask(PADAPTER padapter, struct sta_info *psta) + { + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); +@@ -4392,6 +4395,7 @@ inline s32 rtw_hal_set_FwMediaStatusRpt_range_cmd(_adapter *adapter, bool opmode + return rtw_hal_set_FwMediaStatusRpt_cmd(adapter, opmode, miracast, miracast_sink, role, macid, 1, macid_end); + } + ++void rtw_hal_set_FwRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc); + void rtw_hal_set_FwRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) + { + struct hal_ops *pHalFunc = &padapter->hal_func; +@@ -4536,6 +4540,7 @@ void rtw_hal_set_input_gpio(_adapter *padapter, u8 index) + + #endif + ++void rtw_hal_set_FwAoacRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc); + void rtw_hal_set_FwAoacRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) + { + struct hal_ops *pHalFunc = &padapter->hal_func; +@@ -7669,6 +7674,8 @@ void rtw_hal_construct_NullFunctionData( + *pLength = pktlen; + } + ++void rtw_hal_construct_ProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, ++ BOOLEAN bHideSSID); + void rtw_hal_construct_ProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, + BOOLEAN bHideSSID) + { +@@ -11502,6 +11509,7 @@ s32 rtw_hal_set_wifi_btc_port_id_cmd(_adapter *adapter) + #endif + + #define LPS_ACTIVE_TIMEOUT 50 /*number of times*/ ++void rtw_lps_state_chk(_adapter *adapter, u8 ps_mode); + void rtw_lps_state_chk(_adapter *adapter, u8 ps_mode) + { + if (ps_mode == PS_MODE_ACTIVE) { +@@ -11973,6 +11981,7 @@ SetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value) + } + + #ifdef CONFIG_BEAMFORMING ++u8 rtw_hal_query_txbfer_rf_num(_adapter *adapter); + u8 rtw_hal_query_txbfer_rf_num(_adapter *adapter) + { + struct registry_priv *pregistrypriv = &adapter->registrypriv; +@@ -11998,6 +12007,7 @@ u8 rtw_hal_query_txbfer_rf_num(_adapter *adapter) + return 1; + + } ++u8 rtw_hal_query_txbfee_rf_num(_adapter *adapter); + u8 rtw_hal_query_txbfee_rf_num(_adapter *adapter) + { + struct registry_priv *pregistrypriv = &adapter->registrypriv; +@@ -13001,6 +13011,7 @@ bool kfree_data_is_bb_gain_empty(struct kfree_data_t *data) + } + + #ifdef CONFIG_USB_RX_AGGREGATION ++void rtw_set_usb_agg_by_mode_normal(_adapter *padapter, u8 cur_wireless_mode); + void rtw_set_usb_agg_by_mode_normal(_adapter *padapter, u8 cur_wireless_mode) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +@@ -13069,6 +13080,7 @@ void rtw_set_usb_agg_by_mode_normal(_adapter *padapter, u8 cur_wireless_mode) + } + } + ++void rtw_set_usb_agg_by_mode_customer(_adapter *padapter, u8 cur_wireless_mode, u8 UsbDmaSize, u8 Legacy_UsbDmaSize); + void rtw_set_usb_agg_by_mode_customer(_adapter *padapter, u8 cur_wireless_mode, u8 UsbDmaSize, u8 Legacy_UsbDmaSize) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +@@ -13096,6 +13108,7 @@ void rtw_set_usb_agg_by_mode_customer(_adapter *padapter, u8 cur_wireless_mode, + } + } + ++void rtw_set_usb_agg_by_mode(_adapter *padapter, u8 cur_wireless_mode); + void rtw_set_usb_agg_by_mode(_adapter *padapter, u8 cur_wireless_mode) + { + #ifdef CONFIG_PLATFORM_NOVATEK_NT72668 +@@ -14391,6 +14404,7 @@ void rtw_dump_phy_cap_by_phydmapi(void *sel, _adapter *adapter) + #endif + } + #else ++void rtw_dump_phy_cap_by_hal(void *sel, _adapter *adapter); + void rtw_dump_phy_cap_by_hal(void *sel, _adapter *adapter) + { + u8 phy_cap = _FALSE; +diff --git a/drivers/staging/rtl8812au/hal/hal_com_phycfg.c b/drivers/staging/rtl8812au/hal/hal_com_phycfg.c +index ada38b221..5ca3b824e 100644 +--- a/drivers/staging/rtl8812au/hal/hal_com_phycfg.c ++++ b/drivers/staging/rtl8812au/hal/hal_com_phycfg.c +@@ -610,6 +610,13 @@ static inline void hal_init_pg_txpwr_info_5g(_adapter *adapter, TxPowerInfo5G *p + #define LOAD_PG_TXPWR_WARN_COND(_txpwr_src) (_txpwr_src > PG_TXPWR_SRC_PG_DATA) + #endif + ++u16 hal_load_pg_txpwr_info_path_2g( ++ _adapter *adapter, ++ TxPowerInfo24G *pwr_info, ++ u32 path, ++ u8 txpwr_src, ++ const struct map_t *txpwr_map, ++ u16 pg_offset); + u16 hal_load_pg_txpwr_info_path_2g( + _adapter *adapter, + TxPowerInfo24G *pwr_info, +@@ -738,6 +745,13 @@ u16 hal_load_pg_txpwr_info_path_2g( + return offset; + } + ++u16 hal_load_pg_txpwr_info_path_5g( ++ _adapter *adapter, ++ TxPowerInfo5G *pwr_info, ++ u32 path, ++ u8 txpwr_src, ++ const struct map_t *txpwr_map, ++ u16 pg_offset); + u16 hal_load_pg_txpwr_info_path_5g( + _adapter *adapter, + TxPowerInfo5G *pwr_info, +@@ -897,6 +911,13 @@ u16 hal_load_pg_txpwr_info_path_5g( + return offset; + } + ++void hal_load_pg_txpwr_info( ++ _adapter *adapter, ++ TxPowerInfo24G *pwr_info_2g, ++ TxPowerInfo5G *pwr_info_5g, ++ u8 *pg_data, ++ BOOLEAN AutoLoadFail ++); + void hal_load_pg_txpwr_info( + _adapter *adapter, + TxPowerInfo24G *pwr_info_2g, +@@ -1317,6 +1338,12 @@ void dump_hal_txpwr_info_5g(void *sel, _adapter *adapter, u8 rfpath_num, u8 max_ + * + * Return dBm or -1 for undefined + */ ++s8 rtw_regsty_get_target_tx_power( ++ IN PADAPTER Adapter, ++ IN u8 Band, ++ IN u8 RfPath, ++ IN RATE_SECTION RateSection ++); + s8 rtw_regsty_get_target_tx_power( + IN PADAPTER Adapter, + IN u8 Band, +@@ -1361,6 +1388,7 @@ s8 rtw_regsty_get_target_tx_power( + return value; + } + ++bool rtw_regsty_chk_target_tx_power_valid(_adapter *adapter); + bool rtw_regsty_chk_target_tx_power_valid(_adapter *adapter) + { + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); +@@ -1441,6 +1469,14 @@ PHY_GetTxPowerByRateBase( + return value; + } + ++VOID ++phy_SetTxPowerByRateBase( ++ IN PADAPTER Adapter, ++ IN u8 Band, ++ IN u8 RfPath, ++ IN RATE_SECTION RateSection, ++ IN u8 Value ++); + VOID + phy_SetTxPowerByRateBase( + IN PADAPTER Adapter, +@@ -1558,6 +1594,10 @@ static void phy_txpwr_by_rate_chk_for_path_dup(_adapter *adapter) + } + } + ++VOID ++phy_StoreTxPowerByRateBase( ++ IN PADAPTER pAdapter ++); + VOID + phy_StoreTxPowerByRateBase( + IN PADAPTER pAdapter +@@ -1964,6 +2004,15 @@ PHY_GetRateValuesOfTxPowerByRate( + }; + } + ++void ++PHY_StoreTxPowerByRateNew( ++ IN PADAPTER pAdapter, ++ IN u32 Band, ++ IN u32 RfPath, ++ IN u32 RegAddr, ++ IN u32 BitMask, ++ IN u32 Data ++); + void + PHY_StoreTxPowerByRateNew( + IN PADAPTER pAdapter, +@@ -2032,6 +2081,10 @@ phy_store_tx_power_by_rate( + + } + ++VOID ++phy_ConvertTxPowerByRateInDbmToRelativeValues( ++ IN PADAPTER pAdapter ++); + VOID + phy_ConvertTxPowerByRateInDbmToRelativeValues( + IN PADAPTER pAdapter +@@ -2162,6 +2215,11 @@ phy_set_tx_power_index_by_rate_section( + return; + } + ++BOOLEAN ++phy_GetChnlIndex( ++ IN u8 Channel, ++ OUT u8 *ChannelIdx ++); + BOOLEAN + phy_GetChnlIndex( + IN u8 Channel, +@@ -3524,6 +3582,11 @@ static void phy_txpwr_lmt_post_hdl(_adapter *adapter) + _exit_critical_mutex(&rfctl->txpwr_lmt_mutex, &irqL); + } + ++BOOLEAN ++GetS1ByteIntegerFromStringInDecimal( ++ IN char *str, ++ IN OUT s8 *val ++); + BOOLEAN + GetS1ByteIntegerFromStringInDecimal( + IN char *str, +@@ -4243,6 +4306,11 @@ phy_ConfigBBWithParaFile( + return rtStatus; + } + ++VOID ++phy_DecryptBBPgParaFile( ++ PADAPTER Adapter, ++ char *buffer ++); + VOID + phy_DecryptBBPgParaFile( + PADAPTER Adapter, +@@ -4285,6 +4353,11 @@ phy_DecryptBBPgParaFile( + #define DBG_TXPWR_BY_RATE_FILE_PARSE 0 + #endif + ++int ++phy_ParseBBPgParaFile( ++ PADAPTER Adapter, ++ char *buffer ++); + int + phy_ParseBBPgParaFile( + PADAPTER Adapter, +@@ -4714,6 +4787,16 @@ PHY_ConfigRFWithParaFile( + return rtStatus; + } + ++VOID ++initDeltaSwingIndexTables( ++ PADAPTER Adapter, ++ char *Band, ++ char *Path, ++ char *Sign, ++ char *Channel, ++ char *Rate, ++ char *Data ++); + VOID + initDeltaSwingIndexTables( + PADAPTER Adapter, +diff --git a/drivers/staging/rtl8812au/hal/hal_dm.c b/drivers/staging/rtl8812au/hal/hal_dm.c +index 0df8f64eb..1236b51ad 100644 +--- a/drivers/staging/rtl8812au/hal/hal_dm.c ++++ b/drivers/staging/rtl8812au/hal/hal_dm.c +@@ -17,7 +17,8 @@ + #include + + /* A mapping from HalData to ODM. */ +-enum odm_board_type boardType(u8 InterfaceSel) ++enum odm_board_type boardType(u8 InterfaceSel); ++enum odm_board_type boardType(u8 InterfaceSel) + { + enum odm_board_type board = ODM_BOARD_DEFAULT; + +@@ -94,6 +95,7 @@ void rtw_phydm_iqk_trigger(_adapter *adapter) + } + #endif + ++void rtw_phydm_iqk_trigger_dbg(_adapter *adapter, bool recovery, bool clear, bool segment); + void rtw_phydm_iqk_trigger_dbg(_adapter *adapter, bool recovery, bool clear, bool segment) + { + struct dm_struct *p_dm_odm = adapter_to_phydm(adapter); +@@ -104,6 +106,7 @@ void rtw_phydm_iqk_trigger_dbg(_adapter *adapter, bool recovery, bool clear, boo + halrf_iqk_trigger(p_dm_odm, recovery); + #endif + } ++void rtw_phydm_lck_trigger(_adapter *adapter); + void rtw_phydm_lck_trigger(_adapter *adapter) + { + struct dm_struct *p_dm_odm = adapter_to_phydm(adapter); +@@ -162,6 +165,7 @@ void rtw_hal_update_param_init_fw_offload_cap(_adapter *adapter) + } + #endif + ++void record_ra_info(void *p_dm_void, u8 macid, struct cmn_sta_info *p_sta, u64 ra_mask); + void record_ra_info(void *p_dm_void, u8 macid, struct cmn_sta_info *p_sta, u64 ra_mask) + { + struct dm_struct *p_dm = (struct dm_struct *)p_dm_void; +@@ -285,6 +289,7 @@ void rtw_phydm_tdmadig(_adapter *adapter, u8 state) + } + } + #endif/*CONFIG_TDMADIG*/ ++void rtw_phydm_ops_func_init(struct dm_struct *p_phydm); + void rtw_phydm_ops_func_init(struct dm_struct *p_phydm) + { + struct ra_table *p_ra_t = &p_phydm->dm_ra_table; +diff --git a/drivers/staging/rtl8812au/hal/hal_intf.c b/drivers/staging/rtl8812au/hal/hal_intf.c +index 66a2954c5..de72c9612 100644 +--- a/drivers/staging/rtl8812au/hal/hal_intf.c ++++ b/drivers/staging/rtl8812au/hal/hal_intf.c +@@ -260,6 +260,7 @@ void rtw_hal_power_off(_adapter *padapter) + } + + ++void rtw_hal_init_opmode(_adapter *padapter); + void rtw_hal_init_opmode(_adapter *padapter) + { + NDIS_802_11_NETWORK_INFRASTRUCTURE networkType = Ndis802_11InfrastructureMax; +@@ -639,6 +640,7 @@ void rtw_hal_free_recv_priv(_adapter *padapter) + padapter->hal_func.free_recv_priv(padapter); + } + ++void rtw_sta_ra_registed(_adapter *padapter, struct sta_info *psta); + void rtw_sta_ra_registed(_adapter *padapter, struct sta_info *psta) + { + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); +diff --git a/drivers/staging/rtl8812au/hal/hal_mp.c b/drivers/staging/rtl8812au/hal/hal_mp.c +index 7960556f2..2d2af16c8 100644 +--- a/drivers/staging/rtl8812au/hal/hal_mp.c ++++ b/drivers/staging/rtl8812au/hal/hal_mp.c +@@ -373,6 +373,7 @@ void hal_mpt_SetBandwidth(PADAPTER pAdapter) + + } + ++void mpt_SetTxPower_Old(PADAPTER pAdapter, MPT_TXPWR_DEF Rate, u8 *pTxPower); + void mpt_SetTxPower_Old(PADAPTER pAdapter, MPT_TXPWR_DEF Rate, u8 *pTxPower) + { + switch (Rate) { +@@ -431,6 +432,12 @@ void mpt_SetTxPower_Old(PADAPTER pAdapter, MPT_TXPWR_DEF Rate, u8 *pTxPower) + RTW_INFO("<===mpt_SetTxPower_Old()\n"); + } + ++void ++mpt_SetTxPower( ++ PADAPTER pAdapter, ++ MPT_TXPWR_DEF Rate, ++ pu1Byte pTxPower ++); + void + mpt_SetTxPower( + PADAPTER pAdapter, +@@ -603,6 +610,7 @@ void hal_mpt_SetDataRate(PADAPTER pAdapter) + #define RF_PATH_AB 22 + + #ifdef CONFIG_RTL8814A ++VOID mpt_ToggleIG_8814A(PADAPTER pAdapter); + VOID mpt_ToggleIG_8814A(PADAPTER pAdapter) + { + u1Byte Path = 0; +@@ -632,6 +640,7 @@ VOID mpt_ToggleIG_8814A(PADAPTER pAdapter) + + } + ++VOID mpt_SetRFPath_8814A(PADAPTER pAdapter); + VOID mpt_SetRFPath_8814A(PADAPTER pAdapter) + { + +@@ -866,6 +875,11 @@ VOID mpt_SetRFPath_8814A(PADAPTER pAdapter) + #endif /* CONFIG_RTL8814A */ + #if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) || defined(CONFIG_RTL8812A) + VOID ++mpt_SetSingleTone_8814A( ++ IN PADAPTER pAdapter, ++ IN BOOLEAN bSingleTone, ++ IN BOOLEAN bEnPMacTx); ++VOID + mpt_SetSingleTone_8814A( + IN PADAPTER pAdapter, + IN BOOLEAN bSingleTone, +@@ -1167,6 +1181,7 @@ void mpt_SetRFPath_8723D(PADAPTER pAdapter) + } + #endif + ++VOID mpt_SetRFPath_819X(PADAPTER pAdapter); + VOID mpt_SetRFPath_819X(PADAPTER pAdapter) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); +diff --git a/drivers/staging/rtl8812au/hal/led/hal_usb_led.c b/drivers/staging/rtl8812au/hal/led/hal_usb_led.c +index 80f7a393c..16fd74bad 100644 +--- a/drivers/staging/rtl8812au/hal/led/hal_usb_led.c ++++ b/drivers/staging/rtl8812au/hal/led/hal_usb_led.c +@@ -23,6 +23,10 @@ + * It toggle off LED and schedule corresponding timer if necessary. + * */ + void ++SwLedBlink( ++ PLED_USB pLed ++); ++void + SwLedBlink( + PLED_USB pLed + ) +@@ -112,6 +116,10 @@ SwLedBlink( + } + } + ++void ++SwLedBlink1( ++ PLED_USB pLed ++); + void + SwLedBlink1( + PLED_USB pLed +@@ -289,6 +297,10 @@ SwLedBlink1( + + } + ++void ++SwLedBlink2( ++ PLED_USB pLed ++); + void + SwLedBlink2( + PLED_USB pLed +@@ -375,6 +387,10 @@ SwLedBlink2( + + } + ++void ++SwLedBlink3( ++ PLED_USB pLed ++); + void + SwLedBlink3( + PLED_USB pLed +@@ -501,6 +517,10 @@ SwLedBlink3( + } + + ++void ++SwLedBlink4( ++ PLED_USB pLed ++); + void + SwLedBlink4( + PLED_USB pLed +@@ -689,6 +709,10 @@ SwLedBlink4( + + } + ++void ++SwLedBlink5( ++ PLED_USB pLed ++); + void + SwLedBlink5( + PLED_USB pLed +@@ -779,6 +803,10 @@ SwLedBlink5( + + } + ++void ++SwLedBlink6( ++ PLED_USB pLed ++); + void + SwLedBlink6( + PLED_USB pLed +@@ -797,6 +825,10 @@ SwLedBlink6( + + } + ++void ++SwLedBlink7( ++ PLED_USB pLed ++); + void + SwLedBlink7( + PLED_USB pLed +@@ -886,6 +918,10 @@ SwLedBlink7( + + } + ++void ++SwLedBlink8( ++ PLED_USB pLed ++); + void + SwLedBlink8( + PLED_USB pLed +@@ -905,6 +941,10 @@ SwLedBlink8( + + /* page added for Belkin AC950. 20120813 */ + void ++SwLedBlink9( ++ PLED_USB pLed ++); ++void + SwLedBlink9( + PLED_USB pLed + ) +@@ -1141,6 +1181,10 @@ SwLedBlink9( + + /* page added for Netgear A6200V2. 20120827 */ + void ++SwLedBlink10( ++ PLED_USB pLed ++); ++void + SwLedBlink10( + PLED_USB pLed + ) +@@ -1340,6 +1384,10 @@ SwLedBlink10( + + } + ++void ++SwLedBlink11( ++ PLED_USB pLed ++); + void + SwLedBlink11( + PLED_USB pLed +@@ -1411,6 +1459,10 @@ SwLedBlink11( + + } + ++void ++SwLedBlink12( ++ PLED_USB pLed ++); + void + SwLedBlink12( + PLED_USB pLed +@@ -1479,6 +1531,10 @@ SwLedBlink12( + + } + ++VOID ++SwLedBlink13( ++ IN PLED_USB pLed ++); + VOID + SwLedBlink13( + IN PLED_USB pLed +@@ -1540,6 +1596,10 @@ SwLedBlink13( + + } + ++VOID ++SwLedBlink14( ++ IN PLED_USB pLed ++); + VOID + SwLedBlink14( + IN PLED_USB pLed +@@ -1597,6 +1657,10 @@ SwLedBlink14( + + } + ++VOID ++SwLedBlink15( ++ IN PLED_USB pLed ++); + VOID + SwLedBlink15( + IN PLED_USB pLed +@@ -2909,6 +2973,11 @@ SwLedControlMode6( + + /* Netgear, added by sinda, 2011/11/11 */ + void ++SwLedControlMode7( ++ PADAPTER Adapter, ++ LED_CTL_MODE LedAction ++); ++void + SwLedControlMode7( + PADAPTER Adapter, + LED_CTL_MODE LedAction +@@ -3047,6 +3116,11 @@ SwLedControlMode7( + + } + ++void ++SwLedControlMode8( ++ PADAPTER Adapter, ++ LED_CTL_MODE LedAction ++); + void + SwLedControlMode8( + PADAPTER Adapter, +@@ -3085,6 +3159,11 @@ SwLedControlMode8( + + /* page added for Belkin AC950, 20120813 */ + void ++SwLedControlMode9( ++ IN PADAPTER Adapter, ++ IN LED_CTL_MODE LedAction ++); ++void + SwLedControlMode9( + IN PADAPTER Adapter, + IN LED_CTL_MODE LedAction +@@ -3387,6 +3466,11 @@ SwLedControlMode9( + + /* page added for Netgear A6200V2, 20120827 */ + void ++SwLedControlMode10( ++ PADAPTER Adapter, ++ LED_CTL_MODE LedAction ++); ++void + SwLedControlMode10( + PADAPTER Adapter, + LED_CTL_MODE LedAction +@@ -3585,6 +3669,11 @@ SwLedControlMode10( + + /* Edimax-ASUS, added by Page, 20121221 */ + void ++SwLedControlMode11( ++ PADAPTER Adapter, ++ LED_CTL_MODE LedAction ++); ++void + SwLedControlMode11( + PADAPTER Adapter, + LED_CTL_MODE LedAction +@@ -3683,6 +3772,11 @@ SwLedControlMode11( + + /* page added for NEC */ + ++VOID ++SwLedControlMode12( ++ PADAPTER Adapter, ++ LED_CTL_MODE LedAction ++); + VOID + SwLedControlMode12( + PADAPTER Adapter, +@@ -3764,6 +3858,11 @@ SwLedControlMode12( + + /* Maddest add for NETGEAR R6100 */ + ++VOID ++SwLedControlMode13( ++ IN PADAPTER Adapter, ++ IN LED_CTL_MODE LedAction ++); + VOID + SwLedControlMode13( + IN PADAPTER Adapter, +@@ -3910,6 +4009,11 @@ SwLedControlMode13( + + /* Maddest add for DNI Buffalo */ + ++VOID ++SwLedControlMode14( ++ IN PADAPTER Adapter, ++ IN LED_CTL_MODE LedAction ++); + VOID + SwLedControlMode14( + IN PADAPTER Adapter, +@@ -3969,6 +4073,11 @@ SwLedControlMode14( + + /* Maddest add for Dlink */ + ++VOID ++SwLedControlMode15( ++ IN PADAPTER Adapter, ++ IN LED_CTL_MODE LedAction ++); + VOID + SwLedControlMode15( + IN PADAPTER Adapter, +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c +index c8753e500..4443c7289 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c +@@ -152,6 +152,7 @@ void odm_clear_txpowertracking_state(void *dm_void) + cali_info->modify_tx_agc_value_ofdm = 0; + } + ++void odm_get_tracking_table(void *dm_void, u8 thermal_value, u8 delta); + void odm_get_tracking_table(void *dm_void, u8 thermal_value, u8 delta) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -352,6 +353,7 @@ void odm_get_tracking_table(void *dm_void, u8 thermal_value, u8 delta) + } + } + ++void odm_pwrtrk_method(void *dm_void); + void odm_pwrtrk_method(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -858,6 +860,7 @@ u8 odm_get_right_chnl_place_for_iqk(u8 chnl) + } + #endif + ++void odm_iq_calibrate(struct dm_struct *dm); + void odm_iq_calibrate(struct dm_struct *dm) + { + void *adapter = dm->adapter; +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c +index 32fd1f3db..09ab5bae9 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c +@@ -1135,6 +1135,7 @@ u64 halrf_cmn_info_get(void *dm_void, u32 cmn_info) + return return_value; + } + ++void halrf_supportability_init_mp(void *dm_void); + void halrf_supportability_init_mp(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1353,6 +1354,7 @@ halrf_iqk_init( + } + #endif + ++void halrf_dack_trigger(void *dm_void); + void halrf_dack_trigger(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1674,6 +1676,7 @@ void halrf_lck_trigger(void *dm_void) + } + } + ++void halrf_aac_check(struct dm_struct *dm); + void halrf_aac_check(struct dm_struct *dm) + { + switch (dm->support_ic_type) { +@@ -2052,6 +2055,7 @@ halrf_config_rfk_with_header_file(void *dm_void, u32 config_type) + return result; + } + ++void halrf_txgapk_trigger(void *dm_void); + void halrf_txgapk_trigger(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c +index 85a7cb22b..4d61870d8 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c +@@ -31,6 +31,7 @@ + #include "mp_precomp.h" + #include "phydm_precomp.h" + ++void halrf_basic_profile(void *dm_void, u32 *_used, char *output, u32 *_out_len); + void halrf_basic_profile(void *dm_void, u32 *_used, char *output, u32 *_out_len) + { + #ifdef CONFIG_PHYDM_DEBUG_FUNCTION +@@ -65,6 +66,8 @@ void halrf_basic_profile(void *dm_void, u32 *_used, char *output, u32 *_out_len) + #endif + } + ++void halrf_debug_trace(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void halrf_debug_trace(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c +index cee13be26..773364310 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c +@@ -32,6 +32,7 @@ + /*@ Add for KFree Feature Requested by RF David.*/ + /*@This is a phydm API*/ + ++void phydm_set_kfree_to_rf_8814a(void *dm_void, u8 e_rf_path, u8 data); + void phydm_set_kfree_to_rf_8814a(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -124,6 +125,7 @@ void phydm_set_kfree_to_rf_8814a(void *dm_void, u8 e_rf_path, u8 data) + } + } + ++void phydm_get_thermal_trim_offset_8821c(void *dm_void); + void phydm_get_thermal_trim_offset_8821c(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -151,6 +153,7 @@ void phydm_get_thermal_trim_offset_8821c(void *dm_void) + power_trim_info->thermal); + } + ++void phydm_get_power_trim_offset_8821c(void *dm_void); + void phydm_get_power_trim_offset_8821c(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -188,6 +191,8 @@ void phydm_get_power_trim_offset_8821c(void *dm_void) + } + } + ++void phydm_set_kfree_to_rf_8821c(void *dm_void, u8 e_rf_path, boolean wlg_btg, ++ u8 data); + void phydm_set_kfree_to_rf_8821c(void *dm_void, u8 e_rf_path, boolean wlg_btg, + u8 data) + { +@@ -223,6 +228,7 @@ void phydm_set_kfree_to_rf_8821c(void *dm_void, u8 e_rf_path, boolean wlg_btg, + odm_get_rf_reg(dm, e_rf_path, RF_0x65, s_gain_bmask)); + } + ++void phydm_clear_kfree_to_rf_8821c(void *dm_void, u8 e_rf_path, u8 data); + void phydm_clear_kfree_to_rf_8821c(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -252,6 +258,7 @@ void phydm_clear_kfree_to_rf_8821c(void *dm_void, u8 e_rf_path, u8 data) + odm_get_rf_reg(dm, e_rf_path, RF_0x65, s_gain_bmask)); + } + ++void phydm_get_thermal_trim_offset_8822b(void *dm_void); + void phydm_get_thermal_trim_offset_8822b(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -279,6 +286,7 @@ void phydm_get_thermal_trim_offset_8822b(void *dm_void) + power_trim_info->thermal); + } + ++void phydm_get_power_trim_offset_8822b(void *dm_void); + void phydm_get_power_trim_offset_8822b(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -346,6 +354,7 @@ void phydm_get_power_trim_offset_8822b(void *dm_void) + } + } + ++void phydm_set_pa_bias_to_rf_8822b(void *dm_void, u8 e_rf_path, s8 tx_pa_bias); + void phydm_set_pa_bias_to_rf_8822b(void *dm_void, u8 e_rf_path, s8 tx_pa_bias) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -405,6 +414,7 @@ void phydm_set_pa_bias_to_rf_8822b(void *dm_void, u8 e_rf_path, s8 tx_pa_bias) + e_rf_path); + } + ++void phydm_get_pa_bias_offset_8822b(void *dm_void); + void phydm_get_pa_bias_offset_8822b(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -450,6 +460,7 @@ void phydm_get_pa_bias_offset_8822b(void *dm_void) + } + } + ++void phydm_set_kfree_to_rf_8822b(void *dm_void, u8 e_rf_path, u8 data); + void phydm_set_kfree_to_rf_8822b(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -470,6 +481,7 @@ void phydm_set_kfree_to_rf_8822b(void *dm_void, u8 e_rf_path, u8 data) + BIT(15) | BIT(14))), e_rf_path); + } + ++void phydm_clear_kfree_to_rf_8822b(void *dm_void, u8 e_rf_path, u8 data); + void phydm_clear_kfree_to_rf_8822b(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -497,6 +509,7 @@ void phydm_clear_kfree_to_rf_8822b(void *dm_void, u8 e_rf_path, u8 data) + BIT(15) | BIT(14))), e_rf_path); + } + ++void phydm_get_thermal_trim_offset_8710b(void *dm_void); + void phydm_get_thermal_trim_offset_8710b(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -524,6 +537,7 @@ void phydm_get_thermal_trim_offset_8710b(void *dm_void) + power_trim_info->thermal); + } + ++void phydm_get_power_trim_offset_8710b(void *dm_void); + void phydm_get_power_trim_offset_8710b(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -551,6 +565,7 @@ void phydm_get_power_trim_offset_8710b(void *dm_void) + power_trim_info->bb_gain[0][0]); + } + ++void phydm_set_kfree_to_rf_8710b(void *dm_void, u8 e_rf_path, u8 data); + void phydm_set_kfree_to_rf_8710b(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -565,6 +580,7 @@ void phydm_set_kfree_to_rf_8710b(void *dm_void, u8 e_rf_path, u8 data) + BIT(15) | BIT(14))), e_rf_path); + } + ++void phydm_clear_kfree_to_rf_8710b(void *dm_void, u8 e_rf_path, u8 data); + void phydm_clear_kfree_to_rf_8710b(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -581,6 +597,7 @@ void phydm_clear_kfree_to_rf_8710b(void *dm_void, u8 e_rf_path, u8 data) + BIT(15) | BIT(14))), e_rf_path); + } + ++void phydm_get_thermal_trim_offset_8192f(void *dm_void); + void phydm_get_thermal_trim_offset_8192f(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -608,6 +625,7 @@ void phydm_get_thermal_trim_offset_8192f(void *dm_void) + power_trim_info->thermal); + } + ++void phydm_get_power_trim_offset_8192f(void *dm_void); + void phydm_get_power_trim_offset_8192f(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -677,6 +695,8 @@ void phydm_get_power_trim_offset_8192f(void *dm_void) + } + } + ++void phydm_set_kfree_to_rf_8192f(void *dm_void, u8 e_rf_path, u8 channel_idx, ++ u8 data); + void phydm_set_kfree_to_rf_8192f(void *dm_void, u8 e_rf_path, u8 channel_idx, + u8 data) + { +@@ -765,6 +785,7 @@ void phydm_clear_kfree_to_rf_8192f(void *dm_void, u8 e_rf_path, u8 data) + */ + #endif + ++void phydm_get_thermal_trim_offset_8198f(void *dm_void); + void phydm_get_thermal_trim_offset_8198f(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -792,6 +813,7 @@ void phydm_get_thermal_trim_offset_8198f(void *dm_void) + power_trim_info->thermal); + } + ++void phydm_get_power_trim_offset_8198f(void *dm_void); + void phydm_get_power_trim_offset_8198f(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -843,6 +865,7 @@ void phydm_get_power_trim_offset_8198f(void *dm_void) + } + } + ++void phydm_set_kfree_to_rf_8198f(void *dm_void, u8 e_rf_path, u8 data); + void phydm_set_kfree_to_rf_8198f(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -885,6 +908,7 @@ void phydm_set_kfree_to_rf_8198f(void *dm_void, u8 e_rf_path, u8 data) + + } + ++void phydm_clear_kfree_to_rf_8198f(void *dm_void, u8 e_rf_path, u8 data); + void phydm_clear_kfree_to_rf_8198f(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -930,6 +954,7 @@ void phydm_clear_kfree_to_rf_8198f(void *dm_void, u8 e_rf_path, u8 data) + } + + ++void phydm_set_kfree_to_rf(void *dm_void, u8 e_rf_path, u8 data); + void phydm_set_kfree_to_rf(void *dm_void, u8 e_rf_path, u8 data) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1048,6 +1073,7 @@ s8 phydm_get_thermal_offset(void *dm_void) + return 0; + } + ++void phydm_do_kfree(void *dm_void, u8 channel_to_sw); + void phydm_do_kfree(void *dm_void, u8 channel_to_sw) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c +index 55ec7bf16..32671c854 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c +@@ -592,6 +592,7 @@ void odm_txpowertracking_init(void *dm_void) + odm_txpowertracking_thermal_meter_init(dm); + } + ++u8 get_swing_index(void *dm_void); + u8 get_swing_index(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -642,6 +643,7 @@ u8 get_swing_index(void *dm_void) + return i; + } + ++u8 get_cck_swing_index(void *dm_void); + u8 get_cck_swing_index(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +index cebb7265d..a66721465 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +@@ -428,6 +428,8 @@ void configure_txpower_track_8812a(struct txpwrtrack_cfg *config) + #define BW_40M 1 + #define BW_80M 2 + ++void _iqk_rx_fill_iqc_8812a(struct dm_struct *dm, enum rf_path path, ++ unsigned int RX_X, unsigned int RX_Y); + void _iqk_rx_fill_iqc_8812a(struct dm_struct *dm, enum rf_path path, + unsigned int RX_X, unsigned int RX_Y) + { +@@ -473,6 +475,8 @@ void _iqk_rx_fill_iqc_8812a(struct dm_struct *dm, enum rf_path path, + }; + } + ++void _iqk_tx_fill_iqc_8812a(struct dm_struct *dm, enum rf_path path, ++ unsigned int TX_X, unsigned int TX_Y); + void _iqk_tx_fill_iqc_8812a(struct dm_struct *dm, enum rf_path path, + unsigned int TX_X, unsigned int TX_Y) + { +@@ -518,6 +522,8 @@ void _iqk_tx_fill_iqc_8812a(struct dm_struct *dm, enum rf_path path, + }; + } + ++void _iqk_backup_mac_bb_8812a(struct dm_struct *dm, u32 *MACBB_backup, ++ u32 *backup_macbb_reg, u32 MACBB_NUM); + void _iqk_backup_mac_bb_8812a(struct dm_struct *dm, u32 *MACBB_backup, + u32 *backup_macbb_reg, u32 MACBB_NUM) + { +@@ -529,6 +535,8 @@ void _iqk_backup_mac_bb_8812a(struct dm_struct *dm, u32 *MACBB_backup, + + RF_DBG(dm, DBG_RF_IQK, "BackupMacBB Success!!!!\n"); + } ++void _iqk_backup_rf_8812a(struct dm_struct *dm, u32 *RFA_backup, ++ u32 *RFB_backup, u32 *backup_rf_reg, u32 RF_NUM); + void _iqk_backup_rf_8812a(struct dm_struct *dm, u32 *RFA_backup, + u32 *RFB_backup, u32 *backup_rf_reg, u32 RF_NUM) + { +@@ -541,6 +549,8 @@ void _iqk_backup_rf_8812a(struct dm_struct *dm, u32 *RFA_backup, + } + RF_DBG(dm, DBG_RF_IQK, "BackupRF Success!!!!\n"); + } ++void _iqk_backup_afe_8812a(struct dm_struct *dm, u32 *AFE_backup, ++ u32 *backup_afe_reg, u32 AFE_NUM); + void _iqk_backup_afe_8812a(struct dm_struct *dm, u32 *AFE_backup, + u32 *backup_afe_reg, u32 AFE_NUM) + { +@@ -551,6 +561,8 @@ void _iqk_backup_afe_8812a(struct dm_struct *dm, u32 *AFE_backup, + AFE_backup[i] = odm_read_4byte(dm, backup_afe_reg[i]); + RF_DBG(dm, DBG_RF_IQK, "BackupAFE Success!!!!\n"); + } ++void _iqk_restore_mac_bb_8812a(struct dm_struct *dm, u32 *MACBB_backup, ++ u32 *backup_macbb_reg, u32 MACBB_NUM); + void _iqk_restore_mac_bb_8812a(struct dm_struct *dm, u32 *MACBB_backup, + u32 *backup_macbb_reg, u32 MACBB_NUM) + { +@@ -561,6 +573,8 @@ void _iqk_restore_mac_bb_8812a(struct dm_struct *dm, u32 *MACBB_backup, + odm_write_4byte(dm, backup_macbb_reg[i], MACBB_backup[i]); + RF_DBG(dm, DBG_RF_IQK, "RestoreMacBB Success!!!!\n"); + } ++void _iqk_restore_rf_8812a(struct dm_struct *dm, enum rf_path path, ++ u32 *backup_rf_reg, u32 *RF_backup, u32 RF_REG_NUM); + void _iqk_restore_rf_8812a(struct dm_struct *dm, enum rf_path path, + u32 *backup_rf_reg, u32 *RF_backup, u32 RF_REG_NUM) + { +@@ -583,6 +597,8 @@ void _iqk_restore_rf_8812a(struct dm_struct *dm, enum rf_path path, + break; + } + } ++void _iqk_restore_afe_8812a(struct dm_struct *dm, u32 *AFE_backup, ++ u32 *backup_afe_reg, u32 AFE_NUM); + void _iqk_restore_afe_8812a(struct dm_struct *dm, u32 *AFE_backup, + u32 *backup_afe_reg, u32 AFE_NUM) + { +@@ -616,6 +632,7 @@ void _iqk_restore_afe_8812a(struct dm_struct *dm, u32 *AFE_backup, + RF_DBG(dm, DBG_RF_IQK, "RestoreAFE Success!!!!\n"); + } + ++void _iqk_configure_mac_8812a(struct dm_struct *dm); + void _iqk_configure_mac_8812a(struct dm_struct *dm) + { + /* ========MAC register setting======== */ +@@ -629,6 +646,7 @@ void _iqk_configure_mac_8812a(struct dm_struct *dm) + + #define cal_num 10 + ++void _iqk_tx_8812a(struct dm_struct *dm, u8 chnl_idx); + void _iqk_tx_8812a(struct dm_struct *dm, u8 chnl_idx) + { + u8 delay_count, cal = 0; +@@ -1122,6 +1140,7 @@ void _iqk_tx_8812a(struct dm_struct *dm, u8 chnl_idx) + #define RF_REG_NUM 3 + + /* Maintained by BB James. */ ++void _phy_iq_calibrate_8812a(struct dm_struct *dm, u8 channel); + void _phy_iq_calibrate_8812a(struct dm_struct *dm, u8 channel) + { + u32 MACBB_backup[MACBB_REG_NUM], AFE_backup[AFE_REG_NUM] = {0}, RFA_backup[RF_REG_NUM] = {0}, RFB_backup[RF_REG_NUM] = {0}; +@@ -1153,6 +1172,7 @@ void _phy_iq_calibrate_8812a(struct dm_struct *dm, u8 channel) + _iqk_restore_mac_bb_8812a(dm, MACBB_backup, backup_macbb_reg, MACBB_REG_NUM); + } + ++void _phy_lc_calibrate_8812a(struct dm_struct *dm, boolean is2T); + void _phy_lc_calibrate_8812a(struct dm_struct *dm, boolean is2T) + { + u32 /*rf_amode=0, rf_bmode=0,*/ lc_cal = 0, tmp = 0; +@@ -1218,6 +1238,7 @@ void _phy_lc_calibrate_8812a(struct dm_struct *dm, boolean is2T) + */ + } + ++void phy_reload_iqk_setting_8812a(struct dm_struct *dm, u8 channel); + void phy_reload_iqk_setting_8812a(struct dm_struct *dm, u8 channel) + { + struct dm_rf_calibration_struct *cali_info = &(dm->rf_calibrate_info); +@@ -1243,6 +1264,7 @@ void phy_reload_iqk_setting_8812a(struct dm_struct *dm, u8 channel) + odm_set_bb_reg(dm, R_0xe10, 0x03ff0000, (cali_info->iqk_matrix_reg_setting[chnl_idx].value[*dm->band_width][3] & 0x7ff) >> 1); + } + ++void phy_reset_iqk_result_8812a(struct dm_struct *dm); + void phy_reset_iqk_result_8812a(struct dm_struct *dm) + { + odm_set_bb_reg(dm, R_0x82c, BIT(31), 0x1); /* [31] = 1 --> Page C1 */ +@@ -1257,6 +1279,7 @@ void phy_reset_iqk_result_8812a(struct dm_struct *dm) + odm_set_bb_reg(dm, R_0xe10, 0x000003ff, 0x100); + } + ++void _phy_iq_calibrate_by_fw_8812a(struct dm_struct *dm); + void _phy_iq_calibrate_by_fw_8812a(struct dm_struct *dm) + { + u8 iqk_cmd[3] = {*dm->channel, 0x0, 0x0}; +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c +index 09c65ed3f..41ce0a6dd 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c +@@ -400,6 +400,11 @@ void configure_txpower_track_8814a( + pConfig->get_delta_swing_table8814only = GetDeltaSwingTable_8814A_PathCD; + } + ++VOID ++_phy_lc_calibrate_8814a( ++ IN struct dm_struct * pDM_Odm, ++ IN BOOLEAN is2T ++ ); + VOID + _phy_lc_calibrate_8814a( + IN struct dm_struct * pDM_Odm, +@@ -513,6 +518,10 @@ PHY_DPCalibrate_8814A( + } + + ++BOOLEAN ++phy_QueryRFPathSwitch_8814A( ++ IN PADAPTER pAdapter ++ ); + BOOLEAN + phy_QueryRFPathSwitch_8814A( + IN PADAPTER pAdapter +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c +index e019df35a..f8a7a020d 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c +@@ -63,6 +63,14 @@ void DoIQK_8814A( + #endif + //1 7. IQK + ++VOID ++_IQK_BackupMacBB_8814A( ++ IN struct dm_struct * pDM_Odm, ++ u32* MAC_backup, ++ u32* BB_backup, ++ u32* Backup_MAC_REG, ++ u32* Backup_BB_REG ++ ); + VOID + _IQK_BackupMacBB_8814A( + IN struct dm_struct * pDM_Odm, +@@ -90,7 +98,13 @@ _IQK_BackupRF_8814A( + IN struct dm_struct * pDM_Odm, + u32 RF_backup[][4], + u32* Backup_RF_REG +- ) ++ ); ++VOID ++_IQK_BackupRF_8814A( ++ IN struct dm_struct * pDM_Odm, ++ u32 RF_backup[][4], ++ u32* Backup_RF_REG ++ ) + { + u32 i; + //Save RF Parameters +@@ -105,6 +119,11 @@ _IQK_BackupRF_8814A( + } + + ++VOID ++_IQK_AFESetting_8814A( ++ IN struct dm_struct * pDM_Odm, ++ IN boolean Do_IQK ++ ); + VOID + _IQK_AFESetting_8814A( + IN struct dm_struct * pDM_Odm, +@@ -155,7 +174,15 @@ _IQK_RestoreMacBB_8814A( + u32* BB_backup, + u32* Backup_MAC_REG, + u32* Backup_BB_REG +- ) ++ ); ++VOID ++_IQK_RestoreMacBB_8814A( ++ IN struct dm_struct * pDM_Odm, ++ u32* MAC_backup, ++ u32* BB_backup, ++ u32* Backup_MAC_REG, ++ u32* Backup_BB_REG ++ ) + { + u32 i; + //Reload MacBB Parameters +@@ -168,6 +195,12 @@ _IQK_RestoreMacBB_8814A( + ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("RestoreMacBB Success!!!!\n")); + } + ++VOID ++_IQK_RestoreRF_8814A( ++ IN struct dm_struct * pDM_Odm, ++ u32* Backup_RF_REG, ++ u32 RF_backup[][4] ++ ); + VOID + _IQK_RestoreRF_8814A( + IN struct dm_struct * pDM_Odm, +@@ -193,6 +226,10 @@ _IQK_RestoreRF_8814A( + + } + ++VOID ++PHY_ResetIQKResult_8814A( ++ IN struct dm_struct * pDM_Odm ++); + VOID + PHY_ResetIQKResult_8814A( + IN struct dm_struct * pDM_Odm +@@ -212,6 +249,10 @@ PHY_ResetIQKResult_8814A( + odm_write_4byte(pDM_Odm, 0x1a10, 0x100); + } + ++VOID ++_IQK_ResetNCTL_8814A( ++ IN struct dm_struct * pDM_Odm ++); + VOID + _IQK_ResetNCTL_8814A( + IN struct dm_struct * pDM_Odm +@@ -224,6 +265,10 @@ _IQK_ResetNCTL_8814A( + ODM_RT_TRACE(pDM_Odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ResetNCTL Success!!!!\n")); + } + ++VOID ++_IQK_ConfigureMAC_8814A( ++ IN struct dm_struct * pDM_Odm ++ ); + VOID + _IQK_ConfigureMAC_8814A( + IN struct dm_struct * pDM_Odm +@@ -244,6 +289,10 @@ _IQK_ConfigureMAC_8814A( + odm_set_bb_reg(pDM_Odm, 0xcbc, 0xf, 0x0); + } + ++VOID ++_LOK_One_Shot( ++ IN void* pDM_VOID ++); + VOID + _LOK_One_Shot( + IN void* pDM_VOID +@@ -314,6 +363,10 @@ _LOK_One_Shot( + pIQK_info->lok_fail[0], pIQK_info->lok_fail[1], pIQK_info->lok_fail[2], pIQK_info->lok_fail[3])); + } + ++VOID ++_IQK_One_Shot( ++ IN void* pDM_VOID ++); + VOID + _IQK_One_Shot( + IN void* pDM_VOID +@@ -434,6 +487,11 @@ _IQK_One_Shot( + } + } + ++VOID ++_IQK_Tx_8814A( ++ IN struct dm_struct * pDM_Odm, ++ IN u8 chnlIdx ++ ); + VOID + _IQK_Tx_8814A( + IN struct dm_struct * pDM_Odm, +@@ -469,6 +527,11 @@ _IQK_Tx_8814A( + + } + ++VOID ++_phy_iq_calibrate_8814a( ++ IN struct dm_struct * pDM_Odm, ++ IN u8 Channel ++ ); + VOID + _phy_iq_calibrate_8814a( + IN struct dm_struct * pDM_Odm, +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c +index b6491baf7..cc46c94e1 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c +@@ -37,6 +37,12 @@ void do_iqk_8821a( + halrf_iqk_trigger(dm, false); + } + #endif ++void _iqk_rx_fill_iqc_8821a( ++ struct dm_struct *dm, ++ enum rf_path path, ++ unsigned int RX_X, ++ unsigned int RX_Y ++); + void _iqk_rx_fill_iqc_8821a( + struct dm_struct *dm, + enum rf_path path, +@@ -59,6 +65,12 @@ void _iqk_rx_fill_iqc_8821a( + }; + } + ++void _iqk_tx_fill_iqc_8821a( ++ struct dm_struct *dm, ++ enum rf_path path, ++ unsigned int TX_X, ++ unsigned int TX_Y ++); + void _iqk_tx_fill_iqc_8821a( + struct dm_struct *dm, + enum rf_path path, +@@ -84,6 +96,12 @@ void _iqk_tx_fill_iqc_8821a( + }; + } + ++void _iqk_backup_mac_bb_8821a( ++ struct dm_struct *dm, ++ u32 *MACBB_backup, ++ u32 *backup_macbb_reg, ++ u32 MACBB_NUM ++); + void _iqk_backup_mac_bb_8821a( + struct dm_struct *dm, + u32 *MACBB_backup, +@@ -100,6 +118,13 @@ void _iqk_backup_mac_bb_8821a( + PHYDM_DBG(dm, DBG_COMP_MCC, "BackupMacBB Success!!!!\n"); + } + ++void _iqk_backup_rf_8821a( ++ struct dm_struct *dm, ++ u32 *RFA_backup, ++ u32 *RFB_backup, ++ u32 *backup_rf_reg, ++ u32 RF_NUM ++); + void _iqk_backup_rf_8821a( + struct dm_struct *dm, + u32 *RFA_backup, +@@ -117,6 +142,12 @@ void _iqk_backup_rf_8821a( + PHYDM_DBG(dm, DBG_COMP_MCC, "BackupRF Success!!!!\n"); + } + ++void _iqk_backup_afe_8821a( ++ struct dm_struct *dm, ++ u32 *AFE_backup, ++ u32 *backup_afe_reg, ++ u32 AFE_NUM ++); + void _iqk_backup_afe_8821a( + struct dm_struct *dm, + u32 *AFE_backup, +@@ -132,6 +163,12 @@ void _iqk_backup_afe_8821a( + PHYDM_DBG(dm, DBG_COMP_MCC, "BackupAFE Success!!!!\n"); + } + ++void _iqk_restore_mac_bb_8821a( ++ struct dm_struct *dm, ++ u32 *MACBB_backup, ++ u32 *backup_macbb_reg, ++ u32 MACBB_NUM ++); + void _iqk_restore_mac_bb_8821a( + struct dm_struct *dm, + u32 *MACBB_backup, +@@ -147,6 +184,13 @@ void _iqk_restore_mac_bb_8821a( + PHYDM_DBG(dm, DBG_COMP_MCC, "RestoreMacBB Success!!!!\n"); + } + ++void _iqk_restore_rf_8821a( ++ struct dm_struct *dm, ++ enum rf_path path, ++ u32 *backup_rf_reg, ++ u32 *RF_backup, ++ u32 RF_REG_NUM ++); + void _iqk_restore_rf_8821a( + struct dm_struct *dm, + enum rf_path path, +@@ -172,6 +216,12 @@ void _iqk_restore_rf_8821a( + } + } + ++void _iqk_restore_afe_8821a( ++ struct dm_struct *dm, ++ u32 *AFE_backup, ++ u32 *backup_afe_reg, ++ u32 AFE_NUM ++); + void _iqk_restore_afe_8821a( + struct dm_struct *dm, + u32 *AFE_backup, +@@ -197,6 +247,9 @@ void _iqk_restore_afe_8821a( + PHYDM_DBG(dm, DBG_COMP_MCC, "RestoreAFE Success!!!!\n"); + } + ++void _iqk_configure_mac_8821a( ++ struct dm_struct *dm ++); + void _iqk_configure_mac_8821a( + struct dm_struct *dm + ) +@@ -210,6 +263,10 @@ void _iqk_configure_mac_8821a( + odm_write_1byte(dm, 0xa07, 0xf); /* CCK RX path off */ + } + ++void _iqk_tx_8821a( ++ struct dm_struct *dm, ++ enum rf_path path ++); + void _iqk_tx_8821a( + struct dm_struct *dm, + enum rf_path path +@@ -680,6 +737,10 @@ void _iqk_tx_8821a( + + #if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + void ++_phy_iq_calibrate_by_fw_8821a( ++ struct dm_struct *dm ++); ++void + _phy_iq_calibrate_by_fw_8821a( + struct dm_struct *dm + ) +@@ -714,6 +775,10 @@ _phy_iq_calibrate_by_fw_8821a( + } + #endif + ++void ++_phy_iq_calibrate_8821a( ++ struct dm_struct *dm ++); + void + _phy_iq_calibrate_8821a( + struct dm_struct *dm +@@ -736,6 +801,10 @@ _phy_iq_calibrate_8821a( + _iqk_restore_mac_bb_8821a(dm, MACBB_backup, backup_macbb_reg, MACBB_REG_NUM_8821A); + } + ++void ++phy_reset_iqk_result_8821a( ++ struct dm_struct *dm ++); + void + phy_reset_iqk_result_8821a( + struct dm_struct *dm +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm.c b/drivers/staging/rtl8812au/hal/phydm/phydm.c +index 1e980630e..867e8a073 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm.c +@@ -38,6 +38,7 @@ const u16 phy_rate_table[] = { + 13, 26, 39, 52, 78, 104, 117, 130 /*@MCS8~15*/ + }; + ++void phydm_traffic_load_decision(void *dm_void); + void phydm_traffic_load_decision(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -109,6 +110,7 @@ void phydm_traffic_load_decision(void *dm_void) + #endif + } + ++void phydm_cck_new_agc_chk(struct dm_struct *dm); + void phydm_cck_new_agc_chk(struct dm_struct *dm) + { + dm->cck_new_agc = 0; +@@ -132,6 +134,7 @@ void phydm_cck_new_agc_chk(struct dm_struct *dm) + } + + /*select 3 or 4 bit LNA */ ++void phydm_cck_lna_bit_num_chk(struct dm_struct *dm); + void phydm_cck_lna_bit_num_chk(struct dm_struct *dm) + { + boolean report_type = 0; +@@ -177,6 +180,7 @@ void phydm_cck_lna_bit_num_chk(struct dm_struct *dm) + dm->cck_agc_report_type); + } + ++void phydm_init_cck_setting(struct dm_struct *dm); + void phydm_init_cck_setting(struct dm_struct *dm) + { + u32 reg_tmp = 0; +@@ -200,6 +204,7 @@ void phydm_init_cck_setting(struct dm_struct *dm) + phydm_get_cck_rssi_table_from_reg(dm); + } + ++void phydm_init_hw_info_by_rfe(struct dm_struct *dm); + void phydm_init_hw_info_by_rfe(struct dm_struct *dm) + { + #if (RTL8822B_SUPPORT == 1) +@@ -216,6 +221,7 @@ void phydm_init_hw_info_by_rfe(struct dm_struct *dm) + #endif + } + ++void phydm_common_info_self_init(struct dm_struct *dm); + void phydm_common_info_self_init(struct dm_struct *dm) + { + u32 reg_tmp = 0; +@@ -298,6 +304,7 @@ void phydm_common_info_self_init(struct dm_struct *dm) + dm->pause_lv_table.lv_dig = PHYDM_PAUSE_RELEASE; + } + ++void phydm_cmn_sta_info_update(void *dm_void, u8 macid); + void phydm_cmn_sta_info_update(void *dm_void, u8 macid) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -326,6 +333,7 @@ void phydm_cmn_sta_info_update(void *dm_void, u8 macid) + ra->is_noisy = dm->noisy_decision; + } + ++void phydm_common_info_self_update(struct dm_struct *dm); + void phydm_common_info_self_update(struct dm_struct *dm) + { + u8 sta_cnt = 0, num_active_client = 0; +@@ -431,6 +439,7 @@ void phydm_common_info_self_update(struct dm_struct *dm) + dm->phy_dbg_info.show_phy_sts_cnt = 0; + } + ++void phydm_common_info_self_reset(struct dm_struct *dm); + void phydm_common_info_self_reset(struct dm_struct *dm) + { + struct odm_phy_dbg_info *dbg_t = &dm->phy_dbg_info; +@@ -474,6 +483,7 @@ phydm_get_structure(struct dm_struct *dm, u8 structure_type) + return structure; + } + ++void phydm_phy_info_update(struct dm_struct *dm); + void phydm_phy_info_update(struct dm_struct *dm) + { + #if (RTL8822B_SUPPORT == 1) +@@ -482,6 +492,7 @@ void phydm_phy_info_update(struct dm_struct *dm) + #endif + } + ++void phydm_hw_setting(struct dm_struct *dm); + void phydm_hw_setting(struct dm_struct *dm) + { + #if (RTL8821A_SUPPORT == 1) +@@ -783,6 +794,7 @@ u64 phydm_supportability_init_win( + #endif + + #if (DM_ODM_SUPPORT_TYPE & (ODM_CE)) ++u64 phydm_supportability_init_ce(void *dm_void); + u64 phydm_supportability_init_ce(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1401,6 +1413,7 @@ void phydm_fwoffload_ability_clear(struct dm_struct *dm, + dm->fw_offload_ability); + } + ++void phydm_supportability_init(void *dm_void); + void phydm_supportability_init(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1440,6 +1453,7 @@ void phydm_supportability_init(void *dm_void) + dm->support_ic_type, *dm->mp_mode, dm->support_ability); + } + ++void phydm_rfe_init(void *dm_void); + void phydm_rfe_init(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1970,6 +1984,7 @@ void phydm_pause_func_console(void *dm_void, char input[][16], u32 *_used, + *_out_len = out_len; + } + ++u8 phydm_stop_dm_watchdog_check(void *dm_void); + u8 phydm_stop_dm_watchdog_check(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c b/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c +index 086903624..e72e9d41d 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c +@@ -111,6 +111,7 @@ phydm_soft_ap_special_set(void *dm_void) + } + #endif + ++void phydm_dig_up_bound_lmt_en(void *dm_void); + void phydm_dig_up_bound_lmt_en(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -140,6 +141,7 @@ void phydm_dig_up_bound_lmt_en(void *dm_void) + adapt->igi_up_bound_lmt_cnt); + } + ++void phydm_check_adaptivity(void *dm_void); + void phydm_check_adaptivity(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -174,6 +176,7 @@ void phydm_check_adaptivity(void *dm_void) + #endif + } + ++void phydm_set_edcca_threshold(void *dm_void, s8 H2L, s8 L2H); + void phydm_set_edcca_threshold(void *dm_void, s8 H2L, s8 L2H) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -190,6 +193,7 @@ void phydm_set_edcca_threshold(void *dm_void, s8 H2L, s8 L2H) + } + } + ++void phydm_mac_edcca_state(void *dm_void, enum phydm_mac_edcca_type state); + void phydm_mac_edcca_state(void *dm_void, enum phydm_mac_edcca_type state) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -208,6 +212,7 @@ void phydm_mac_edcca_state(void *dm_void, enum phydm_mac_edcca_type state) + PHYDM_DBG(dm, DBG_ADPTVTY, "EDCCA enable state = %d\n", state); + } + ++void phydm_search_pwdb_lower_bound(void *dm_void); + void phydm_search_pwdb_lower_bound(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -285,6 +290,8 @@ void phydm_search_pwdb_lower_bound(void *dm_void) + phydm_set_edcca_threshold(dm, 0x7f, 0x7f); /*resume to no link state*/ + } + ++boolean ++phydm_re_search_condition(void *dm_void); + boolean + phydm_re_search_condition(void *dm_void) + { +@@ -298,6 +305,7 @@ phydm_re_search_condition(void *dm_void) + return false; + } + ++void phydm_set_l2h_th_ini(void *dm_void); + void phydm_set_l2h_th_ini(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -317,6 +325,7 @@ void phydm_set_l2h_th_ini(void *dm_void) + } + } + ++void phydm_set_forgetting_factor(void *dm_void); + void phydm_set_forgetting_factor(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -327,6 +336,7 @@ void phydm_set_forgetting_factor(void *dm_void) + odm_set_bb_reg(dm, R_0x83c, BIT(31) | BIT(30) | BIT(29), 0x7); + } + ++void phydm_set_pwdb_mode(void *dm_void); + void phydm_set_pwdb_mode(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -445,6 +455,7 @@ void phydm_set_edcca_val(void *dm_void, u32 *val_buf, u8 val_len) + phydm_set_edcca_threshold(dm, (s8)val_buf[1], (s8)val_buf[0]); + } + ++boolean phydm_edcca_abort(void *dm_void); + boolean phydm_edcca_abort(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c b/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c +index d2278560e..903aa635b 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c +@@ -43,6 +43,8 @@ + + #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE | ODM_AP)) + boolean ++phydm_la_buffer_allocate(void *dm_void); ++boolean + phydm_la_buffer_allocate(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -77,6 +79,7 @@ phydm_la_buffer_allocate(void *dm_void) + } + #endif + ++void phydm_la_get_tx_pkt_buf(void *dm_void); + void phydm_la_get_tx_pkt_buf(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -260,6 +263,7 @@ void phydm_la_get_tx_pkt_buf(void *dm_void) + #endif + } + ++void phydm_la_mode_set_mac_iq_dump(void *dm_void, boolean en_fake_trig); + void phydm_la_mode_set_mac_iq_dump(void *dm_void, boolean en_fake_trig) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -327,6 +331,7 @@ void phydm_la_mode_set_mac_iq_dump(void *dm_void, boolean en_fake_trig) + #endif + } + ++void phydm_adc_smp_start(void *dm_void); + void phydm_adc_smp_start(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_api.c b/drivers/staging/rtl8812au/hal/phydm/phydm_api.c +index f84279c39..f16510291 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_api.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_api.c +@@ -105,6 +105,7 @@ void phydm_ant_weight_dbg(void *dm_void, char input[][16], u32 *_used, + } + #endif + ++void phydm_iq_gen_en(void *dm_void); + void phydm_iq_gen_en(void *dm_void) + { + #ifdef PHYDM_COMPILE_IC_2SS +@@ -160,6 +161,7 @@ void phydm_iq_gen_en(void *dm_void) + #endif + } + ++void phydm_dis_cdd(void *dm_void); + void phydm_dis_cdd(void *dm_void) + { + #ifdef PHYDM_COMPILE_IC_2SS +@@ -310,6 +312,7 @@ void phydm_trx_antenna_setting_init(void *dm_void, u8 num_rf_path) + __func__, dm->tx_ant_status, dm->rx_ant_status); + } + ++void phydm_config_ofdm_tx_path(void *dm_void, u32 path); + void phydm_config_ofdm_tx_path(void *dm_void, u32 path) + { + #if (RTL8192E_SUPPORT || RTL8812A_SUPPORT) +@@ -475,6 +478,7 @@ void phydm_config_cck_rx_path(void *dm_void, enum bb_path path) + #endif + } + ++void phydm_config_cck_tx_path(void *dm_void, enum bb_path path); + void phydm_config_cck_tx_path(void *dm_void, enum bb_path path) + { + #if (defined(PHYDM_COMPILE_ABOVE_2SS)) +@@ -489,6 +493,8 @@ void phydm_config_cck_tx_path(void *dm_void, enum bb_path path) + #endif + } + ++void phydm_config_trx_path_v2(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_config_trx_path_v2(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -542,6 +548,8 @@ void phydm_config_trx_path_v2(void *dm_void, char input[][16], u32 *_used, + #endif + } + ++void phydm_config_trx_path_v1(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_config_trx_path_v1(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -895,6 +903,7 @@ void phydm_set_ext_switch(void *dm_void, u32 ext_ant_switch) + #endif + } + ++void phydm_csi_mask_enable(void *dm_void, u32 enable); + void phydm_csi_mask_enable(void *dm_void, u32 enable) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -919,6 +928,7 @@ void phydm_csi_mask_enable(void *dm_void, u32 enable) + } + } + ++void phydm_clean_all_csi_mask(void *dm_void); + void phydm_clean_all_csi_mask(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -957,6 +967,7 @@ void phydm_clean_all_csi_mask(void *dm_void) + } + } + ++void phydm_set_csi_mask(void *dm_void, u32 tone_idx_tmp, u8 tone_direction); + void phydm_set_csi_mask(void *dm_void, u32 tone_idx_tmp, u8 tone_direction) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1016,6 +1027,7 @@ void phydm_set_csi_mask(void *dm_void, u32 tone_idx_tmp, u8 tone_direction) + (tone_idx_tmp + tone_num_shift), target_reg, reg_tmp_value); + } + ++void phydm_set_nbi_reg(void *dm_void, u32 tone_idx_tmp, u32 bw); + void phydm_set_nbi_reg(void *dm_void, u32 tone_idx_tmp, u32 bw) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1111,6 +1123,7 @@ void phydm_nbi_enable(void *dm_void, u32 enable) + } + } + ++u8 phydm_find_fc(void *dm_void, u32 channel, u32 bw, u32 second_ch, u32 *fc_in); + u8 phydm_find_fc(void *dm_void, u32 channel, u32 bw, u32 second_ch, u32 *fc_in) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1186,6 +1199,8 @@ u8 phydm_find_fc(void *dm_void, u32 channel, u32 bw, u32 second_ch, u32 *fc_in) + return PHYDM_SET_SUCCESS; + } + ++u8 phydm_find_intf_distance(void *dm_void, u32 bw, u32 fc, u32 f_interference, ++ u32 *tone_idx_tmp_in); + u8 phydm_find_intf_distance(void *dm_void, u32 bw, u32 fc, u32 f_interference, + u32 *tone_idx_tmp_in) + { +@@ -2577,6 +2592,7 @@ phydm_api_trx_mode(void *dm_void, enum bb_path tx_path, enum bb_path rx_path, + return ret; + } + #else ++u8 config_phydm_read_txagc_n(void *dm_void, enum rf_path path, u8 hw_rate); + u8 config_phydm_read_txagc_n(void *dm_void, enum rf_path path, u8 hw_rate) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c b/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c +index bc4855c15..be4246612 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c +@@ -92,6 +92,8 @@ void phydm_get_txbf_device_num( + } + + struct _RT_BEAMFORM_STAINFO * ++phydm_sta_info_init(struct dm_struct *dm, u16 sta_idx, u8 *my_mac_addr); ++struct _RT_BEAMFORM_STAINFO * + phydm_sta_info_init(struct dm_struct *dm, u16 sta_idx, u8 *my_mac_addr) + { + struct _RT_BEAMFORMING_INFO *beam_info = &dm->beamforming_info; +@@ -158,6 +160,10 @@ phydm_sta_info_init(struct dm_struct *dm, u16 sta_idx, u8 *my_mac_addr) + entry->cur_beamform, entry->cur_beamform_vht); + return entry; + } ++void phydm_sta_info_update( ++ struct dm_struct *dm, ++ u16 sta_idx, ++ struct _RT_BEAMFORMEE_ENTRY *beamform_entry); + void phydm_sta_info_update( + struct dm_struct *dm, + u16 sta_idx, +@@ -213,6 +219,11 @@ phydm_beamforming_get_bfer_entry_by_addr( + } + + struct _RT_BEAMFORMEE_ENTRY * ++phydm_beamforming_get_entry_by_mac_id( ++ void *dm_void, ++ u8 mac_id, ++ u8 *idx); ++struct _RT_BEAMFORMEE_ENTRY * + phydm_beamforming_get_entry_by_mac_id( + void *dm_void, + u8 mac_id, +@@ -253,6 +264,10 @@ phydm_beamforming_get_entry_beam_cap_by_mac_id( + } + + struct _RT_BEAMFORMEE_ENTRY * ++phydm_beamforming_get_free_bfee_entry( ++ void *dm_void, ++ u8 *idx); ++struct _RT_BEAMFORMEE_ENTRY * + phydm_beamforming_get_free_bfee_entry( + void *dm_void, + u8 *idx) +@@ -271,6 +286,10 @@ phydm_beamforming_get_free_bfee_entry( + } + + struct _RT_BEAMFORMER_ENTRY * ++phydm_beamforming_get_free_bfer_entry( ++ void *dm_void, ++ u8 *idx); ++struct _RT_BEAMFORMER_ENTRY * + phydm_beamforming_get_free_bfer_entry( + void *dm_void, + u8 *idx) +@@ -298,6 +317,8 @@ phydm_beamforming_get_free_bfer_entry( + * 2015.05.25. Created by tynli. + * + */ ++u8 phydm_beamforming_get_first_mu_bfee_entry_idx( ++ void *dm_void); + u8 phydm_beamforming_get_first_mu_bfee_entry_idx( + void *dm_void) + { +@@ -323,6 +344,14 @@ u8 phydm_beamforming_get_first_mu_bfee_entry_idx( + + /*@Add SU BFee and MU BFee*/ + struct _RT_BEAMFORMEE_ENTRY * ++beamforming_add_bfee_entry( ++ void *dm_void, ++ struct _RT_BEAMFORM_STAINFO *sta, ++ enum beamforming_cap beamform_cap, ++ u8 num_of_sounding_dim, ++ u8 comp_steering_num_of_bfer, ++ u8 *idx); ++struct _RT_BEAMFORMEE_ENTRY * + beamforming_add_bfee_entry( + void *dm_void, + struct _RT_BEAMFORM_STAINFO *sta, +@@ -400,6 +429,13 @@ beamforming_add_bfee_entry( + + /*@Add SU BFee and MU BFer*/ + struct _RT_BEAMFORMER_ENTRY * ++beamforming_add_bfer_entry( ++ void *dm_void, ++ struct _RT_BEAMFORM_STAINFO *sta, ++ enum beamforming_cap beamform_cap, ++ u8 num_of_sounding_dim, ++ u8 *idx); ++struct _RT_BEAMFORMER_ENTRY * + beamforming_add_bfer_entry( + void *dm_void, + struct _RT_BEAMFORM_STAINFO *sta, +@@ -496,6 +532,10 @@ beamforming_remove_entry( + #endif + + /* Used for beamforming_start_v1 */ ++void phydm_beamforming_ndpa_rate( ++ void *dm_void, ++ enum channel_width BW, ++ u8 rate); + void phydm_beamforming_ndpa_rate( + void *dm_void, + enum channel_width BW, +@@ -521,6 +561,8 @@ void phydm_beamforming_ndpa_rate( + } + + /* Used for beamforming_start_sw and beamforming_start_fw */ ++void phydm_beamforming_dym_ndpa_rate( ++ void *dm_void); + void phydm_beamforming_dym_ndpa_rate( + void *dm_void) + { +@@ -541,6 +583,9 @@ void phydm_beamforming_dym_ndpa_rate( + * HW Timer unit (1/32000) s 32k is clock. + * FW Sounding : FW Timer unit 10ms + */ ++void beamforming_dym_period( ++ void *dm_void, ++ u8 status); + void beamforming_dym_period( + void *dm_void, + u8 status) +@@ -655,6 +700,11 @@ beamforming_send_vht_ndpa_packet( + } + + enum beamforming_notify_state ++phydm_beamfomring_is_sounding( ++ void *dm_void, ++ struct _RT_BEAMFORMING_INFO *beam_info, ++ u8 *idx); ++enum beamforming_notify_state + phydm_beamfomring_is_sounding( + void *dm_void, + struct _RT_BEAMFORMING_INFO *beam_info, +@@ -707,6 +757,9 @@ phydm_beamfomring_is_sounding( + } + + /* This function is unused */ ++u8 phydm_beamforming_sounding_idx( ++ void *dm_void, ++ struct _RT_BEAMFORMING_INFO *beam_info); + u8 phydm_beamforming_sounding_idx( + void *dm_void, + struct _RT_BEAMFORMING_INFO *beam_info) +@@ -734,6 +787,11 @@ u8 phydm_beamforming_sounding_idx( + } + + enum sounding_mode ++phydm_beamforming_sounding_mode( ++ void *dm_void, ++ struct _RT_BEAMFORMING_INFO *beam_info, ++ u8 idx); ++enum sounding_mode + phydm_beamforming_sounding_mode( + void *dm_void, + struct _RT_BEAMFORMING_INFO *beam_info, +@@ -775,6 +833,11 @@ phydm_beamforming_sounding_mode( + return mode; + } + ++u16 phydm_beamforming_sounding_time( ++ void *dm_void, ++ struct _RT_BEAMFORMING_INFO *beam_info, ++ enum sounding_mode mode, ++ u8 idx); + u16 phydm_beamforming_sounding_time( + void *dm_void, + struct _RT_BEAMFORMING_INFO *beam_info, +@@ -800,6 +863,12 @@ u16 phydm_beamforming_sounding_time( + } + + enum channel_width ++phydm_beamforming_sounding_bw( ++ void *dm_void, ++ struct _RT_BEAMFORMING_INFO *beam_info, ++ enum sounding_mode mode, ++ u8 idx); ++enum channel_width + phydm_beamforming_sounding_bw( + void *dm_void, + struct _RT_BEAMFORMING_INFO *beam_info, +@@ -825,6 +894,10 @@ phydm_beamforming_sounding_bw( + return sounding_bw; + } + ++boolean ++phydm_beamforming_select_beam_entry( ++ void *dm_void, ++ struct _RT_BEAMFORMING_INFO *beam_info); + boolean + phydm_beamforming_select_beam_entry( + void *dm_void, +@@ -857,6 +930,9 @@ phydm_beamforming_select_beam_entry( + + /*SU BFee Entry Only*/ + boolean ++phydm_beamforming_start_period( ++ void *dm_void); ++boolean + phydm_beamforming_start_period( + void *dm_void) + { +@@ -901,6 +977,8 @@ phydm_beamforming_start_period( + + /* Used after beamforming_leave, and will clear the setting of the "already deleted" entry + *SU BFee Entry Only*/ ++void phydm_beamforming_end_period_sw( ++ void *dm_void); + void phydm_beamforming_end_period_sw( + void *dm_void) + { +@@ -922,6 +1000,8 @@ void phydm_beamforming_end_period_sw( + /*odm_write_1byte(dm, 0x15F, 0);*/ + } + ++void phydm_beamforming_end_period_fw( ++ void *dm_void); + void phydm_beamforming_end_period_fw( + void *dm_void) + { +@@ -933,6 +1013,10 @@ void phydm_beamforming_end_period_fw( + } + + /*SU BFee Entry Only*/ ++void phydm_beamforming_clear_entry_sw( ++ void *dm_void, ++ boolean is_delete, ++ u8 delete_idx); + void phydm_beamforming_clear_entry_sw( + void *dm_void, + boolean is_delete, +@@ -998,6 +1082,10 @@ void phydm_beamforming_clear_entry_sw( + } + } + ++void phydm_beamforming_clear_entry_fw( ++ void *dm_void, ++ boolean is_delete, ++ u8 delete_idx); + void phydm_beamforming_clear_entry_fw( + void *dm_void, + boolean is_delete, +@@ -1143,6 +1231,9 @@ void phydm_beamforming_notify( + } + } + ++boolean ++beamforming_init_entry(void *dm_void, u16 sta_idx, u8 *bfer_bfee_idx, ++ u8 *my_mac_addr); + boolean + beamforming_init_entry(void *dm_void, u16 sta_idx, u8 *bfer_bfee_idx, + u8 *my_mac_addr) +@@ -1293,6 +1384,9 @@ beamforming_init_entry(void *dm_void, u16 sta_idx, u8 *bfer_bfee_idx, + return true; + } + ++void beamforming_deinit_entry( ++ void *dm_void, ++ u8 *RA); + void beamforming_deinit_entry( + void *dm_void, + u8 *RA) +@@ -1336,6 +1430,13 @@ void beamforming_deinit_entry( + PHYDM_DBG(dm, DBG_TXBF, "%s End, idx = 0x%X\n", __func__, idx); + } + ++boolean ++beamforming_start_v1( ++ void *dm_void, ++ u8 *RA, ++ boolean mode, ++ enum channel_width BW, ++ u8 rate); + boolean + beamforming_start_v1( + void *dm_void, +@@ -1402,6 +1503,12 @@ beamforming_start_v1( + return true; + } + ++boolean ++beamforming_start_sw( ++ void *dm_void, ++ u8 idx, ++ u8 mode, ++ enum channel_width BW); + boolean + beamforming_start_sw( + void *dm_void, +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c b/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c +index 8f5229abf..0be5ae0fc 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c +@@ -32,6 +32,7 @@ + + #ifdef PHYDM_SUPPORT_CCKPD + #ifdef PHYDM_COMPILE_CCKPD_TYPE1 ++void phydm_write_cck_pd_type1(void *dm_void, u8 cca_th); + void phydm_write_cck_pd_type1(void *dm_void, u8 cca_th) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -44,6 +45,7 @@ void phydm_write_cck_pd_type1(void *dm_void, u8 cca_th) + cckpd_t->cur_cck_cca_thres = cca_th; + } + ++void phydm_set_cckpd_lv_type1(void *dm_void, enum cckpd_lv lv); + void phydm_set_cckpd_lv_type1(void *dm_void, enum cckpd_lv lv) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -75,6 +77,7 @@ void phydm_set_cckpd_lv_type1(void *dm_void, enum cckpd_lv lv) + phydm_write_cck_pd_type1(dm, pd_th); + } + ++void phydm_cckpd_type1(void *dm_void); + void phydm_cckpd_type1(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -952,6 +955,8 @@ void phydm_set_cckpd_val(void *dm_void, u32 *val_buf, u8 val_len) + } + } + ++boolean ++phydm_stop_cck_pd_th(void *dm_void); + boolean + phydm_stop_cck_pd_th(void *dm_void) + { +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c b/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c +index f9ea9bb99..e0f42c0be 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c +@@ -328,6 +328,7 @@ void phydm_fahm_dbg(void *dm_void, char input[][16], u32 *_used, char *output, + + #ifdef NHM_SUPPORT + ++void phydm_nhm_racing_release(void *dm_void); + void phydm_nhm_racing_release(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -348,6 +349,7 @@ void phydm_nhm_racing_release(void *dm_void) + ccx->nhm_app = NHM_BACKGROUND; + } + ++u8 phydm_nhm_racing_ctrl(void *dm_void, enum phydm_nhm_level nhm_lv); + u8 phydm_nhm_racing_ctrl(void *dm_void, enum phydm_nhm_level nhm_lv) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -397,6 +399,8 @@ void phydm_nhm_trigger(void *dm_void) + ccx->nhm_ongoing = true; + } + ++boolean ++phydm_nhm_check_rdy(void *dm_void); + boolean + phydm_nhm_check_rdy(void *dm_void) + { +@@ -487,6 +491,7 @@ phydm_nhm_check_rdy(void *dm_void) + return is_ready; + } + ++void phydm_nhm_get_utility(void *dm_void); + void phydm_nhm_get_utility(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -504,6 +509,8 @@ void phydm_nhm_get_utility(void *dm_void) + PHYDM_DBG(dm, DBG_ENV_MNTR, "nhm_ratio=%d\n", ccx->nhm_ratio); + } + ++boolean ++phydm_nhm_get_result(void *dm_void); + boolean + phydm_nhm_get_result(void *dm_void) + { +@@ -629,6 +636,7 @@ phydm_nhm_get_result(void *dm_void) + return true; + } + ++void phydm_nhm_set_th_reg(void *dm_void); + void phydm_nhm_set_th_reg(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -679,6 +687,9 @@ void phydm_nhm_set_th_reg(void *dm_void) + ccx->nhm_th[1], ccx->nhm_th[0]); + } + ++boolean ++phydm_nhm_th_update_chk(void *dm_void, enum nhm_application nhm_app, u8 *nhm_th, ++ u32 *igi_new); + boolean + phydm_nhm_th_update_chk(void *dm_void, enum nhm_application nhm_app, u8 *nhm_th, + u32 *igi_new) +@@ -763,6 +774,10 @@ phydm_nhm_th_update_chk(void *dm_void, enum nhm_application nhm_app, u8 *nhm_th, + return is_update; + } + ++void phydm_nhm_set(void *dm_void, enum nhm_option_txon_all include_tx, ++ enum nhm_option_cca_all include_cca, ++ enum nhm_divider_opt_all divi_opt, ++ enum nhm_application nhm_app, u16 period); + void phydm_nhm_set(void *dm_void, enum nhm_option_txon_all include_tx, + enum nhm_option_cca_all include_cca, + enum nhm_divider_opt_all divi_opt, +@@ -854,6 +869,7 @@ void phydm_nhm_set(void *dm_void, enum nhm_option_txon_all include_tx, + } + } + ++u8 phydm_nhm_mntr_set(void *dm_void, struct nhm_para_info *nhm_para); + u8 phydm_nhm_mntr_set(void *dm_void, struct nhm_para_info *nhm_para) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -885,6 +901,8 @@ u8 phydm_nhm_mntr_set(void *dm_void, struct nhm_para_info *nhm_para) + + /*@Environment Monitor*/ + boolean ++phydm_nhm_mntr_chk(void *dm_void, u16 monitor_time /*unit ms*/); ++boolean + phydm_nhm_mntr_chk(void *dm_void, u16 monitor_time /*unit ms*/) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1067,6 +1085,7 @@ void phydm_nhm_dbg(void *dm_void, char input[][16], u32 *_used, char *output, + + #ifdef CLM_SUPPORT + ++void phydm_clm_racing_release(void *dm_void); + void phydm_clm_racing_release(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1080,6 +1099,7 @@ void phydm_clm_racing_release(void *dm_void) + ccx->clm_app = CLM_BACKGROUND; + } + ++u8 phydm_clm_racing_ctrl(void *dm_void, enum phydm_nhm_level clm_lv); + u8 phydm_clm_racing_ctrl(void *dm_void, enum phydm_nhm_level clm_lv) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1318,6 +1338,7 @@ phydm_clm_get_result(void *dm_void) + return true; + } + ++void phydm_clm_mntr_fw(void *dm_void, u16 monitor_time /*unit ms*/); + void phydm_clm_mntr_fw(void *dm_void, u16 monitor_time /*unit ms*/) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1378,6 +1399,8 @@ u8 phydm_clm_mntr_set(void *dm_void, struct clm_para_info *clm_para) + return PHYDM_SET_SUCCESS; + } + ++boolean ++phydm_clm_mntr_chk(void *dm_void, u16 monitor_time /*unit ms*/); + boolean + phydm_clm_mntr_chk(void *dm_void, u16 monitor_time /*unit ms*/) + { +@@ -1441,6 +1464,7 @@ void phydm_set_clm_mntr_mode(void *dm_void, enum clm_monitor_mode mode) + } + } + ++void phydm_clm_init(void *dm_void); + void phydm_clm_init(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c b/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c +index 95d89e379..8aac6b094 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c +@@ -25,6 +25,7 @@ + #include "mp_precomp.h" + #include "phydm_precomp.h" + ++s32 phydm_get_cfo_hz(void *dm_void, u32 val, u8 bit_num, u8 frac_num); + s32 phydm_get_cfo_hz(void *dm_void, u32 val, u8 bit_num, u8 frac_num) + { + s32 val_s = 0; +@@ -42,6 +43,7 @@ s32 phydm_get_cfo_hz(void *dm_void, u32 val, u8 bit_num, u8 frac_num) + } + + #if (ODM_IC_11AC_SERIES_SUPPORT) ++void phydm_get_cfo_info_ac(void *dm_void, struct phydm_cfo_rpt *cfo); + void phydm_get_cfo_info_ac(void *dm_void, struct phydm_cfo_rpt *cfo) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -310,6 +312,7 @@ phydm_set_crystal_cap_reg(void *dm_void, u8 crystal_cap) + return true; + } + ++void phydm_cfo_tracking_reset(void *dm_void); + void phydm_cfo_tracking_reset(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c b/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c +index 57d24e0e6..bab92632e 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c +@@ -101,6 +101,7 @@ void phydm_bb_dbg_port_header_sel(void *dm_void, u32 header_idx) + } + } + ++void phydm_bb_dbg_port_clock_en(void *dm_void, u8 enable); + void phydm_bb_dbg_port_clock_en(void *dm_void, u8 enable) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -400,6 +401,8 @@ void phydm_bb_hw_dbg_info_8822b(void *dm_void, u32 *_used, char *output, + } + #endif + ++void phydm_bb_hw_dbg_info_ac(void *dm_void, u32 *_used, char *output, ++ u32 *_out_len); + void phydm_bb_hw_dbg_info_ac(void *dm_void, u32 *_used, char *output, + u32 *_out_len) + { +@@ -926,6 +929,8 @@ u8 phydm_get_l_sig_rate(void *dm_void, u8 rate_idx_l_sig) + return rate_idx; + } + ++void phydm_bb_hw_dbg_info(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_bb_hw_dbg_info(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -1656,6 +1661,8 @@ void phydm_rx_rate_distribution(void *dm_void) + #endif + } + ++void phydm_print_hist_2_buf(void *dm_void, u16 *val, u16 len, char *buf, ++ u16 buf_size); + void phydm_print_hist_2_buf(void *dm_void, u16 *val, u16 len, char *buf, + u16 buf_size) + { +@@ -1676,6 +1683,7 @@ void phydm_print_hist_2_buf(void *dm_void, u16 *val, u16 len, char *buf, + } + } + ++void phydm_nss_hitogram(void *dm_void, enum PDM_RATE_TYPE rate_type); + void phydm_nss_hitogram(void *dm_void, enum PDM_RATE_TYPE rate_type) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1935,6 +1943,7 @@ void phydm_get_phy_statistic(void *dm_void) + phydm_reset_phystatus_statistic(dm); + }; + ++void phydm_basic_dbg_msg_linked(void *dm_void); + void phydm_basic_dbg_msg_linked(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -2554,6 +2563,8 @@ void phydm_fw_trace_en_h2c(void *dm_void, boolean enable, + odm_fill_h2c_cmd(dm, PHYDM_H2C_FW_TRACE_EN, cmd_length, h2c_parameter); + } + ++void phydm_get_per_path_txagc(void *dm_void, u8 path, u32 *_used, char *output, ++ u32 *_out_len); + void phydm_get_per_path_txagc(void *dm_void, u8 path, u32 *_used, char *output, + u32 *_out_len) + { +@@ -2628,6 +2639,7 @@ void phydm_get_per_path_txagc(void *dm_void, u8 path, u32 *_used, char *output, + *_out_len = out_len; + } + ++void phydm_get_txagc(void *dm_void, u32 *_used, char *output, u32 *_out_len); + void phydm_get_txagc(void *dm_void, u32 *_used, char *output, u32 *_out_len) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -2658,6 +2670,8 @@ void phydm_get_txagc(void *dm_void, u32 *_used, char *output, u32 *_out_len) + *_out_len = out_len; + } + ++void phydm_set_txagc(void *dm_void, u32 *const val, u32 *_used, ++ char *output, u32 *_out_len); + void phydm_set_txagc(void *dm_void, u32 *const val, u32 *_used, + char *output, u32 *_out_len) + { +@@ -2738,6 +2752,8 @@ void phydm_set_txagc(void *dm_void, u32 *const val, u32 *_used, + *_out_len = out_len; + } + ++void phydm_shift_txagc(void *dm_void, u32 *const val, u32 *_used, char *output, ++ u32 *_out_len); + void phydm_shift_txagc(void *dm_void, u32 *const val, u32 *_used, char *output, + u32 *_out_len) + { +@@ -2850,6 +2866,8 @@ void phydm_shift_txagc(void *dm_void, u32 *const val, u32 *_used, char *output, + *_out_len = out_len; + } + ++void phydm_set_txagc_dbg(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_set_txagc_dbg(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -2891,6 +2909,8 @@ void phydm_set_txagc_dbg(void *dm_void, char input[][16], u32 *_used, + *_out_len = out_len; + } + ++void phydm_debug_trace(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_debug_trace(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -3047,6 +3067,8 @@ void phydm_debug_trace(void *dm_void, char input[][16], u32 *_used, + *_out_len = out_len; + } + ++void phydm_fw_debug_trace(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_fw_debug_trace(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -3126,6 +3148,8 @@ void phydm_dump_bb_reg_n(void *dm_void, u32 *_used, char *output, u32 *_out_len) + #endif + + #if (ODM_IC_11AC_SERIES_SUPPORT) ++void phydm_dump_bb_reg_ac(void *dm_void, u32 *_used, char *output, ++ u32 *_out_len); + void phydm_dump_bb_reg_ac(void *dm_void, u32 *_used, char *output, + u32 *_out_len) + { +@@ -3247,6 +3271,7 @@ void phydm_dump_bb_reg2_jgr3(void *dm_void, u32 *_used, char *output, + } + #endif + ++void phydm_dump_bb_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len); + void phydm_dump_bb_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -3277,6 +3302,7 @@ void phydm_dump_bb_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len) + *_out_len = out_len; + } + ++void phydm_dump_rf_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len); + void phydm_dump_rf_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -3341,6 +3367,7 @@ void phydm_dump_rf_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len) + *_out_len = out_len; + } + ++void phydm_dump_mac_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len); + void phydm_dump_mac_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -3366,6 +3393,8 @@ void phydm_dump_mac_reg(void *dm_void, u32 *_used, char *output, u32 *_out_len) + *_out_len = out_len; + } + ++void phydm_dump_reg(void *dm_void, char input[][16], u32 *_used, char *output, ++ u32 *_out_len); + void phydm_dump_reg(void *dm_void, char input[][16], u32 *_used, char *output, + u32 *_out_len) + { +@@ -3416,6 +3445,8 @@ void phydm_dump_reg(void *dm_void, char input[][16], u32 *_used, char *output, + *_out_len = out_len; + } + ++void phydm_enable_big_jump(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_enable_big_jump(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -3453,6 +3484,8 @@ void phydm_enable_big_jump(void *dm_void, char input[][16], u32 *_used, + #endif + } + ++void phydm_show_rx_rate(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_show_rx_rate(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -3541,6 +3574,8 @@ void phydm_show_rx_rate(void *dm_void, char input[][16], u32 *_used, + #endif + } + ++void phydm_per_tone_evm(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_per_tone_evm(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -3754,6 +3789,8 @@ void phydm_per_tone_evm(void *dm_void, char input[][16], u32 *_used, + *_out_len = out_len; + } + ++void phydm_bw_ch_adjust(void *dm_void, char input[][16], ++ u32 *_used, char *output, u32 *_out_len); + void phydm_bw_ch_adjust(void *dm_void, char input[][16], + u32 *_used, char *output, u32 *_out_len) + { +@@ -3806,6 +3843,8 @@ void phydm_bw_ch_adjust(void *dm_void, char input[][16], + *_out_len = out_len; + } + ++void phydm_ext_rf_element_ctrl(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_ext_rf_element_ctrl(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +@@ -3828,6 +3867,8 @@ void phydm_ext_rf_element_ctrl(void *dm_void, char input[][16], u32 *_used, + } + } + ++void phydm_print_dbgport(void *dm_void, char input[][16], u32 *_used, ++ char *output, u32 *_out_len); + void phydm_print_dbgport(void *dm_void, char input[][16], u32 *_used, + char *output, u32 *_out_len) + { +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_dig.c b/drivers/staging/rtl8812au/hal/phydm/phydm_dig.c +index eea6dcee4..b26e85515 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_dig.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_dig.c +@@ -31,6 +31,7 @@ + #include "phydm_precomp.h" + + #ifdef CFG_DIG_DAMPING_CHK ++void phydm_dig_recorder_reset(void *dm_void); + void phydm_dig_recorder_reset(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -43,6 +44,8 @@ void phydm_dig_recorder_reset(void *dm_void) + sizeof(struct phydm_dig_recorder_strcut)); + } + ++void phydm_dig_recorder(void *dm_void, boolean first_connect, u8 igi_curr, ++ u32 fa_cnt); + void phydm_dig_recorder(void *dm_void, boolean first_connect, u8 igi_curr, + u32 fa_cnt) + { +@@ -95,6 +98,7 @@ void phydm_dig_recorder(void *dm_void, boolean first_connect, u8 igi_curr, + dig_rc->igi_bitmap); + } + ++void phydm_dig_damping_chk(void *dm_void); + void phydm_dig_damping_chk(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -195,6 +199,8 @@ void phydm_dig_damping_chk(void *dm_void) + } + #endif + ++boolean ++phydm_dig_go_up_check(void *dm_void); + boolean + phydm_dig_go_up_check(void *dm_void) + { +@@ -271,6 +277,7 @@ phydm_dig_go_up_check(void *dm_void) + return ret; + } + ++void phydm_fa_threshold_check(void *dm_void, boolean is_dfs_band); + void phydm_fa_threshold_check(void *dm_void, boolean is_dfs_band) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -310,6 +317,7 @@ void phydm_fa_threshold_check(void *dm_void, boolean is_dfs_band) + dig_t->fa_th[1], dig_t->fa_th[2]); + } + ++void phydm_set_big_jump_step(void *dm_void, u8 curr_igi); + void phydm_set_big_jump_step(void *dm_void, u8 curr_igi) + { + #if (RTL8822B_SUPPORT || RTL8197F_SUPPORT || RTL8192F_SUPPORT) +@@ -498,6 +506,7 @@ void phydm_fa_cnt_statistics_jgr3(void *dm_void) + + #endif + ++void phydm_write_dig_reg_c50(void *dm_void, u8 igi); + void phydm_write_dig_reg_c50(void *dm_void, u8 igi) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -598,6 +607,7 @@ void odm_write_dig(void *dm_void, u8 new_igi) + PHYDM_DBG(dm, DBG_DIG, "New_igi=((0x%x))\n\n", new_igi); + } + ++u8 phydm_get_igi_reg_val(void *dm_void, enum bb_path path); + u8 phydm_get_igi_reg_val(void *dm_void, enum bb_path path) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -689,6 +699,8 @@ void odm_pause_dig(void *dm_void, enum phydm_pause_type type, + PHYDM_DBG(dm, DBG_DIG, "pause_result=%d\n", rpt); + } + ++boolean ++phydm_dig_abort(void *dm_void); + boolean + phydm_dig_abort(void *dm_void) + { +@@ -787,6 +799,7 @@ void phydm_dig_init(void *dm_void) + #endif + } + ++void phydm_dig_abs_boundary_decision(struct dm_struct *dm, boolean is_dfs_band); + void phydm_dig_abs_boundary_decision(struct dm_struct *dm, boolean is_dfs_band) + { + struct phydm_dig_struct *dig_t = &dm->dm_dig_table; +@@ -839,6 +852,7 @@ void phydm_dig_abs_boundary_decision(struct dm_struct *dm, boolean is_dfs_band) + dig_t->dm_dig_max, dig_t->dm_dig_min, dig_t->dig_max_of_min); + } + ++void phydm_dig_dym_boundary_decision(struct dm_struct *dm); + void phydm_dig_dym_boundary_decision(struct dm_struct *dm) + { + struct phydm_dig_struct *dig_t = &dm->dm_dig_table; +@@ -918,6 +932,7 @@ void phydm_dig_dym_boundary_decision(struct dm_struct *dm) + dig_t->rx_gain_range_max, dig_t->rx_gain_range_min); + } + ++void phydm_dig_abnormal_case(struct dm_struct *dm); + void phydm_dig_abnormal_case(struct dm_struct *dm) + { + struct phydm_dig_struct *dig_t = &dm->dm_dig_table; +@@ -930,6 +945,7 @@ void phydm_dig_abnormal_case(struct dm_struct *dm) + dig_t->rx_gain_range_max, dig_t->rx_gain_range_min); + } + ++u8 phydm_new_igi_by_fa(struct dm_struct *dm, u8 igi, u32 fa_cnt, u8 *step_size); + u8 phydm_new_igi_by_fa(struct dm_struct *dm, u8 igi, u32 fa_cnt, u8 *step_size) + { + boolean dig_go_up_check = true; +@@ -949,6 +965,8 @@ u8 phydm_new_igi_by_fa(struct dm_struct *dm, u8 igi, u32 fa_cnt, u8 *step_size) + return igi; + } + ++u8 phydm_get_new_igi(struct dm_struct *dm, u8 igi, u32 fa_cnt, ++ boolean is_dfs_band); + u8 phydm_get_new_igi(struct dm_struct *dm, u8 igi, u32 fa_cnt, + boolean is_dfs_band) + { +@@ -1045,6 +1063,7 @@ u8 phydm_get_new_igi(struct dm_struct *dm, u8 igi, u32 fa_cnt, + return igi; + } + ++boolean phydm_dig_dfs_mode_en(void *dm_void); + boolean phydm_dig_dfs_mode_en(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1203,6 +1222,7 @@ void phydm_dig_by_rssi_lps(void *dm_void) + * 3 FASLE ALARM CHECK + * 3============================================================ + */ ++void phydm_false_alarm_counter_reg_reset(void *dm_void); + void phydm_false_alarm_counter_reg_reset(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1299,6 +1319,7 @@ void phydm_false_alarm_counter_reg_reset(void *dm_void) + #endif /* @#if (ODM_IC_11AC_SERIES_SUPPORT) */ + } + ++void phydm_false_alarm_counter_reg_hold(void *dm_void); + void phydm_false_alarm_counter_reg_hold(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1418,6 +1439,7 @@ void phydm_fa_cnt_statistics_n(void *dm_void) + #endif + + #if (ODM_IC_11AC_SERIES_SUPPORT) ++void phydm_fa_cnt_statistics_ac(void *dm_void); + void phydm_fa_cnt_statistics_ac(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1510,6 +1532,7 @@ void phydm_fa_cnt_statistics_ac(void *dm_void) + } + #endif + ++void phydm_get_dbg_port_info(void *dm_void); + void phydm_get_dbg_port_info(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_interface.c b/drivers/staging/rtl8812au/hal/phydm/phydm_interface.c +index fe0f5c220..ef2cac6d0 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_interface.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_interface.c +@@ -749,6 +749,7 @@ void odm_release_timer(struct dm_struct *dm, struct phydm_timer_list *timer) + #endif + } + ++u8 phydm_trans_h2c_id(struct dm_struct *dm, u8 phydm_h2c_id); + u8 phydm_trans_h2c_id(struct dm_struct *dm, u8 phydm_h2c_id) + { + u8 platform_h2c_id = phydm_h2c_id; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c b/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c +index 77fe94e3f..6e76266d9 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c +@@ -39,6 +39,7 @@ + * + *************************************************/ + ++void phydm_set_noise_data_sum(struct noise_level *noise_data, u8 max_rf_path); + void phydm_set_noise_data_sum(struct noise_level *noise_data, u8 max_rf_path) + { + u8 i = 0; +@@ -152,6 +153,8 @@ s16 odm_inband_noise_monitor_n(struct dm_struct *dm, u8 is_pause_dig, u8 igi, + #endif + + #if (ODM_IC_11AC_SERIES_SUPPORT) ++s16 phydm_idle_noise_measure_ac(struct dm_struct *dm, u8 pause_dig, ++ u8 igi, u32 max_time); + s16 phydm_idle_noise_measure_ac(struct dm_struct *dm, u8 pause_dig, + u8 igi, u32 max_time) + { +@@ -251,6 +254,8 @@ s16 phydm_idle_noise_measure_ac(struct dm_struct *dm, u8 pause_dig, + return dm->noise_level.noise_all; + } + ++s16 odm_inband_noise_monitor_ac(struct dm_struct *dm, u8 pause_dig, u8 igi, ++ u32 max_time); + s16 odm_inband_noise_monitor_ac(struct dm_struct *dm, u8 pause_dig, u8 igi, + u32 max_time) + { +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c b/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c +index 060390b3c..627eb5074 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c +@@ -68,6 +68,10 @@ u8 phydm_get_gid(struct dm_struct *dm, u8 *phy_status_inf) + } + #endif + ++void phydm_rx_statistic_cal(struct dm_struct *dm, ++ struct phydm_phyinfo_struct *phy_info, ++ u8 *phy_status_inf, ++ struct phydm_perpkt_info_struct *pktinfo); + void phydm_rx_statistic_cal(struct dm_struct *dm, + struct phydm_phyinfo_struct *phy_info, + u8 *phy_status_inf, +@@ -186,6 +190,9 @@ void phydm_reset_phystatus_statistic(struct dm_struct *dm) + sizeof(struct phydm_phystatus_statistic)); + } + ++void phydm_avg_phystatus_index(void *dm_void, ++ struct phydm_phyinfo_struct *phy_info, ++ struct phydm_perpkt_info_struct *pktinfo); + void phydm_avg_phystatus_index(void *dm_void, + struct phydm_phyinfo_struct *phy_info, + struct phydm_perpkt_info_struct *pktinfo) +@@ -326,6 +333,7 @@ void phydm_avg_phystatus_index(void *dm_void, + } + } + ++void phydm_avg_phystatus_init(void *dm_void); + void phydm_avg_phystatus_init(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -340,6 +348,9 @@ void phydm_avg_phystatus_init(void *dm_void) + odm_move_memory(dm, dbg_i->evm_hist_th, evm_hist_th, size); + } + ++u8 phydm_get_signal_quality(struct phydm_phyinfo_struct *phy_info, ++ struct dm_struct *dm, ++ struct phy_status_rpt_8192cd *phy_sts); + u8 phydm_get_signal_quality(struct phydm_phyinfo_struct *phy_info, + struct dm_struct *dm, + struct phy_status_rpt_8192cd *phy_sts) +@@ -363,6 +374,7 @@ u8 phydm_get_signal_quality(struct phydm_phyinfo_struct *phy_info, + return result; + } + ++u8 phydm_pwr_2_percent(s8 ant_power); + u8 phydm_pwr_2_percent(s8 ant_power) + { + if ((ant_power <= -100) || ant_power >= 20) +@@ -750,6 +762,7 @@ phydm_cfo(s8 value) + return ret_val; + } + ++s8 phydm_cck_rssi_convert(struct dm_struct *dm, u16 lna_idx, u8 vga_idx); + s8 phydm_cck_rssi_convert(struct dm_struct *dm, u16 lna_idx, u8 vga_idx) + { + /*@phydm_get_cck_rssi_table_from_reg*/ +@@ -791,6 +804,7 @@ void phydm_get_cck_rssi_table_from_reg(struct dm_struct *dm) + dm->cck_lna_gain_table[6], dm->cck_lna_gain_table[7]); + } + ++s8 phydm_get_cck_rssi(void *dm_void, u8 lna_idx, u8 vga_idx); + s8 phydm_get_cck_rssi(void *dm_void, u8 lna_idx, u8 vga_idx) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1071,6 +1085,11 @@ void phydm_phy_sts_n_parsing(struct dm_struct *dm, + #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, ++ struct phy_status_rpt_8812 * ++ phy_sts); + void phydm_rx_physts_bw_parsing(struct phydm_phyinfo_struct *phy_info, + struct phydm_perpkt_info_struct * + pktinfo, +@@ -1104,6 +1123,8 @@ void phydm_rx_physts_bw_parsing(struct phydm_phyinfo_struct *phy_info, + } + } + ++void phydm_get_sq(struct dm_struct *dm, struct phydm_phyinfo_struct *phy_info, ++ u8 is_cck_rate); + void phydm_get_sq(struct dm_struct *dm, struct phydm_phyinfo_struct *phy_info, + u8 is_cck_rate) + { +@@ -1144,6 +1165,10 @@ void phydm_get_sq(struct dm_struct *dm, struct phydm_phyinfo_struct *phy_info, + phy_info->signal_quality = sq; + } + ++void phydm_rx_physts_1st_type(struct dm_struct *dm, ++ struct phydm_phyinfo_struct *phy_info, ++ u8 *phy_status_inf, ++ struct phydm_perpkt_info_struct *pktinfo); + void phydm_rx_physts_1st_type(struct dm_struct *dm, + struct phydm_phyinfo_struct *phy_info, + u8 *phy_status_inf, +@@ -1312,6 +1337,7 @@ void phydm_reset_rssi_for_dm(struct dm_struct *dm, u8 station_id) + + #if (ODM_IC_11N_SERIES_SUPPORT || ODM_IC_11AC_SERIES_SUPPORT) + ++s32 phydm_get_rssi_8814_ofdm(struct dm_struct *dm, u8 *rssi_in); + s32 phydm_get_rssi_8814_ofdm(struct dm_struct *dm, u8 *rssi_in) + { + s32 rssi_avg; +@@ -1358,6 +1384,9 @@ s32 phydm_get_rssi_8814_ofdm(struct dm_struct *dm, u8 *rssi_in) + return rssi_avg; + } + ++void phydm_process_rssi_for_dm(struct dm_struct *dm, ++ struct phydm_phyinfo_struct *phy_info, ++ struct phydm_perpkt_info_struct *pktinfo); + void phydm_process_rssi_for_dm(struct dm_struct *dm, + struct phydm_phyinfo_struct *phy_info, + struct phydm_perpkt_info_struct *pktinfo) +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c b/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c +index 077585dfc..2c24b9be9 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c +@@ -51,6 +51,7 @@ boolean phydm_is_cck_rate(void *dm_void, u8 rate) + return ((rate & 0x7f) <= ODM_RATE11M) ? true : false; + } + ++u8 phydm_rate_2_rate_digit(void *dm_void, u8 rate); + u8 phydm_rate_2_rate_digit(void *dm_void, u8 rate) + { + u8 legacy_table[12] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54}; +@@ -151,6 +152,7 @@ void phydm_h2C_debug(void *dm_void, char input[][16], u32 *_used, + *_out_len = out_len; + } + ++void phydm_fw_fix_rate(void *dm_void, u8 en, u8 macid, u8 bw, u8 rate); + void phydm_fw_fix_rate(void *dm_void, u8 en, u8 macid, u8 bw, u8 rate) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -661,6 +663,7 @@ void phydm_update_hal_ra_mask( + + #endif + ++void phydm_rate_adaptive_mask_init(void *dm_void); + void phydm_rate_adaptive_mask_init(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -812,6 +815,7 @@ void phydm_show_sta_info(void *dm_void, char input[][16], u32 *_used, + *_out_len = out_len; + } + ++u8 phydm_get_tx_stream_num(void *dm_void, enum rf_type type); + u8 phydm_get_tx_stream_num(void *dm_void, enum rf_type type) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -831,6 +835,7 @@ u8 phydm_get_tx_stream_num(void *dm_void, enum rf_type type) + return tx_num; + } + ++u64 phydm_get_bb_mod_ra_mask(void *dm_void, u8 sta_idx); + u64 phydm_get_bb_mod_ra_mask(void *dm_void, u8 sta_idx) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1005,6 +1010,7 @@ u8 phydm_get_rate_from_rssi_lv(void *dm_void, u8 sta_idx) + return rate_idx; + } + ++u8 phydm_get_rate_id(void *dm_void, u8 sta_idx); + u8 phydm_get_rate_id(void *dm_void, u8 sta_idx) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -1109,6 +1115,8 @@ u8 phydm_get_rate_id(void *dm_void, u8 sta_idx) + return rate_id_idx; + } + ++void phydm_ra_h2c(void *dm_void, u8 sta_idx, u8 dis_ra, u8 dis_pt, ++ u8 no_update_bw, u8 init_ra_lv, u64 ra_mask); + void phydm_ra_h2c(void *dm_void, u8 sta_idx, u8 dis_ra, u8 dis_pt, + u8 no_update_bw, u8 init_ra_lv, u64 ra_mask) + { +@@ -1379,6 +1387,7 @@ u8 phydm_vht_en_mapping(void *dm_void, u32 wireless_mode) + return vht_en_out; + } + ++u8 phydm_rftype2rateid_2g_n20(void *dm_void, u8 rf_type); + u8 phydm_rftype2rateid_2g_n20(void *dm_void, u8 rf_type) + { + u8 rate_id_idx = 0; +@@ -1394,6 +1403,7 @@ u8 phydm_rftype2rateid_2g_n20(void *dm_void, u8 rf_type) + return rate_id_idx; + } + ++u8 phydm_rftype2rateid_2g_n40(void *dm_void, u8 rf_type); + u8 phydm_rftype2rateid_2g_n40(void *dm_void, u8 rf_type) + { + u8 rate_id_idx = 0; +@@ -1409,6 +1419,7 @@ u8 phydm_rftype2rateid_2g_n40(void *dm_void, u8 rf_type) + return rate_id_idx; + } + ++u8 phydm_rftype2rateid_5g_n(void *dm_void, u8 rf_type); + u8 phydm_rftype2rateid_5g_n(void *dm_void, u8 rf_type) + { + u8 rate_id_idx = 0; +@@ -1424,6 +1435,7 @@ u8 phydm_rftype2rateid_5g_n(void *dm_void, u8 rf_type) + return rate_id_idx; + } + ++u8 phydm_rftype2rateid_ac80(void *dm_void, u8 rf_type); + u8 phydm_rftype2rateid_ac80(void *dm_void, u8 rf_type) + { + u8 rate_id_idx = 0; +@@ -1439,6 +1451,7 @@ u8 phydm_rftype2rateid_ac80(void *dm_void, u8 rf_type) + return rate_id_idx; + } + ++u8 phydm_rftype2rateid_ac40(void *dm_void, u8 rf_type); + u8 phydm_rftype2rateid_ac40(void *dm_void, u8 rf_type) + { + u8 rate_id_idx = 0; +@@ -1566,6 +1579,7 @@ u8 phydm_rate_order_compute(void *dm_void, u8 rate_idx) + } + + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++u8 phydm_rate2ss(void *dm_void, u8 rate_idx); + u8 phydm_rate2ss(void *dm_void, u8 rate_idx) + { + u8 ret = 0xff; +@@ -1591,6 +1605,7 @@ u8 phydm_rate2ss(void *dm_void, u8 rate_idx) + return ret; + } + ++u8 phydm_rate2plcp(void *dm_void, u8 rate_idx); + u8 phydm_rate2plcp(void *dm_void, u8 rate_idx) + { + u8 rate2ss = 0; +@@ -1635,6 +1650,7 @@ u8 phydm_get_plcp(void *dm_void, u16 macid) + } + #endif + ++void phydm_ra_common_info_update(void *dm_void); + void phydm_ra_common_info_update(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c b/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c +index 0d5e41766..8936cc31e 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c +@@ -32,6 +32,7 @@ + + #ifdef PHYDM_SUPPORT_RSSI_MONITOR + ++void phydm_rssi_monitor_h2c(void *dm_void, u8 macid); + void phydm_rssi_monitor_h2c(void *dm_void, u8 macid) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -95,6 +96,7 @@ void phydm_rssi_monitor_h2c(void *dm_void, u8 macid) + } + } + ++void phydm_calculate_rssi_min_max(void *dm_void); + void phydm_calculate_rssi_min_max(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +diff --git a/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c b/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c +index 5de0754da..ba3432e60 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c ++++ b/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c +@@ -86,6 +86,10 @@ phydm_set_ext_band_switch_8821A( + } + + ++void ++odm_dynamic_try_state_agg_8821a( ++ struct dm_struct *dm ++); + void + odm_dynamic_try_state_agg_8821a( + struct dm_struct *dm +@@ -99,6 +103,10 @@ odm_dynamic_try_state_agg_8821a( + } + } + ++void ++odm_dynamic_packet_detection_th_8821a( ++ struct dm_struct *dm ++); + void + odm_dynamic_packet_detection_th_8821a( + struct dm_struct *dm +diff --git a/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c b/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c +index ae45a5b1a..4329dcaee 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c ++++ b/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c +@@ -47,6 +47,8 @@ void hal_com_txbf_config_gtab( + hal_txbf_8822b_config_gtab(dm); + } + ++void phydm_beamform_set_sounding_enter( ++ void *dm_void); + void phydm_beamform_set_sounding_enter( + void *dm_void) + { +@@ -61,6 +63,8 @@ void phydm_beamform_set_sounding_enter( + #endif + } + ++void phydm_beamform_set_sounding_leave( ++ void *dm_void); + void phydm_beamform_set_sounding_leave( + void *dm_void) + { +@@ -75,6 +79,8 @@ void phydm_beamform_set_sounding_leave( + #endif + } + ++void phydm_beamform_set_sounding_rate( ++ void *dm_void); + void phydm_beamform_set_sounding_rate( + void *dm_void) + { +@@ -89,6 +95,8 @@ void phydm_beamform_set_sounding_rate( + #endif + } + ++void phydm_beamform_set_sounding_status( ++ void *dm_void); + void phydm_beamform_set_sounding_status( + void *dm_void) + { +@@ -103,6 +111,8 @@ void phydm_beamform_set_sounding_status( + #endif + } + ++void phydm_beamform_set_sounding_fw_ndpa( ++ void *dm_void); + void phydm_beamform_set_sounding_fw_ndpa( + void *dm_void) + { +@@ -119,6 +129,8 @@ void phydm_beamform_set_sounding_fw_ndpa( + #endif + } + ++void phydm_beamform_set_sounding_clk( ++ void *dm_void); + void phydm_beamform_set_sounding_clk( + void *dm_void) + { +@@ -135,6 +147,8 @@ void phydm_beamform_set_sounding_clk( + #endif + } + ++void phydm_beamform_set_reset_tx_path( ++ void *dm_void); + void phydm_beamform_set_reset_tx_path( + void *dm_void) + { +@@ -150,6 +164,8 @@ void phydm_beamform_set_reset_tx_path( + #endif + } + ++void phydm_beamform_set_get_tx_rate( ++ void *dm_void); + void phydm_beamform_set_get_tx_rate( + void *dm_void) + { +diff --git a/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c b/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c +index 7ad6ca909..328a4b5d2 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c ++++ b/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c +@@ -233,6 +233,7 @@ u8 hal_txbf_8814a_get_ntx(void *dm_void) + return ntx; + } + ++u8 hal_txbf_8814a_get_nrx(void *dm_void); + u8 hal_txbf_8814a_get_nrx(void *dm_void) + { + struct dm_struct *dm = (struct dm_struct *)dm_void; +@@ -259,6 +260,9 @@ u8 hal_txbf_8814a_get_nrx(void *dm_void) + return nrx; + } + ++void hal_txbf_8814a_rf_mode(void *dm_void, ++ struct _RT_BEAMFORMING_INFO *beamforming_info, ++ u8 idx); + void hal_txbf_8814a_rf_mode(void *dm_void, + struct _RT_BEAMFORMING_INFO *beamforming_info, + u8 idx) +diff --git a/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c b/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c +index 18a47d4a9..c42fa53a6 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c ++++ b/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c +@@ -33,6 +33,9 @@ void hal_txbf_8812a_set_ndpa_rate( + odm_write_1byte(dm, REG_NDPA_OPT_CTRL_8812A, (rate << 2 | BW)); + } + ++void hal_txbf_jaguar_rf_mode( ++ void *dm_void, ++ struct _RT_BEAMFORMING_INFO *beam_info); + void hal_txbf_jaguar_rf_mode( + void *dm_void, + struct _RT_BEAMFORMING_INFO *beam_info) +@@ -76,6 +79,9 @@ void hal_txbf_jaguar_rf_mode( + odm_set_bb_reg(dm, R_0x80c, MASKBYTE1, 0x11); + } + ++void hal_txbf_jaguar_download_ndpa( ++ void *dm_void, ++ u8 idx); + void hal_txbf_jaguar_download_ndpa( + void *dm_void, + u8 idx) +@@ -165,6 +171,8 @@ void hal_txbf_jaguar_download_ndpa( + #endif + } + ++void hal_txbf_jaguar_fw_txbf_cmd( ++ void *dm_void); + void hal_txbf_jaguar_fw_txbf_cmd( + void *dm_void) + { +diff --git a/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c b/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c +index ecbb397d5..75a0594ef 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c ++++ b/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c +@@ -158,6 +158,11 @@ u8 rtl8812_set_rssi_cmd(_adapter *padapter, u8 *param) + return res; + } + ++u8 Get_VHT_ENI( ++ u32 IOTAction, ++ u32 WirelessMode, ++ u32 ratr_bitmap ++); + u8 Get_VHT_ENI( + u32 IOTAction, + u32 WirelessMode, +@@ -178,6 +183,13 @@ u8 Get_VHT_ENI( + return Ret << 4; + } + ++BOOLEAN ++Get_RA_ShortGI_8812( ++ PADAPTER Adapter, ++ struct sta_info *psta, ++ u8 shortGIrate, ++ u32 ratr_bitmap ++); + BOOLEAN + Get_RA_ShortGI_8812( + PADAPTER Adapter, +@@ -449,6 +461,7 @@ void rtl8812_set_p2p_ps_offload_cmd(_adapter *padapter, u8 p2p_ps_state) + } + #endif /* CONFIG_P2P */ + ++void rtl8812_download_rsvd_page(PADAPTER padapter, u8 mstatus); + void rtl8812_download_rsvd_page(PADAPTER padapter, u8 mstatus) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +diff --git a/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c b/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c +index 4a21818b7..5e26efadb 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c ++++ b/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c +@@ -685,6 +685,11 @@ void InitializeFirmwareVars8812(PADAPTER padapter) + * Porting from 8723B. 2013.04.01 + * */ + VOID ++SetFwBTFwPatchCmd_8821( ++ IN PADAPTER Adapter, ++ IN u2Byte FwSize ++); ++VOID + SetFwBTFwPatchCmd_8821( + IN PADAPTER Adapter, + IN u2Byte FwSize +@@ -705,6 +710,7 @@ SetFwBTFwPatchCmd_8821( + } + + #ifdef CONFIG_MP_INCLUDED ++int ReservedPage_Compare(PADAPTER Adapter, PRT_MP_FIRMWARE pFirmware, u32 BTPatchSize); + int ReservedPage_Compare(PADAPTER Adapter, PRT_MP_FIRMWARE pFirmware, u32 BTPatchSize) + { + u8 temp, ret, lastBTsz; +@@ -1119,6 +1125,12 @@ Hal_ReadAntennaDiversity8812A( + #endif + } + ++VOID ++hal_ReadPAType_8812A( ++ IN PADAPTER Adapter, ++ IN u8 *PROMContent, ++ IN BOOLEAN AutoloadFail ++); + VOID + hal_ReadPAType_8812A( + IN PADAPTER Adapter, +@@ -1976,6 +1988,13 @@ rtl8812_ReadEFuse( + + /* Do not support BT */ + VOID ++Hal_EFUSEGetEfuseDefinition8812A( ++ IN PADAPTER pAdapter, ++ IN u1Byte efuseType, ++ IN u1Byte type, ++ OUT PVOID pOut ++); ++VOID + Hal_EFUSEGetEfuseDefinition8812A( + IN PADAPTER pAdapter, + IN u1Byte efuseType, +@@ -2057,6 +2076,13 @@ Hal_EFUSEGetEfuseDefinition8812A( + } + } + VOID ++Hal_EFUSEGetEfuseDefinition_Pseudo8812A( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u8 type, ++ OUT PVOID pOut ++); ++VOID + Hal_EFUSEGetEfuseDefinition_Pseudo8812A( + IN PADAPTER pAdapter, + IN u8 efuseType, +@@ -2486,6 +2512,14 @@ rtl8812_Efuse_PgPacketRead(IN PADAPTER pAdapter, + } + + ++BOOLEAN ++hal_EfuseFixHeaderProcess( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN PPGPKT_STRUCT pFixPkt, ++ IN u16 *pAddr, ++ IN BOOLEAN bPseudoTest ++); + BOOLEAN + hal_EfuseFixHeaderProcess( + IN PADAPTER pAdapter, +@@ -2687,6 +2721,11 @@ hal_EfusePgPacketWriteData( + return _TRUE; + } + ++BOOLEAN efuse_PgPacketCheck( ++ PADAPTER pAdapter, ++ u8 efuseType, ++ BOOLEAN bPseudoTest ++); + BOOLEAN efuse_PgPacketCheck( + PADAPTER pAdapter, + u8 efuseType, +@@ -2704,6 +2743,13 @@ BOOLEAN efuse_PgPacketCheck( + } + + ++VOID ++efuse_PgPacketConstruct( ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *pData, ++ IN OUT PPGPKT_STRUCT pTargetPkt ++); + VOID + efuse_PgPacketConstruct( + IN u8 offset, +@@ -2721,6 +2767,11 @@ efuse_PgPacketConstruct( + RTW_INFO("efuse_PgPacketConstruct(), targetPkt, offset=%d, word_en=0x%x, word_cnts=%d\n", pTargetPkt->offset, pTargetPkt->word_en, pTargetPkt->word_cnts); + } + ++u2Byte ++Hal_EfusePgPacketExceptionHandle_8812A( ++ PADAPTER pAdapter, ++ u2Byte ErrOffset ++ ); + u2Byte + Hal_EfusePgPacketExceptionHandle_8812A( + PADAPTER pAdapter, +@@ -2794,6 +2845,12 @@ Hal_EfusePgPacketExceptionHandle_8812A( + } + + ++BOOLEAN hal_EfuseCheckIfDatafollowed( ++ IN PADAPTER pAdapter, ++ IN u8 word_cnts, ++ IN u16 startAddr, ++ IN BOOLEAN bPseudoTest ++); + BOOLEAN hal_EfuseCheckIfDatafollowed( + IN PADAPTER pAdapter, + IN u8 word_cnts, +@@ -2813,6 +2870,12 @@ BOOLEAN hal_EfuseCheckIfDatafollowed( + } + + ++BOOLEAN ++hal_EfuseWordEnMatched( ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN PPGPKT_STRUCT pCurPkt, ++ IN u8 *pWden ++); + BOOLEAN + hal_EfuseWordEnMatched( + IN PPGPKT_STRUCT pTargetPkt, +@@ -2849,6 +2912,14 @@ hal_EfuseWordEnMatched( + } + + ++BOOLEAN ++efuse_PgPacketPartialWrite( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN OUT u16 *pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest ++); + BOOLEAN + efuse_PgPacketPartialWrite( + IN PADAPTER pAdapter, +@@ -3004,6 +3075,12 @@ efuse_PgPacketPartialWrite( + return bRet; + } + ++BOOLEAN efuse_PgPacketWriteHeader( ++ PADAPTER pAdapter, ++ u8 efuseType, ++ u16 *pAddr, ++ PPGPKT_STRUCT pTargetPkt, ++ BOOLEAN bPseudoTest); + BOOLEAN efuse_PgPacketWriteHeader( + PADAPTER pAdapter, + u8 efuseType, +@@ -3021,6 +3098,12 @@ BOOLEAN efuse_PgPacketWriteHeader( + return bRet; + } + ++int ++hal_EfusePgPacketWrite_8812A(IN PADAPTER pAdapter, ++ u8 offset, ++ u8 word_en, ++ u8 *pData, ++ BOOLEAN bPseudoTest); + int + hal_EfusePgPacketWrite_8812A(IN PADAPTER pAdapter, + u8 offset, +@@ -3288,6 +3371,7 @@ void rtl8812_stop_thread(PADAPTER padapter) + { + } + ++void hal_notch_filter_8812(_adapter *adapter, bool enable); + void hal_notch_filter_8812(_adapter *adapter, bool enable) + { + if (enable) { +@@ -5194,6 +5278,7 @@ struct bcn_qinfo_8812a { + u16 pkt_num:8; + }; + ++void dump_qinfo_8812a(void *sel, struct qinfo_8812a *info, const char *tag); + void dump_qinfo_8812a(void *sel, struct qinfo_8812a *info, const char *tag) + { + /* if (info->pkt_num) */ +@@ -5202,6 +5287,7 @@ void dump_qinfo_8812a(void *sel, struct qinfo_8812a *info, const char *tag) + ); + } + ++void dump_bcn_qinfo_8812a(void *sel, struct bcn_qinfo_8812a *info, const char *tag); + void dump_bcn_qinfo_8812a(void *sel, struct bcn_qinfo_8812a *info, const char *tag) + { + /* if (info->pkt_num) */ +@@ -5210,6 +5296,7 @@ void dump_bcn_qinfo_8812a(void *sel, struct bcn_qinfo_8812a *info, const char *t + ); + } + ++void dump_mac_qinfo_8812a(void *sel, _adapter *adapter); + void dump_mac_qinfo_8812a(void *sel, _adapter *adapter) + { + u32 q0_info; +@@ -5277,6 +5364,7 @@ static void dump_mac_txfifo_8812a(void *sel, _adapter *adapter) + } + } + ++void rtl8812a_read_wmmedca_reg(PADAPTER adapter, u16 *vo_params, u16 *vi_params, u16 *be_params, u16 *bk_params); + void rtl8812a_read_wmmedca_reg(PADAPTER adapter, u16 *vo_params, u16 *vi_params, u16 *be_params, u16 *bk_params) + { + u8 vo_reg_params[4]; +@@ -5447,6 +5535,7 @@ u8 SetHalDefVar8812A(PADAPTER padapter, HAL_DEF_VARIABLE variable, void *pval) + return bResult; + } + ++void hal_ra_info_dump(_adapter *padapter , void *sel); + void hal_ra_info_dump(_adapter *padapter , void *sel) + { + int i; +diff --git a/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c b/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c +index 464168823..f44fb3c3e 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c ++++ b/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c +@@ -446,6 +446,13 @@ PHY_RFConfig8812( + return rtStatus; + } + ++VOID ++PHY_TxPowerTrainingByPath_8812( ++ IN PADAPTER Adapter, ++ IN enum channel_width BandWidth, ++ IN u8 Channel, ++ IN u8 RfPath ++); + VOID + PHY_TxPowerTrainingByPath_8812( + IN PADAPTER Adapter, +@@ -1097,6 +1104,11 @@ u32 phy_get_tx_bb_swing_8812a( + return out; + } + ++VOID ++phy_SetRFEReg8812( ++ IN PADAPTER Adapter, ++ IN u8 Band ++); + VOID + phy_SetRFEReg8812( + IN PADAPTER Adapter, +@@ -1218,6 +1230,11 @@ phy_SetRFEReg8812( + } + } + ++void phy_SetBBSwingByBand_8812A( ++ IN PADAPTER Adapter, ++ IN u8 Band, ++ IN u1Byte PreviousBand ++); + void phy_SetBBSwingByBand_8812A( + IN PADAPTER Adapter, + IN u8 Band, +@@ -1260,6 +1277,11 @@ void phy_SetBBSwingByBand_8812A( + } + + ++VOID ++phy_SetRFEReg8821( ++ IN PADAPTER Adapter, ++ IN u1Byte Band ++); + VOID + phy_SetRFEReg8821( + IN PADAPTER Adapter, +@@ -1459,6 +1481,11 @@ PHY_SwitchWirelessBand8812( + return _SUCCESS; + } + ++BOOLEAN ++phy_SwBand8812( ++ IN PADAPTER pAdapter, ++ IN u8 channelToSW ++); + BOOLEAN + phy_SwBand8812( + IN PADAPTER pAdapter, +@@ -1489,6 +1516,10 @@ phy_SwBand8812( + + #pragma clang optimize off + u8 ++phy_GetSecondaryChnl_8812( ++ IN PADAPTER Adapter ++); ++u8 + phy_GetSecondaryChnl_8812( + IN PADAPTER Adapter + ) +@@ -1531,6 +1562,11 @@ phy_GetSecondaryChnl_8812( + } + #pragma clang optimize on + ++VOID ++phy_SetRegBW_8812( ++ IN PADAPTER Adapter, ++ enum channel_width CurrentBW ++); + VOID + phy_SetRegBW_8812( + IN PADAPTER Adapter, +@@ -1562,6 +1598,12 @@ phy_SetRegBW_8812( + + } + ++void ++phy_FixSpur_8812A( ++ IN PADAPTER pAdapter, ++ IN enum channel_width Bandwidth, ++ IN u1Byte Channel ++); + void + phy_FixSpur_8812A( + IN PADAPTER pAdapter, +@@ -1605,6 +1647,10 @@ phy_FixSpur_8812A( + + } + ++VOID ++phy_PostSetBwMode8812( ++ IN PADAPTER Adapter ++); + VOID + phy_PostSetBwMode8812( + IN PADAPTER Adapter +@@ -1699,6 +1745,9 @@ phy_PostSetBwMode8812( + } + + /* <20130207, Kordan> The variales initialized here are used in odm_LNAPowerControl(). */ ++VOID phy_InitRssiTRSW( ++ IN PADAPTER pAdapter ++); + VOID phy_InitRssiTRSW( + IN PADAPTER pAdapter + ) +@@ -1723,6 +1772,12 @@ VOID phy_InitRssiTRSW( + + /*Referenced from "WB-20130801-YN-RL6286 Settings for Spur Issues R02.xls"*/ + VOID ++phy_SpurCalibration_8812A( ++ IN PADAPTER pAdapter, ++ IN u8 Channel, ++ IN u8 Bandwidth ++); ++VOID + phy_SpurCalibration_8812A( + IN PADAPTER pAdapter, + IN u8 Channel, +@@ -1769,6 +1824,10 @@ phy_SpurCalibration_8812A( + + } + ++VOID ++phy_SwChnl8812( ++ IN PADAPTER pAdapter ++); + VOID + phy_SwChnl8812( + IN PADAPTER pAdapter +@@ -1861,6 +1920,10 @@ phy_SwChnl8812( + phy_SpurCalibration_8812A(pAdapter, channelToSW, bandwidthToSw); + } + ++VOID ++phy_SwChnlAndSetBwMode8812( ++ IN PADAPTER Adapter ++); + VOID + phy_SwChnlAndSetBwMode8812( + IN PADAPTER Adapter +@@ -1918,6 +1981,17 @@ phy_SwChnlAndSetBwMode8812( + } + } + ++VOID ++PHY_HandleSwChnlAndSetBW8812( ++ 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 ++); + VOID + PHY_HandleSwChnlAndSetBW8812( + IN PADAPTER Adapter, +diff --git a/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c b/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c +index 37d6cec0a..d2b2b2c99 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c ++++ b/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c +@@ -145,6 +145,7 @@ static BOOLEAN HalUsbSetQueuePipeMapping8812AUsb( + + } + ++void rtl8812au_interface_configure(_adapter *padapter); + void rtl8812au_interface_configure(_adapter *padapter) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +@@ -1116,6 +1117,10 @@ init_UsbAggregationSetting_8812A( + * + *---------------------------------------------------------------------------*/ + VOID ++USB_AggModeSwitch( ++ IN PADAPTER Adapter ++); ++VOID + USB_AggModeSwitch( + IN PADAPTER Adapter + ) +@@ -1278,6 +1283,7 @@ HalDetectSelectiveSuspendMode( + #endif + } /* HalDetectSelectiveSuspendMode */ + ++rt_rf_power_state RfOnOffDetect(IN PADAPTER pAdapter); + rt_rf_power_state RfOnOffDetect(IN PADAPTER pAdapter) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); +@@ -1298,12 +1304,14 @@ rt_rf_power_state RfOnOffDetect(IN PADAPTER pAdapter) + return rfpowerstate; + } /* HalDetectPwrDownMode */ + ++void _ps_open_RF(_adapter *padapter); + void _ps_open_RF(_adapter *padapter) + { + /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */ + /* phy_SsPwrSwitch92CU(padapter, rf_on, 1); */ + } + ++void _ps_close_RF(_adapter *padapter); + void _ps_close_RF(_adapter *padapter) + { + /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */ +@@ -1353,6 +1361,7 @@ static void rtl8812au_hw_reset(_adapter *Adapter) + } + } + ++u32 rtl8812au_hal_init(PADAPTER Adapter); + u32 rtl8812au_hal_init(PADAPTER Adapter) + { + u8 value8 = 0, u1bRegCR; +@@ -1804,6 +1813,10 @@ u32 rtl8812au_hal_init(PADAPTER Adapter) + return status; + } + ++VOID ++hal_poweroff_8812au( ++ IN PADAPTER Adapter ++); + VOID + hal_poweroff_8812au( + IN PADAPTER Adapter +@@ -1872,6 +1885,7 @@ static void rtl8812au_hw_power_down(_adapter *padapter) + rtw_write16(padapter, REG_APS_FSMCO, 0x8812); + } + ++u32 rtl8812au_hal_deinit(PADAPTER Adapter); + u32 rtl8812au_hal_deinit(PADAPTER Adapter) + { + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(Adapter); +@@ -1922,7 +1936,8 @@ u32 rtl8812au_hal_deinit(PADAPTER Adapter) + } + + +-unsigned int rtl8812au_inirp_init(PADAPTER Adapter) ++unsigned int rtl8812au_inirp_init(PADAPTER Adapter); ++unsigned int rtl8812au_inirp_init(PADAPTER Adapter) + { + u8 i; + struct recv_buf *precvbuf; +@@ -1976,7 +1991,8 @@ unsigned int rtl8812au_inirp_init(PADAPTER Adapter) + + } + +-unsigned int rtl8812au_inirp_deinit(PADAPTER Adapter) ++unsigned int rtl8812au_inirp_deinit(PADAPTER Adapter); ++unsigned int rtl8812au_inirp_deinit(PADAPTER Adapter) + { + + rtw_read_port_cancel(Adapter); +@@ -1991,6 +2007,12 @@ unsigned int rtl8812au_inirp_deinit(PADAPTER Adapter) + * + * ------------------------------------------------------------------- */ + VOID ++hal_ReadIDs_8812AU( ++ IN PADAPTER Adapter, ++ IN pu1Byte PROMContent, ++ IN BOOLEAN AutoloadFail ++); ++VOID + hal_ReadIDs_8812AU( + IN PADAPTER Adapter, + IN pu1Byte PROMContent, +@@ -2049,6 +2071,11 @@ hal_ReadIDs_8812AU( + RTW_INFO("Customer ID: 0x%02X, SubCustomer ID: 0x%02X\n", pHalData->EEPROMCustomerID, pHalData->EEPROMSubCustomerID); + } + ++VOID ++hal_InitPGData_8812A( ++ IN PADAPTER padapter, ++ IN OUT u8 *PROMContent ++); + VOID + hal_InitPGData_8812A( + IN PADAPTER padapter, +@@ -2127,6 +2154,10 @@ hal_InitPGData_8812A( + + } + ++VOID ++hal_CustomizedBehavior_8812AU( ++ IN PADAPTER Adapter ++); + VOID + hal_CustomizedBehavior_8812AU( + IN PADAPTER Adapter +@@ -2266,6 +2297,12 @@ hal_CustomizeByCustomerID_8812AU( + hal_CustomizedBehavior_8812AU(pAdapter); + } + ++VOID ++hal_ReadUsbModeSwitch_8812AU( ++ IN PADAPTER Adapter, ++ IN u8 *PROMContent, ++ IN BOOLEAN AutoloadFail ++); + VOID + hal_ReadUsbModeSwitch_8812AU( + IN PADAPTER Adapter, +@@ -2302,6 +2339,10 @@ ReadLEDSetting_8812AU( + #endif + } + ++VOID ++InitAdapterVariablesByPROM_8812AU( ++ IN PADAPTER Adapter ++); + VOID + InitAdapterVariablesByPROM_8812AU( + IN PADAPTER Adapter +@@ -2372,6 +2413,10 @@ static void Hal_ReadPROMContent_8812A( + InitAdapterVariablesByPROM_8812AU(Adapter); + } + ++u8 ++ReadAdapterInfo8812AU( ++ IN PADAPTER Adapter ++); + u8 + ReadAdapterInfo8812AU( + IN PADAPTER Adapter +@@ -2386,6 +2431,7 @@ ReadAdapterInfo8812AU( + return _SUCCESS; + } + ++void UpdateInterruptMask8812AU(PADAPTER padapter, u8 bHIMR0 , u32 AddMSR, u32 RemoveMSR); + void UpdateInterruptMask8812AU(PADAPTER padapter, u8 bHIMR0 , u32 AddMSR, u32 RemoveMSR) + { + HAL_DATA_TYPE *pHalData; +@@ -2411,6 +2457,7 @@ void UpdateInterruptMask8812AU(PADAPTER padapter, u8 bHIMR0 , u32 AddMSR, u32 Re + + } + ++u8 SetHwReg8812AU(PADAPTER Adapter, u8 variable, u8 *val); + u8 SetHwReg8812AU(PADAPTER Adapter, u8 variable, u8 *val) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); +@@ -2500,6 +2547,7 @@ u8 SetHwReg8812AU(PADAPTER Adapter, u8 variable, u8 *val) + return ret; + } + ++void GetHwReg8812AU(PADAPTER Adapter, u8 variable, u8 *val); + void GetHwReg8812AU(PADAPTER Adapter, u8 variable, u8 *val) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); +@@ -2531,6 +2579,12 @@ void GetHwReg8812AU(PADAPTER Adapter, u8 variable, u8 *val) + * Change default setting of specified variable. + * */ + u8 ++SetHalDefVar8812AUsb( ++ IN PADAPTER Adapter, ++ IN HAL_DEF_VARIABLE eVariable, ++ IN PVOID pValue ++); ++u8 + SetHalDefVar8812AUsb( + IN PADAPTER Adapter, + IN HAL_DEF_VARIABLE eVariable, +@@ -2554,6 +2608,12 @@ SetHalDefVar8812AUsb( + * Query setting of specified variable. + * */ + u8 ++GetHalDefVar8812AUsb( ++ IN PADAPTER Adapter, ++ IN HAL_DEF_VARIABLE eVariable, ++ IN PVOID pValue ++); ++u8 + GetHalDefVar8812AUsb( + IN PADAPTER Adapter, + IN HAL_DEF_VARIABLE eVariable, +@@ -2572,6 +2632,7 @@ GetHalDefVar8812AUsb( + return bResult; + } + ++void _update_response_rate(_adapter *padapter, unsigned int mask); + void _update_response_rate(_adapter *padapter, unsigned int mask) + { + u8 RateIndex = 0; +diff --git a/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c b/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c +index 22f8c42cf..db7f3b2c5 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c ++++ b/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c +@@ -101,6 +101,7 @@ void interrupt_handler_8812au(_adapter *padapter, u16 pkt_len, u8 *pbuf) + } + #endif + ++int recvbuf2recvframe(PADAPTER padapter, void *ptr); + int recvbuf2recvframe(PADAPTER padapter, void *ptr) + { + u8 *pbuf; +diff --git a/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c b/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c +index 6aa1fda17..76ed34e50 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c ++++ b/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c +@@ -151,6 +151,7 @@ s32 FillH2CCmd_8814(PADAPTER padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) + return ret; + } + ++u8 rtl8814_set_rssi_cmd(_adapter*padapter, u8 *param); + u8 rtl8814_set_rssi_cmd(_adapter*padapter, u8 *param) + { + u8 res=_SUCCESS; +@@ -206,6 +207,13 @@ static u8 Get_VHT_ENI( + return (Ret << 4); + } + ++BOOLEAN ++Get_RA_ShortGI_8814( ++ PADAPTER Adapter, ++ struct sta_info *psta, ++ u8 shortGIrate, ++ u32 ratr_bitmap ++); + BOOLEAN + Get_RA_ShortGI_8814( + PADAPTER Adapter, +@@ -267,6 +275,10 @@ Set_RA_LDPC_8814( + } + + ++u8 ++Get_RA_LDPC_8814( ++ struct sta_info *psta ++); + u8 + Get_RA_LDPC_8814( + struct sta_info *psta +@@ -597,6 +609,7 @@ static void ConstructNullFunctionData( + *pLength = pktlen; + } + ++void ConstructProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, BOOLEAN bHideSSID); + void ConstructProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, BOOLEAN bHideSSID) + { + struct rtw_ieee80211_hdr *pwlanhdr; +@@ -1152,6 +1165,7 @@ static void rtl8814_set_FwAoacRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvd + #endif + + ++int rtl8814_iqk_wait(_adapter* padapter, u32 timeout_ms); + int rtl8814_iqk_wait(_adapter* padapter, u32 timeout_ms) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +@@ -1164,6 +1178,7 @@ int rtl8814_iqk_wait(_adapter* padapter, u32 timeout_ms) + return rtw_sctx_wait(iqk_sctx, __func__); + } + ++void rtl8814_iqk_done(_adapter* padapter); + void rtl8814_iqk_done(_adapter* padapter) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +diff --git a/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c b/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c +index f1a903d68..d203753b6 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c ++++ b/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c +@@ -119,6 +119,11 @@ void hal_DetectWoWMode(PADAPTER pAdapter) + #endif + + ++VOID ++_FWDownloadEnable_8814A( ++ IN PADAPTER Adapter, ++ IN BOOLEAN enable ++ ); + VOID + _FWDownloadEnable_8814A( + IN PADAPTER Adapter, +@@ -152,6 +157,12 @@ _FWDownloadEnable_8814A( + + #define MAX_REG_BOLCK_SIZE 196 + ++VOID ++_BlockWrite_8814A( ++ IN PADAPTER Adapter, ++ IN PVOID buffer, ++ IN u32 buffSize ++ ); + VOID + _BlockWrite_8814A( + IN PADAPTER Adapter, +@@ -212,6 +223,13 @@ _BlockWrite_8814A( + } + } + ++VOID ++_PageWrite_8814A( ++ IN PADAPTER Adapter, ++ IN u32 page, ++ IN PVOID buffer, ++ IN u32 size ++ ); + VOID + _PageWrite_8814A( + IN PADAPTER Adapter, +@@ -229,6 +247,11 @@ _PageWrite_8814A( + _BlockWrite_8814A(Adapter,buffer,size); + } + ++VOID ++_FillDummy_8814A( ++ u8* pFwBuf, ++ pu4Byte pFwLen ++ ); + VOID + _FillDummy_8814A( + u8* pFwBuf, +@@ -249,6 +272,12 @@ _FillDummy_8814A( + *pFwLen = FwLen; + } + ++VOID ++_WriteFW_8814A( ++ IN PADAPTER Adapter, ++ IN PVOID buffer, ++ IN u32 size ++ ); + VOID + _WriteFW_8814A( + IN PADAPTER Adapter, +@@ -284,6 +313,10 @@ _WriteFW_8814A( + } + } + ++VOID ++_3081Disable8814A( ++ IN PADAPTER Adapter ++ ); + VOID + _3081Disable8814A( + IN PADAPTER Adapter +@@ -296,6 +329,10 @@ _3081Disable8814A( + + } + ++VOID ++_3081Enable8814A( ++ IN PADAPTER Adapter ++ ); + VOID + _3081Enable8814A( + IN PADAPTER Adapter +@@ -453,6 +490,12 @@ WaitDownLoadRSVDPageOK_3081( + } + + ++VOID ++SetDownLoadFwRsvdPagePkt_8814A( ++ IN PADAPTER Adapter, ++ IN PVOID buffer, ++ IN u32 len ++ ); + VOID + SetDownLoadFwRsvdPagePkt_8814A( + IN PADAPTER Adapter, +@@ -535,6 +578,12 @@ static void SetBcnCtrlReg( + rtw_write8(padapter, REG_BCN_CTRL, RegBcnCtrlVal); + } + ++VOID ++HalROMDownloadFWRSVDPage8814A( ++ IN PADAPTER Adapter, ++ IN PVOID buffer, ++ IN u32 Len ++); + VOID + HalROMDownloadFWRSVDPage8814A( + IN PADAPTER Adapter, +@@ -726,6 +775,10 @@ HalROMDownloadFWRSVDPage8814A( + } + } + ++s32 ++_FWFreeToGo8814A( ++ IN PADAPTER Adapter ++ ); + s32 + _FWFreeToGo8814A( + IN PADAPTER Adapter +@@ -1444,6 +1497,11 @@ SetFwRelatedForWoWLAN8812( + // Efuse related code + //=========================================================== + BOOLEAN ++hal_GetChnlGroup8814A( ++ IN u8 Channel, ++ OUT u8* pGroup ++ ); ++BOOLEAN + hal_GetChnlGroup8814A( + IN u8 Channel, + OUT u8* pGroup +@@ -1774,6 +1832,10 @@ hal_ReadPowerValueFromPROM8814A( + } + #endif + ++VOID ++HALBT_InitHalVars( ++ IN PADAPTER Adapter ++ ); + VOID + HALBT_InitHalVars( + IN PADAPTER Adapter +@@ -1792,6 +1854,10 @@ HALBT_InitHalVars( + } + + ++VOID ++BT_InitHalVars( ++ IN PADAPTER Adapter ++ ); + VOID + BT_InitHalVars( + IN PADAPTER Adapter +@@ -2789,6 +2855,13 @@ rtl8814_ReadEFuse( + + //Do not support BT + VOID ++hal_EFUSEGetEfuseDefinition8814A( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u8 type, ++ OUT PVOID pOut ++ ); ++VOID + hal_EFUSEGetEfuseDefinition8814A( + IN PADAPTER pAdapter, + IN u8 efuseType, +@@ -3231,6 +3304,11 @@ efuse_PgPacketConstruct( + } + + ++u16 ++efuse_PgPacketExceptionHandle( ++ IN PADAPTER pAdapter, ++ IN u16 ErrOffset ++ ); + u16 + efuse_PgPacketExceptionHandle( + IN PADAPTER pAdapter, +@@ -3528,6 +3606,13 @@ hal_EfuseFixHeaderProcess( + } + + ++BOOLEAN ++efuse_PgPacketWrite2ByteHeader( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN OUT u16* pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest); + BOOLEAN + efuse_PgPacketWrite2ByteHeader( + IN PADAPTER pAdapter, +@@ -3631,6 +3716,13 @@ efuse_PgPacketWrite2ByteHeader( + } + + ++BOOLEAN ++efuse_PgPacketWrite1ByteHeader( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN OUT u16* pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest); + BOOLEAN + efuse_PgPacketWrite1ByteHeader( + IN PADAPTER pAdapter, +@@ -3724,6 +3816,13 @@ efuse_PgPacketWriteHeader( + return bRet; + } + ++BOOLEAN ++efuse_PgPacketWriteData( ++ IN PADAPTER pAdapter, ++ IN u8 efuseType, ++ IN u16* pAddr, ++ IN PPGPKT_STRUCT pTargetPkt, ++ IN BOOLEAN bPseudoTest); + BOOLEAN + efuse_PgPacketWriteData( + IN PADAPTER pAdapter, +@@ -3760,6 +3859,12 @@ efuse_PgPacketWriteData( + } + + ++int ++hal_EfusePgPacketWrite_8814A(IN PADAPTER pAdapter, ++ IN u8 offset, ++ IN u8 word_en, ++ IN u8 *pData, ++ IN BOOLEAN bPseudoTest); + int + hal_EfusePgPacketWrite_8814A(IN PADAPTER pAdapter, + IN u8 offset, +@@ -3871,6 +3976,7 @@ void rtl8814_stop_thread(PADAPTER padapter) + { + } + ++void hal_notch_filter_8814(_adapter *adapter, bool enable); + void hal_notch_filter_8814(_adapter *adapter, bool enable) + { + if (enable) { +@@ -3918,6 +4024,7 @@ void CheckAutoloadState8812A(PADAPTER padapter) + } + */ + ++void InitPGData8814A(PADAPTER padapter); + void InitPGData8814A(PADAPTER padapter) + { + u32 i; +@@ -3997,6 +4104,11 @@ static void read_chip_version_8814a(PADAPTER Adapter) + + } + ++VOID ++hal_PatchwithJaguar_8814( ++ IN PADAPTER Adapter, ++ IN RT_MEDIA_STATUS MediaStatus ++ ); + VOID + hal_PatchwithJaguar_8814( + IN PADAPTER Adapter, +@@ -6300,6 +6412,7 @@ struct bcn_qinfo_8814a { + u16 pkt_num:8; + }; + ++void dump_qinfo_8814a(void *sel, struct qinfo_8814a *info, const char *tag); + void dump_qinfo_8814a(void *sel, struct qinfo_8814a *info, const char *tag) + { + //if (info->pkt_num) +@@ -6308,6 +6421,7 @@ void dump_qinfo_8814a(void *sel, struct qinfo_8814a *info, const char *tag) + ); + } + ++void dump_bcn_qinfo_8814a(void *sel, struct bcn_qinfo_8814a *info, const char *tag); + void dump_bcn_qinfo_8814a(void *sel, struct bcn_qinfo_8814a *info, const char *tag) + { + //if (info->pkt_num) +@@ -6316,6 +6430,7 @@ void dump_bcn_qinfo_8814a(void *sel, struct bcn_qinfo_8814a *info, const char *t + ); + } + ++void dump_mac_qinfo_8814a(void *sel, _adapter *adapter); + void dump_mac_qinfo_8814a(void *sel, _adapter *adapter) + { + u32 q0_info; +diff --git a/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c b/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c +index 1c212540c..675a0591b 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c ++++ b/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c +@@ -1102,6 +1102,10 @@ PHY_SetRFPowerState8814A( + todo */ + //1 5. Tx Power setting API + ++VOID ++phy_TxPwrAdjInPercentage( ++ IN PADAPTER Adapter, ++ OUT u8* pTxPwrIdx); + VOID + phy_TxPwrAdjInPercentage( + IN PADAPTER Adapter, +@@ -1455,7 +1459,13 @@ phy_SetBwRegAdc_8814A( + IN PADAPTER Adapter, + IN u8 Band, + IN enum channel_width CurrentBW +-) ++); ++VOID ++phy_SetBwRegAdc_8814A( ++ IN PADAPTER Adapter, ++ IN u8 Band, ++ IN enum channel_width CurrentBW ++) + { + switch(CurrentBW) + { +@@ -1497,7 +1507,13 @@ phy_SetBwRegAgc_8814A( + IN PADAPTER Adapter, + IN u8 Band, + IN enum channel_width CurrentBW +-) ++); ++VOID ++phy_SetBwRegAgc_8814A( ++ IN PADAPTER Adapter, ++ IN u8 Band, ++ IN enum channel_width CurrentBW ++) + { + u32 AgcValue = 7; + switch(CurrentBW) +@@ -1529,6 +1545,10 @@ phy_SetBwRegAgc_8814A( + } + + ++BOOLEAN ++phy_SwBand8814A( ++ IN PADAPTER pAdapter, ++ IN u8 channelToSW); + BOOLEAN + phy_SwBand8814A( + IN PADAPTER pAdapter, +@@ -1648,6 +1668,12 @@ PHY_SetRFEReg8814A( + } + } + ++VOID ++phy_SetBBSwingByBand_8814A( ++ IN PADAPTER Adapter, ++ IN u8 Band, ++ IN u8 PreviousBand ++ ); + VOID + phy_SetBBSwingByBand_8814A( + IN PADAPTER Adapter, +@@ -1766,6 +1792,10 @@ PHY_SwitchWirelessBand8814A( + } + + ++u8 ++phy_GetSecondaryChnl_8814A( ++ IN PADAPTER Adapter ++); + u8 + phy_GetSecondaryChnl_8814A( + IN PADAPTER Adapter +@@ -1823,7 +1853,12 @@ VOID + phy_SetBwRegMac_8814A( + IN PADAPTER Adapter, + enum channel_width CurrentBW +-) ++); ++VOID ++phy_SetBwRegMac_8814A( ++ IN PADAPTER Adapter, ++ enum channel_width CurrentBW ++) + { + u16 RegRfMod_BW, u2tmp = 0; + RegRfMod_BW = PlatformEFIORead2Byte(Adapter, REG_TRXPTCL_CTL_8814A); +@@ -1974,7 +2009,8 @@ void PHY_Set_SecCCATH_by_RXANT_8814A(PADAPTER pAdapter,u4Byte ulAntennaRx) + } + + +-VOID PHY_SetRXSC_by_TXSC_8814A(PADAPTER Adapter, u1Byte SubChnlNum) ++VOID PHY_SetRXSC_by_TXSC_8814A(PADAPTER Adapter, u1Byte SubChnlNum); ++VOID PHY_SetRXSC_by_TXSC_8814A(PADAPTER Adapter, u1Byte SubChnlNum) + { + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + +@@ -2004,6 +2040,7 @@ VOID PHY_SetRXSC_by_TXSC_8814A(PADAPTER Adapter, u1Byte SubChnlNum) + + + /* <20141230, James> A workaround to eliminate the 5280MHz & 5600MHz & 5760MHzspur of 8814A. (Asked by BBSD Neil.)*/ ++VOID phy_SpurCalibration_8814A(PADAPTER Adapter); + VOID phy_SpurCalibration_8814A(PADAPTER Adapter) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); +@@ -2125,6 +2162,8 @@ VOID phy_SpurCalibration_8814A(PADAPTER Adapter) + } + + ++void phy_ModifyInitialGain_8814A( ++ PADAPTER Adapter); + void phy_ModifyInitialGain_8814A( + PADAPTER Adapter) + { +@@ -2179,6 +2218,7 @@ void phy_ModifyInitialGain_8814A( + } + + ++VOID phy_SetBwMode8814A(PADAPTER Adapter); + VOID phy_SetBwMode8814A(PADAPTER Adapter) + { + u8 SubChnlNum = 0; +@@ -2445,6 +2485,10 @@ phy_ConfigKFree8814A( + } + #endif + VOID ++phy_SwChnl8814A( ++ IN PADAPTER pAdapter ++ ); ++VOID + phy_SwChnl8814A( + IN PADAPTER pAdapter + ) +@@ -2658,6 +2702,10 @@ HAL_HandleSwChnl8814A( // Call after initialization + } + */ + ++VOID ++phy_SwChnlAndSetBwMode8814A( ++ IN PADAPTER Adapter ++); + VOID + phy_SwChnlAndSetBwMode8814A( + IN PADAPTER Adapter +@@ -2980,6 +3028,12 @@ SetAntennaConfig8814A( + return TRUE; + } + ++VOID ++PHY_SetBWMode8814( ++ IN PADAPTER Adapter, ++ IN enum channel_width Bandwidth, // 20M or 40M ++ IN u8 Offset // Upper, Lower, or Don't care ++); + VOID + PHY_SetBWMode8814( + IN PADAPTER Adapter, +@@ -2996,6 +3050,11 @@ PHY_SetBWMode8814( + //RTW_INFO("<==%s()\n",__FUNCTION__); + } + ++VOID ++PHY_SwChnl8814( ++ IN PADAPTER Adapter, ++ IN u8 channel ++ ); + VOID + PHY_SwChnl8814( + IN PADAPTER Adapter, +diff --git a/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c b/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c +index 5c0bf0d03..f08839b93 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c ++++ b/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c +@@ -102,6 +102,7 @@ static BOOLEAN HalUsbSetQueuePipeMapping8814AUsb( + + } + ++void rtl8814au_interface_configure(_adapter *padapter); + void rtl8814au_interface_configure(_adapter *padapter) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +@@ -229,6 +230,10 @@ _InitBurstPktLen(IN PADAPTER Adapter) + } + + ++VOID ++_InitQueueReservedPage_8814AUsb( ++ IN PADAPTER Adapter ++ ); + VOID + _InitQueueReservedPage_8814AUsb( + IN PADAPTER Adapter +@@ -1216,6 +1221,7 @@ static void rtl8814au_hw_reset(_adapter *Adapter) + #endif //0 + } + ++u32 rtl8814au_hal_init(PADAPTER Adapter); + u32 rtl8814au_hal_init(PADAPTER Adapter) + { + u8 value8 = 0, u1bRegCR; +@@ -1697,6 +1703,10 @@ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END); + return status; + } + ++VOID ++hal_carddisable_8814( ++ IN PADAPTER Adapter ++); + VOID + hal_carddisable_8814( + IN PADAPTER Adapter +@@ -1726,8 +1736,9 @@ static void rtl8814au_hw_power_down(_adapter *padapter) + rtw_write16(padapter, REG_APS_FSMCO, 0x8812); + } + ++u32 rtl8814au_hal_deinit(PADAPTER Adapter); + u32 rtl8814au_hal_deinit(PADAPTER Adapter) +- { ++{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(Adapter); + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + RTW_INFO("==> %s \n",__FUNCTION__); +@@ -1781,7 +1792,8 @@ u32 rtl8814au_hal_deinit(PADAPTER Adapter) + } + + +-unsigned int rtl8814au_inirp_init(PADAPTER Adapter) ++unsigned int rtl8814au_inirp_init(PADAPTER Adapter); ++unsigned int rtl8814au_inirp_init(PADAPTER Adapter) + { + u8 i; + struct recv_buf *precvbuf; +@@ -1840,7 +1852,8 @@ unsigned int rtl8814au_inirp_init(PADAPTER Adapter) + + } + +-unsigned int rtl8814au_inirp_deinit(PADAPTER Adapter) ++unsigned int rtl8814au_inirp_deinit(PADAPTER Adapter); ++unsigned int rtl8814au_inirp_deinit(PADAPTER Adapter) + { + RTW_INFO("\n ===> usb_rx_deinit \n"); + +@@ -1857,6 +1870,12 @@ unsigned int rtl8814au_inirp_deinit(PADAPTER Adapter) + // + //------------------------------------------------------------------- + VOID ++hal_ReadIDs_8814AU( ++ IN PADAPTER Adapter, ++ IN pu1Byte PROMContent, ++ IN BOOLEAN AutoloadFail ++ ); ++VOID + hal_ReadIDs_8814AU( + IN PADAPTER Adapter, + IN pu1Byte PROMContent, +@@ -1923,6 +1942,10 @@ hal_InitPGData_8814A( + #endif + } + ++VOID ++hal_CustomizedBehavior_8814AU( ++ IN PADAPTER Adapter ++ ); + VOID + hal_CustomizedBehavior_8814AU( + IN PADAPTER Adapter +@@ -1999,6 +2022,12 @@ hal_CustomizeByCustomerID_8814AU( + hal_CustomizedBehavior_8814AU(pAdapter); + } + ++VOID ++hal_ReadUsbModeSwitch_8814AU( ++ IN PADAPTER Adapter, ++ IN u8* PROMContent, ++ IN BOOLEAN AutoloadFail ++ ); + VOID + hal_ReadUsbModeSwitch_8814AU( + IN PADAPTER Adapter, +@@ -2032,6 +2061,10 @@ ReadLEDSetting_8814AU( + #endif //CONFIG_RTW_LED + } + ++VOID ++InitAdapterVariablesByPROM_8814AU( ++ IN PADAPTER Adapter ++ ); + VOID + InitAdapterVariablesByPROM_8814AU( + IN PADAPTER Adapter +@@ -2091,6 +2124,10 @@ static void hal_ReadPROMContent_8814A( + InitAdapterVariablesByPROM_8814AU(Adapter); + } + ++u8 ++ReadAdapterInfo8814AU( ++ IN PADAPTER Adapter ++ ); + u8 + ReadAdapterInfo8814AU( + IN PADAPTER Adapter +@@ -2107,6 +2144,7 @@ ReadAdapterInfo8814AU( + return _SUCCESS; + } + ++void UpdateInterruptMask8814AU(PADAPTER padapter,u8 bHIMR0 ,u32 AddMSR, u32 RemoveMSR); + void UpdateInterruptMask8814AU(PADAPTER padapter,u8 bHIMR0 ,u32 AddMSR, u32 RemoveMSR) + { + HAL_DATA_TYPE *pHalData; +@@ -2132,6 +2170,7 @@ void UpdateInterruptMask8814AU(PADAPTER padapter,u8 bHIMR0 ,u32 AddMSR, u32 Remo + + } + ++u8 SetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val); + u8 SetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); +@@ -2221,6 +2260,7 @@ u8 SetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val) + return ret; + } + ++void GetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val); + void GetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val) + { + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); +@@ -2239,6 +2279,12 @@ void GetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val) + // Change default setting of specified variable. + // + u8 ++SetHalDefVar8814AUsb( ++ IN PADAPTER Adapter, ++ IN HAL_DEF_VARIABLE eVariable, ++ IN PVOID pValue ++ ); ++u8 + SetHalDefVar8814AUsb( + IN PADAPTER Adapter, + IN HAL_DEF_VARIABLE eVariable, +@@ -2263,6 +2309,12 @@ SetHalDefVar8814AUsb( + // Query setting of specified variable. + // + u8 ++GetHalDefVar8814AUsb( ++ IN PADAPTER Adapter, ++ IN HAL_DEF_VARIABLE eVariable, ++ IN PVOID pValue ++ ); ++u8 + GetHalDefVar8814AUsb( + IN PADAPTER Adapter, + IN HAL_DEF_VARIABLE eVariable, +diff --git a/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c b/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c +index 320024cae..1f0ca9682 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c ++++ b/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c +@@ -273,6 +273,7 @@ void rtl8814au_xmit_tasklet(void *priv) + + } + ++void rtl8814au_set_intf_ops(struct _io_ops *pops); + void rtl8814au_set_intf_ops(struct _io_ops *pops) + { + _rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops)); +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index 6f5d97a11..ae4202ad4 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -428,6 +428,7 @@ static void rtw_get_chbw_from_cfg80211_chan_def(struct cfg80211_chan_def *chdef, + #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) */ + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) ++bool rtw_cfg80211_allow_ch_switch_notify(_adapter *adapter); + bool rtw_cfg80211_allow_ch_switch_notify(_adapter *adapter) + { + #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)) +@@ -505,16 +506,19 @@ u8 rtw_cfg80211_ch_switch_notify(_adapter *adapter, u8 ch, u8 bw, u8 offset, + } + #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */ + ++void rtw_2g_channels_init(struct ieee80211_channel *channels); + void rtw_2g_channels_init(struct ieee80211_channel *channels) + { + _rtw_memcpy((void *)channels, (void *)rtw_2ghz_channels, sizeof(rtw_2ghz_channels)); + } + ++void rtw_5g_channels_init(struct ieee80211_channel *channels); + void rtw_5g_channels_init(struct ieee80211_channel *channels) + { + _rtw_memcpy((void *)channels, (void *)rtw_5ghz_a_channels, sizeof(rtw_5ghz_a_channels)); + } + ++void rtw_2g_rates_init(struct ieee80211_rate *rates); + void rtw_2g_rates_init(struct ieee80211_rate *rates) + { + _rtw_memcpy(rates, rtw_g_rates, +@@ -522,6 +526,7 @@ void rtw_2g_rates_init(struct ieee80211_rate *rates) + ); + } + ++void rtw_5g_rates_init(struct ieee80211_rate *rates); + void rtw_5g_rates_init(struct ieee80211_rate *rates) + { + _rtw_memcpy(rates, rtw_a_rates, +@@ -572,6 +577,7 @@ struct ieee80211_supported_band *rtw_spt_band_alloc(BAND_TYPE band) + return spt_band; + } + ++void rtw_spt_band_free(struct ieee80211_supported_band *spt_band); + void rtw_spt_band_free(struct ieee80211_supported_band *spt_band) + { + u32 size = 0; +@@ -660,6 +666,7 @@ static const struct ieee80211_txrx_stypes + }; + #endif + ++NDIS_802_11_NETWORK_INFRASTRUCTURE nl80211_iftype_to_rtw_network_type(enum nl80211_iftype type); + NDIS_802_11_NETWORK_INFRASTRUCTURE nl80211_iftype_to_rtw_network_type(enum nl80211_iftype type) + { + switch (type) { +@@ -693,6 +700,7 @@ NDIS_802_11_NETWORK_INFRASTRUCTURE nl80211_iftype_to_rtw_network_type(enum nl802 + } + } + ++u32 nl80211_iftype_to_rtw_mlme_state(enum nl80211_iftype type); + u32 nl80211_iftype_to_rtw_mlme_state(enum nl80211_iftype type) + { + switch (type) { +@@ -2711,6 +2719,7 @@ void rtw_cfg80211_unlink_bss(_adapter *padapter, struct wlan_network *pnetwork) + } + + /* if target wps scan ongoing, target_ssid is filled */ ++int rtw_cfg80211_is_target_wps_scan(struct cfg80211_scan_request *scan_req, struct cfg80211_ssid *target_ssid); + int rtw_cfg80211_is_target_wps_scan(struct cfg80211_scan_request *scan_req, struct cfg80211_ssid *target_ssid) + { + int ret = 0; +@@ -5420,6 +5429,7 @@ const char *_nl80211_mesh_power_mode_str[] = { + #define nl80211_mesh_power_mode_str(_p) ((_p <= NL80211_MESH_POWER_MAX) ? _nl80211_mesh_power_mode_str[_p] : _nl80211_mesh_power_mode_str[0]) + #endif + ++void dump_station_parameters(void *sel, struct wiphy *wiphy, const struct station_parameters *params); + void dump_station_parameters(void *sel, struct wiphy *wiphy, const struct station_parameters *params) + { + #if DBG_RTW_CFG80211_STA_PARAM +@@ -10093,6 +10103,8 @@ int rtw_hostapd_acs_dump_survey(struct wiphy *wiphy, struct net_device *netdev, + #endif /* defined(CONFIG_RTW_HOSTAPD_ACS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) */ + + #if (KERNEL_VERSION(4, 17, 0) <= LINUX_VERSION_CODE) ++int cfg80211_rtw_external_auth(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_external_auth_params *params); + int cfg80211_rtw_external_auth(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_external_auth_params *params) + { +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c +index c5776117f..27eb11239 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c +@@ -188,6 +188,7 @@ void indicate_wx_scan_complete_event(_adapter *padapter) + #endif + } + ++void rtw_indicate_wx_assoc_event(_adapter *padapter); + void rtw_indicate_wx_assoc_event(_adapter *padapter) + { + union iwreq_data wrqu; +@@ -211,6 +212,7 @@ void rtw_indicate_wx_assoc_event(_adapter *padapter) + #endif + } + ++void rtw_indicate_wx_disassoc_event(_adapter *padapter); + void rtw_indicate_wx_disassoc_event(_adapter *padapter) + { + union iwreq_data wrqu; +diff --git a/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c b/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c +index f4f2ef90e..0b95a14e5 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c +@@ -836,6 +836,7 @@ uint rtw_suspend_type = RTW_SUSPEND_TYPE; + module_param(rtw_suspend_type, uint, 0644); + #endif + ++void rtw_regsty_load_target_tx_power(struct registry_priv *regsty); + void rtw_regsty_load_target_tx_power(struct registry_priv *regsty) + { + int path, rs; +@@ -1351,7 +1352,8 @@ static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev) + static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; + + /* Given a data frame determine the 802.1p/1d tag to use. */ +-unsigned int rtw_classify8021d(struct sk_buff *skb) ++unsigned int rtw_classify8021d(struct sk_buff *skb); ++unsigned int rtw_classify8021d(struct sk_buff *skb) + { + unsigned int dscp; + +@@ -1499,6 +1501,7 @@ void rtw_ndev_notifier_unregister(void) + unregister_netdevice_notifier(&rtw_ndev_notifier); + } + ++int rtw_ndev_init(struct net_device *dev); + int rtw_ndev_init(struct net_device *dev) + { + _adapter *adapter = rtw_netdev_priv(dev); +@@ -1512,6 +1515,7 @@ int rtw_ndev_init(struct net_device *dev) + return 0; + } + ++void rtw_ndev_uninit(struct net_device *dev); + void rtw_ndev_uninit(struct net_device *dev) + { + _adapter *adapter = rtw_netdev_priv(dev); +@@ -1584,6 +1588,7 @@ int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname) + return 0; + } + ++void rtw_hook_if_ops(struct net_device *ndev); + void rtw_hook_if_ops(struct net_device *ndev) + { + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)) +@@ -1676,6 +1681,7 @@ struct net_device *rtw_init_netdev(_adapter *old_padapter) + return pnetdev; + } + ++int rtw_os_ndev_alloc(_adapter *adapter); + int rtw_os_ndev_alloc(_adapter *adapter) + { + int ret = _FAIL; +@@ -1730,6 +1736,7 @@ void rtw_os_ndev_free(_adapter *adapter) + } + } + ++int rtw_os_ndev_register(_adapter *adapter, const char *name); + int rtw_os_ndev_register(_adapter *adapter, const char *name) + { + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); +@@ -1872,6 +1879,7 @@ void rtw_os_ndev_deinit(_adapter *adapter) + rtw_os_ndev_free(adapter); + } + ++int rtw_os_ndevs_alloc(struct dvobj_priv *dvobj); + int rtw_os_ndevs_alloc(struct dvobj_priv *dvobj) + { + int i, status = _SUCCESS; +@@ -1925,6 +1933,7 @@ int rtw_os_ndevs_alloc(struct dvobj_priv *dvobj) + return status; + } + ++void rtw_os_ndevs_free(struct dvobj_priv *dvobj); + void rtw_os_ndevs_free(struct dvobj_priv *dvobj) + { + int i; +@@ -2056,6 +2065,7 @@ void rtw_stop_drv_threads(_adapter *padapter) + rtw_hal_stop_thread(padapter); + } + ++u8 rtw_init_default_value(_adapter *padapter); + u8 rtw_init_default_value(_adapter *padapter) + { + u8 ret = _SUCCESS; +@@ -3141,6 +3151,7 @@ void rtw_inetaddr_notifier_unregister(void) + #endif + } + ++int rtw_os_ndevs_register(struct dvobj_priv *dvobj); + int rtw_os_ndevs_register(struct dvobj_priv *dvobj) + { + int i, status = _SUCCESS; +@@ -3260,6 +3271,7 @@ void rtw_os_ndevs_deinit(struct dvobj_priv *dvobj) + } + + #ifdef CONFIG_BR_EXT ++void netdev_br_init(struct net_device *netdev); + void netdev_br_init(struct net_device *netdev) + { + _adapter *adapter = (_adapter *)rtw_netdev_priv(netdev); +@@ -3899,6 +3911,7 @@ static int netdev_close(struct net_device *pnetdev) + + } + ++int pm_netdev_close(struct net_device *pnetdev, u8 bnormal); + int pm_netdev_close(struct net_device *pnetdev, u8 bnormal) + { + int status = 0; +@@ -4585,6 +4598,7 @@ int rtw_suspend_ap_wow(_adapter *padapter) + } + #endif /* #ifdef CONFIG_AP_WOWLAN */ + ++int rtw_suspend_normal(_adapter *padapter); + int rtw_suspend_normal(_adapter *padapter) + { + int ret = _SUCCESS; +@@ -4991,6 +5005,7 @@ int rtw_resume_process_ap_wow(_adapter *padapter) + } + #endif /* #ifdef CONFIG_APWOWLAN */ + ++void rtw_mi_resume_process_normal(_adapter *padapter); + void rtw_mi_resume_process_normal(_adapter *padapter) + { + int i; +@@ -5020,6 +5035,7 @@ void rtw_mi_resume_process_normal(_adapter *padapter) + } + } + ++int rtw_resume_process_normal(_adapter *padapter); + int rtw_resume_process_normal(_adapter *padapter) + { + struct net_device *pnetdev; +diff --git a/drivers/staging/rtl8812au/os_dep/linux/rtw_android.c b/drivers/staging/rtl8812au/os_dep/linux/rtw_android.c +index 480ea83f9..bd599ecd3 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/rtw_android.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/rtw_android.c +@@ -364,6 +364,7 @@ int rtw_android_cmdstr_to_num(char *cmdstr) + return cmd_num; + } + ++int rtw_android_get_rssi(struct net_device *net, char *command, int total_len); + int rtw_android_get_rssi(struct net_device *net, char *command, int total_len) + { + _adapter *padapter = (_adapter *)rtw_netdev_priv(net); +@@ -379,6 +380,7 @@ int rtw_android_get_rssi(struct net_device *net, char *command, int total_len) + return bytes_written; + } + ++int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len); + int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len) + { + _adapter *padapter = (_adapter *)rtw_netdev_priv(net); +@@ -391,6 +393,7 @@ int rtw_android_get_link_speed(struct net_device *net, char *command, int total_ + return bytes_written; + } + ++int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len); + int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len) + { + int bytes_written = 0; +@@ -399,6 +402,7 @@ int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len + return bytes_written; + } + ++int rtw_android_set_country(struct net_device *net, char *command, int total_len); + int rtw_android_set_country(struct net_device *net, char *command, int total_len) + { + _adapter *adapter = (_adapter *)rtw_netdev_priv(net); +@@ -410,6 +414,7 @@ int rtw_android_set_country(struct net_device *net, char *command, int total_len + return (ret == _SUCCESS) ? 0 : -1; + } + ++int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len); + int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len) + { + int bytes_written = 0; +@@ -421,6 +426,7 @@ int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int tota + return bytes_written; + } + ++int rtw_android_set_block_scan(struct net_device *net, char *command, int total_len); + int rtw_android_set_block_scan(struct net_device *net, char *command, int total_len) + { + _adapter *adapter = (_adapter *)rtw_netdev_priv(net); +@@ -433,6 +439,7 @@ int rtw_android_set_block_scan(struct net_device *net, char *command, int total_ + return 0; + } + ++int rtw_android_set_block(struct net_device *net, char *command, int total_len); + int rtw_android_set_block(struct net_device *net, char *command, int total_len) + { + _adapter *adapter = (_adapter *)rtw_netdev_priv(net); +@@ -445,6 +452,7 @@ int rtw_android_set_block(struct net_device *net, char *command, int total_len) + return 0; + } + ++int rtw_android_setband(struct net_device *net, char *command, int total_len); + int rtw_android_setband(struct net_device *net, char *command, int total_len) + { + _adapter *adapter = (_adapter *)rtw_netdev_priv(net); +@@ -458,6 +466,7 @@ int rtw_android_setband(struct net_device *net, char *command, int total_len) + return (ret == _SUCCESS) ? 0 : -1; + } + ++int rtw_android_getband(struct net_device *net, char *command, int total_len); + int rtw_android_getband(struct net_device *net, char *command, int total_len) + { + _adapter *adapter = (_adapter *)rtw_netdev_priv(net); +@@ -469,6 +478,7 @@ int rtw_android_getband(struct net_device *net, char *command, int total_len) + } + + #ifdef CONFIG_WFD ++int rtw_android_set_miracast_mode(struct net_device *net, char *command, int total_len); + int rtw_android_set_miracast_mode(struct net_device *net, char *command, int total_len) + { + _adapter *adapter = (_adapter *)rtw_netdev_priv(net); +@@ -505,6 +515,7 @@ int rtw_android_set_miracast_mode(struct net_device *net, char *command, int tot + } + #endif /* CONFIG_WFD */ + ++int get_int_from_command(char *pcmd); + int get_int_from_command(char *pcmd) + { + int i = 0; +diff --git a/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c b/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c +index 840a675cc..db1177c3a 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c +@@ -483,6 +483,7 @@ static int proc_get_rf_reg_dump(struct seq_file *m, void *v) + } + + #ifdef CONFIG_RTW_LED ++int proc_get_led_config(struct seq_file *m, void *v); + int proc_get_led_config(struct seq_file *m, void *v) + { + struct net_device *dev = m->private; +@@ -493,6 +494,7 @@ int proc_get_led_config(struct seq_file *m, void *v) + return 0; + } + ++ssize_t proc_set_led_config(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); + ssize_t proc_set_led_config(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) + { + struct net_device *dev = data; +@@ -525,6 +527,7 @@ ssize_t proc_set_led_config(struct file *file, const char __user *buffer, size_t + #endif /* CONFIG_RTW_LED */ + + #ifdef CONFIG_AP_MODE ++int proc_get_aid_status(struct seq_file *m, void *v); + int proc_get_aid_status(struct seq_file *m, void *v) + { + struct net_device *dev = m->private; +@@ -535,6 +538,7 @@ int proc_get_aid_status(struct seq_file *m, void *v) + return 0; + } + ++ssize_t proc_set_aid_status(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); + ssize_t proc_set_aid_status(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) + { + struct net_device *dev = data; +@@ -1287,6 +1291,7 @@ static int proc_get_macaddr_acl(struct seq_file *m, void *v) + return 0; + } + ++ssize_t proc_set_macaddr_acl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); + ssize_t proc_set_macaddr_acl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) + { + struct net_device *dev = data; +@@ -1745,6 +1750,7 @@ static ssize_t proc_set_dfs_slave_with_rd(struct file *file, const char __user * + #endif /* CONFIG_DFS_MASTER */ + + #ifdef CONFIG_80211N_HT ++int proc_get_rx_ampdu_size_limit(struct seq_file *m, void *v); + int proc_get_rx_ampdu_size_limit(struct seq_file *m, void *v) + { + struct net_device *dev = m->private; +@@ -1755,6 +1761,7 @@ int proc_get_rx_ampdu_size_limit(struct seq_file *m, void *v) + return 0; + } + ++ssize_t proc_set_rx_ampdu_size_limit(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); + ssize_t proc_set_rx_ampdu_size_limit(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) + { + struct net_device *dev = data; +@@ -2765,6 +2772,7 @@ int proc_get_mbid_cam_cache(struct seq_file *m, void *v) + } + #endif /* CONFIG_MBSSID_CAM */ + ++int proc_get_mac_addr(struct seq_file *m, void *v); + int proc_get_mac_addr(struct seq_file *m, void *v) + { + struct net_device *dev = m->private; +@@ -3146,6 +3154,7 @@ static ssize_t proc_set_napi_th(struct file *file, const char __user *buffer, si + #endif /* CONFIG_RTW_NAPI_DYNAMIC */ + + ++ssize_t proc_set_dynamic_agg_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); + ssize_t proc_set_dynamic_agg_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) + { + struct net_device *dev = data; +@@ -3775,6 +3784,7 @@ static ssize_t proc_set_tpt_mode(struct file *file, const char __user *buffer, + } + #endif /* CONFIG_RTW_TPT_MODE */ + ++int proc_get_cur_beacon_keys(struct seq_file *m, void *v); + int proc_get_cur_beacon_keys(struct seq_file *m, void *v) + { + struct net_device *dev = m->private; +@@ -4281,6 +4291,7 @@ ssize_t proc_set_odm_adaptivity(struct file *file, const char __user *buffer, si + static char *phydm_msg = NULL; + #define PHYDM_MSG_LEN 80*24 + ++int proc_get_phydm_cmd(struct seq_file *m, void *v); + int proc_get_phydm_cmd(struct seq_file *m, void *v) + { + struct net_device *netdev; +@@ -4308,6 +4319,7 @@ int proc_get_phydm_cmd(struct seq_file *m, void *v) + return 0; + } + ++ssize_t proc_set_phydm_cmd(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data); + ssize_t proc_set_phydm_cmd(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) + { + struct net_device *netdev; +@@ -4477,6 +4489,7 @@ struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev) + return dir_odm; + } + ++void rtw_odm_proc_deinit(_adapter *adapter); + void rtw_odm_proc_deinit(_adapter *adapter) + { + struct proc_dir_entry *dir_odm = NULL; +diff --git a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +index a285c011c..915ef6476 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +@@ -951,6 +951,7 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) + return ret; + } + ++int rtw_resume_process(_adapter *padapter); + int rtw_resume_process(_adapter *padapter) + { + int ret; +diff --git a/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c b/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c +index fd03f8696..c7eb7ea40 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c +@@ -705,6 +705,7 @@ void usb_write_port_cancel(struct intf_hdl *pintfhdl) + } + } + ++void usb_init_recvbuf(_adapter *padapter, struct recv_buf *precvbuf); + void usb_init_recvbuf(_adapter *padapter, struct recv_buf *precvbuf) + { + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c b/drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c +index f08dd8e8c..c931a8014 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c +@@ -366,6 +366,7 @@ void rtw_os_wake_queue_at_free_stainfo(_adapter *padapter, int *qcnt_freed) + } + + #ifdef CONFIG_TX_MCAST2UNI ++int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb); + int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb) + { + struct sta_priv *pstapriv = &padapter->stapriv; +diff --git a/drivers/staging/rtl8812au/os_dep/osdep_service.c b/drivers/staging/rtl8812au/os_dep/osdep_service.c +index d24b3e1f0..5b2aa5d00 100644 +--- a/drivers/staging/rtl8812au/os_dep/osdep_service.c ++++ b/drivers/staging/rtl8812au/os_dep/osdep_service.c +@@ -2258,6 +2258,7 @@ void rtw_free_netdev(struct net_device *netdev) + return; + } + ++int rtw_change_ifname(_adapter *padapter, const char *ifname); + int rtw_change_ifname(_adapter *padapter, const char *ifname) + { + struct dvobj_priv *dvobj; +diff --git a/drivers/staging/rtl8812au/platform/platform_ops.c b/drivers/staging/rtl8812au/platform/platform_ops.c +index 10766aad8..eac273047 100644 +--- a/drivers/staging/rtl8812au/platform/platform_ops.c ++++ b/drivers/staging/rtl8812au/platform/platform_ops.c +@@ -18,6 +18,7 @@ + * 0: power on successfully + * others: power on failed + */ ++int platform_wifi_power_on(void); + int platform_wifi_power_on(void) + { + int ret = 0; +@@ -26,6 +27,7 @@ int platform_wifi_power_on(void) + return ret; + } + ++void platform_wifi_power_off(void); + void platform_wifi_power_off(void) + { + } +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0002-rtl8812au-fix-warnings.patch b/kernel/tools/perf/files/patches/mageia/0002-rtl8812au-fix-warnings.patch new file mode 100644 index 0000000000..25f5aacc2f --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0002-rtl8812au-fix-warnings.patch @@ -0,0 +1,22 @@ +diff -up linux-6.12/drivers/staging/rtl8812au/core/rtw_mlme_ext.c.fixwarning linux-6.12/drivers/staging/rtl8812au/core/rtw_mlme_ext.c +--- linux-6.12/drivers/staging/rtl8812au/core/rtw_mlme_ext.c.fixwarning 2024-11-20 22:55:13.263847617 +0100 ++++ linux-6.12/drivers/staging/rtl8812au/core/rtw_mlme_ext.c 2024-11-20 22:56:20.104794574 +0100 +@@ -2152,13 +2152,15 @@ unsigned int OnAuth(_adapter *padapter, + if (rtw_is_list_empty(&pstat->asoc_list) == _FALSE) { + rtw_list_delete(&pstat->asoc_list); + pstapriv->asoc_list_cnt--; +- if (pstat->expire_to > 0) +- ;/* TODO: STA re_auth within expire_to */ ++ if (pstat->expire_to > 0) { ++ ; /* TODO: STA re_auth within expire_to */ ++ } + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + +- if (seq == 1) ++ if (seq == 1) { + ; /* TODO: STA re_auth and auth timeout */ ++ } + + } + } diff --git a/kernel/tools/perf/files/patches/mageia/0005-rtl8812au-add-missed-prototypes.patch b/kernel/tools/perf/files/patches/mageia/0005-rtl8812au-add-missed-prototypes.patch new file mode 100644 index 0000000000..c8b423799e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0005-rtl8812au-add-missed-prototypes.patch @@ -0,0 +1,188 @@ +From 61116d468dd551124c1ae2c01fff5da99d787fad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Giuseppe=20Ghib=C3=B2?= +Date: Thu, 21 Nov 2024 15:47:58 +0100 +Subject: [PATCH] rtl8812au: add missed prototypes + +--- + drivers/staging/rtl8812au/core/rtw_br_ext.c | 2 ++ + drivers/staging/rtl8812au/core/rtw_p2p.c | 1 + + drivers/staging/rtl8812au/core/rtw_xmit.c | 1 + + .../hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c | 7 +++++++ + .../hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c | 21 ++++++++++++++++++- + .../staging/rtl8812au/hal/phydm/phydm_ccx.c | 1 + + .../rtl8812au/os_dep/linux/ioctl_cfg80211.c | 12 +++++++++++ + .../staging/rtl8812au/os_dep/linux/rtw_proc.c | 1 + + .../staging/rtl8812au/os_dep/linux/usb_intf.c | 2 ++ + 9 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/rtl8812au/core/rtw_br_ext.c b/drivers/staging/rtl8812au/core/rtw_br_ext.c +index 955a50912..283676d36 100644 +--- a/drivers/staging/rtl8812au/core/rtw_br_ext.c ++++ b/drivers/staging/rtl8812au/core/rtw_br_ext.c +@@ -1369,6 +1369,8 @@ void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb) + } + + ++void *scdb_findEntry(_adapter *priv, unsigned char *macAddr, ++ unsigned char *ipAddr); + void *scdb_findEntry(_adapter *priv, unsigned char *macAddr, + unsigned char *ipAddr) + { +diff --git a/drivers/staging/rtl8812au/core/rtw_p2p.c b/drivers/staging/rtl8812au/core/rtw_p2p.c +index 167dd067f..c560d1712 100644 +--- a/drivers/staging/rtl8812au/core/rtw_p2p.c ++++ b/drivers/staging/rtl8812au/core/rtw_p2p.c +@@ -3898,6 +3898,7 @@ void rtw_xframe_chk_wfd_ie(struct xmit_frame *xframe) + #endif + } + ++u8 *dump_p2p_attr_ch_list(u8 *p2p_ie, uint p2p_ielen, u8 *buf, u32 buf_len); + u8 *dump_p2p_attr_ch_list(u8 *p2p_ie, uint p2p_ielen, u8 *buf, u32 buf_len) + { + uint attr_contentlen = 0; +diff --git a/drivers/staging/rtl8812au/core/rtw_xmit.c b/drivers/staging/rtl8812au/core/rtw_xmit.c +index 0b97e5099..e40c0aecc 100644 +--- a/drivers/staging/rtl8812au/core/rtw_xmit.c ++++ b/drivers/staging/rtl8812au/core/rtw_xmit.c +@@ -3766,6 +3766,7 @@ static struct xmit_frame *get_one_xmitframe(struct xmit_priv *pxmitpriv, struct + return pxmitframe; + } + ++struct xmit_frame *rtw_get_xframe(struct xmit_priv *pxmitpriv, int *num_frame); + struct xmit_frame *rtw_get_xframe(struct xmit_priv *pxmitpriv, int *num_frame) + { + _irqL irqL0; +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +index a66721465..e2113e37a 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +@@ -1334,6 +1334,13 @@ void phy_lc_calibrate_8812a(void *dm_void) + _phy_lc_calibrate_8812a(dm, true); + } + ++void _phy_set_rf_path_switch_8812a( ++#if ((DM_ODM_SUPPORT_TYPE & ODM_AP) || (DM_ODM_SUPPORT_TYPE == ODM_CE)) ++ struct dm_struct *dm, ++#else ++ void *adapter, ++#endif ++ boolean is_main, boolean is2T); + void _phy_set_rf_path_switch_8812a( + #if ((DM_ODM_SUPPORT_TYPE & ODM_AP) || (DM_ODM_SUPPORT_TYPE == ODM_CE)) + struct dm_struct *dm, +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c +index 41ce0a6dd..ae060a648 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c +@@ -450,7 +450,17 @@ _phy_lc_calibrate_8814a( + + + VOID +-phy_APCalibrate_8814A( ++ phy_APCalibrate_8814A( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN struct dm_struct * pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN s1Byte delta, ++ IN BOOLEAN is2T ++ ); ++VOID ++ phy_APCalibrate_8814A( + #if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN struct dm_struct * pDM_Odm, + #else +@@ -545,6 +555,15 @@ BOOLEAN PHY_QueryRFPathSwitch_8814A( + } + + ++VOID _phy_SetRFPathSwitch_8814A( ++#if (DM_ODM_SUPPORT_TYPE & ODM_AP) ++ IN struct dm_struct * pDM_Odm, ++#else ++ IN PADAPTER pAdapter, ++#endif ++ IN BOOLEAN bMain, ++ IN BOOLEAN is2T ++ ); + VOID _phy_SetRFPathSwitch_8814A( + #if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN struct dm_struct * pDM_Odm, +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c b/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c +index e0f42c0be..fe69c19b2 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c +@@ -26,6 +26,7 @@ + #include "mp_precomp.h" + #include "phydm_precomp.h" + ++void phydm_ccx_hw_restart(void *dm_void); + void phydm_ccx_hw_restart(void *dm_void) + /*@Will Restart NHM/CLM/FAHM simultaneously*/ + { +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index ae4202ad4..c0f563430 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -534,6 +534,7 @@ void rtw_5g_rates_init(struct ieee80211_rate *rates) + ); + } + ++struct ieee80211_supported_band *rtw_spt_band_alloc(BAND_TYPE band); + struct ieee80211_supported_band *rtw_spt_band_alloc(BAND_TYPE band) + { + struct ieee80211_supported_band *spt_band = NULL; +@@ -2083,6 +2084,16 @@ static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev, + return 0; + } + ++static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ int link_id, ++#endif ++ u8 key_index ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE) ++ , bool unicast, bool multicast ++ #endif ++); + static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) +@@ -5956,6 +5967,7 @@ static int cfg80211_rtw_change_station(struct wiphy *wiphy, struct net_device *n + return ret; + } + ++struct sta_info *rtw_sta_info_get_by_idx(struct sta_priv *pstapriv, const int idx, u8 *asoc_list_num); + struct sta_info *rtw_sta_info_get_by_idx(struct sta_priv *pstapriv, const int idx, u8 *asoc_list_num) + { + _list *phead, *plist; +diff --git a/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c b/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c +index db1177c3a..3b9246bc9 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c +@@ -4446,6 +4446,7 @@ static const struct file_operations rtw_odm_proc_sseq_ops = { + }; + #endif + ++struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev); + struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev) + { + struct proc_dir_entry *dir_odm = NULL; +diff --git a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +index 915ef6476..ae2a5a0b9 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +@@ -1206,6 +1206,8 @@ extern void rtd2885_wlan_netlink_sendMsg(char *action_string, char *name); + + _adapter *rtw_sw_export = NULL; + ++_adapter *rtw_usb_primary_adapter_init(struct dvobj_priv *dvobj, ++ struct usb_interface *pusb_intf); + _adapter *rtw_usb_primary_adapter_init(struct dvobj_priv *dvobj, + struct usb_interface *pusb_intf) + { +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0006-rtl8812au-add-suggested-braces-around-empty-body-in-.patch b/kernel/tools/perf/files/patches/mageia/0006-rtl8812au-add-suggested-braces-around-empty-body-in-.patch new file mode 100644 index 0000000000..af28127e92 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0006-rtl8812au-add-suggested-braces-around-empty-body-in-.patch @@ -0,0 +1,33 @@ +From a9d9038b7a15077395013f1954665656959c81b8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Giuseppe=20Ghib=C3=B2?= +From: Your Name +Date: Thu, 21 Nov 2024 15:53:01 +0100 +Subject: [PATCH 6/8] rtl8812au: add suggested braces around empty body in an + else statement + +--- + drivers/staging/rtl8812au/os_dep/linux/recv_linux.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/recv_linux.c b/drivers/staging/rtl8812au/os_dep/linux/recv_linux.c +index 5637e9970..051abba70 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/recv_linux.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/recv_linux.c +@@ -531,10 +531,12 @@ void rtw_os_recv_indicate_pkt(_adapter *padapter, _pkt *pkt, union recv_frame *r + #endif /* CONFIG_RTW_NAPI */ + + ret = rtw_netif_rx(padapter->pnetdev, pkt); +- if (ret == NET_RX_SUCCESS) ++ if (ret == NET_RX_SUCCESS) { + DBG_COUNTER(padapter->rx_logs.os_netif_ok); +- else ++ } ++ else { + DBG_COUNTER(padapter->rx_logs.os_netif_err); ++ } + } + } + +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0007-rtl8812au-add-suggested-braces-around-empty-body-in-.patch b/kernel/tools/perf/files/patches/mageia/0007-rtl8812au-add-suggested-braces-around-empty-body-in-.patch new file mode 100644 index 0000000000..685574b53d --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0007-rtl8812au-add-suggested-braces-around-empty-body-in-.patch @@ -0,0 +1,45 @@ +From e7f5d03d8bde8f104ed06ad0946e2e40eaf51094 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Giuseppe=20Ghib=C3=B2?= +Date: Thu, 21 Nov 2024 16:06:25 +0100 +Subject: [PATCH 7/8] rtl8812au: add suggested braces around empty body in an + else statement + +--- + drivers/staging/rtl8812au/hal/phydm/phydm_debug.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c b/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c +index bab92632e..a3e8bc48e 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c +@@ -2222,10 +2222,12 @@ void phydm_basic_dbg_message(void *dm_void) + PHYDM_DBG(dm, DBG_CMN, "[%s] System up time: ((%d sec))---->\n", + __func__, dm->phydm_sys_up_time); + +- if (dm->is_linked) ++ if (dm->is_linked) { + phydm_basic_dbg_msg_linked(dm); +- else ++ } ++ else { + PHYDM_DBG(dm, DBG_CMN, "No Link !!!\n"); ++ } + + PHYDM_DBG(dm, DBG_CMN, "[CCA Cnt] {CCK, OFDM, Total} = {%d, %d, %d}\n", + fa_t->cnt_cck_cca, fa_t->cnt_ofdm_cca, fa_t->cnt_cca_all); +@@ -4491,10 +4493,11 @@ void phydm_fw_trace_handler_code(void *dm_void, u8 *buffer, u8 cmd_len) + u16 content_3 = (((u16)buffer[9]) << 8) | ((u16)buffer[8]); + u16 content_4 = (((u16)buffer[11]) << 8) | ((u16)buffer[10]); + +- if (cmd_len > 12) ++ if (cmd_len > 12) { + PHYDM_DBG(dm, DBG_FW_TRACE, + "[FW Msg] Invalid cmd length (( %d )) >12\n", + cmd_len); ++ } + /*@--------------------------------------------*/ + #ifdef CONFIG_RA_FW_DBG_CODE + if (function == RATE_DECISION) { +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0008-rtl8812au-add-suggested-braces-around-empty-body-in-.patch b/kernel/tools/perf/files/patches/mageia/0008-rtl8812au-add-suggested-braces-around-empty-body-in-.patch new file mode 100644 index 0000000000..a99c5627d0 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0008-rtl8812au-add-suggested-braces-around-empty-body-in-.patch @@ -0,0 +1,311 @@ +From 22b4d5685d828b85d9fc80bfa3d8c5e97b289224 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Giuseppe=20Ghib=C3=B2?= +Date: Thu, 21 Nov 2024 16:27:10 +0100 +Subject: [PATCH 8/8] rtl8812au: add suggested braces around empty body in an + else statement + +--- + .../rtl8812au/hal/phydm/halrf/halphyrf_ce.c | 3 ++- + .../staging/rtl8812au/hal/phydm/halrf/halrf.c | 3 ++- + .../rtl8812au/hal/phydm/halrf/halrf_kfree.c | 18 ++++++++++++------ + .../hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c | 3 ++- + .../rtl8812au/hal/phydm/phydm_beamforming.c | 6 ++++-- + .../rtl8812au/hal/phydm/phydm_cfotracking.c | 6 ++++-- + .../staging/rtl8812au/hal/phydm/phydm_psd.c | 3 ++- + .../staging/rtl8812au/hal/phydm/phydm_rainfo.c | 6 ++++-- + .../rtl8812au/hal/phydm/txbf/halcomtxbf.c | 15 ++++++++++----- + .../rtl8812au/hal/phydm/txbf/haltxbfjaguar.c | 3 ++- + 10 files changed, 44 insertions(+), 22 deletions(-) + +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c +index 4443c7289..3b05d87c8 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c +@@ -478,9 +478,10 @@ void odm_txpowertracking_callback_thermal_meter(void *adapter) + + /*@4 3. Initialize ThermalValues of rf_calibrate_info*/ + +- if (cali_info->is_reloadtxpowerindex) ++ if (cali_info->is_reloadtxpowerindex) { + RF_DBG(dm, DBG_RF_TX_PWR_TRACK, + "reload ofdm index for band switch\n"); ++ } + + /*@4 4. Calculate average thermal meter*/ + +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c +index 09ab5bae9..609333db8 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c +@@ -2270,8 +2270,9 @@ boolean halrf_compare(void *dm_void, u32 value) + else if (value < 0x200 && value > 0x64) + fail = true; + +- if (fail) ++ if (fail) { + RF_DBG(dm, DBG_RF_DACK, "[DACK]overflow!!!!!!!!!!!!!!!"); ++ } + return fail; + } + +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c +index 773364310..a4e3504a3 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c +@@ -148,9 +148,10 @@ void phydm_get_thermal_trim_offset_8821c(void *dm_void) + RF_DBG(dm, DBG_RF_MP, "[kfree] 8821c thermal trim flag:0x%02x\n", + power_trim_info->flag); + +- if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) ++ if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) { + RF_DBG(dm, DBG_RF_MP, "[kfree] 8821c thermal:%d\n", + power_trim_info->thermal); ++ } + } + + void phydm_get_power_trim_offset_8821c(void *dm_void); +@@ -281,9 +282,10 @@ void phydm_get_thermal_trim_offset_8822b(void *dm_void) + RF_DBG(dm, DBG_RF_MP, "[kfree] 8822b thermal trim flag:0x%02x\n", + power_trim_info->flag); + +- if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) ++ if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) { + RF_DBG(dm, DBG_RF_MP, "[kfree] 8822b thermal:%d\n", + power_trim_info->thermal); ++ } + } + + void phydm_get_power_trim_offset_8822b(void *dm_void); +@@ -532,9 +534,10 @@ void phydm_get_thermal_trim_offset_8710b(void *dm_void) + RF_DBG(dm, DBG_RF_MP, "[kfree] 8710b thermal trim flag:0x%02x\n", + power_trim_info->flag); + +- if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) ++ if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) { + RF_DBG(dm, DBG_RF_MP, "[kfree] 8710b thermal:%d\n", + power_trim_info->thermal); ++ } + } + + void phydm_get_power_trim_offset_8710b(void *dm_void); +@@ -559,10 +562,11 @@ void phydm_get_power_trim_offset_8710b(void *dm_void) + RF_DBG(dm, DBG_RF_MP, "[kfree] 8710b power trim flag:0x%02x\n", + power_trim_info->flag); + +- if (power_trim_info->flag & KFREE_FLAG_ON) ++ if (power_trim_info->flag & KFREE_FLAG_ON) { + RF_DBG(dm, DBG_RF_MP, + "[kfree] 8710b power_trim_data->bb_gain[0][0]=0x%X\n", + power_trim_info->bb_gain[0][0]); ++ } + } + + void phydm_set_kfree_to_rf_8710b(void *dm_void, u8 e_rf_path, u8 data); +@@ -620,9 +624,10 @@ void phydm_get_thermal_trim_offset_8192f(void *dm_void) + RF_DBG(dm, DBG_RF_MP, "[kfree] 8192f thermal trim flag:0x%02x\n", + power_trim_info->flag); + +- if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) ++ if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) { + RF_DBG(dm, DBG_RF_MP, "[kfree] 8192f thermal:%d\n", + power_trim_info->thermal); ++ } + } + + void phydm_get_power_trim_offset_8192f(void *dm_void); +@@ -799,8 +804,9 @@ void phydm_get_thermal_trim_offset_8198f(void *dm_void) + pg_therm = pg_therm & 0x1f; + if ((pg_therm & BIT(0)) == 0) + power_trim_info->thermal = (-1 * (pg_therm >> 1)); +- else ++ else { + power_trim_info->thermal = (pg_therm >> 1); ++ } + + power_trim_info->flag |= KFREE_FLAG_THERMAL_K_ON; + } +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +index e2113e37a..a006d7e74 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +@@ -1323,8 +1323,9 @@ void phy_iq_calibrate_8812a(void *dm_void, boolean is_recovery) + if (dm->rf_calibrate_info.is_iqk_in_progress) + RF_DBG(dm, DBG_RF_IQK, + "== FW IQK TIMEOUT (Still in progress after 500ms) ==\n"); +- } else ++ } else { + _phy_iq_calibrate_8812a(dm, *dm->channel); ++ } + } + + void phy_lc_calibrate_8812a(void *dm_void) +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c b/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c +index 4a770aa72..952b5600b 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c +@@ -1337,10 +1337,11 @@ beamforming_init_entry(void *dm_void, u16 sta_idx, u8 *bfer_bfee_idx, + + if (beamformer_entry == NULL) { + beamformer_entry = beamforming_add_bfer_entry(dm, sta, beamform_cap, num_of_sounding_dim, &bfer_idx); +- if (beamformer_entry == NULL) ++ if (beamformer_entry == NULL) { + PHYDM_DBG(dm, DBG_TXBF, + "[%s]Not enough BFer entry!!!!!\n", + __func__); ++ } + } + } + +@@ -1781,10 +1782,11 @@ void beamforming_timer_callback( + #endif + if (ret) + ret = beamforming_start_sw(dm, sound_info->sound_idx, sound_info->sound_mode, sound_info->sound_bw); +- else ++ else { + PHYDM_DBG(dm, DBG_TXBF, + "%s, Error value return from BeamformingStart_V2\n", + __func__); ++ } + + if (beam_info->beamformee_su_cnt != 0 || beam_info->beamformee_mu_cnt > 1) { + if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER) +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c b/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c +index 8aac6b094..d88d7a6c0 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c +@@ -213,11 +213,13 @@ void phydm_set_crystal_cap(void *dm_void, u8 crystal_cap) + if (cfo_track->crystal_cap == crystal_cap) + return; + +- if (phydm_set_crystal_cap_reg(dm, crystal_cap)) ++ if (phydm_set_crystal_cap_reg(dm, crystal_cap)) { + PHYDM_DBG(dm, DBG_CFO_TRK, "Set crystal_cap = 0x%x\n", + cfo_track->crystal_cap); +- else ++ } ++ else { + PHYDM_DBG(dm, DBG_CFO_TRK, "Set fail\n"); ++ } + } + + boolean +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_psd.c b/drivers/staging/rtl8812au/hal/phydm/phydm_psd.c +index 458677b59..33f715bcc 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_psd.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_psd.c +@@ -199,9 +199,10 @@ u8 phydm_psd(void *dm_void, u32 igi, u16 start_point, u16 stop_point) + if (dm->support_ic_type & ODM_IC_JGR3_SERIES) + PHYDM_DBG(dm, ODM_COMP_API, "0x1d70=((0x%x))\n", + odm_get_bb_reg(dm, R_0x1d70, MASKDWORD)); +- else ++ else { + PHYDM_DBG(dm, ODM_COMP_API, "0xc50=((0x%x))\n", + odm_get_bb_reg(dm, R_0xc50, MASKDWORD)); ++ } + + PHYDM_DBG(dm, ODM_COMP_API, "RF0x18=((0x%x))\n", + odm_get_rf_reg(dm, RF_PATH_A, RF_0x18, RFREG_MASK)); +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c b/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c +index 2c24b9be9..ca341c827 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c +@@ -443,8 +443,9 @@ void phydm_c2h_ra_report_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len) + PHYDM_DBG(dm, DBG_RA, "Rate Back\n"); + else if (cmd_buf[3] == 4) + PHYDM_DBG(dm, DBG_RA, "Start rate by RSSI\n"); +- else if (cmd_buf[3] == 5) ++ else if (cmd_buf[3] == 5) { + PHYDM_DBG(dm, DBG_RA, "Try rate\n"); ++ } + } + phydm_print_rate_2_buff(dm, rate, dbg_buf, PHYDM_SNPRINT_SIZE); + PHYDM_DBG(dm, DBG_RA, "Tx Rate=%s (%d)", dbg_buf, rate); +@@ -829,8 +830,9 @@ u8 phydm_get_tx_stream_num(void *dm_void, enum rf_type type) + tx_num = 3; + else if (type == RF_4T4R) + tx_num = 4; +- else ++ else { + PHYDM_DBG(dm, DBG_RA, "[Warrning] no mimo_type is found\n"); ++ } + + return tx_num; + } +diff --git a/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c b/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c +index 4329dcaee..286105ec0 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c ++++ b/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c +@@ -43,8 +43,9 @@ void hal_com_txbf_config_gtab( + { + struct dm_struct *dm = (struct dm_struct *)dm_void; + +- if (dm->support_ic_type & ODM_RTL8822B) ++ if (dm->support_ic_type & ODM_RTL8822B) { + hal_txbf_8822b_config_gtab(dm); ++ } + } + + void phydm_beamform_set_sounding_enter( +@@ -206,8 +207,9 @@ void hal_com_txbf_enter_work_item_callback( + hal_txbf_8192e_enter(dm, idx); + else if (dm->support_ic_type & ODM_RTL8814A) + hal_txbf_8814a_enter(dm, idx); +- else if (dm->support_ic_type & ODM_RTL8822B) ++ else if (dm->support_ic_type & ODM_RTL8822B) { + hal_txbf_8822b_enter(dm, idx); ++ } + } + + void hal_com_txbf_leave_work_item_callback( +@@ -236,8 +238,9 @@ void hal_com_txbf_leave_work_item_callback( + hal_txbf_8192e_leave(dm, idx); + else if (dm->support_ic_type & ODM_RTL8814A) + hal_txbf_8814a_leave(dm, idx); +- else if (dm->support_ic_type & ODM_RTL8822B) ++ else if (dm->support_ic_type & ODM_RTL8822B) { + hal_txbf_8822b_leave(dm, idx); ++ } + } + + void hal_com_txbf_fw_ndpa_work_item_callback( +@@ -265,8 +268,9 @@ void hal_com_txbf_fw_ndpa_work_item_callback( + hal_txbf_8192e_fw_tx_bf(dm, idx); + else if (dm->support_ic_type & ODM_RTL8814A) + hal_txbf_8814a_fw_txbf(dm, idx); +- else if (dm->support_ic_type & ODM_RTL8822B) ++ else if (dm->support_ic_type & ODM_RTL8822B) { + hal_txbf_8822b_fw_txbf(dm, idx); ++ } + } + + void hal_com_txbf_clk_work_item_callback( +@@ -363,8 +367,9 @@ void hal_com_txbf_status_work_item_callback( + hal_txbf_8192e_status(dm, idx); + else if (dm->support_ic_type & ODM_RTL8814A) + hal_txbf_8814a_status(dm, idx); +- else if (dm->support_ic_type & ODM_RTL8822B) ++ else if (dm->support_ic_type & ODM_RTL8822B) { + hal_txbf_8822b_status(dm, idx); ++ } + } + + void hal_com_txbf_reset_tx_path_work_item_callback( +diff --git a/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c b/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c +index c42fa53a6..78bb399d9 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c ++++ b/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c +@@ -145,9 +145,10 @@ void hal_txbf_jaguar_download_ndpa( + dl_bcn_count++; + } while (!(bcn_valid_reg & BIT(0)) && dl_bcn_count < 5); + +- if (!(bcn_valid_reg & BIT(0))) ++ if (!(bcn_valid_reg & BIT(0))) { + PHYDM_DBG(dm, DBG_TXBF, "%s Download RSVD page failed!\n", + __func__); ++ } + + /*TDECTRL[15:8] 0x209[7:0] = 0xF6 Beacon Head for TXDMA*/ + odm_write_1byte(dm, REG_TDECTRL_8812A + 1, tx_page_bndy); +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0009-rtl8812au-add-suggested-braces-around-empty-body-in-.patch b/kernel/tools/perf/files/patches/mageia/0009-rtl8812au-add-suggested-braces-around-empty-body-in-.patch new file mode 100644 index 0000000000..3571454ea4 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0009-rtl8812au-add-suggested-braces-around-empty-body-in-.patch @@ -0,0 +1,96 @@ +From f9a18119d2a8f5bd4c35197c89c60305d58d3abd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Giuseppe=20Ghib=C3=B2?= +Date: Thu, 21 Nov 2024 17:03:25 +0100 +Subject: [PATCH 09/10] rtl8812au: add suggested braces around empty body in an + else statement + +--- + drivers/staging/rtl8812au/core/rtw_recv.c | 3 ++- + drivers/staging/rtl8812au/core/rtw_xmit.c | 3 ++- + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c | 3 ++- + .../rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c | 3 ++- + drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c | 3 ++- + 5 files changed, 10 insertions(+), 5 deletions(-) + +diff --git a/drivers/staging/rtl8812au/core/rtw_recv.c b/drivers/staging/rtl8812au/core/rtw_recv.c +index ed2bf605c..bdbc146ca 100644 +--- a/drivers/staging/rtl8812au/core/rtw_recv.c ++++ b/drivers/staging/rtl8812au/core/rtw_recv.c +@@ -2404,8 +2404,9 @@ sint validate_recv_frame(_adapter *adapter, union recv_frame *precv_frame) + dump_rx_packet(ptr); + } + #endif +- } else ++ } else { + DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_handled); ++ } + break; + default: + DBG_COUNTER(adapter->rx_logs.core_rx_pre_unknown); +diff --git a/drivers/staging/rtl8812au/core/rtw_xmit.c b/drivers/staging/rtl8812au/core/rtw_xmit.c +index e40c0aecc..12a2d5d79 100644 +--- a/drivers/staging/rtl8812au/core/rtw_xmit.c ++++ b/drivers/staging/rtl8812au/core/rtw_xmit.c +@@ -1374,8 +1374,9 @@ static s32 update_attrib(_adapter *padapter, _pkt *pkt, struct pkt_attrib *pattr + _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_ap); +- } else ++ } else { + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_unknown); ++ } + + get_sta_info: + bmcast = IS_MCAST(pattrib->ra); +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c +index a4e3504a3..c31566d70 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c +@@ -814,9 +814,10 @@ void phydm_get_thermal_trim_offset_8198f(void *dm_void) + RF_DBG(dm, DBG_RF_MP, "[kfree] 8198f thermal trim flag:0x%02x\n", + power_trim_info->flag); + +- if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) ++ if (power_trim_info->flag & KFREE_FLAG_THERMAL_K_ON) { + RF_DBG(dm, DBG_RF_MP, "[kfree] 8198f thermal:%d\n", + power_trim_info->thermal); ++ } + } + + void phydm_get_power_trim_offset_8198f(void *dm_void); +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +index a006d7e74..4f11b8223 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +@@ -1320,9 +1320,10 @@ void phy_iq_calibrate_8812a(void *dm_void, boolean is_recovery) + if (dm->fw_offload_ability & PHYDM_RF_IQK_OFFLOAD) { + _phy_iq_calibrate_by_fw_8812a(dm); + phydm_iqk_wait(dm, 500); +- if (dm->rf_calibrate_info.is_iqk_in_progress) ++ if (dm->rf_calibrate_info.is_iqk_in_progress) { + RF_DBG(dm, DBG_RF_IQK, + "== FW IQK TIMEOUT (Still in progress after 500ms) ==\n"); ++ } + } else { + _phy_iq_calibrate_8812a(dm, *dm->channel); + } +diff --git a/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c b/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c +index 952b5600b..28ab2dd54 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c ++++ b/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c +@@ -1196,10 +1196,11 @@ void phydm_beamforming_notify( + /*@if (sound_info->sound_mode == SOUNDING_SW_VHT_TIMER || sound_info->sound_mode == SOUNDING_SW_HT_TIMER) + odm_set_timer(dm, &beam_info->beamforming_timer, sound_info->sound_period);*/ + odm_set_timer(dm, &beam_info->beamforming_timer, 1000); /*@Do MU sounding every 1sec*/ +- } else ++ } else { + PHYDM_DBG(dm, DBG_TXBF, + "%s: Less or larger than 2 MU STAs, not to set timer\n", + __func__); ++ } + break; + + case BEAMFORMEE_NOTIFY_DELETE_MU: +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0010-rtl8812au-add-missed-prototypes.patch b/kernel/tools/perf/files/patches/mageia/0010-rtl8812au-add-missed-prototypes.patch new file mode 100644 index 0000000000..c6f47d7f07 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0010-rtl8812au-add-missed-prototypes.patch @@ -0,0 +1,42 @@ +From 18bb3090b6c0876842813ac10d1822412f51e97e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Giuseppe=20Ghib=C3=B2?= +Date: Thu, 21 Nov 2024 17:07:41 +0100 +Subject: [PATCH 10/10] rtl8812au: add missed prototypes + +--- + drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c | 7 +++++++ + drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c | 1 + + 2 files changed, 8 insertions(+) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index c0f563430..72538365a 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -2151,6 +2151,12 @@ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, + #endif ++ u8 key_index); ++int cfg80211_rtw_set_default_mgmt_key(struct wiphy *wiphy, ++ struct net_device *ndev, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ int link_id, ++#endif + u8 key_index) + { + #define SET_DEF_KEY_PARAM_FMT " key_index=%d" +diff --git a/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c b/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c +index c7eb7ea40..9ced824fe 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c +@@ -898,6 +898,7 @@ void usb_recv_tasklet(unsigned long priv) + } + } + ++void usb_read_port_complete(struct urb *purb, struct pt_regs *regs); + void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) + { + struct recv_buf *precvbuf = (struct recv_buf *)purb->context; +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0122-Fix-change_beacon-for-kernel-6.7.patch b/kernel/tools/perf/files/patches/mageia/0122-Fix-change_beacon-for-kernel-6.7.patch new file mode 100644 index 0000000000..88ad49646b --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0122-Fix-change_beacon-for-kernel-6.7.patch @@ -0,0 +1,33 @@ +From c0d16813f5af3b464cdb6dd415c83d1f238e3548 Mon Sep 17 00:00:00 2001 +From: CamiKaseM7 +Date: Tue, 16 Jan 2024 03:44:34 -0300 +Subject: [PATCH 122/132] Fix change_beacon for kernel 6.7 + +--- + os_dep/linux/ioctl_cfg80211.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index 510fa45..a135804 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -5283,9 +5283,16 @@ exit: + return ret; + } + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)) ++static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *ndev, ++ struct cfg80211_ap_update *params) ++{ ++ struct cfg80211_beacon_data *info = ¶ms->beacon; ++#else + static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_beacon_data *info) + { ++#endif + int ret = 0; + _adapter *adapter = (_adapter *)rtw_netdev_priv(ndev); + +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0123-Update-os_intfs.c-for-kernel-6.8.patch b/kernel/tools/perf/files/patches/mageia/0123-Update-os_intfs.c-for-kernel-6.8.patch new file mode 100644 index 0000000000..c740ce5e50 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0123-Update-os_intfs.c-for-kernel-6.8.patch @@ -0,0 +1,27 @@ +From d3feb6ae9398834d7778c0e43ebd1fa757eaecd8 Mon Sep 17 00:00:00 2001 +From: alium +Date: Tue, 12 Mar 2024 07:11:35 +0100 +Subject: [PATCH 123/132] Update os_intfs.c for kernel 6.8 + +--- + os_dep/linux/os_intfs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c b/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c +index 2dadae0..f4f2ef9 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c +@@ -17,6 +17,10 @@ + #include + #include + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)) ++#define strlcpy strscpy ++#endif ++ + MODULE_LICENSE("GPL"); + MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); + MODULE_AUTHOR("Realtek Semiconductor Corp."); +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0124-Update-usb_intf.c-for-kernel-6.8.patch b/kernel/tools/perf/files/patches/mageia/0124-Update-usb_intf.c-for-kernel-6.8.patch new file mode 100644 index 0000000000..15e2203b64 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0124-Update-usb_intf.c-for-kernel-6.8.patch @@ -0,0 +1,25 @@ +From 88d0f5ca85cb8f6a7970ccca9d06a5aa424a18b2 Mon Sep 17 00:00:00 2001 +From: alium +Date: Tue, 12 Mar 2024 07:14:38 +0100 +Subject: [PATCH 124/132] Update usb_intf.c for kernel 6.8 + +--- + os_dep/linux/usb_intf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +index be0f654..709e935 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +@@ -270,7 +270,7 @@ struct rtw_usb_drv usb_drv = { + .usbdrv.supports_autosuspend = 1, + #endif + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 8, 0)) + .usbdrv.drvwrap.driver.shutdown = rtw_dev_shutdown, + #else + .usbdrv.driver.shutdown = rtw_dev_shutdown, +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/0128-Update-ioctl_cfg80211.c-support-for-kernel-6.9.patch b/kernel/tools/perf/files/patches/mageia/0128-Update-ioctl_cfg80211.c-support-for-kernel-6.9.patch new file mode 100644 index 0000000000..78fce1824c --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/0128-Update-ioctl_cfg80211.c-support-for-kernel-6.9.patch @@ -0,0 +1,35 @@ +From 860ccf31655e160ec921190e443f0b532d8d3308 Mon Sep 17 00:00:00 2001 +From: alium +Date: Sat, 30 Mar 2024 09:50:44 +0100 +Subject: [PATCH 128/132] Update ioctl_cfg80211.c - support for kernel 6.9 + + support for kernel 6.9 +--- + drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index a135804..c1f20e9 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -460,7 +460,7 @@ u8 rtw_cfg80211_ch_switch_notify(_adapter *adapter, u8 ch, u8 bw, u8 offset, + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) + if (started) { +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 9, 0)) + cfg80211_ch_switch_started_notify(adapter->pnetdev, &chdef, 0, 0, false, 0); + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + cfg80211_ch_switch_started_notify(adapter->pnetdev, &chdef, 0, 0, false); +@@ -476,7 +476,7 @@ u8 rtw_cfg80211_ch_switch_notify(_adapter *adapter, u8 ch, u8 bw, u8 offset, + if (!rtw_cfg80211_allow_ch_switch_notify(adapter)) + goto exit; + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 9, 0)) + cfg80211_ch_switch_notify(adapter->pnetdev, &chdef, 0, 0); + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) + cfg80211_ch_switch_notify(adapter->pnetdev, &chdef, 0); +-- +2.41.1 + diff --git a/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch b/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch deleted file mode 100644 index 78d502ec1d..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-merge.patch +++ /dev/null @@ -1,57 +0,0 @@ - -Include 3rdparty directory into the main build-system. - -Original author is unknown. -(Was either Juan Quintela or Jeff Garzik) - -Signed-off-by: Luiz Fernando N. Capitulino -Signed-off-by: Herton Ronaldo Krzesinski -[Simplified for Mageia 7 / kernel 5.1.6 and up / tmb] -Signed-off-by: Thomas Backlund - ---- - Makefile | 2 +- - arch/arm/Kconfig | 2 ++ - arch/arm64/Kconfig | 2 ++ - arch/x86/Kconfig | 2 ++ - 4 files changed, 7 insertions(+), 1 deletion(-) - -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-3rdparty-tree.patch b/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-tree.patch deleted file mode 100644 index 483e4e5757..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-3rdparty-tree.patch +++ /dev/null @@ -1,21 +0,0 @@ - - 3rdparty/Kconfig | 5 +++++ - 3rdparty/Makefile | 3 +++ - 2 files changed, 8 insertions(+) - -diff -Nurp linux-5.1.6/3rdparty/Kconfig linux-5.1.6-3rd/3rdparty/Kconfig ---- linux-5.1.6/3rdparty/Kconfig 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.1.6-3rd/3rdparty/Kconfig 2019-05-31 23:02:53.380127780 +0300 -@@ -0,0 +1,5 @@ -+# -+ -+menu "External 3rdparty kernel additions" -+ -+endmenu -diff -Nurp linux-5.1.6/3rdparty/Makefile linux-5.1.6-3rd/3rdparty/Makefile ---- linux-5.1.6/3rdparty/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.1.6-3rd/3rdparty/Makefile 2019-05-31 23:03:58.338529850 +0300 -@@ -0,0 +1,3 @@ -+# -+ -+obj- := 3rdparty.o # Dummy rule to force built-in.o to be made diff --git a/kernel/tools/perf/files/patches/mageia/3rd-fix-kconfig.patch b/kernel/tools/perf/files/patches/mageia/3rd-fix-kconfig.patch deleted file mode 100644 index 783807d71e..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-fix-kconfig.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -up ./3rdparty/rtl8723de/Kconfig.tv ./3rdparty/rtl8723de/Kconfig ---- ./3rdparty/rtl8723de/Kconfig.tv 2020-10-13 21:02:42.452125426 +0200 -+++ ./3rdparty/rtl8723de/Kconfig 2020-10-13 20:59:14.012371730 +0200 -@@ -1,6 +1,6 @@ - config RTL8723DE - tristate "Realtek 8723DE PCI WiFi" - depends on PCI -- ---help--- -+ help - Help message of RTL8723DE - -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 -@@ -1,6 +1,6 @@ - config RTL8821CE - tristate "Realtek 8821C PCI WiFi" - depends on PCI -- ---help--- -+ help - Help message of RTL8821CE - -diff -up ./3rdparty/viahss/Kconfig.tv ./3rdparty/viahss/Kconfig ---- ./3rdparty/viahss/Kconfig.tv 2020-10-13 21:02:44.844168369 +0200 -+++ ./3rdparty/viahss/Kconfig 2020-10-13 20:59:19.875488718 +0200 -@@ -1,7 +1,7 @@ - config VIAHSS - tristate "VIA High Speed Serial" - depends on SERIAL_CORE && m -- ---help--- -+ help - VIA High Speed Serial is a little kernel module (1 KB) which enables - high speed serial port modes of VIA VT82C686A or VT82C686B - southbridge-equipped motherboards. With this module, you can use the diff --git a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-1.63.patch b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-1.63.patch deleted file mode 100644 index f513309396..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-1.63.patch +++ /dev/null @@ -1,26570 +0,0 @@ -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/crt.c linux-5.6.11-ndis/3rdparty/ndiswrapper/crt.c ---- linux-5.6.11/3rdparty/ndiswrapper/crt.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/crt.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,589 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ntoskernel.h" -+#include "crt_exports.h" -+ -+#ifdef CONFIG_X86_64 -+/* Windows long is 32-bit, so strip single 'l' in integer formats */ -+static void strip_l_modifier(char *str) -+{ -+ char *ptr = str; -+ int in_format = 0; -+ char *lptr = NULL; -+ char last = 0; -+ char *end_ptr; -+ char *wptr; -+ -+ /* Replace single 'l' inside integer formats with '\0' */ -+ for (ptr = str; *ptr; ptr++) { -+ if (!in_format) { -+ if (*ptr == '%') -+ in_format = 1; -+ last = *ptr; -+ continue; -+ } -+ switch (*ptr) { -+ case 'd': -+ case 'i': -+ case 'o': -+ case 'u': -+ case 'x': -+ case 'X': -+ case 'p': -+ case 'n': -+ case 'm': -+ if (lptr) { -+ *lptr = '\0'; -+ lptr = NULL; -+ } -+ in_format = 0; -+ break; -+ case 'c': -+ case 'C': -+ case 's': -+ case 'S': -+ case 'f': -+ case 'e': -+ case 'E': -+ case 'g': -+ case 'G': -+ case 'a': -+ case 'A': -+ lptr = NULL; -+ in_format = 0; -+ break; -+ case '%': -+ lptr = NULL; -+ if (last == '%') -+ in_format = 0; -+ else -+ in_format = 1; /* ignore previous junk */ -+ break; -+ case 'l': -+ if (last == 'l') -+ lptr = NULL; -+ else -+ lptr = ptr; -+ break; -+ default: -+ break; -+ } -+ last = *ptr; -+ } -+ -+ /* Purge zeroes from the resulting string */ -+ end_ptr = ptr; -+ wptr = str; -+ for (ptr = str; ptr < end_ptr; ptr++) -+ if (*ptr != 0) -+ *(wptr++) = *ptr; -+ *wptr = 0; -+} -+ -+/* -+ * va_list on x86_64 Linux is designed to allow passing arguments in registers -+ * even to variadic functions. va_list is a structure holding pointers to the -+ * register save area, which holds the arguments passed in registers, and to -+ * the stack, which may have the arguments that did not fit the registers. -+ * va_list also holds offsets in the register save area for the next general -+ * purpose and floating point registers that the next va_arg() would fetch. -+ * -+ * Unlike Linux, the Windows va_list is just a pointer to the stack. No -+ * arguments are passed in the registers. That's why we construct the Linux -+ * va_list so that the register save area is never used. For that goal, we set -+ * the offsets to the maximal allowed values, meaning that the arguments passed -+ * in the registers have been exhausted. The values are 48 for general purpose -+ * registers (6 registers, 8 bytes each) and 304 for floating point registers -+ * (16 registers, 16 bytes each, on top of general purpose register). -+ */ -+ -+struct x86_64_va_list { -+ int gp_offset; -+ int fp_offset; -+ void *overflow_arg_area; -+ void *reg_save_area; -+}; -+ -+#define VA_LIST_DECL(_args) \ -+ va_list _args##new; \ -+ struct x86_64_va_list *_args##x; -+#define VA_LIST_PREP(_args) \ -+do { \ -+ _args##x = (struct x86_64_va_list *)&_args##new; \ -+ _args##x->gp_offset = 6 * 8; /* GP registers exhausted */ \ -+ _args##x->fp_offset = 6 * 8 + 16 * 16; /* FP registers exhausted */ \ -+ _args##x->overflow_arg_area = (void *)_args; \ -+ _args##x->reg_save_area = NULL; \ -+} while (0) -+#define VA_LIST_CONV(_args) (_args##new) -+#define VA_LIST_FREE(_args) -+#define FMT_DECL(_fmt) \ -+ char *_fmt##copy; \ -+ int _fmt##len; -+#define FMT_PREP(_fmt) \ -+do { \ -+ _fmt##len = strlen(format) + 1; \ -+ _fmt##copy = kmalloc(_fmt##len, irql_gfp()); \ -+ if (_fmt##copy) { \ -+ memcpy(_fmt##copy, format, _fmt##len); \ -+ strip_l_modifier(_fmt##copy); \ -+ } \ -+} while (0) -+#define FMT_CONV(_fmt) (_fmt##copy ? _fmt##copy : format) -+#define FMT_FREE(_fmt) kfree(_fmt##copy) -+ -+#else /* !CONFIG_X86_64 */ -+ -+#define VA_LIST_DECL(_args) -+#define VA_LIST_PREP(_args) -+#define VA_LIST_CONV(_args) (_args) -+#define VA_LIST_FREE(_args) -+#define FMT_DECL(_fmt) -+#define FMT_PREP(_fmt) -+#define FMT_CONV(_fmt) (format) -+#define FMT_FREE(_fmt) -+ -+#endif /* !CONFIG_X86_64 */ -+ -+__attribute__((format(printf, 2, 3))) -+noregparm INT WIN_FUNC(_win_sprintf,12) -+ (char *buf, const char *format, ...) -+{ -+ va_list args; -+ int res; -+ FMT_DECL(format) -+ -+ FMT_PREP(format); -+ va_start(args, format); -+ res = vsprintf(buf, FMT_CONV(format), args); -+ va_end(args); -+ FMT_FREE(format); -+ -+ TRACE2("buf: %p: %s", buf, buf); -+ return res; -+} -+ -+noregparm INT WIN_FUNC(swprintf,12) -+ (wchar_t *buf, const wchar_t *format, ...) -+{ -+ TODO(); -+ EXIT2(return 0); -+} -+ -+noregparm INT WIN_FUNC(_win_vsprintf,3) -+ (char *str, const char *format, va_list ap) -+{ -+ INT i; -+ VA_LIST_DECL(ap) -+ FMT_DECL(format) -+ -+ VA_LIST_PREP(ap); -+ FMT_PREP(format); -+ -+ i = vsprintf(str, FMT_CONV(format), VA_LIST_CONV(ap)); -+ TRACE2("str: %p: %s", str, str); -+ -+ FMT_FREE(format); -+ VA_LIST_FREE(ap); -+ EXIT2(return i); -+} -+ -+__attribute__((format(printf, 3, 4))) -+noregparm INT WIN_FUNC(_win_snprintf,12) -+ (char *buf, SIZE_T count, const char *format, ...) -+{ -+ va_list args; -+ int res; -+ FMT_DECL(format) -+ -+ FMT_PREP(format); -+ va_start(args, format); -+ res = vsnprintf(buf, count, FMT_CONV(format), args); -+ va_end(args); -+ TRACE2("buf: %p: %s", buf, buf); -+ -+ FMT_FREE(format); -+ return res; -+} -+ -+__attribute__((format(printf, 3, 4))) -+noregparm INT WIN_FUNC(_win__snprintf,12) -+ (char *buf, SIZE_T count, const char *format, ...) -+{ -+ va_list args; -+ int res; -+ FMT_DECL(format) -+ -+ FMT_PREP(format); -+ va_start(args, format); -+ res = vsnprintf(buf, count, FMT_CONV(format), args); -+ va_end(args); -+ TRACE2("buf: %p: %s", buf, buf); -+ -+ FMT_FREE(format); -+ return res; -+} -+ -+noregparm INT WIN_FUNC(_win_vsnprintf,4) -+ (char *str, SIZE_T size, const char *format, va_list ap) -+{ -+ INT i; -+ VA_LIST_DECL(ap) -+ FMT_DECL(format) -+ -+ VA_LIST_PREP(ap); -+ FMT_PREP(format); -+ -+ i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap)); -+ TRACE2("str: %p: %s", str, str); -+ -+ FMT_FREE(format); -+ VA_LIST_FREE(ap); -+ EXIT2(return i); -+} -+ -+noregparm INT WIN_FUNC(_win__vsnprintf,4) -+ (char *str, SIZE_T size, const char *format, va_list ap) -+{ -+ INT i; -+ VA_LIST_DECL(ap) -+ FMT_DECL(format) -+ -+ VA_LIST_PREP(ap); -+ FMT_PREP(format); -+ -+ i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap)); -+ TRACE2("str: %p: %s", str, str); -+ -+ FMT_FREE(format); -+ VA_LIST_FREE(ap); -+ EXIT2(return i); -+} -+ -+noregparm INT WIN_FUNC(_win__vsnwprintf,4) -+ (wchar_t *str, SIZE_T size, const wchar_t *format, va_list ap) -+{ -+ int ret; -+ -+ TODO(); /* format expansion not implemented */ -+ _win_wcsncpy(str, format, size); -+ ret = _win_wcslen(format); -+ if (ret >= size) -+ ret = -1; -+ return ret; -+} -+ -+noregparm char *WIN_FUNC(_win_strncpy,3) -+ (char *dst, char *src, SIZE_T n) -+{ -+ return strncpy(dst, src, n); -+} -+ -+noregparm SIZE_T WIN_FUNC(_win_strlen,1) -+ (const char *s) -+{ -+ return strlen(s); -+} -+ -+noregparm INT WIN_FUNC(_win_strncmp,3) -+ (const char *s1, const char *s2, SIZE_T n) -+{ -+ return strncmp(s1, s2, n); -+} -+ -+noregparm INT WIN_FUNC(_win_strcmp,2) -+ (const char *s1, const char *s2) -+{ -+ return strcmp(s1, s2); -+} -+ -+noregparm INT WIN_FUNC(_win_stricmp,2) -+ (const char *s1, const char *s2) -+{ -+ return stricmp(s1, s2); -+} -+ -+noregparm char *WIN_FUNC(_win_strncat,3) -+ (char *dest, const char *src, SIZE_T n) -+{ -+ return strncat(dest, src, n); -+} -+ -+noregparm INT WIN_FUNC(_win_wcscmp,2) -+ (const wchar_t *s1, const wchar_t *s2) -+{ -+ while (*s1 && *s1 == *s2) { -+ s1++; -+ s2++; -+ } -+ return *s1 - *s2; -+} -+ -+noregparm INT WIN_FUNC(_win_wcsicmp,2) -+ (const wchar_t *s1, const wchar_t *s2) -+{ -+ while (*s1 && tolower((char)*s1) == tolower((char)*s2)) { -+ s1++; -+ s2++; -+ } -+ return tolower((char)*s1) - tolower((char)*s2); -+} -+ -+noregparm SIZE_T WIN_FUNC(_win_wcslen,1) -+ (const wchar_t *s) -+{ -+ const wchar_t *t = s; -+ while (*t) -+ t++; -+ return t - s; -+} -+ -+noregparm wchar_t *WIN_FUNC(_win_wcsncpy,3) -+ (wchar_t *dest, const wchar_t *src, SIZE_T n) -+{ -+ const wchar_t *s; -+ wchar_t *d; -+ s = src + n; -+ d = dest; -+ while (src < s && (*d++ = *src++)) -+ ; -+ if (s > src) -+ memset(d, 0, (s - src) * sizeof(wchar_t)); -+ return dest; -+} -+ -+noregparm wchar_t *WIN_FUNC(_win_wcscpy,2) -+ (wchar_t *dest, const wchar_t *src) -+{ -+ wchar_t *d = dest; -+ while ((*d++ = *src++)) -+ ; -+ return dest; -+} -+ -+noregparm wchar_t *WIN_FUNC(_win_wcscat,2) -+ (wchar_t *dest, const wchar_t *src) -+{ -+ wchar_t *d; -+ d = dest; -+ while (*d) -+ d++; -+ while ((*d++ = *src++)) -+ ; -+ return dest; -+} -+ -+noregparm INT WIN_FUNC(_win_towupper,1) -+ (wchar_t c) -+{ -+ return toupper(c); -+} -+ -+noregparm INT WIN_FUNC(_win_towlower,1) -+ (wchar_t c) -+{ -+ return tolower(c); -+} -+ -+noregparm INT WIN_FUNC(_win_tolower,1) -+ (INT c) -+{ -+ return tolower(c); -+} -+ -+noregparm INT WIN_FUNC(_win_toupper,1) -+ (INT c) -+{ -+ return toupper(c); -+} -+ -+noregparm void *WIN_FUNC(_win_strcpy,2) -+ (void *to, const void *from) -+{ -+ return strcpy(to, from); -+} -+ -+noregparm char *WIN_FUNC(_win_strstr,2) -+ (const char *s1, const char *s2) -+{ -+ return strstr(s1, s2); -+} -+ -+noregparm char *WIN_FUNC(_win_strchr,2) -+ (const char *s, int c) -+{ -+ return strchr(s, c); -+} -+ -+noregparm char *WIN_FUNC(_win_strrchr,2) -+ (const char *s, int c) -+{ -+ return strrchr(s, c); -+} -+ -+noregparm void *WIN_FUNC(_win_memmove,3) -+ (void *to, void *from, SIZE_T count) -+{ -+ return memmove(to, from, count); -+} -+ -+noregparm void *WIN_FUNC(_win_memchr,3) -+ (const void *s, INT c, SIZE_T n) -+{ -+ return memchr(s, c, n); -+} -+ -+noregparm void *WIN_FUNC(_win_memcpy,3) -+ (void *to, const void *from, SIZE_T n) -+{ -+ return memcpy(to, from, n); -+} -+ -+noregparm void *WIN_FUNC(_win_memset,3) -+ (void *s, char c, SIZE_T count) -+{ -+ return memset(s, c, count); -+} -+ -+noregparm int WIN_FUNC(_win_memcmp,3) -+ (void *s1, void *s2, SIZE_T n) -+{ -+ return memcmp(s1, s2, n); -+} -+ -+noregparm void WIN_FUNC(_win_srand,1) -+ (UINT seed) -+{ -+ prandom_seed(seed); -+} -+ -+noregparm int WIN_FUNC(rand,0) -+ (void) -+{ -+ char buf[6]; -+ int i, n; -+ -+ get_random_bytes(buf, sizeof(buf)); -+ for (n = i = 0; i < sizeof(buf); i++) -+ n += buf[i]; -+ return n; -+} -+ -+noregparm int WIN_FUNC(_win_atoi,1) -+ (const char *ptr) -+{ -+ int i = simple_strtol(ptr, NULL, 10); -+ return i; -+} -+ -+noregparm int WIN_FUNC(_win_isdigit,1) -+ (int c) -+{ -+ return isdigit(c); -+} -+ -+noregparm int WIN_FUNC(_win_isprint,1) -+ (int c) -+{ -+ return isprint(c); -+} -+ -+wstdcall s64 WIN_FUNC(_alldiv,2) -+ (s64 a, s64 b) -+{ -+ return a / b; -+} -+ -+wstdcall u64 WIN_FUNC(_aulldiv,2) -+ (u64 a, u64 b) -+{ -+ return a / b; -+} -+ -+wstdcall s64 WIN_FUNC(_allmul,2) -+ (s64 a, s64 b) -+{ -+ return a * b; -+} -+ -+wstdcall u64 WIN_FUNC(_aullmul,2) -+ (u64 a, u64 b) -+{ -+ return a * b; -+} -+ -+wstdcall s64 WIN_FUNC(_allrem,2) -+ (s64 a, s64 b) -+{ -+ return a % b; -+} -+ -+wstdcall u64 WIN_FUNC(_aullrem,2) -+ (u64 a, u64 b) -+{ -+ return a % b; -+} -+ -+regparm3 s64 WIN_FUNC(_allshl,2) -+ (s64 a, u8 b) -+{ -+ return a << b; -+} -+ -+regparm3 u64 WIN_FUNC(_aullshl,2) -+ (u64 a, u8 b) -+{ -+ return a << b; -+} -+ -+regparm3 s64 WIN_FUNC(_allshr,2) -+ (s64 a, u8 b) -+{ -+ return a >> b; -+} -+ -+regparm3 u64 WIN_FUNC(_aullshr,2) -+ (u64 a, u8 b) -+{ -+ return a >> b; -+} -+ -+int stricmp(const char *s1, const char *s2) -+{ -+ while (*s1 && tolower(*s1) == tolower(*s2)) { -+ s1++; -+ s2++; -+ } -+ return *s1 - *s2; -+} -+ -+void dump_bytes(const char *ctx, const u8 *from, int len) -+{ -+ int i, j; -+ u8 *buf; -+ -+ buf = kmalloc(len * 3 + 1, irql_gfp()); -+ if (!buf) { -+ ERROR("couldn't allocate memory"); -+ return; -+ } -+ for (i = j = 0; i < len; i++, j += 3) { -+ sprintf(&buf[j], "%02x ", from[i]); -+ } -+ buf[j] = 0; -+ printk(KERN_DEBUG "%s: %p: %s\n", ctx, from, buf); -+ kfree(buf); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/divdi3.c linux-5.6.11-ndis/3rdparty/ndiswrapper/divdi3.c ---- linux-5.6.11/3rdparty/ndiswrapper/divdi3.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/divdi3.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,329 @@ -+/* 64-bit multiplication and division -+ Copyright (C) 1989, 1992-1999, 2000, 2001, 2002, 2003 -+ Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library 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 -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, write to the Free -+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -+ 02111-1307 USA. */ -+ -+#include -+#include -+ -+#if BITS_PER_LONG != 32 -+#error This is for 32-bit targets only -+#endif -+ -+typedef unsigned int UQItype __attribute__ ((mode (QI))); -+typedef int SItype __attribute__ ((mode (SI))); -+typedef unsigned int USItype __attribute__ ((mode (SI))); -+typedef int DItype __attribute__ ((mode (DI))); -+typedef unsigned int UDItype __attribute__ ((mode (DI))); -+#define Wtype SItype -+#define HWtype SItype -+#define DWtype DItype -+#define UWtype USItype -+#define UHWtype USItype -+#define UDWtype UDItype -+#define W_TYPE_SIZE 32 -+ -+#include "longlong.h" -+ -+#if defined(__BIG_ENDIAN) -+struct DWstruct { Wtype high, low;}; -+#elif defined(__LITTLE_ENDIAN) -+struct DWstruct { Wtype low, high;}; -+#else -+#error Unhandled endianity -+#endif -+typedef union { struct DWstruct s; DWtype ll; } DWunion; -+ -+/* Prototypes of exported functions. */ -+extern DWtype __divdi3 (DWtype u, DWtype v); -+extern DWtype __moddi3 (DWtype u, DWtype v); -+extern UDWtype __udivdi3 (UDWtype u, UDWtype v); -+extern UDWtype __umoddi3 (UDWtype u, UDWtype v); -+ -+static UDWtype -+__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) -+{ -+ DWunion ww; -+ DWunion nn, dd; -+ DWunion rr; -+ UWtype d0, d1, n0, n1, n2; -+ UWtype q0, q1; -+ UWtype b, bm; -+ -+ nn.ll = n; -+ dd.ll = d; -+ -+ d0 = dd.s.low; -+ d1 = dd.s.high; -+ n0 = nn.s.low; -+ n1 = nn.s.high; -+ -+#if !UDIV_NEEDS_NORMALIZATION -+ if (d1 == 0) -+ { -+ if (d0 > n1) -+ { -+ /* 0q = nn / 0D */ -+ -+ udiv_qrnnd (q0, n0, n1, n0, d0); -+ q1 = 0; -+ -+ /* Remainder in n0. */ -+ } -+ else -+ { -+ /* qq = NN / 0d */ -+ -+ if (d0 == 0) -+ d0 = 1 / d0; /* Divide intentionally by zero. */ -+ -+ udiv_qrnnd (q1, n1, 0, n1, d0); -+ udiv_qrnnd (q0, n0, n1, n0, d0); -+ -+ /* Remainder in n0. */ -+ } -+ -+ if (rp != NULL) -+ { -+ rr.s.low = n0; -+ rr.s.high = 0; -+ *rp = rr.ll; -+ } -+ } -+ -+#else /* UDIV_NEEDS_NORMALIZATION */ -+ -+ if (d1 == 0) -+ { -+ if (d0 > n1) -+ { -+ /* 0q = nn / 0D */ -+ -+ count_leading_zeros (bm, d0); -+ -+ if (bm != 0) -+ { -+ /* Normalize, i.e. make the most significant bit of the -+ denominator set. */ -+ -+ d0 = d0 << bm; -+ n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); -+ n0 = n0 << bm; -+ } -+ -+ udiv_qrnnd (q0, n0, n1, n0, d0); -+ q1 = 0; -+ -+ /* Remainder in n0 >> bm. */ -+ } -+ else -+ { -+ /* qq = NN / 0d */ -+ -+ if (d0 == 0) -+ d0 = 1 / d0; /* Divide intentionally by zero. */ -+ -+ count_leading_zeros (bm, d0); -+ -+ if (bm == 0) -+ { -+ /* From (n1 >= d0) /\ (the most significant bit of d0 is set), -+ conclude (the most significant bit of n1 is set) /\ (the -+ leading quotient digit q1 = 1). -+ -+ This special case is necessary, not an optimization. -+ (Shifts counts of W_TYPE_SIZE are undefined.) */ -+ -+ n1 -= d0; -+ q1 = 1; -+ } -+ else -+ { -+ /* Normalize. */ -+ -+ b = W_TYPE_SIZE - bm; -+ -+ d0 = d0 << bm; -+ n2 = n1 >> b; -+ n1 = (n1 << bm) | (n0 >> b); -+ n0 = n0 << bm; -+ -+ udiv_qrnnd (q1, n1, n2, n1, d0); -+ } -+ -+ /* n1 != d0... */ -+ -+ udiv_qrnnd (q0, n0, n1, n0, d0); -+ -+ /* Remainder in n0 >> bm. */ -+ } -+ -+ if (rp != NULL) -+ { -+ rr.s.low = n0 >> bm; -+ rr.s.high = 0; -+ *rp = rr.ll; -+ } -+ } -+#endif /* UDIV_NEEDS_NORMALIZATION */ -+ -+ else -+ { -+ if (d1 > n1) -+ { -+ /* 00 = nn / DD */ -+ -+ q0 = 0; -+ q1 = 0; -+ -+ /* Remainder in n1n0. */ -+ if (rp != NULL) -+ { -+ rr.s.low = n0; -+ rr.s.high = n1; -+ *rp = rr.ll; -+ } -+ } -+ else -+ { -+ /* 0q = NN / dd */ -+ -+ count_leading_zeros (bm, d1); -+ if (bm == 0) -+ { -+ /* From (n1 >= d1) /\ (the most significant bit of d1 is set), -+ conclude (the most significant bit of n1 is set) /\ (the -+ quotient digit q0 = 0 or 1). -+ -+ This special case is necessary, not an optimization. */ -+ -+ /* The condition on the next line takes advantage of that -+ n1 >= d1 (true due to program flow). */ -+ if (n1 > d1 || n0 >= d0) -+ { -+ q0 = 1; -+ sub_ddmmss (n1, n0, n1, n0, d1, d0); -+ } -+ else -+ q0 = 0; -+ -+ q1 = 0; -+ -+ if (rp != NULL) -+ { -+ rr.s.low = n0; -+ rr.s.high = n1; -+ *rp = rr.ll; -+ } -+ } -+ else -+ { -+ UWtype m1, m0; -+ /* Normalize. */ -+ -+ b = W_TYPE_SIZE - bm; -+ -+ d1 = (d1 << bm) | (d0 >> b); -+ d0 = d0 << bm; -+ n2 = n1 >> b; -+ n1 = (n1 << bm) | (n0 >> b); -+ n0 = n0 << bm; -+ -+ udiv_qrnnd (q0, n1, n2, n1, d1); -+ umul_ppmm (m1, m0, q0, d0); -+ -+ if (m1 > n1 || (m1 == n1 && m0 > n0)) -+ { -+ q0--; -+ sub_ddmmss (m1, m0, m1, m0, d1, d0); -+ } -+ -+ q1 = 0; -+ -+ /* Remainder in (n1n0 - m1m0) >> bm. */ -+ if (rp != NULL) -+ { -+ sub_ddmmss (n1, n0, n1, n0, m1, m0); -+ rr.s.low = (n1 << b) | (n0 >> bm); -+ rr.s.high = n1 >> bm; -+ *rp = rr.ll; -+ } -+ } -+ } -+ } -+ -+ ww.s.low = q0; -+ ww.s.high = q1; -+ return ww.ll; -+} -+ -+DWtype -+__divdi3 (DWtype u, DWtype v) -+{ -+ Wtype c = 0; -+ DWtype w; -+ -+ if (u < 0) -+ { -+ c = ~c; -+ u = -u; -+ } -+ if (v < 0) -+ { -+ c = ~c; -+ v = -v; -+ } -+ w = __udivmoddi4 (u, v, NULL); -+ if (c) -+ w = -w; -+ return w; -+} -+ -+DWtype -+__moddi3 (DWtype u, DWtype v) -+{ -+ Wtype c = 0; -+ DWtype w; -+ -+ if (u < 0) -+ { -+ c = ~c; -+ u = -u; -+ } -+ if (v < 0) -+ v = -v; -+ __udivmoddi4 (u, v, &w); -+ if (c) -+ w = -w; -+ return w; -+} -+ -+UDWtype -+__udivdi3 (UDWtype u, UDWtype v) -+{ -+ return __udivmoddi4 (u, v, NULL); -+} -+ -+UDWtype -+__umoddi3 (UDWtype u, UDWtype v) -+{ -+ UDWtype w; -+ -+ __udivmoddi4 (u, v, &w); -+ return w; -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/hal.c linux-5.6.11-ndis/3rdparty/ndiswrapper/hal.c ---- linux-5.6.11/3rdparty/ndiswrapper/hal.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/hal.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,157 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ntoskernel.h" -+#include "hal_exports.h" -+ -+wstdcall void WIN_FUNC(WRITE_PORT_ULONG,2) -+ (ULONG_PTR port, ULONG value) -+{ -+ outl(value, port); -+} -+ -+wstdcall ULONG WIN_FUNC(READ_PORT_ULONG,1) -+ (ULONG_PTR port) -+{ -+ return inl(port); -+} -+ -+wstdcall void WIN_FUNC(WRITE_PORT_USHORT,2) -+ (ULONG_PTR port, USHORT value) -+{ -+ outw(value, port); -+} -+ -+wstdcall USHORT WIN_FUNC(READ_PORT_USHORT,1) -+ (ULONG_PTR port) -+{ -+ return inw(port); -+} -+ -+wstdcall void WIN_FUNC(WRITE_PORT_UCHAR,2) -+ (ULONG_PTR port, UCHAR value) -+{ -+ outb(value, port); -+} -+ -+wstdcall UCHAR WIN_FUNC(READ_PORT_UCHAR,1) -+ (ULONG_PTR port) -+{ -+ return inb(port); -+} -+ -+wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_USHORT,3) -+ (ULONG_PTR port, USHORT *buf, ULONG count) -+{ -+ outsw(port, buf, count); -+} -+ -+wstdcall void WIN_FUNC(READ_PORT_BUFFER_USHORT,3) -+ (ULONG_PTR port, USHORT *buf, ULONG count) -+{ -+ insw(port, buf, count); -+} -+ -+wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_ULONG,3) -+ (ULONG_PTR port, ULONG *buf, ULONG count) -+{ -+ outsl(port, buf, count); -+} -+ -+wstdcall void WIN_FUNC(READ_PORT_BUFFER_ULONG,3) -+ (ULONG_PTR port, ULONG *buf, ULONG count) -+{ -+ insl(port, buf, count); -+} -+ -+wstdcall USHORT WIN_FUNC(READ_REGISTER_USHORT,1) -+ (void __iomem *reg) -+{ -+ return readw(reg); -+} -+ -+wstdcall void WIN_FUNC(WRITE_REGISTER_ULONG,2) -+ (void __iomem *reg, UINT val) -+{ -+ writel(val, reg); -+} -+ -+wstdcall void WIN_FUNC(WRITE_REGISTER_USHORT,2) -+ (void __iomem *reg, USHORT val) -+{ -+ writew(val, reg); -+} -+ -+wstdcall void WIN_FUNC(WRITE_REGISTER_UCHAR,2) -+ (void __iomem *reg, UCHAR val) -+{ -+ writeb(val, reg); -+} -+ -+wstdcall void WIN_FUNC(KeStallExecutionProcessor,1) -+ (ULONG usecs) -+{ -+ udelay(usecs); -+} -+ -+wstdcall KIRQL WIN_FUNC(KeGetCurrentIrql,0) -+ (void) -+{ -+ return current_irql(); -+} -+ -+wfastcall KIRQL WIN_FUNC(KfRaiseIrql,1) -+ (KIRQL newirql) -+{ -+ return raise_irql(newirql); -+} -+ -+wfastcall void WIN_FUNC(KfLowerIrql,1) -+ (KIRQL oldirql) -+{ -+ lower_irql(oldirql); -+} -+ -+wfastcall KIRQL WIN_FUNC(KfAcquireSpinLock,1) -+ (NT_SPIN_LOCK *lock) -+{ -+ return nt_spin_lock_irql(lock, DISPATCH_LEVEL); -+} -+ -+wfastcall void WIN_FUNC(KfReleaseSpinLock,2) -+ (NT_SPIN_LOCK *lock, KIRQL oldirql) -+{ -+ nt_spin_unlock_irql(lock, oldirql); -+} -+ -+wfastcall void WIN_FUNC(KefAcquireSpinLockAtDpcLevel,1) -+ (NT_SPIN_LOCK *lock) -+{ -+#ifdef DEBUG_IRQL -+ if (current_irql() != DISPATCH_LEVEL) -+ ERROR("irql != DISPATCH_LEVEL"); -+#endif -+ nt_spin_lock(lock); -+} -+ -+wfastcall void WIN_FUNC(KefReleaseSpinLockFromDpcLevel,1) -+ (NT_SPIN_LOCK *lock) -+{ -+#ifdef DEBUG_IRQL -+ if (current_irql() != DISPATCH_LEVEL) -+ ERROR("irql != DISPATCH_LEVEL"); -+#endif -+ nt_spin_unlock(lock); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/iw_ndis.c linux-5.6.11-ndis/3rdparty/ndiswrapper/iw_ndis.c ---- linux-5.6.11/3rdparty/ndiswrapper/iw_ndis.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/iw_ndis.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,2002 @@ -+ /* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "iw_ndis.h" -+#include "wrapndis.h" -+ -+#ifdef CONFIG_WIRELESS_EXT -+ -+static int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, -+ 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; -+ -+static const char *network_names[] = {"IEEE 802.11FH", "IEEE 802.11b", -+ "IEEE 802.11a", "IEEE 802.11g", "Auto"}; -+ -+static int set_essid(struct ndis_device *wnd, const char *ssid, int ssid_len) -+{ -+ NDIS_STATUS res; -+ struct ndis_essid req; -+ -+ if (ssid_len > NDIS_ESSID_MAX_SIZE) -+ return -EINVAL; -+ -+ memset(&req, 0, sizeof(req)); -+ req.length = ssid_len; -+ if (ssid_len) -+ memcpy(&req.essid, ssid, ssid_len); -+ -+ res = mp_set(wnd, OID_802_11_SSID, &req, sizeof(req)); -+ if (res) { -+ WARNING("setting essid failed (%08X)", res); -+ EXIT2(return -EINVAL); -+ } -+ memcpy(&wnd->essid, &req, sizeof(req)); -+ EXIT2(return 0); -+} -+ -+static int set_iw_auth_mode(struct ndis_device *wnd, int wpa_version, -+ int auth_80211_alg) -+{ -+ NDIS_STATUS res; -+ ULONG auth_mode; -+ -+ ENTER2("%d, %d", wpa_version, auth_80211_alg); -+ if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { -+ if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X) -+ auth_mode = Ndis802_11AuthModeWPA2; -+ else -+ auth_mode = Ndis802_11AuthModeWPA2PSK; -+ } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { -+ if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X) -+ auth_mode = Ndis802_11AuthModeWPA; -+ else if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_PSK) -+ auth_mode = Ndis802_11AuthModeWPAPSK; -+ else -+ auth_mode = Ndis802_11AuthModeWPANone; -+ } else if (auth_80211_alg & IW_AUTH_ALG_SHARED_KEY) { -+ if (auth_80211_alg & IW_AUTH_ALG_OPEN_SYSTEM) -+ auth_mode = Ndis802_11AuthModeAutoSwitch; -+ else -+ auth_mode = Ndis802_11AuthModeShared; -+ } else -+ auth_mode = Ndis802_11AuthModeOpen; -+ -+ res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode); -+ if (res) { -+ WARNING("setting auth mode to %u failed (%08X)", -+ auth_mode, res); -+ if (res == NDIS_STATUS_INVALID_DATA) -+ EXIT2(return -EINVAL); -+ return -EOPNOTSUPP; -+ } -+ wnd->iw_auth_wpa_version = wpa_version; -+ wnd->iw_auth_80211_alg = auth_80211_alg; -+ EXIT2(return 0); -+} -+ -+static int set_auth_mode(struct ndis_device *wnd) -+{ -+ return set_iw_auth_mode(wnd, wnd->iw_auth_wpa_version, -+ wnd->iw_auth_80211_alg); -+} -+ -+static enum ndis_priv_filter ndis_priv_mode(struct ndis_device *wnd) -+{ -+ if (wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2 || -+ wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA) -+ return Ndis802_11PrivFilter8021xWEP; -+ else -+ return Ndis802_11PrivFilterAcceptAll; -+} -+ -+static int set_priv_filter(struct ndis_device *wnd) -+{ -+ NDIS_STATUS res; -+ ULONG flags; -+ -+ flags = ndis_priv_mode(wnd); -+ ENTER2("filter: %d", flags); -+ res = mp_set_int(wnd, OID_802_11_PRIVACY_FILTER, flags); -+ if (res) -+ TRACE2("setting privacy filter to %d failed (%08X)", -+ flags, res); -+ EXIT2(return 0); -+} -+ -+static int set_encr_mode(struct ndis_device *wnd) -+{ -+ return set_iw_encr_mode(wnd, wnd->iw_auth_cipher_pairwise, -+ wnd->iw_auth_cipher_group); -+} -+ -+static int set_assoc_params(struct ndis_device *wnd) -+{ -+ TRACE2("wpa_version=0x%x auth_alg=0x%x key_mgmt=0x%x " -+ "cipher_pairwise=0x%x cipher_group=0x%x", -+ wnd->iw_auth_wpa_version, wnd->iw_auth_80211_alg, -+ wnd->iw_auth_key_mgmt, wnd->iw_auth_cipher_pairwise, -+ wnd->iw_auth_cipher_group); -+ set_auth_mode(wnd); -+ set_priv_filter(wnd); -+ set_encr_mode(wnd); -+ return 0; -+} -+ -+static int iw_set_essid(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ int length; -+ -+ ENTER2(""); -+ /* there is no way to turn off essid other than to set to -+ * random bytes; instead, we use off to mean any */ -+ if (wrqu->essid.flags) { -+ length = wrqu->essid.length; -+ /* Strip '\0' appended by wireless extensions 19 and older */ -+ if (length > 0 && extra[length - 1] == '\0') -+ length--; -+ TRACE2("%d", length); -+ if (length <= 0 || length > NDIS_ESSID_MAX_SIZE) -+ EXIT2(return -EINVAL); -+ } else -+ length = 0; -+ -+ set_assoc_params(wnd); -+ -+ if (set_essid(wnd, extra, length)) -+ EXIT2(return -EINVAL); -+ -+ EXIT2(return 0); -+} -+ -+static int iw_get_essid(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ struct ndis_essid req; -+ -+ ENTER2(""); -+ memset(&req, 0, sizeof(req)); -+ res = mp_query(wnd, OID_802_11_SSID, &req, sizeof(req)); -+ if (res) { -+ WARNING("getting essid failed (%08X)", res); -+ EXIT2(return -EOPNOTSUPP); -+ } -+ memcpy(extra, req.essid, req.length); -+ if (req.length > 0) -+ wrqu->essid.flags = 1; -+ else -+ wrqu->essid.flags = 0; -+ wrqu->essid.length = req.length; -+ EXIT2(return 0); -+} -+ -+/* index must be 0 - N, as per NDIS */ -+static int add_wep_key(struct ndis_device *wnd, char *key, int key_len, -+ int index) -+{ -+ struct ndis_encr_key ndis_key; -+ NDIS_STATUS res; -+ -+ ENTER2("key index: %d, length: %d", index, key_len); -+ if (key_len <= 0 || key_len > NDIS_ENCODING_TOKEN_MAX) { -+ WARNING("invalid key length (%d)", key_len); -+ EXIT2(return -EINVAL); -+ } -+ if (index < 0 || index >= MAX_ENCR_KEYS) { -+ WARNING("invalid key index (%d)", index); -+ EXIT2(return -EINVAL); -+ } -+ ndis_key.struct_size = sizeof(ndis_key); -+ ndis_key.length = key_len; -+ memcpy(&ndis_key.key, key, key_len); -+ ndis_key.index = index; -+ -+ if (index == wnd->encr_info.tx_key_index) { -+ ndis_key.index |= (1 << 31); -+ res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, -+ IW_AUTH_CIPHER_NONE); -+ if (res) -+ WARNING("encryption couldn't be enabled (%08X)", res); -+ } -+ TRACE2("key %d: " MACSTRSEP, index, MAC2STR(key)); -+ res = mp_set(wnd, OID_802_11_ADD_WEP, &ndis_key, sizeof(ndis_key)); -+ if (res) { -+ WARNING("adding encryption key %d failed (%08X)", -+ index+1, res); -+ EXIT2(return -EINVAL); -+ } -+ -+ /* Atheros driver messes up ndis_key during ADD_WEP, so -+ * don't rely on that; instead use info in key and key_len */ -+ wnd->encr_info.keys[index].length = key_len; -+ memcpy(&wnd->encr_info.keys[index].key, key, key_len); -+ -+ EXIT2(return 0); -+} -+ -+static int set_infra_mode(struct ndis_device *wnd, -+ enum ndis_infrastructure_mode mode) -+{ -+ NDIS_STATUS res; -+ unsigned int i; -+ -+ ENTER2("%d", mode); -+ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, -+ &wnd->infrastructure_mode); -+ if (res != NDIS_STATUS_SUCCESS) { -+ WARNING("getting operating mode failed (%08X)", res); -+ EXIT2(return -EINVAL); -+ } -+ if (wnd->infrastructure_mode == mode) -+ EXIT2(return 0); -+ res = mp_set_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, mode); -+ if (res) { -+ WARNING("setting operating mode to %d failed (%08X)", -+ mode, res); -+ EXIT2(return -EINVAL); -+ } -+ /* NDIS drivers clear keys when infrastructure mode is -+ * changed. But Linux tools assume otherwise. So set the -+ * keys */ -+ if (wnd->iw_auth_key_mgmt == 0 || -+ wnd->iw_auth_key_mgmt == IW_AUTH_KEY_MGMT_802_1X) { -+ for (i = 0; i < MAX_ENCR_KEYS; i++) { -+ if (wnd->encr_info.keys[i].length > 0) -+ add_wep_key(wnd, wnd->encr_info.keys[i].key, -+ wnd->encr_info.keys[i].length, i); -+ } -+ } -+ wnd->infrastructure_mode = mode; -+ EXIT2(return 0); -+} -+ -+static int iw_set_infra_mode(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ enum ndis_infrastructure_mode ndis_mode; -+ -+ ENTER2("%d", wrqu->mode); -+ switch (wrqu->mode) { -+ case IW_MODE_ADHOC: -+ ndis_mode = Ndis802_11IBSS; -+ break; -+ case IW_MODE_INFRA: -+ ndis_mode = Ndis802_11Infrastructure; -+ break; -+ case IW_MODE_AUTO: -+ ndis_mode = Ndis802_11AutoUnknown; -+ break; -+ default: -+ EXIT2(return -EINVAL); -+ } -+ -+ if (set_infra_mode(wnd, ndis_mode)) -+ EXIT2(return -EINVAL); -+ -+ EXIT2(return 0); -+} -+ -+static int iw_get_infra_mode(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ int ndis_mode, iw_mode; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &ndis_mode); -+ if (res) { -+ WARNING("getting operating mode failed (%08X)", res); -+ EXIT2(return -EOPNOTSUPP); -+ } -+ -+ switch (ndis_mode) { -+ case Ndis802_11IBSS: -+ iw_mode = IW_MODE_ADHOC; -+ break; -+ case Ndis802_11Infrastructure: -+ iw_mode = IW_MODE_INFRA; -+ break; -+ case Ndis802_11AutoUnknown: -+ iw_mode = IW_MODE_AUTO; -+ break; -+ default: -+ ERROR("invalid operating mode (%u)", ndis_mode); -+ EXIT2(return -EINVAL); -+ } -+ wrqu->mode = iw_mode; -+ EXIT2(return 0); -+} -+ -+static const char *network_type_to_name(int net_type) -+{ -+ if (net_type >= 0 && net_type < ARRAY_SIZE(network_names)) -+ return network_names[net_type]; -+ else -+ return network_names[ARRAY_SIZE(network_names) - 1]; -+} -+ -+static int iw_get_network_type(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ unsigned int network_type; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ res = mp_query_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, -+ &network_type); -+ if (res) { -+ WARNING("getting network type failed: %08X", res); -+ network_type = -1; -+ } -+ strncpy(wrqu->name, network_type_to_name(network_type), -+ sizeof(wrqu->name) - 1); -+ wrqu->name[sizeof(wrqu->name)-1] = 0; -+ return 0; -+} -+ -+static int iw_get_freq(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ struct ndis_configuration req; -+ -+ ENTER2(""); -+ memset(&req, 0, sizeof(req)); -+ res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); -+ if (res) { -+ WARNING("getting configuration failed (%08X)", res); -+ EXIT2(return -EOPNOTSUPP); -+ } -+ -+ memset(&(wrqu->freq), 0, sizeof(struct iw_freq)); -+ -+ /* see comment in wireless.h above the "struct iw_freq" -+ definition for an explanation of this if -+ NOTE: 1000000 is due to the kHz -+ */ -+ if (req.ds_config > 1000000) { -+ wrqu->freq.m = req.ds_config / 10; -+ wrqu->freq.e = 1; -+ } -+ else -+ wrqu->freq.m = req.ds_config; -+ -+ /* convert from kHz to Hz */ -+ wrqu->freq.e += 3; -+ -+ return 0; -+} -+ -+static int iw_set_freq(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ struct ndis_configuration req; -+ -+ ENTER2(""); -+ /* this OID is valid only when not associated */ -+ if (netif_carrier_ok(wnd->net_dev)) -+ EXIT2(return 0); -+ memset(&req, 0, sizeof(req)); -+ res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); -+ if (res) { -+ WARNING("getting configuration failed (%08X)", res); -+ EXIT2(return 0); -+ } -+ -+ if (wrqu->freq.m < 1000 && wrqu->freq.e == 0) { -+ if (wrqu->freq.m >= 1 && wrqu->freq.m <= ARRAY_SIZE(freq_chan)) -+ req.ds_config = freq_chan[wrqu->freq.m - 1] * 1000; -+ else -+ return -EINVAL; -+ } else { -+ int i; -+ req.ds_config = wrqu->freq.m; -+ for (i = wrqu->freq.e; i > 0; i--) -+ req.ds_config *= 10; -+ req.ds_config /= 1000; -+ } -+ res = mp_set(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); -+ if (res) -+ WARNING("setting configuration failed (%08X)", res); -+ return 0; -+} -+ -+static int iw_get_tx_power(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ ndis_tx_power_level ndis_power; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, -+ &ndis_power, sizeof(ndis_power)); -+ if (res) -+ return -EOPNOTSUPP; -+ wrqu->txpower.flags = IW_TXPOW_MWATT; -+ wrqu->txpower.disabled = 0; -+ wrqu->txpower.fixed = 0; -+ wrqu->txpower.value = ndis_power; -+ return 0; -+} -+ -+static int iw_set_tx_power(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ ndis_tx_power_level ndis_power; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ if (wrqu->txpower.disabled) -+ ndis_power = 0; -+ else { -+ if (wrqu->txpower.flags == IW_TXPOW_MWATT) -+ ndis_power = wrqu->txpower.value; -+ else { // wrqu->txpower.flags == IW_TXPOW_DBM -+ if (wrqu->txpower.value > 20) -+ ndis_power = 128; -+ else if (wrqu->txpower.value < -43) -+ ndis_power = 127; -+ else { -+ signed char tmp; -+ tmp = wrqu->txpower.value; -+ tmp = -12 - tmp; -+ tmp <<= 2; -+ ndis_power = (unsigned char)tmp; -+ } -+ } -+ } -+ TRACE2("%d", ndis_power); -+ res = mp_set(wnd, OID_802_11_TX_POWER_LEVEL, -+ &ndis_power, sizeof(ndis_power)); -+ if (res) -+ EXIT2(return -EOPNOTSUPP); -+ if (ndis_power == 0) -+ res = disassociate(wnd, 0); -+ EXIT2(return 0); -+} -+ -+static int iw_get_bitrate(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ ULONG ndis_rate; -+ int res; -+ -+ ENTER2(""); -+ res = mp_query(wnd, OID_GEN_LINK_SPEED, &ndis_rate, sizeof(ndis_rate)); -+ if (res) { -+ WARNING("getting bitrate failed (%08X)", res); -+ ndis_rate = 0; -+ } -+ -+ wrqu->bitrate.value = ndis_rate * 100; -+ return 0; -+} -+ -+static int iw_set_bitrate(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ int i, n; -+ NDIS_STATUS res; -+ UCHAR rates[NDIS_MAX_RATES_EX]; -+ -+ ENTER2(""); -+ if (wrqu->bitrate.fixed == 0) -+ EXIT2(return 0); -+ -+ res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, &rates, -+ sizeof(rates), &n, NULL); -+ if (res) { -+ WARNING("getting bit rate failed (%08X)", res); -+ EXIT2(return 0); -+ } -+ for (i = 0; i < n; i++) { -+ if (rates[i] & 0x80) -+ continue; -+ if ((rates[i] & 0x7f) * 500000 > wrqu->bitrate.value) { -+ TRACE2("setting rate %d to 0", -+ (rates[i] & 0x7f) * 500000); -+ rates[i] = 0; -+ } -+ } -+ -+ res = mp_set(wnd, OID_802_11_DESIRED_RATES, &rates, n); -+ if (res) { -+ WARNING("setting bit rate failed (%08X)", res); -+ EXIT2(return 0); -+ } -+ -+ return 0; -+} -+ -+static int iw_set_dummy(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ /* Do nothing. Used for ioctls that are not implemented. */ -+ return 0; -+} -+ -+static int iw_get_rts_threshold(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ ndis_rts_threshold threshold; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ res = mp_query(wnd, OID_802_11_RTS_THRESHOLD, -+ &threshold, sizeof(threshold)); -+ if (res) -+ return -EOPNOTSUPP; -+ -+ wrqu->rts.value = threshold; -+ return 0; -+} -+ -+static int iw_set_rts_threshold(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ ndis_rts_threshold threshold; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ threshold = wrqu->rts.value; -+ res = mp_set(wnd, OID_802_11_RTS_THRESHOLD, -+ &threshold, sizeof(threshold)); -+ if (res == NDIS_STATUS_INVALID_DATA) -+ return -EINVAL; -+ if (res) -+ return -EOPNOTSUPP; -+ -+ return 0; -+} -+ -+static int iw_get_frag_threshold(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ ndis_fragmentation_threshold frag_threshold; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, -+ &frag_threshold, sizeof(frag_threshold)); -+ if (res) -+ return -ENOTSUPP; -+ -+ wrqu->frag.value = frag_threshold; -+ return 0; -+} -+ -+static int iw_set_frag_threshold(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ ndis_rts_threshold threshold; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ threshold = wrqu->frag.value; -+ res = mp_set(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, -+ &threshold, sizeof(threshold)); -+ if (res == NDIS_STATUS_INVALID_DATA) -+ return -EINVAL; -+ if (res) -+ return -EOPNOTSUPP; -+ return 0; -+} -+ -+int get_ap_address(struct ndis_device *wnd, mac_address ap_addr) -+{ -+ NDIS_STATUS res; -+ -+ res = mp_query(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN); -+ TRACE2(MACSTRSEP, MAC2STR(ap_addr)); -+ if (res) { -+ TRACE2("res: %08X", res); -+ memset(ap_addr, 0x0, ETH_ALEN); -+ EXIT2(return -EOPNOTSUPP); -+ } -+ EXIT2(return 0); -+} -+ -+static int iw_get_ap_address(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ mac_address ap_addr; -+ -+ ENTER2(""); -+ get_ap_address(wnd, ap_addr); -+ memcpy(wrqu->ap_addr.sa_data, ap_addr, ETH_ALEN); -+ wrqu->ap_addr.sa_family = ARPHRD_ETHER; -+ EXIT2(return 0); -+} -+ -+static int iw_set_ap_address(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ mac_address ap_addr; -+ -+ ENTER2(""); -+ memcpy(ap_addr, wrqu->ap_addr.sa_data, ETH_ALEN); -+ TRACE2(MACSTRSEP, MAC2STR(ap_addr)); -+ res = mp_set(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN); -+ /* user apps may set ap's mac address, which is not required; -+ * they may fail to work if this function fails, so return -+ * success */ -+ if (res) -+ WARNING("setting AP mac address failed (%08X)", res); -+ -+ EXIT2(return 0); -+} -+ -+int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode) -+{ -+ NDIS_STATUS res; -+ -+ ENTER2("%d", auth_mode); -+ res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode); -+ if (res) { -+ WARNING("setting auth mode to %u failed (%08X)", -+ auth_mode, res); -+ if (res == NDIS_STATUS_INVALID_DATA) -+ EXIT2(return -EINVAL); -+ return -EOPNOTSUPP; -+ } -+ switch (auth_mode) { -+ case Ndis802_11AuthModeWPA: -+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA; -+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X; -+ break; -+ case Ndis802_11AuthModeWPAPSK: -+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA; -+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; -+ break; -+ case Ndis802_11AuthModeWPANone: -+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; -+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; -+ break; -+ case Ndis802_11AuthModeWPA2: -+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2; -+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X; -+ break; -+ case Ndis802_11AuthModeWPA2PSK: -+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2; -+ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; -+ break; -+ case Ndis802_11AuthModeOpen: -+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; -+ wnd->iw_auth_80211_alg = IW_AUTH_ALG_OPEN_SYSTEM; -+ break; -+ case Ndis802_11AuthModeShared: -+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; -+ wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY; -+ break; -+ case Ndis802_11AuthModeAutoSwitch: -+ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; -+ wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY; -+ wnd->iw_auth_80211_alg |= IW_AUTH_ALG_OPEN_SYSTEM; -+ break; -+ default: -+ WARNING("invalid authentication algorithm: %d", auth_mode); -+ break; -+ } -+ EXIT2(return 0); -+} -+ -+int get_ndis_auth_mode(struct ndis_device *wnd) -+{ -+ ULONG mode; -+ NDIS_STATUS res; -+ -+ res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &mode); -+ if (res) { -+ WARNING("getting authentication mode failed (%08X)", res); -+ EXIT2(return -EOPNOTSUPP); -+ } -+ TRACE2("%d", mode); -+ return mode; -+} -+ -+int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise, -+ int cipher_groupwise) -+{ -+ NDIS_STATUS res; -+ ULONG ndis_mode; -+ -+ ENTER2("%d, %d", cipher_pairwise, cipher_groupwise); -+ if (cipher_pairwise & IW_AUTH_CIPHER_CCMP) -+ ndis_mode = Ndis802_11Encryption3Enabled; -+ else if (cipher_pairwise & IW_AUTH_CIPHER_TKIP) -+ ndis_mode = Ndis802_11Encryption2Enabled; -+ else if (cipher_pairwise & -+ (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) -+ ndis_mode = Ndis802_11Encryption1Enabled; -+ else if (cipher_groupwise & IW_AUTH_CIPHER_CCMP) -+ ndis_mode = Ndis802_11Encryption3Enabled; -+ else if (cipher_groupwise & IW_AUTH_CIPHER_TKIP) -+ ndis_mode = Ndis802_11Encryption2Enabled; -+ else -+ ndis_mode = Ndis802_11EncryptionDisabled; -+ -+ res = mp_set_int(wnd, OID_802_11_ENCRYPTION_STATUS, ndis_mode); -+ if (res) { -+ WARNING("setting encryption mode to %u failed (%08X)", -+ ndis_mode, res); -+ if (res == NDIS_STATUS_INVALID_DATA) -+ EXIT2(return -EINVAL); -+ return -EOPNOTSUPP; -+ } -+ wnd->iw_auth_cipher_pairwise = cipher_pairwise; -+ wnd->iw_auth_cipher_group = cipher_groupwise; -+ EXIT2(return 0); -+} -+ -+int get_ndis_encr_mode(struct ndis_device *wnd) -+{ -+ ULONG mode; -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &mode); -+ if (res) { -+ WARNING("getting encryption status failed (%08X)", res); -+ EXIT2(return -EOPNOTSUPP); -+ } else -+ EXIT2(return mode); -+} -+ -+static int iw_get_encr(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ int index, mode; -+ struct encr_info *encr_info = &wnd->encr_info; -+ -+ ENTER2("wnd = %p", wnd); -+ wrqu->data.length = 0; -+ extra[0] = 0; -+ -+ index = (wrqu->encoding.flags & IW_ENCODE_INDEX); -+ TRACE2("index = %u", index); -+ if (index > 0) -+ index--; -+ else -+ index = encr_info->tx_key_index; -+ -+ if (index < 0 || index >= MAX_ENCR_KEYS) { -+ WARNING("encryption index out of range (%u)", index); -+ EXIT2(return -EINVAL); -+ } -+ -+ if (index != encr_info->tx_key_index) { -+ if (encr_info->keys[index].length > 0) { -+ wrqu->data.flags |= IW_ENCODE_ENABLED; -+ wrqu->data.length = encr_info->keys[index].length; -+ memcpy(extra, encr_info->keys[index].key, -+ encr_info->keys[index].length); -+ } -+ else -+ wrqu->data.flags |= IW_ENCODE_DISABLED; -+ -+ EXIT2(return 0); -+ } -+ -+ /* transmit key */ -+ mode = get_ndis_encr_mode(wnd); -+ if (mode < 0) -+ EXIT2(return -EOPNOTSUPP); -+ -+ if (mode == Ndis802_11EncryptionDisabled || -+ mode == Ndis802_11EncryptionNotSupported) -+ wrqu->data.flags |= IW_ENCODE_DISABLED; -+ else { -+ if (mode == Ndis802_11Encryption1KeyAbsent || -+ mode == Ndis802_11Encryption2KeyAbsent || -+ mode == Ndis802_11Encryption3KeyAbsent) -+ wrqu->data.flags |= IW_ENCODE_NOKEY; -+ else { -+ wrqu->data.flags |= IW_ENCODE_ENABLED; -+ wrqu->encoding.flags |= index+1; -+ wrqu->data.length = encr_info->keys[index].length; -+ memcpy(extra, encr_info->keys[index].key, -+ encr_info->keys[index].length); -+ } -+ } -+ mode = get_ndis_auth_mode(wnd); -+ if (mode < 0) -+ EXIT2(return -EOPNOTSUPP); -+ -+ if (mode == Ndis802_11AuthModeOpen) -+ wrqu->data.flags |= IW_ENCODE_OPEN; -+ else if (mode == Ndis802_11AuthModeAutoSwitch) -+ wrqu->data.flags |= IW_ENCODE_RESTRICTED; -+ else // Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA etc. -+ wrqu->data.flags |= IW_ENCODE_RESTRICTED; -+ -+ EXIT2(return 0); -+} -+ -+/* remove_key is for both wep and wpa */ -+static int remove_key(struct ndis_device *wnd, int index, -+ mac_address bssid) -+{ -+ NDIS_STATUS res; -+ if (wnd->encr_info.keys[index].length == 0) -+ EXIT2(return 0); -+ wnd->encr_info.keys[index].length = 0; -+ memset(&wnd->encr_info.keys[index].key, 0, -+ sizeof(wnd->encr_info.keys[index].length)); -+ if (wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_TKIP || -+ wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_CCMP || -+ wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_TKIP || -+ wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_CCMP) { -+ struct ndis_remove_key rmkey; -+ rmkey.struct_size = sizeof(rmkey); -+ rmkey.index = index; -+ if (bssid) { -+ /* pairwise key */ -+ if (memcmp(bssid, "\xff\xff\xff\xff\xff\xff", -+ ETH_ALEN) != 0) -+ rmkey.index |= (1 << 30); -+ memcpy(rmkey.bssid, bssid, sizeof(rmkey.bssid)); -+ } else -+ memset(rmkey.bssid, 0xff, sizeof(rmkey.bssid)); -+ if (mp_set(wnd, OID_802_11_REMOVE_KEY, &rmkey, sizeof(rmkey))) -+ EXIT2(return -EINVAL); -+ } else { -+ ndis_key_index keyindex = index; -+ res = mp_set_int(wnd, OID_802_11_REMOVE_WEP, keyindex); -+ if (res) { -+ WARNING("removing encryption key %d failed (%08X)", -+ keyindex, res); -+ EXIT2(return -EINVAL); -+ } -+ } -+ /* if it is transmit key, disable encryption */ -+ if (index == wnd->encr_info.tx_key_index) { -+ res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, -+ IW_AUTH_CIPHER_NONE); -+ if (res) -+ WARNING("changing encr status failed (%08X)", res); -+ } -+ TRACE2("key %d removed", index); -+ EXIT2(return 0); -+} -+ -+static int iw_set_wep(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ unsigned int index, key_len; -+ struct encr_info *encr_info = &wnd->encr_info; -+ unsigned char *key; -+ -+ ENTER2(""); -+ index = (wrqu->encoding.flags & IW_ENCODE_INDEX); -+ TRACE2("index = %u", index); -+ -+ /* iwconfig gives index as 1 - N */ -+ if (index > 0) -+ index--; -+ else -+ index = encr_info->tx_key_index; -+ -+ if (index >= MAX_ENCR_KEYS) { -+ WARNING("encryption index out of range (%u)", index); -+ EXIT2(return -EINVAL); -+ } -+ -+ /* remove key if disabled */ -+ if (wrqu->data.flags & IW_ENCODE_DISABLED) { -+ if (remove_key(wnd, index, NULL)) -+ EXIT2(return -EINVAL); -+ else -+ EXIT2(return 0); -+ } -+ -+ /* global encryption state (for all keys) */ -+ if (wrqu->data.flags & IW_ENCODE_OPEN) -+ res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen); -+ else // if (wrqu->data.flags & IW_ENCODE_RESTRICTED) -+ res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeShared); -+ if (res) { -+ WARNING("setting authentication mode failed (%08X)", res); -+ EXIT2(return -EINVAL); -+ } -+ -+ TRACE2("key length: %d", wrqu->data.length); -+ -+ if (wrqu->data.length > 0) { -+ key_len = wrqu->data.length; -+ key = extra; -+ } else { // must be set as tx key -+ if (encr_info->keys[index].length == 0) { -+ WARNING("key %d is not set", index+1); -+ EXIT2(return -EINVAL); -+ } -+ key_len = encr_info->keys[index].length; -+ key = encr_info->keys[index].key; -+ encr_info->tx_key_index = index; -+ } -+ -+ if (add_wep_key(wnd, key, key_len, index)) -+ EXIT2(return -EINVAL); -+ -+ if (index == encr_info->tx_key_index) { -+ /* if transmit key is at index other than 0, some -+ * drivers, at least Atheros and TI, want another -+ * (global) non-transmit key to be set; don't know why */ -+ if (index != 0) { -+ int i; -+ for (i = 0; i < MAX_ENCR_KEYS; i++) -+ if (i != index && -+ encr_info->keys[i].length != 0) -+ break; -+ if (i == MAX_ENCR_KEYS) { -+ if (index == 0) -+ i = index + 1; -+ else -+ i = index - 1; -+ if (add_wep_key(wnd, key, key_len, i)) -+ WARNING("couldn't add broadcast key" -+ " at %d", i); -+ } -+ } -+ /* ndis drivers want essid to be set after setting encr */ -+ set_essid(wnd, wnd->essid.essid, wnd->essid.length); -+ } -+ EXIT2(return 0); -+} -+ -+static int iw_set_nick(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ if (wrqu->data.length >= sizeof(wnd->nick)) -+ return -EINVAL; -+ memcpy(wnd->nick, extra, wrqu->data.length); -+ wnd->nick[wrqu->data.length] = 0; -+ return 0; -+} -+ -+static int iw_get_nick(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ wrqu->data.length = strlen(wnd->nick); -+ memcpy(extra, wnd->nick, wrqu->data.length); -+ return 0; -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) && !defined(IW_REQUEST_FLAG_COMPAT) -+#define iwe_stream_add_event(a, b, c, d, e) iwe_stream_add_event(b, c, d, e) -+#define iwe_stream_add_point(a, b, c, d, e) iwe_stream_add_point(b, c, d, e) -+#define iwe_stream_add_value(a, b, c, d, e, f) \ -+ iwe_stream_add_value(b, c, d, e, f) -+#define iwe_stream_lcp_len(a) IW_EV_LCP_LEN -+#endif -+ -+static char *ndis_translate_scan(struct net_device *dev, -+ struct iw_request_info *info, char *event, -+ char *end_buf, void *item) -+{ -+ struct iw_event iwe; -+ char *current_val; -+ char *ret; -+ int i, nrates; -+ unsigned char custom_str[64]; -+ struct ndis_wlan_bssid *bssid; -+ struct ndis_wlan_bssid_ex *bssid_ex; -+ int extended; -+ -+ ENTER2("%p, %p", event, item); -+ bssid = item; -+ bssid_ex = item; -+ extended = (bssid->length > offsetof(struct ndis_wlan_bssid_ex, var)); -+ -+ /* add mac address */ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = SIOCGIWAP; -+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; -+ iwe.len = IW_EV_ADDR_LEN; -+ memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); -+ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_ADDR_LEN); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ /* add essid */ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = SIOCGIWESSID; -+ iwe.u.data.length = bssid->ssid.length; -+ if (iwe.u.data.length > IW_ESSID_MAX_SIZE) -+ iwe.u.data.length = IW_ESSID_MAX_SIZE; -+ iwe.u.data.flags = 1; -+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; -+ ret = iwe_stream_add_point(info, event, end_buf, &iwe, -+ bssid->ssid.essid); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ /* add protocol name */ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = SIOCGIWNAME; -+ strncpy(iwe.u.name, network_type_to_name(bssid->net_type), IFNAMSIZ - 1); -+ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_CHAR_LEN); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ /* add mode */ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = SIOCGIWMODE; -+ if (bssid->mode == Ndis802_11IBSS) -+ iwe.u.mode = IW_MODE_ADHOC; -+ else if (bssid->mode == Ndis802_11Infrastructure) -+ iwe.u.mode = IW_MODE_MASTER; -+ else // if (bssid->mode == Ndis802_11AutoUnknown) -+ iwe.u.mode = IW_MODE_AUTO; -+ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_UINT_LEN); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ /* add freq */ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = SIOCGIWFREQ; -+ iwe.u.freq.m = bssid->config.ds_config; -+ if (bssid->config.ds_config > 1000000) { -+ iwe.u.freq.m = bssid->config.ds_config / 10; -+ iwe.u.freq.e = 1; -+ } -+ else -+ iwe.u.freq.m = bssid->config.ds_config; -+ /* convert from kHz to Hz */ -+ iwe.u.freq.e += 3; -+ iwe.len = IW_EV_FREQ_LEN; -+ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_FREQ_LEN); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ /* add qual */ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = IWEVQUAL; -+ i = 100 * (bssid->rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE); -+ if (i < 0) -+ i = 0; -+ else if (i > 100) -+ i = 100; -+ iwe.u.qual.level = bssid->rssi; -+ iwe.u.qual.noise = WL_NOISE; -+ iwe.u.qual.qual = i; -+ iwe.len = IW_EV_QUAL_LEN; -+ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_QUAL_LEN); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ /* add key info */ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = SIOCGIWENCODE; -+ if (bssid->privacy == Ndis802_11PrivFilterAcceptAll) -+ iwe.u.data.flags = IW_ENCODE_DISABLED; -+ else -+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; -+ iwe.u.data.length = 0; -+ iwe.len = IW_EV_POINT_LEN; -+ ret = iwe_stream_add_point(info, event, end_buf, &iwe, -+ bssid->ssid.essid); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ /* add rate */ -+ memset(&iwe, 0, sizeof(iwe)); -+ current_val = event + iwe_stream_lcp_len(info); -+ iwe.cmd = SIOCGIWRATE; -+ if (extended) -+ nrates = ARRAY_SIZE(bssid->rates); -+ else -+ nrates = ARRAY_SIZE(bssid_ex->rates_ex); -+ for (i = 0; i < nrates; i++) { -+ if (bssid_ex->rates_ex[i] & 0x7f) { -+ iwe.u.bitrate.value = ((bssid->rates[i] & 0x7f) * -+ 500000); -+ ret = iwe_stream_add_value(info, event, current_val, -+ end_buf, &iwe, -+ IW_EV_PARAM_LEN); -+ if (ret == current_val) -+ return NULL; -+ current_val = ret; -+ } -+ } -+ -+ if ((current_val - event) > iwe_stream_lcp_len(info)) -+ event = current_val; -+ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = IWEVCUSTOM; -+ sprintf(custom_str, "bcn_int=%d", bssid->config.beacon_period); -+ iwe.u.data.length = strlen(custom_str); -+ ret = iwe_stream_add_point(info, event, end_buf, &iwe, custom_str); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = IWEVCUSTOM; -+ sprintf(custom_str, "atim=%u", bssid->config.atim_window); -+ iwe.u.data.length = strlen(custom_str); -+ ret = iwe_stream_add_point(info, event, end_buf, &iwe, custom_str); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ -+ TRACE2("%d, %zu", bssid->length, sizeof(*bssid)); -+ if (extended) { -+ struct ndis_variable_ies *iep = bssid_ex->var; -+ unsigned char *end = (unsigned char *)&bssid_ex->fixed + -+ bssid_ex->ie_length; -+ -+ while (&iep->length < end && &iep->data[iep->length] <= end) { -+ unsigned char ielen = iep->length + 2; -+ -+ memset(&iwe, 0, sizeof(iwe)); -+ iwe.cmd = IWEVGENIE; -+ iwe.u.data.length = ielen; -+ ret = iwe_stream_add_point(info, event, end_buf, &iwe, -+ (char *)iep); -+ if (ret == event) -+ return NULL; -+ event = ret; -+ iep = (typeof(iep))&iep->data[iep->length]; -+ } -+ } -+ TRACE2("event = %p, current_val = %p", event, current_val); -+ EXIT2(return event); -+} -+ -+static int set_scan(struct ndis_device *wnd) -+{ -+ NDIS_STATUS res; -+ -+ ENTER2(""); -+ res = mp_set(wnd, OID_802_11_BSSID_LIST_SCAN, NULL, 0); -+ if (res) { -+ WARNING("scanning failed (%08X)", res); -+ EXIT2(return -EOPNOTSUPP); -+ } -+ wnd->scan_timestamp = jiffies; -+ EXIT2(return 0); -+} -+ -+static int iw_set_scan(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ return set_scan(wnd); -+} -+ -+static int iw_get_scan(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ unsigned int i, buf_len, needed, data_len; -+ NDIS_STATUS res; -+ struct ndis_bssid_list *bssid_list = NULL; -+ char *event = extra; -+ struct ndis_wlan_bssid *cur_item; -+ -+ ENTER2(""); -+ if (time_before(jiffies, wnd->scan_timestamp + 3 * HZ)) -+ return -EAGAIN; -+ /* try with space for a few scan items */ -+ buf_len = sizeof(ULONG) + offsetof(struct ndis_wlan_bssid_ex, var) * 8; -+ -+ /* Try many times, as the needed space may grow between queries */ -+ for (i = 0; i < 10; i++) { -+ bssid_list = kzalloc(buf_len, GFP_KERNEL); -+ if (!bssid_list) { -+ ERROR("couldn't allocate %u bytes for scan results", -+ buf_len); -+ return -ENOMEM; -+ } -+ -+ needed = 0; -+ data_len = 0; -+ res = mp_query_info(wnd, OID_802_11_BSSID_LIST, bssid_list, -+ buf_len, &data_len, &needed); -+ TRACE2("try %d: given %d bytes, needed %d, written %d", -+ i, buf_len, needed, data_len); -+ if (needed <= buf_len) -+ break; -+ kfree(bssid_list); -+ buf_len = needed; -+ } -+ if (res) { -+ WARNING("getting BSSID list failed (%08X)", res); -+ kfree(bssid_list); -+ EXIT2(return -EOPNOTSUPP); -+ } -+ -+ /* some drivers don't set bssid_list->num_items to 0 if -+ OID_802_11_BSSID_LIST returns no items (prism54 driver, e.g.,) */ -+ TRACE2("items: %d", bssid_list->num_items); -+ cur_item = &bssid_list->bssid[0]; -+ for (i = 0; i < bssid_list->num_items; i++) { -+ TRACE2("item %d: len %d, remaining data %d", -+ i, cur_item->length, data_len); -+ /* drop truncated items */ -+ if (cur_item->length > data_len) -+ break; -+ event = ndis_translate_scan(dev, info, event, -+ extra + wrqu->data.length, -+ cur_item); -+ if (!event) { -+ kfree(bssid_list); -+ return -E2BIG; -+ } -+ data_len -= cur_item->length; -+ cur_item = (struct ndis_wlan_bssid *)((char *)cur_item + -+ cur_item->length); -+ } -+ wrqu->data.length = event - extra; -+ wrqu->data.flags = 0; -+ kfree(bssid_list); -+ EXIT2(return 0); -+} -+ -+static int iw_set_power_mode(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ enum ndis_power power_mode; -+ -+ if (wrqu->power.disabled == 1) -+ power_mode = NDIS_POWER_OFF; -+ else if (wrqu->power.flags & IW_POWER_MIN) -+ power_mode = NDIS_POWER_MIN; -+ else // if (wrqu->power.flags & IW_POWER_MAX) -+ power_mode = NDIS_POWER_MAX; -+ -+ TRACE2("%d", power_mode); -+ res = mp_set(wnd, OID_802_11_POWER_MODE, -+ &power_mode, sizeof(power_mode)); -+ if (res) -+ WARNING("setting power mode failed (%08X)", res); -+ return 0; -+} -+ -+static int iw_get_power_mode(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ enum ndis_power power_mode; -+ -+ ENTER2(""); -+ res = mp_query(wnd, OID_802_11_POWER_MODE, -+ &power_mode, sizeof(power_mode)); -+ if (res) -+ return -ENOTSUPP; -+ -+ if (power_mode == NDIS_POWER_OFF) -+ wrqu->power.disabled = 1; -+ else { -+ if (wrqu->power.flags != 0) -+ return 0; -+ wrqu->power.flags |= IW_POWER_ALL_R; -+ wrqu->power.flags |= IW_POWER_TIMEOUT; -+ wrqu->power.value = 0; -+ wrqu->power.disabled = 0; -+ -+ if (power_mode == NDIS_POWER_MIN) -+ wrqu->power.flags |= IW_POWER_MIN; -+ else // if (power_mode == NDIS_POWER_MAX) -+ wrqu->power.flags |= IW_POWER_MAX; -+ } -+ return 0; -+} -+ -+static int iw_get_sensitivity(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ ndis_rssi rssi_trigger; -+ -+ ENTER2(""); -+ res = mp_query(wnd, OID_802_11_RSSI_TRIGGER, -+ &rssi_trigger, sizeof(rssi_trigger)); -+ if (res) -+ return -EOPNOTSUPP; -+ wrqu->param.value = rssi_trigger; -+ wrqu->param.disabled = (rssi_trigger == 0); -+ wrqu->param.fixed = 1; -+ return 0; -+} -+ -+static int iw_set_sensitivity(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ ndis_rssi rssi_trigger; -+ -+ ENTER2(""); -+ if (wrqu->param.disabled) -+ rssi_trigger = 0; -+ else -+ rssi_trigger = wrqu->param.value; -+ res = mp_set(wnd, OID_802_11_RSSI_TRIGGER, -+ &rssi_trigger, sizeof(rssi_trigger)); -+ if (res == NDIS_STATUS_INVALID_DATA) -+ return -EINVAL; -+ if (res) -+ return -EOPNOTSUPP; -+ return 0; -+} -+ -+static int iw_get_ndis_stats(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ struct iw_statistics *stats = &wnd->iw_stats; -+ memcpy(&wrqu->qual, &stats->qual, sizeof(stats->qual)); -+ return 0; -+} -+ -+static int iw_get_range(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct iw_range *range = (struct iw_range *)extra; -+ struct iw_point *data = &wrqu->data; -+ struct ndis_device *wnd = netdev_priv(dev); -+ unsigned int i, n; -+ NDIS_STATUS res; -+ UCHAR rates[NDIS_MAX_RATES_EX]; -+ ndis_tx_power_level tx_power; -+ -+ ENTER2(""); -+ data->length = sizeof(struct iw_range); -+ memset(range, 0, sizeof(struct iw_range)); -+ -+ range->txpower_capa = IW_TXPOW_MWATT; -+ range->num_txpower = 0; -+ -+ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, -+ &tx_power, sizeof(tx_power)); -+ if (!res) { -+ range->num_txpower = 1; -+ range->txpower[0] = tx_power; -+ } -+ -+ range->we_version_compiled = WIRELESS_EXT; -+ range->we_version_source = 19; -+ -+ range->retry_capa = IW_RETRY_LIMIT; -+ range->retry_flags = IW_RETRY_LIMIT; -+ range->min_retry = 0; -+ range->max_retry = 255; -+ -+ range->num_channels = 1; -+ -+ range->max_qual.qual = 100; -+ range->max_qual.level = 154; -+ range->max_qual.noise = 154; -+ range->sensitivity = 3; -+ -+ range->max_encoding_tokens = 4; -+ range->num_encoding_sizes = 2; -+ range->encoding_size[0] = 5; -+ range->encoding_size[1] = 13; -+ -+ range->num_bitrates = 0; -+ memset(&rates, 0, sizeof(rates)); -+ res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, -+ &rates, sizeof(rates), &n, NULL); -+ if (res) -+ WARNING("getting bit rates failed: %08X", res); -+ else { -+ for (i = 0; i < n && range->num_bitrates < IW_MAX_BITRATES; i++) -+ if (rates[i] & 0x80) -+ continue; -+ else if (rates[i] & 0x7f) { -+ range->bitrate[range->num_bitrates] = -+ (rates[i] & 0x7f) * 500000; -+ range->num_bitrates++; -+ } -+ } -+ -+ range->num_channels = ARRAY_SIZE(freq_chan); -+ -+ for (i = 0; i < ARRAY_SIZE(freq_chan) && i < IW_MAX_FREQUENCIES; i++) { -+ range->freq[i].i = i + 1; -+ range->freq[i].m = freq_chan[i] * 100000; -+ range->freq[i].e = 1; -+ } -+ range->num_frequency = i; -+ -+ range->min_rts = 0; -+ range->max_rts = 2347; -+ range->min_frag = 256; -+ range->max_frag = 2346; -+ -+ /* Event capability (kernel + driver) */ -+ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | -+ IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | -+ IW_EVENT_CAPA_MASK(SIOCGIWAP) | -+ IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); -+ range->event_capa[1] = IW_EVENT_CAPA_K_1; -+ range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | -+ IW_EVENT_CAPA_MASK(IWEVCUSTOM) | -+ IW_EVENT_CAPA_MASK(IWEVREGISTERED) | -+ IW_EVENT_CAPA_MASK(IWEVEXPIRED)); -+ -+ range->enc_capa = 0; -+ -+ if (test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr)) -+ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; -+ if (test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr)) -+ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; -+ -+ if (test_bit(Ndis802_11AuthModeWPA, &wnd->capa.auth) || -+ test_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth)) -+ range->enc_capa |= IW_ENC_CAPA_WPA; -+ if (test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) || -+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth)) -+ range->enc_capa |= IW_ENC_CAPA_WPA2; -+ -+ return 0; -+} -+ -+void set_default_iw_params(struct ndis_device *wnd) -+{ -+ wnd->iw_auth_key_mgmt = 0; -+ wnd->iw_auth_wpa_version = 0; -+ set_infra_mode(wnd, Ndis802_11Infrastructure); -+ set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen); -+ set_priv_filter(wnd); -+ set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); -+} -+ -+static int deauthenticate(struct ndis_device *wnd) -+{ -+ int ret; -+ -+ ENTER2(""); -+ ret = disassociate(wnd, 1); -+ set_default_iw_params(wnd); -+ EXIT2(return ret); -+} -+ -+NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid) -+{ -+ NDIS_STATUS res; -+ u8 buf[NDIS_ESSID_MAX_SIZE]; -+ int i; -+ -+ TRACE2(""); -+ res = mp_set(wnd, OID_802_11_DISASSOCIATE, NULL, 0); -+ /* disassociate causes radio to be turned off; if reset_ssid -+ * is given, set ssid to random to enable radio */ -+ if (reset_ssid) { -+ get_random_bytes(buf, sizeof(buf)); -+ for (i = 0; i < sizeof(buf); i++) -+ buf[i] = 'a' + (buf[i] % 26); -+ set_essid(wnd, buf, sizeof(buf)); -+ } -+ return res; -+} -+ -+static int iw_set_mlme(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ struct iw_mlme *mlme = (struct iw_mlme *)extra; -+ -+ ENTER2(""); -+ switch (mlme->cmd) { -+ case IW_MLME_DEAUTH: -+ return deauthenticate(wnd); -+ case IW_MLME_DISASSOC: -+ TRACE2("cmd=%d reason_code=%d", mlme->cmd, mlme->reason_code); -+ return disassociate(wnd, 1); -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static int iw_set_genie(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ /* -+ * NDIS drivers do not allow IEs to be configured; this is -+ * done by the driver based on other configuration. Return 0 -+ * to avoid causing issues with user space programs that -+ * expect this function to succeed. -+ */ -+ return 0; -+} -+ -+static int iw_set_auth(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ TRACE2("index=%d value=%d", wrqu->param.flags & IW_AUTH_INDEX, -+ wrqu->param.value); -+ switch (wrqu->param.flags & IW_AUTH_INDEX) { -+ case IW_AUTH_WPA_VERSION: -+ wnd->iw_auth_wpa_version = wrqu->param.value; -+ break; -+ case IW_AUTH_CIPHER_PAIRWISE: -+ wnd->iw_auth_cipher_pairwise = wrqu->param.value; -+ break; -+ case IW_AUTH_CIPHER_GROUP: -+ wnd->iw_auth_cipher_group = wrqu->param.value; -+ break; -+ case IW_AUTH_KEY_MGMT: -+ wnd->iw_auth_key_mgmt = wrqu->param.value; -+ break; -+ case IW_AUTH_80211_AUTH_ALG: -+ wnd->iw_auth_80211_alg = wrqu->param.value; -+ break; -+ case IW_AUTH_WPA_ENABLED: -+ if (wrqu->param.value) -+ deauthenticate(wnd); -+ break; -+#ifdef IW_AUTH_MFP -+ case IW_AUTH_MFP: -+ if (wrqu->param.value == IW_AUTH_MFP_DISABLED || -+ wrqu->param.value == IW_AUTH_MFP_OPTIONAL) -+ break; -+ WARNING("MFP not implemented"); -+ return -EOPNOTSUPP; -+#endif -+ case IW_AUTH_TKIP_COUNTERMEASURES: -+ case IW_AUTH_DROP_UNENCRYPTED: -+ case IW_AUTH_RX_UNENCRYPTED_EAPOL: -+ case IW_AUTH_PRIVACY_INVOKED: -+ TRACE2("%d not implemented: %d", -+ wrqu->param.flags & IW_AUTH_INDEX, wrqu->param.value); -+ break; -+ default: -+ WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX); -+ return -EOPNOTSUPP; -+ } -+ return 0; -+} -+ -+static int iw_get_auth(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ ENTER2("index=%d", wrqu->param.flags & IW_AUTH_INDEX); -+ switch (wrqu->param.flags & IW_AUTH_INDEX) { -+ case IW_AUTH_WPA_VERSION: -+ wrqu->param.value = wnd->iw_auth_wpa_version; -+ break; -+ case IW_AUTH_CIPHER_PAIRWISE: -+ wrqu->param.value = wnd->iw_auth_cipher_pairwise; -+ break; -+ case IW_AUTH_CIPHER_GROUP: -+ wrqu->param.value = wnd->iw_auth_cipher_group; -+ break; -+ case IW_AUTH_KEY_MGMT: -+ wrqu->param.value = wnd->iw_auth_key_mgmt; -+ break; -+ case IW_AUTH_80211_AUTH_ALG: -+ wrqu->param.value = wnd->iw_auth_80211_alg; -+ break; -+ default: -+ WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX); -+ return -EOPNOTSUPP; -+ } -+ return 0; -+} -+ -+static int iw_set_encodeext(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; -+ struct ndis_device *wnd = netdev_priv(dev); -+ struct ndis_add_key ndis_key; -+ int i, keyidx; -+ NDIS_STATUS res; -+ u8 *addr; -+ -+ keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; -+ ENTER2("%d", keyidx); -+ if (keyidx) -+ keyidx--; -+ else -+ keyidx = wnd->encr_info.tx_key_index; -+ -+ if (keyidx < 0 || keyidx >= MAX_ENCR_KEYS) -+ return -EINVAL; -+ -+ if (ext->alg == WPA_ALG_WEP) { -+ if (!test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr)) -+ EXIT2(return -1); -+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) -+ wnd->encr_info.tx_key_index = keyidx; -+ if (add_wep_key(wnd, ext->key, ext->key_len, keyidx)) -+ EXIT2(return -1); -+ else -+ EXIT2(return 0); -+ } -+ if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || -+ ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) -+ EXIT2(return remove_key(wnd, keyidx, ndis_key.bssid)); -+ -+ if (ext->key_len > sizeof(ndis_key.key)) { -+ TRACE2("incorrect key length (%u)", ext->key_len); -+ EXIT2(return -1); -+ } -+ -+ memset(&ndis_key, 0, sizeof(ndis_key)); -+ -+ ndis_key.struct_size = -+ sizeof(ndis_key) - sizeof(ndis_key.key) + ext->key_len; -+ ndis_key.length = ext->key_len; -+ ndis_key.index = keyidx; -+ -+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { -+ for (i = 0; i < 6; i++) -+ ndis_key.rsc |= (((u64)ext->rx_seq[i]) << (i * 8)); -+ TRACE2("0x%llx", ndis_key.rsc); -+ ndis_key.index |= 1 << 29; -+ } -+ -+ addr = ext->addr.sa_data; -+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { -+ /* group key */ -+ if (wnd->infrastructure_mode == Ndis802_11IBSS) -+ memset(ndis_key.bssid, 0xff, ETH_ALEN); -+ else -+ get_ap_address(wnd, ndis_key.bssid); -+ } else { -+ /* pairwise key */ -+ ndis_key.index |= (1 << 30); -+ memcpy(ndis_key.bssid, addr, ETH_ALEN); -+ } -+ TRACE2(MACSTRSEP, MAC2STR(ndis_key.bssid)); -+ -+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) -+ ndis_key.index |= (1 << 31); -+ -+ if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { -+ /* wpa_supplicant gives us the Michael MIC RX/TX keys in -+ * different order than NDIS spec, so swap the order here. */ -+ memcpy(ndis_key.key, ext->key, 16); -+ memcpy(ndis_key.key + 16, ext->key + 24, 8); -+ memcpy(ndis_key.key + 24, ext->key + 16, 8); -+ } else -+ memcpy(ndis_key.key, ext->key, ext->key_len); -+ -+ res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); -+ if (res) { -+ TRACE2("adding key failed (%08X), %u", -+ res, ndis_key.struct_size); -+ EXIT2(return -1); -+ } -+ wnd->encr_info.keys[keyidx].length = ext->key_len; -+ memcpy(&wnd->encr_info.keys[keyidx].key, ndis_key.key, ext->key_len); -+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) -+ wnd->encr_info.tx_key_index = keyidx; -+ TRACE2("key %d added", keyidx); -+ -+ EXIT2(return 0); -+} -+ -+static int iw_get_encodeext(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ /* struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; */ -+ /* TODO */ -+ ENTER2(""); -+ return 0; -+} -+ -+static int iw_set_pmksa(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; -+ struct ndis_pmkid pmkid; -+ NDIS_STATUS res; -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ /* TODO: must keep local list of PMKIDs since NDIS drivers -+ * expect that all PMKID entries are included whenever a new -+ * one is added. */ -+ -+ ENTER2("%d", pmksa->cmd); -+ if ((pmksa->cmd == IW_PMKSA_ADD || pmksa->cmd == IW_PMKSA_REMOVE) && -+ (!(wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2))) -+ EXIT2(return -EOPNOTSUPP); -+ -+ memset(&pmkid, 0, sizeof(pmkid)); -+ if (pmksa->cmd == IW_PMKSA_ADD) { -+ pmkid.bssid_info_count = 1; -+ memcpy(pmkid.bssid_info[0].bssid, pmksa->bssid.sa_data, -+ ETH_ALEN); -+ memcpy(pmkid.bssid_info[0].pmkid, pmksa->pmkid, IW_PMKID_LEN); -+ } -+ pmkid.length = sizeof(pmkid); -+ -+ res = mp_set(wnd, OID_802_11_PMKID, &pmkid, pmkid.length); -+ if (res == NDIS_STATUS_FAILURE) -+ EXIT2(return -EOPNOTSUPP); -+ TRACE2("OID_802_11_PMKID -> %d", res); -+ if (res) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+#define WEXT(id) [id - SIOCIWFIRST] -+ -+static const iw_handler ndis_handler[] = { -+ WEXT(SIOCGIWNAME) = iw_get_network_type, -+ WEXT(SIOCSIWESSID) = iw_set_essid, -+ WEXT(SIOCGIWESSID) = iw_get_essid, -+ WEXT(SIOCSIWMODE) = iw_set_infra_mode, -+ WEXT(SIOCGIWMODE) = iw_get_infra_mode, -+ WEXT(SIOCGIWFREQ) = iw_get_freq, -+ WEXT(SIOCSIWFREQ) = iw_set_freq, -+ WEXT(SIOCGIWTXPOW) = iw_get_tx_power, -+ WEXT(SIOCSIWTXPOW) = iw_set_tx_power, -+ WEXT(SIOCGIWRATE) = iw_get_bitrate, -+ WEXT(SIOCSIWRATE) = iw_set_bitrate, -+ WEXT(SIOCGIWRTS) = iw_get_rts_threshold, -+ WEXT(SIOCSIWRTS) = iw_set_rts_threshold, -+ WEXT(SIOCGIWFRAG) = iw_get_frag_threshold, -+ WEXT(SIOCSIWFRAG) = iw_set_frag_threshold, -+ WEXT(SIOCGIWAP) = iw_get_ap_address, -+ WEXT(SIOCSIWAP) = iw_set_ap_address, -+ WEXT(SIOCSIWENCODE) = iw_set_wep, -+ WEXT(SIOCGIWENCODE) = iw_get_encr, -+ WEXT(SIOCSIWSCAN) = iw_set_scan, -+ WEXT(SIOCGIWSCAN) = iw_get_scan, -+ WEXT(SIOCGIWPOWER) = iw_get_power_mode, -+ WEXT(SIOCSIWPOWER) = iw_set_power_mode, -+ WEXT(SIOCGIWRANGE) = iw_get_range, -+ WEXT(SIOCGIWSTATS) = iw_get_ndis_stats, -+ WEXT(SIOCGIWSENS) = iw_get_sensitivity, -+ WEXT(SIOCSIWSENS) = iw_set_sensitivity, -+ WEXT(SIOCGIWNICKN) = iw_get_nick, -+ WEXT(SIOCSIWNICKN) = iw_set_nick, -+ WEXT(SIOCSIWCOMMIT) = iw_set_dummy, -+ WEXT(SIOCSIWMLME) = iw_set_mlme, -+ WEXT(SIOCSIWGENIE) = iw_set_genie, -+ WEXT(SIOCSIWAUTH) = iw_set_auth, -+ WEXT(SIOCGIWAUTH) = iw_get_auth, -+ WEXT(SIOCSIWENCODEEXT) = iw_set_encodeext, -+ WEXT(SIOCGIWENCODEEXT) = iw_get_encodeext, -+ WEXT(SIOCSIWPMKSA) = iw_set_pmksa, -+}; -+ -+/* private ioctl's */ -+ -+static int priv_reset(struct net_device *dev, struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ int res; -+ ENTER2(""); -+ res = mp_reset(netdev_priv(dev)); -+ if (res) { -+ WARNING("reset failed: %08X", res); -+ return -EOPNOTSUPP; -+ } -+ return 0; -+} -+ -+static int priv_deauthenticate(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ int res; -+ ENTER2(""); -+ res = deauthenticate(netdev_priv(dev)); -+ return res; -+} -+ -+static int priv_power_profile(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ struct miniport *mp; -+ ULONG profile_inf; -+ -+ ENTER2(""); -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ if (!mp->pnp_event_notify) -+ EXIT2(return -EOPNOTSUPP); -+ -+ /* 1 for AC and 0 for Battery */ -+ if (wrqu->param.value) -+ profile_inf = NdisPowerProfileAcOnLine; -+ else -+ profile_inf = NdisPowerProfileBattery; -+ -+ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, -+ NdisDevicePnPEventPowerProfileChanged, -+ &profile_inf, sizeof(profile_inf)); -+ EXIT2(return 0); -+} -+ -+static int priv_network_type(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ enum network_type network_type; -+ NDIS_STATUS res; -+ char type; -+ -+ ENTER2(""); -+ type = wrqu->param.value; -+ if (type == 'f') -+ network_type = Ndis802_11FH; -+ else if (type == 'b') -+ network_type = Ndis802_11DS; -+ else if (type == 'a') -+ network_type = Ndis802_11OFDM5; -+ else if (type == 'g' || type == 'n') -+ network_type = Ndis802_11OFDM24; -+ else -+ network_type = Ndis802_11Automode; -+ -+ res = mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, network_type); -+ if (res) { -+ WARNING("setting network type to %d failed (%08X)", -+ network_type, res); -+ EXIT2(return -EINVAL); -+ } -+ -+ EXIT2(return 0); -+} -+ -+static int priv_media_stream_mode(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ NDIS_STATUS res; -+ int mode; -+ -+ ENTER2(""); -+ if (wrqu->param.value > 0) -+ mode = Ndis802_11MediaStreamOn; -+ else -+ mode = Ndis802_11MediaStreamOff; -+ res = mp_set_int(wnd, OID_802_11_MEDIA_STREAM_MODE, mode); -+ if (res) { -+ WARNING("oid failed (%08X)", res); -+ EXIT2(return -EINVAL); -+ } -+ EXIT2(return 0); -+} -+ -+static int priv_reload_defaults(struct net_device *dev, -+ struct iw_request_info *info, -+ union iwreq_data *wrqu, char *extra) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ int res; -+ ENTER2(""); -+ res = mp_set_int(wnd, OID_802_11_RELOAD_DEFAULTS, -+ Ndis802_11ReloadWEPKeys); -+ if (res) { -+ WARNING("reloading defaults failed: %08X", res); -+ return -EOPNOTSUPP; -+ } -+ return 0; -+} -+ -+static const struct iw_priv_args priv_args[] = { -+ {PRIV_RESET, 0, 0, "ndis_reset"}, -+ {PRIV_POWER_PROFILE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, -+ "power_profile"}, -+ {PRIV_DEAUTHENTICATE, 0, 0, "deauthenticate"}, -+ {PRIV_NETWORK_TYPE, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, -+ "network_type"}, -+ {PRIV_MEDIA_STREAM_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, -+ "media_stream"}, -+ -+ {PRIV_RELOAD_DEFAULTS, 0, 0, "reload_defaults"}, -+}; -+ -+#define WEPRIV(id) [id - SIOCIWFIRSTPRIV] -+ -+static const iw_handler priv_handler[] = { -+ WEPRIV(PRIV_RESET) = priv_reset, -+ WEPRIV(PRIV_POWER_PROFILE) = priv_power_profile, -+ WEPRIV(PRIV_DEAUTHENTICATE) = priv_deauthenticate, -+ WEPRIV(PRIV_NETWORK_TYPE) = priv_network_type, -+ WEPRIV(PRIV_MEDIA_STREAM_MODE) = priv_media_stream_mode, -+ WEPRIV(PRIV_RELOAD_DEFAULTS) = priv_reload_defaults, -+}; -+ -+const struct iw_handler_def ndis_handler_def = { -+ .num_standard = ARRAY_SIZE(ndis_handler), -+ .num_private = ARRAY_SIZE(priv_handler), -+ .num_private_args = ARRAY_SIZE(priv_args), -+ -+ .standard = (iw_handler *)ndis_handler, -+ .private = (iw_handler *)priv_handler, -+ .private_args = (struct iw_priv_args *)priv_args, -+ .get_wireless_stats = get_iw_stats, -+}; -+ -+#endif -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/iw_ndis.h linux-5.6.11-ndis/3rdparty/ndiswrapper/iw_ndis.h ---- linux-5.6.11/3rdparty/ndiswrapper/iw_ndis.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/iw_ndis.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,194 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _IW_NDIS_H_ -+#define _IW_NDIS_H_ -+ -+#include "ndis.h" -+ -+#define WL_NOISE -96 /* typical noise level in dBm */ -+#define WL_SIGMAX -32 /* typical maximum signal level in dBm */ -+ -+struct ndis_encr_key { -+ ULONG struct_size; -+ ULONG index; -+ ULONG length; -+ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; -+}; -+ -+struct ndis_add_key { -+ ULONG struct_size; -+ ndis_key_index index; -+ ULONG length; -+ mac_address bssid; -+ UCHAR pad[6]; -+ ndis_key_rsc rsc; -+ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; -+}; -+ -+struct ndis_remove_key { -+ ULONG struct_size; -+ ndis_key_index index; -+ mac_address bssid; -+}; -+ -+struct ndis_fixed_ies { -+ UCHAR time_stamp[8]; -+ USHORT beacon_interval; -+ USHORT capa; -+}; -+ -+struct ndis_variable_ies { -+ UCHAR elem_id; -+ UCHAR length; -+ UCHAR data[]; -+}; -+ -+enum ndis_reload_defaults { Ndis802_11ReloadWEPKeys }; -+ -+struct ndis_assoc_info { -+ ULONG length; -+ USHORT req_ies; -+ struct req_ie { -+ USHORT capa; -+ USHORT listen_interval; -+ mac_address cur_ap_address; -+ } req_ie; -+ ULONG req_ie_length; -+ ULONG offset_req_ies; -+ USHORT resp_ies; -+ struct resp_ie { -+ USHORT capa; -+ USHORT status_code; -+ USHORT assoc_id; -+ } resp_ie; -+ ULONG resp_ie_length; -+ ULONG offset_resp_ies; -+}; -+ -+struct ndis_configuration_fh { -+ ULONG length; -+ ULONG hop_pattern; -+ ULONG hop_set; -+ ULONG dwell_time; -+}; -+ -+struct ndis_configuration { -+ ULONG length; -+ ULONG beacon_period; -+ ULONG atim_window; -+ ULONG ds_config; -+ struct ndis_configuration_fh fh_config; -+}; -+ -+struct ndis_wlan_bssid { -+ ULONG length; -+ mac_address mac; -+ UCHAR reserved[2]; -+ struct ndis_essid ssid; -+ ULONG privacy; -+ ndis_rssi rssi; -+ UINT net_type; -+ struct ndis_configuration config; -+ UINT mode; -+ UCHAR rates[NDIS_MAX_RATES]; -+}; -+ -+struct ndis_wlan_bssid_ex { -+ ULONG length; -+ mac_address mac; -+ UCHAR reserved[2]; -+ struct ndis_essid ssid; -+ ULONG privacy; -+ ndis_rssi rssi; -+ UINT net_type; -+ struct ndis_configuration config; -+ UINT mode; -+ UCHAR rates_ex[NDIS_MAX_RATES_EX]; -+ ULONG ie_length; -+ struct ndis_fixed_ies fixed; -+ struct ndis_variable_ies var[]; -+}; -+ -+/* we use bssid_list as bssid_list_ex also */ -+struct ndis_bssid_list { -+ ULONG num_items; -+ struct ndis_wlan_bssid bssid[1]; -+}; -+ -+enum ndis_priv_filter { -+ Ndis802_11PrivFilterAcceptAll, Ndis802_11PrivFilter8021xWEP -+}; -+ -+enum network_type { -+ Ndis802_11FH, Ndis802_11DS, Ndis802_11OFDM5, Ndis802_11OFDM24, -+ /* MSDN site uses Ndis802_11Automode, which is not mentioned -+ * in DDK, so add one and assign it to -+ * Ndis802_11NetworkTypeMax */ -+ Ndis802_11Automode, Ndis802_11NetworkTypeMax = Ndis802_11Automode -+}; -+ -+struct network_type_list { -+ ULONG num; -+ enum network_type types[1]; -+}; -+ -+enum ndis_power { -+ NDIS_POWER_OFF = 0, NDIS_POWER_MAX, NDIS_POWER_MIN, -+}; -+ -+struct ndis_auth_req { -+ ULONG length; -+ mac_address bssid; -+ ULONG flags; -+}; -+ -+struct ndis_bssid_info { -+ mac_address bssid; -+ UCHAR pmkid[IW_PMKID_LEN]; -+}; -+ -+struct ndis_pmkid { -+ ULONG length; -+ ULONG bssid_info_count; -+ struct ndis_bssid_info bssid_info[1]; -+}; -+ -+int get_ap_address(struct ndis_device *wnd, mac_address mac); -+int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode); -+int get_ndis_encr_mode(struct ndis_device *wnd); -+int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise, -+ int cipher_groupwise); -+int get_ndis_auth_mode(struct ndis_device *wnd); -+NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid); -+void set_default_iw_params(struct ndis_device *wnd); -+extern const struct iw_handler_def ndis_handler_def; -+ -+#define PRIV_RESET SIOCIWFIRSTPRIV+16 -+#define PRIV_POWER_PROFILE SIOCIWFIRSTPRIV+17 -+#define PRIV_NETWORK_TYPE SIOCIWFIRSTPRIV+18 -+#define PRIV_DEAUTHENTICATE SIOCIWFIRSTPRIV+19 -+#define PRIV_MEDIA_STREAM_MODE SIOCIWFIRSTPRIV+20 -+#define PRIV_RELOAD_DEFAULTS SIOCIWFIRSTPRIV+23 -+ -+/* these have to match what is in wpa_supplicant */ -+ -+enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP }; -+enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, -+ CIPHER_WEP104 }; -+enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, -+ KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE }; -+ -+#endif // IW_NDIS_H -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/lin2win.h linux-5.6.11-ndis/3rdparty/ndiswrapper/lin2win.h ---- linux-5.6.11/3rdparty/ndiswrapper/lin2win.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/lin2win.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,111 @@ -+/* -+ * Copyright (C) 2006 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifdef CONFIG_X86_64 -+ -+u64 lin2win0(void *func); -+u64 lin2win1(void *func, u64 arg1); -+u64 lin2win2(void *func, u64 arg1, u64 arg2); -+u64 lin2win3(void *func, u64 arg1, u64 arg2, u64 arg3); -+u64 lin2win4(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4); -+u64 lin2win5(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5); -+u64 lin2win6(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, -+ u64 arg6); -+ -+#define LIN2WIN0(func) \ -+({ \ -+ if (0) \ -+ func(); \ -+ lin2win0(func); \ -+}) -+ -+#define LIN2WIN1(func, arg1) \ -+({ \ -+ if (0) \ -+ func(arg1); \ -+ lin2win1(func, (u64)arg1); \ -+}) -+ -+#define LIN2WIN2(func, arg1, arg2) \ -+({ \ -+ if (0) \ -+ func(arg1, arg2); \ -+ lin2win2(func, (u64)arg1, (u64)arg2); \ -+}) -+ -+#define LIN2WIN3(func, arg1, arg2, arg3) \ -+({ \ -+ if (0) \ -+ func(arg1, arg2, arg3); \ -+ lin2win3(func, (u64)arg1, (u64)arg2, (u64)arg3); \ -+}) -+ -+#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \ -+({ \ -+ if (0) \ -+ func(arg1, arg2, arg3, arg4); \ -+ lin2win4(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4); \ -+}) -+ -+#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \ -+({ \ -+ if (0) \ -+ func(arg1, arg2, arg3, arg4, arg5); \ -+ lin2win5(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4, \ -+ (u64)arg5); \ -+}) -+ -+#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ -+({ \ -+ if (0) \ -+ func(arg1, arg2, arg3, arg4, arg5, arg6); \ -+ lin2win6(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4, \ -+ (u64)arg5, (u64)arg6); \ -+}) -+ -+#else // CONFIG_X86_64 -+ -+#define LIN2WIN1(func, arg1) \ -+({ \ -+ TRACE6("calling %p", func); \ -+ func(arg1); \ -+}) -+#define LIN2WIN2(func, arg1, arg2) \ -+({ \ -+ TRACE6("calling %p", func); \ -+ func(arg1, arg2); \ -+}) -+#define LIN2WIN3(func, arg1, arg2, arg3) \ -+({ \ -+ TRACE6("calling %p", func); \ -+ func(arg1, arg2, arg3); \ -+}) -+#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \ -+({ \ -+ TRACE6("calling %p", func); \ -+ func(arg1, arg2, arg3, arg4); \ -+}) -+#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \ -+({ \ -+ TRACE6("calling %p", func); \ -+ func(arg1, arg2, arg3, arg4, arg5); \ -+}) -+#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ -+({ \ -+ TRACE6("calling %p", func); \ -+ func(arg1, arg2, arg3, arg4, arg5, arg6); \ -+}) -+ -+#endif // CONFIG_X86_64 -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/lin2win.S linux-5.6.11-ndis/3rdparty/ndiswrapper/lin2win.S ---- linux-5.6.11/3rdparty/ndiswrapper/lin2win.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/lin2win.S 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,147 @@ -+/* -+ * Copyright (C) 2011 Pavel Roskin -+ * -+ * 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. -+ * -+ */ -+ -+#include -+#include -+ -+ .text -+ -+#define WORD_BYTES 8 -+#define LINUX_REG_ARGS 6 -+#define WINDOWS_REG_ARGS 4 -+ -+/* %rbp is saved to create a stack frame, which can help with debugging */ -+#define SAVED_REGS 1 -+ -+/* -+ * When calling a Windows function, stack space is allocated for at least 4 -+ * arguments even if the number of arguments is less than 4. The value of -+ * true is -1 in assembler, so we multiply it by another true value. -+ */ -+#define stack_args(argc) \ -+ (WINDOWS_REG_ARGS + \ -+ (0 < 1) * (argc > WINDOWS_REG_ARGS) * (argc - WINDOWS_REG_ARGS)) -+ -+/* Full required change of stack pointer, in words */ -+#define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1) -+ -+/* Full actual change of stack pointer, in words (must be even) */ -+#define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1) -+ -+/* Space allocated for Linux arguments on stack */ -+#define stack_space(argc) \ -+ ((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES) -+ -+/* -+ * lin2win_win_arg(N) gives the address of the Nth Windows argument on our -+ * stack frame. %rsp points to the first argument. The Nth argument is -+ * therefore at ((N - 1) * 8)(%rsp). -+ * -+ * Don't call with N less than 5! -+ */ -+#define lin2win_win_arg(n) ((n - 1) * WORD_BYTES)(%rsp) -+ -+/* -+ * lin2win_lin_arg(N, ARGC) gives the address of the Nth Linux argument after -+ * the stack has been prepared for a Windows function call with ARGC arguments. -+ * -+ * When called from Linux, the Nth argument is at ((N - 6) * 8)(%rsp). We add -+ * the allocated stack space and saved registers to compensate for %rsp change. -+ * -+ * Don't call with N less than 7! -+ */ -+#define lin2win_lin_arg(n, argc) \ -+ (stack_space(argc) + \ -+ (SAVED_REGS + n - LINUX_REG_ARGS) * WORD_BYTES)(%rsp) -+ -+/* -+ * lin2win(func, winarg1, winarg2, ...) -+ * Call Windows FUNC function with ARGC arguments WINARG1, WINARG2, ... -+ * We get (ARGC + 1) arguments. -+ */ -+.macro lin2win name, argc -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) -+ SYM_FUNC_START(\name) -+#else -+ .type \name, @function -+ ENTRY(\name) -+#endif -+ -+ /* Create a call frame - it's optional, but good for debugging */ -+ .cfi_startproc -+ push %rbp -+ .cfi_def_cfa %rsp, 2 * WORD_BYTES -+ .cfi_offset %rbp, -2 * WORD_BYTES -+ mov %rsp, %rbp -+ .cfi_def_cfa %rbp, 2 * WORD_BYTES -+ -+ /* Allocate space for Windows arguments */ -+ sub $stack_space(\argc), %rsp -+ -+ /* arg7 to winarg6 */ -+ .if (\argc >= 6) -+ mov lin2win_lin_arg(7, \argc), %r11 -+ mov %r11, lin2win_win_arg(6) -+ .endif -+ -+ /* arg6 to winarg5 */ -+ .if (\argc >= 5) -+ mov %r9, lin2win_win_arg(5) -+ .endif -+ -+ /* arg5 to winarg4 */ -+ .if (\argc >= 4) -+ mov %r8, %r9 -+ .endif -+ -+ /* arg4 to winarg3 */ -+ .if (\argc >= 3) -+ mov %rcx, %r8 -+ .endif -+ -+ /* arg3 to winarg2 - nothing needed, both are in %rdx */ -+ -+ /* arg2 to winarg1 */ -+ .if (\argc >= 1) -+ mov %rsi, %rcx -+ .endif -+ -+ /* Call function (arg1) */ -+ call *%rdi -+ -+ /* Reclaim space for Windows arguments */ -+ add $stack_space(\argc), %rsp -+ -+ /* Return to the caller */ -+ leave -+ .cfi_def_cfa %rsp, WORD_BYTES -+ .cfi_restore %rbp -+ ret -+ .cfi_endproc -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) -+ SYM_FUNC_END(\name) -+#else -+ .size \name, (. - \name) -+#endif -+.endm -+ -+/* Define lin2winN functions */ -+lin2win lin2win0, 0 -+lin2win lin2win1, 1 -+lin2win lin2win2, 2 -+lin2win lin2win3, 3 -+lin2win lin2win4, 4 -+lin2win lin2win5, 5 -+lin2win lin2win6, 6 -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/loader.c linux-5.6.11-ndis/3rdparty/ndiswrapper/loader.c ---- linux-5.6.11/3rdparty/ndiswrapper/loader.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/loader.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,967 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ndis.h" -+#include "loader.h" -+#include "wrapndis.h" -+#include "pnp.h" -+ -+#include -+#include -+#include -+#include -+ -+/* -+ Network adapter: ClassGuid = {4d36e972-e325-11ce-bfc1-08002be10318} -+ Network client: ClassGuid = {4d36e973-e325-11ce-bfc1-08002be10318} -+ PCMCIA adapter: ClassGuid = {4d36e977-e325-11ce-bfc1-08002be10318} -+ USB: ClassGuid = {36fc9e60-c465-11cf-8056-444553540000} -+*/ -+ -+/* the indices used here must match macros WRAP_NDIS_DEVICE etc. */ -+static struct guid class_guids[] = { -+ /* Network */ -+ { .data1 = 0x4d36e972, .data2 = 0xe325, .data3 = 0x11ce }, -+ /* USB WDM */ -+ { .data1 = 0x36fc9e60, .data2 = 0xc465, .data3 = 0x11cf }, -+ /* Bluetooth */ -+ { .data1 = 0xe0cbf06c, .data2 = 0xcd8b, .data3 = 0x4647 }, -+ /* ivtcorporation.com's bluetooth device claims this is -+ * bluetooth guid */ -+ { .data1 = 0xf12d3cf8, .data2 = 0xb11d, .data3 = 0x457e}, -+}; -+ -+struct mutex loader_mutex; -+static struct completion loader_complete; -+ -+static struct nt_list wrap_devices; -+static struct nt_list wrap_drivers; -+ -+static int wrap_device_type(int data1) -+{ -+ int i; -+ for (i = 0; i < ARRAY_SIZE(class_guids); i++) -+ if (data1 == class_guids[i].data1) -+ return i; -+ ERROR("unknown device: 0x%x\n", data1); -+ return -1; -+} -+ -+/* load driver for given device, if not already loaded */ -+struct wrap_driver *load_wrap_driver(struct wrap_device *wd) -+{ -+ int ret; -+ struct nt_list *cur; -+ struct wrap_driver *wrap_driver; -+ -+ ENTER1("device: %04X:%04X:%04X:%04X", wd->vendor, wd->device, -+ wd->subvendor, wd->subdevice); -+ mutex_lock(&loader_mutex); -+ wrap_driver = NULL; -+ nt_list_for_each(cur, &wrap_drivers) { -+ wrap_driver = container_of(cur, struct wrap_driver, list); -+ if (!stricmp(wrap_driver->name, wd->driver_name)) { -+ TRACE1("driver %s already loaded", wrap_driver->name); -+ break; -+ } else -+ wrap_driver = NULL; -+ } -+ mutex_unlock(&loader_mutex); -+ -+ if (!wrap_driver) { -+ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DRIVER, -+#if DEBUG >= 1 -+ "1", -+#else -+ "0", -+#endif -+ UTILS_VERSION, wd->driver_name, -+ wd->conf_file_name, NULL}; -+ char *env[] = {NULL}; -+ -+ TRACE1("loading driver %s", wd->driver_name); -+ mutex_lock(&loader_mutex); -+ reinit_completion(&loader_complete); -+ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, -+ UMH_WAIT_PROC); -+ if (ret) { -+ mutex_unlock(&loader_mutex); -+ ERROR("couldn't load driver %s; check system log " -+ "for messages from 'loadndisdriver'", -+ wd->driver_name); -+ EXIT1(return NULL); -+ } -+ wait_for_completion(&loader_complete); -+ TRACE1("%s", wd->driver_name); -+ wrap_driver = NULL; -+ nt_list_for_each(cur, &wrap_drivers) { -+ wrap_driver = container_of(cur, struct wrap_driver, -+ list); -+ if (!stricmp(wrap_driver->name, wd->driver_name)) { -+ wd->driver = wrap_driver; -+ break; -+ } else -+ wrap_driver = NULL; -+ } -+ mutex_unlock(&loader_mutex); -+ if (wrap_driver) -+ TRACE1("driver %s is loaded", wrap_driver->name); -+ else -+ ERROR("couldn't load driver '%s'", wd->driver_name); -+ } -+ EXIT1(return wrap_driver); -+} -+ -+/* load the driver files from userspace. */ -+static int load_sys_files(struct wrap_driver *driver, -+ struct load_driver *load_driver) -+{ -+ int i, err; -+ -+ TRACE1("num_pe_images = %d", load_driver->num_sys_files); -+ TRACE1("loading driver: %s", load_driver->name); -+ strncpy(driver->name, load_driver->name, sizeof(driver->name)); -+ driver->name[sizeof(driver->name)-1] = 0; -+ TRACE1("driver: %s", driver->name); -+ err = 0; -+ driver->num_pe_images = 0; -+ for (i = 0; i < load_driver->num_sys_files; i++) { -+ struct pe_image *pe_image; -+ pe_image = &driver->pe_images[driver->num_pe_images]; -+ -+ strncpy(pe_image->name, load_driver->sys_files[i].name, -+ sizeof(pe_image->name)); -+ pe_image->name[sizeof(pe_image->name)-1] = 0; -+ TRACE1("image size: %zu bytes", load_driver->sys_files[i].size); -+ -+#ifdef CONFIG_X86_64 -+#ifdef PAGE_KERNEL_EXECUTABLE -+ pe_image->image = -+ __vmalloc(load_driver->sys_files[i].size, -+ GFP_KERNEL | __GFP_HIGHMEM -+ ); -+#elif defined PAGE_KERNEL_EXEC -+ pe_image->image = -+ __vmalloc(load_driver->sys_files[i].size, -+ GFP_KERNEL | __GFP_HIGHMEM -+ ); -+#else -+#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC -+#endif -+#else -+ /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is -+ * not available to modules! */ -+#ifdef cpu_has_nx -+ if (cpu_has_nx) -+ pe_image->image = -+ __vmalloc(load_driver->sys_files[i].size, -+ GFP_KERNEL | __GFP_HIGHMEM -+ ); -+ else -+ pe_image->image = -+ vmalloc(load_driver->sys_files[i].size); -+#else -+ pe_image->image = -+ vmalloc(load_driver->sys_files[i].size); -+#endif -+#endif -+ if (!pe_image->image) { -+ ERROR("couldn't allocate memory"); -+ err = -ENOMEM; -+ break; -+ } -+ TRACE1("image is at %p", pe_image->image); -+ -+ if (copy_from_user(pe_image->image, -+ load_driver->sys_files[i].data, -+ load_driver->sys_files[i].size)) { -+ ERROR("couldn't load file %s", -+ load_driver->sys_files[i].name); -+ err = -EFAULT; -+ break; -+ } -+ pe_image->size = load_driver->sys_files[i].size; -+ driver->num_pe_images++; -+ } -+ -+ if (!err && link_pe_images(driver->pe_images, driver->num_pe_images)) { -+ ERROR("couldn't prepare driver '%s'", load_driver->name); -+ err = -EINVAL; -+ } -+ -+ if (driver->num_pe_images < load_driver->num_sys_files || err) { -+ for (i = 0; i < driver->num_pe_images; i++) -+ if (driver->pe_images[i].image) -+ vfree(driver->pe_images[i].image); -+ driver->num_pe_images = 0; -+ EXIT1(return err); -+ } else -+ EXIT1(return 0); -+} -+ -+struct wrap_bin_file *get_bin_file(char *bin_file_name) -+{ -+ int i = 0; -+ struct wrap_driver *driver, *cur; -+ -+ ENTER1("%s", bin_file_name); -+ mutex_lock(&loader_mutex); -+ driver = NULL; -+ nt_list_for_each_entry(cur, &wrap_drivers, list) { -+ for (i = 0; i < cur->num_bin_files; i++) -+ if (!stricmp(cur->bin_files[i].name, bin_file_name)) { -+ driver = cur; -+ break; -+ } -+ if (driver) -+ break; -+ } -+ mutex_unlock(&loader_mutex); -+ if (!driver) { -+ TRACE1("couldn't find bin file '%s'", bin_file_name); -+ return NULL; -+ } -+ -+ if (!driver->bin_files[i].data) { -+ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_BIN_FILE, -+#if DEBUG >= 1 -+ "1", -+#else -+ "0", -+#endif -+ UTILS_VERSION, driver->name, -+ driver->bin_files[i].name, NULL}; -+ char *env[] = {NULL}; -+ int ret; -+ -+ TRACE1("loading bin file %s/%s", driver->name, -+ driver->bin_files[i].name); -+ mutex_lock(&loader_mutex); -+ reinit_completion(&loader_complete); -+ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, -+ UMH_WAIT_PROC); -+ if (ret) { -+ mutex_unlock(&loader_mutex); -+ ERROR("couldn't load file %s/%s; check system log " -+ "for messages from 'loadndisdriver' (%d)", -+ driver->name, driver->bin_files[i].name, ret); -+ EXIT1(return NULL); -+ } -+ wait_for_completion(&loader_complete); -+ mutex_unlock(&loader_mutex); -+ if (!driver->bin_files[i].data) { -+ WARNING("couldn't load binary file %s", -+ driver->bin_files[i].name); -+ EXIT1(return NULL); -+ } -+ } -+ EXIT2(return &(driver->bin_files[i])); -+} -+ -+/* called with loader_mutex down */ -+static int add_bin_file(struct load_driver_file *driver_file) -+{ -+ struct wrap_driver *driver, *cur; -+ struct wrap_bin_file *bin_file; -+ int i = 0; -+ -+ driver = NULL; -+ nt_list_for_each_entry(cur, &wrap_drivers, list) { -+ for (i = 0; i < cur->num_bin_files; i++) -+ if (!stricmp(cur->bin_files[i].name, -+ driver_file->name)) { -+ driver = cur; -+ break; -+ } -+ if (driver) -+ break; -+ } -+ if (!driver) { -+ ERROR("couldn't find %s", driver_file->name); -+ return -EINVAL; -+ } -+ bin_file = &driver->bin_files[i]; -+ strncpy(bin_file->name, driver_file->name, sizeof(bin_file->name)); -+ bin_file->name[sizeof(bin_file->name)-1] = 0; -+ bin_file->data = vmalloc(driver_file->size); -+ if (!bin_file->data) { -+ ERROR("couldn't allocate memory"); -+ return -ENOMEM; -+ } -+ bin_file->size = driver_file->size; -+ if (copy_from_user(bin_file->data, driver_file->data, bin_file->size)) { -+ ERROR("couldn't copy data"); -+ free_bin_file(bin_file); -+ return -EFAULT; -+ } -+ return 0; -+} -+ -+void free_bin_file(struct wrap_bin_file *bin_file) -+{ -+ TRACE2("unloading %s", bin_file->name); -+ if (bin_file->data) -+ vfree(bin_file->data); -+ bin_file->data = NULL; -+ bin_file->size = 0; -+ EXIT2(return); -+} -+ -+/* load firmware files from userspace */ -+static int load_bin_files_info(struct wrap_driver *driver, -+ struct load_driver *load_driver) -+{ -+ struct wrap_bin_file *bin_files; -+ int i; -+ -+ ENTER1("%s, %d", load_driver->name, load_driver->num_bin_files); -+ driver->num_bin_files = 0; -+ driver->bin_files = NULL; -+ if (load_driver->num_bin_files == 0) -+ EXIT1(return 0); -+ bin_files = kzalloc(load_driver->num_bin_files * sizeof(*bin_files), -+ GFP_KERNEL); -+ if (!bin_files) { -+ ERROR("couldn't allocate memory"); -+ EXIT1(return -ENOMEM); -+ } -+ -+ for (i = 0; i < load_driver->num_bin_files; i++) { -+ strncpy(bin_files[i].name, load_driver->bin_files[i].name, -+ sizeof(bin_files[i].name)); -+ bin_files[i].name[sizeof(bin_files[i].name)-1] = 0; -+ TRACE2("loaded bin file %s", bin_files[i].name); -+ } -+ driver->num_bin_files = load_driver->num_bin_files; -+ driver->bin_files = bin_files; -+ EXIT1(return 0); -+} -+ -+/* load settings for a device. called with loader_mutex down */ -+static int load_settings(struct wrap_driver *wrap_driver, -+ struct load_driver *load_driver) -+{ -+ int i, num_settings; -+ -+ ENTER1("%p, %p", wrap_driver, load_driver); -+ -+ num_settings = 0; -+ for (i = 0; i < load_driver->num_settings; i++) { -+ struct load_device_setting *load_setting = -+ &load_driver->settings[i]; -+ struct wrap_device_setting *setting; -+ ULONG data1; -+ -+ setting = kzalloc(sizeof(*setting), GFP_KERNEL); -+ if (!setting) { -+ ERROR("couldn't allocate memory"); -+ break; -+ } -+ strncpy(setting->name, load_setting->name, -+ sizeof(setting->name)); -+ setting->name[sizeof(setting->name)-1] = 0; -+ strncpy(setting->value, load_setting->value, -+ sizeof(setting->value)); -+ setting->value[sizeof(setting->value)-1] = 0; -+ TRACE2("%p: %s=%s", setting, setting->name, setting->value); -+ -+ if (strcmp(setting->name, "driver_version") == 0) { -+ strncpy(wrap_driver->version, setting->value, -+ sizeof(wrap_driver->version)); -+ wrap_driver->version[sizeof(wrap_driver->version)-1] = 0; -+ } else if (strcmp(setting->name, "class_guid") == 0 && -+ sscanf(setting->value, "%x", &data1) == 1) { -+ wrap_driver->dev_type = wrap_device_type(data1); -+ if (wrap_driver->dev_type < 0) { -+ WARNING("unknown guid: %x", data1); -+ wrap_driver->dev_type = 0; -+ } -+ } -+ InsertTailList(&wrap_driver->settings, &setting->list); -+ num_settings++; -+ } -+ /* it is not a fatal error if some settings couldn't be loaded */ -+ if (num_settings > 0) -+ EXIT1(return 0); -+ else -+ EXIT1(return -EINVAL); -+} -+ -+void unload_wrap_device(struct wrap_device *wd) -+{ -+ struct nt_list *cur; -+ ENTER1("unloading device %p (%04X:%04X:%04X:%04X), driver %s", wd, -+ wd->vendor, wd->device, wd->subvendor, wd->subdevice, -+ wd->driver_name); -+ mutex_lock(&loader_mutex); -+ while ((cur = RemoveHeadList(&wd->settings))) { -+ struct wrap_device_setting *setting; -+ setting = container_of(cur, struct wrap_device_setting, list); -+ kfree(setting); -+ } -+ RemoveEntryList(&wd->list); -+ mutex_unlock(&loader_mutex); -+ kfree(wd); -+ EXIT1(return); -+} -+ -+/* should be called with loader_mutex down */ -+void unload_wrap_driver(struct wrap_driver *driver) -+{ -+ int i; -+ struct driver_object *drv_obj; -+ struct nt_list *cur, *next; -+ -+ ENTER1("unloading driver: %s (%p)", driver->name, driver); -+ TRACE1("freeing %d images", driver->num_pe_images); -+ drv_obj = driver->drv_obj; -+ for (i = 0; i < driver->num_pe_images; i++) -+ if (driver->pe_images[i].image) { -+ TRACE1("freeing image at %p", -+ driver->pe_images[i].image); -+ vfree(driver->pe_images[i].image); -+ } -+ -+ TRACE1("freeing %d bin files", driver->num_bin_files); -+ for (i = 0; i < driver->num_bin_files; i++) { -+ TRACE1("freeing image at %p", driver->bin_files[i].data); -+ if (driver->bin_files[i].data) -+ vfree(driver->bin_files[i].data); -+ } -+ kfree(driver->bin_files); -+ RtlFreeUnicodeString(&drv_obj->name); -+ RemoveEntryList(&driver->list); -+ nt_list_for_each_safe(cur, next, &driver->settings) { -+ struct wrap_device_setting *setting; -+ struct ndis_configuration_parameter *param; -+ -+ setting = container_of(cur, struct wrap_device_setting, list); -+ TRACE2("%p", setting); -+ param = setting->encoded; -+ if (param) { -+ TRACE2("%p", param); -+ if (param->type == NdisParameterString) -+ RtlFreeUnicodeString(¶m->data.string); -+ ExFreePool(param); -+ } -+ kfree(setting); -+ } -+ /* this frees driver */ -+ free_custom_extensions(drv_obj->drv_ext); -+ kfree(drv_obj->drv_ext); -+ TRACE1("drv_obj: %p", drv_obj); -+ -+ EXIT1(return); -+} -+ -+/* call the entry point of the driver */ -+static int start_wrap_driver(struct wrap_driver *driver) -+{ -+ int i; -+ NTSTATUS ret, res; -+ struct driver_object *drv_obj; -+ typeof(driver->pe_images[0].entry) entry; -+ -+ ENTER1("%s", driver->name); -+ drv_obj = driver->drv_obj; -+ for (ret = res = 0, i = 0; i < driver->num_pe_images; i++) -+ /* dlls are already started by loader */ -+ if (driver->pe_images[i].type == IMAGE_FILE_EXECUTABLE_IMAGE) { -+ entry = driver->pe_images[i].entry; -+ drv_obj->start = driver->pe_images[i].entry; -+ drv_obj->driver_size = driver->pe_images[i].size; -+ TRACE1("entry: %p, %p, drv_obj: %p", -+ entry, *entry, drv_obj); -+ res = LIN2WIN2(entry, drv_obj, &drv_obj->name); -+ ret |= res; -+ TRACE1("entry returns %08X", res); -+ break; -+ } -+ if (ret) { -+ ERROR("driver initialization failed: %08X", ret); -+ RtlFreeUnicodeString(&drv_obj->name); -+ /* this frees ndis_driver */ -+ free_custom_extensions(drv_obj->drv_ext); -+ kfree(drv_obj->drv_ext); -+ TRACE1("drv_obj: %p", drv_obj); -+ ObDereferenceObject(drv_obj); -+ EXIT1(return -EINVAL); -+ } -+ EXIT1(return 0); -+} -+ -+/* -+ * add driver to list of loaded driver but make sure this driver is -+ * not loaded before. called with loader_mutex down -+ */ -+static int add_wrap_driver(struct wrap_driver *driver) -+{ -+ struct wrap_driver *tmp; -+ -+ ENTER1("name: %s", driver->name); -+ nt_list_for_each_entry(tmp, &wrap_drivers, list) { -+ if (stricmp(tmp->name, driver->name) == 0) { -+ ERROR("cannot add duplicate driver"); -+ EXIT1(return -EBUSY); -+ } -+ } -+ InsertHeadList(&wrap_drivers, &driver->list); -+ EXIT1(return 0); -+} -+ -+/* load a driver from userspace and initialize it. called with -+ * loader_mutex down */ -+static int load_user_space_driver(struct load_driver *load_driver) -+{ -+ struct driver_object *drv_obj; -+ struct ansi_string ansi_reg; -+ struct wrap_driver *wrap_driver = NULL; -+ -+ ENTER1("%p", load_driver); -+ drv_obj = allocate_object(sizeof(*drv_obj), OBJECT_TYPE_DRIVER, NULL); -+ if (!drv_obj) { -+ ERROR("couldn't allocate memory"); -+ EXIT1(return -ENOMEM); -+ } -+ TRACE1("drv_obj: %p", drv_obj); -+ drv_obj->drv_ext = kzalloc(sizeof(*(drv_obj->drv_ext)), GFP_KERNEL); -+ if (!drv_obj->drv_ext) { -+ ERROR("couldn't allocate memory"); -+ ObDereferenceObject(drv_obj); -+ EXIT1(return -ENOMEM); -+ } -+ InitializeListHead(&drv_obj->drv_ext->custom_ext); -+ if (IoAllocateDriverObjectExtension(drv_obj, -+ (void *)WRAP_DRIVER_CLIENT_ID, -+ sizeof(*wrap_driver), -+ (void **)&wrap_driver) != -+ STATUS_SUCCESS) -+ EXIT1(return -ENOMEM); -+ TRACE1("driver: %p", wrap_driver); -+ memset(wrap_driver, 0, sizeof(*wrap_driver)); -+ InitializeListHead(&wrap_driver->list); -+ InitializeListHead(&wrap_driver->settings); -+ wrap_driver->drv_obj = drv_obj; -+ RtlInitAnsiString(&ansi_reg, "/tmp"); -+ if (RtlAnsiStringToUnicodeString(&drv_obj->name, &ansi_reg, TRUE) != -+ STATUS_SUCCESS) { -+ ERROR("couldn't initialize registry path"); -+ free_custom_extensions(drv_obj->drv_ext); -+ kfree(drv_obj->drv_ext); -+ TRACE1("drv_obj: %p", drv_obj); -+ ObDereferenceObject(drv_obj); -+ EXIT1(return -EINVAL); -+ } -+ strncpy(wrap_driver->name, load_driver->name, sizeof(wrap_driver->name)); -+ wrap_driver->name[sizeof(wrap_driver->name)-1] = 0; -+ if (load_sys_files(wrap_driver, load_driver) || -+ load_bin_files_info(wrap_driver, load_driver) || -+ load_settings(wrap_driver, load_driver) || -+ start_wrap_driver(wrap_driver) || -+ add_wrap_driver(wrap_driver)) { -+ unload_wrap_driver(wrap_driver); -+ ObDereferenceObject(drv_obj); -+ EXIT1(return -EINVAL); -+ } else { -+ printk(KERN_INFO "%s: driver %s (%s) loaded\n", -+ DRIVER_NAME, wrap_driver->name, wrap_driver->version); -+ add_taint(TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE); -+ EXIT1(return 0); -+ } -+} -+ -+static struct pci_device_id wrap_pci_id_table[] = { -+ { -+ .vendor = PCI_ANY_ID, -+ .device = PCI_ANY_ID, -+ .subvendor = PCI_ANY_ID, -+ .subdevice = PCI_ANY_ID, -+ .class = 0, -+ .class_mask = 0, -+ .driver_data = 0 -+ } -+}; -+ -+static struct pci_driver wrap_pci_driver = { -+ .name = DRIVER_NAME, -+ .id_table = wrap_pci_id_table, -+ .probe = wrap_pnp_start_pci_device, -+ .remove = wrap_pnp_remove_pci_device, -+ .suspend = wrap_pnp_suspend_pci_device, -+ .resume = wrap_pnp_resume_pci_device, -+}; -+ -+#ifdef ENABLE_USB -+static struct usb_device_id wrap_usb_id_table[] = { -+ { -+ .driver_info = 1 -+ }, -+}; -+ -+static struct usb_driver wrap_usb_driver = { -+ .name = DRIVER_NAME, -+ .id_table = wrap_usb_id_table, -+ .probe = wrap_pnp_start_usb_device, -+ .disconnect = wrap_pnp_remove_usb_device, -+ .suspend = wrap_pnp_suspend_usb_device, -+ .resume = wrap_pnp_resume_usb_device, -+}; -+#endif -+ -+/* register drivers for pci and usb */ -+static void register_devices(void) -+{ -+ int res; -+ -+ res = pci_register_driver(&wrap_pci_driver); -+ if (res < 0) { -+ ERROR("couldn't register pci driver: %d", res); -+ wrap_pci_driver.name = NULL; -+ } -+ -+#ifdef ENABLE_USB -+ res = usb_register(&wrap_usb_driver); -+ if (res < 0) { -+ ERROR("couldn't register usb driver: %d", res); -+ wrap_usb_driver.name = NULL; -+ } -+#endif -+ EXIT1(return); -+} -+ -+static void unregister_devices(void) -+{ -+ struct nt_list *cur, *next; -+ -+ mutex_lock(&loader_mutex); -+ nt_list_for_each_safe(cur, next, &wrap_devices) { -+ struct wrap_device *wd; -+ wd = container_of(cur, struct wrap_device, list); -+ set_bit(HW_DISABLED, &wd->hw_status); -+ } -+ mutex_unlock(&loader_mutex); -+ -+ if (wrap_pci_driver.name) -+ pci_unregister_driver(&wrap_pci_driver); -+#ifdef ENABLE_USB -+ if (wrap_usb_driver.name) -+ usb_deregister(&wrap_usb_driver); -+#endif -+} -+ -+struct wrap_device *load_wrap_device(struct load_device *load_device) -+{ -+ int ret; -+ struct nt_list *cur; -+ struct wrap_device *wd = NULL; -+ char vendor[5], device[5], subvendor[5], subdevice[5], bus[5]; -+ -+ ENTER1("%04x, %04x, %04x, %04x", load_device->vendor, -+ load_device->device, load_device->subvendor, -+ load_device->subdevice); -+ if (sprintf(vendor, "%04x", load_device->vendor) == 4 && -+ sprintf(device, "%04x", load_device->device) == 4 && -+ sprintf(subvendor, "%04x", load_device->subvendor) == 4 && -+ sprintf(subdevice, "%04x", load_device->subdevice) == 4 && -+ sprintf(bus, "%04x", load_device->bus) == 4) { -+ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DEVICE, -+#if DEBUG >= 1 -+ "1", -+#else -+ "0", -+#endif -+ UTILS_VERSION, vendor, device, -+ subvendor, subdevice, bus, NULL}; -+ char *env[] = {NULL}; -+ TRACE2("%s, %s, %s, %s, %s", vendor, device, -+ subvendor, subdevice, bus); -+ mutex_lock(&loader_mutex); -+ reinit_completion(&loader_complete); -+ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, -+ UMH_WAIT_PROC); -+ if (ret) { -+ mutex_unlock(&loader_mutex); -+ TRACE1("couldn't load device %04x:%04x; check system " -+ "log for messages from 'loadndisdriver'", -+ load_device->vendor, load_device->device); -+ EXIT1(return NULL); -+ } -+ wait_for_completion(&loader_complete); -+ wd = NULL; -+ nt_list_for_each(cur, &wrap_devices) { -+ wd = container_of(cur, struct wrap_device, list); -+ TRACE2("%p, %04x, %04x, %04x, %04x", wd, wd->vendor, -+ wd->device, wd->subvendor, wd->subdevice); -+ if (wd->vendor == load_device->vendor && -+ wd->device == load_device->device) -+ break; -+ else -+ wd = NULL; -+ } -+ mutex_unlock(&loader_mutex); -+ } else -+ wd = NULL; -+ EXIT1(return wd); -+} -+ -+struct wrap_device *get_wrap_device(void *dev, int bus) -+{ -+ struct nt_list *cur; -+ struct wrap_device *wd; -+ -+ mutex_lock(&loader_mutex); -+ wd = NULL; -+ nt_list_for_each(cur, &wrap_devices) { -+ wd = container_of(cur, struct wrap_device, list); -+ if (bus == WRAP_PCI_BUS && -+ wrap_is_pci_bus(wd->dev_bus) && wd->pci.pdev == dev) -+ break; -+ else if (bus == WRAP_USB_BUS && -+ wrap_is_usb_bus(wd->dev_bus) && wd->usb.udev == dev) -+ break; -+ else -+ wd = NULL; -+ } -+ mutex_unlock(&loader_mutex); -+ return wd; -+} -+ -+/* called with loader_mutex is down */ -+static long wrapper_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct load_driver *load_driver; -+ struct load_device load_device; -+ struct load_driver_file load_bin_file; -+ int ret; -+ void __user *addr = (void __user *)arg; -+ -+ ENTER1("cmd: 0x%x", cmd); -+ -+ ret = 0; -+ switch (cmd) { -+ case WRAP_IOCTL_LOAD_DEVICE: -+ if (copy_from_user(&load_device, addr, sizeof(load_device))) { -+ ret = -EFAULT; -+ break; -+ } -+ TRACE2("%04x, %04x, %04x, %04x", load_device.vendor, -+ load_device.device, load_device.subvendor, -+ load_device.subdevice); -+ if (load_device.vendor) { -+ struct wrap_device *wd; -+ wd = kzalloc(sizeof(*wd), GFP_KERNEL); -+ if (!wd) { -+ ret = -ENOMEM; -+ break; -+ } -+ InitializeListHead(&wd->settings); -+ wd->dev_bus = WRAP_BUS(load_device.bus); -+ wd->vendor = load_device.vendor; -+ wd->device = load_device.device; -+ wd->subvendor = load_device.subvendor; -+ wd->subdevice = load_device.subdevice; -+ strncpy(wd->conf_file_name, load_device.conf_file_name, -+ sizeof(wd->conf_file_name)); -+ wd->conf_file_name[sizeof(wd->conf_file_name)-1] = 0; -+ strncpy(wd->driver_name, load_device.driver_name, -+ sizeof(wd->driver_name)); -+ wd->driver_name[sizeof(wd->driver_name)-1] = 0; -+ InsertHeadList(&wrap_devices, &wd->list); -+ ret = 0; -+ } else -+ ret = -EINVAL; -+ break; -+ case WRAP_IOCTL_LOAD_DRIVER: -+ TRACE1("loading driver at %p", addr); -+ load_driver = vmalloc(sizeof(*load_driver)); -+ if (!load_driver) { -+ ret = -ENOMEM; -+ break; -+ } -+ if (copy_from_user(load_driver, addr, sizeof(*load_driver))) -+ ret = -EFAULT; -+ else -+ ret = load_user_space_driver(load_driver); -+ vfree(load_driver); -+ break; -+ case WRAP_IOCTL_LOAD_BIN_FILE: -+ if (copy_from_user(&load_bin_file, addr, sizeof(load_bin_file))) -+ ret = -EFAULT; -+ else -+ ret = add_bin_file(&load_bin_file); -+ break; -+ default: -+ ERROR("unknown ioctl 0x%x", cmd); -+ ret = -EINVAL; -+ break; -+ } -+ complete(&loader_complete); -+ EXIT1(return ret); -+} -+ -+#ifdef CONFIG_COMPAT -+static int copy_load_driver_file32(struct load_driver_file *k, -+ struct load_driver_file32 __user *u) -+{ -+ u32 data; -+ -+ if (copy_from_user(&k->driver_name, &u->driver_name, -+ sizeof(u->driver_name) + sizeof(u->name))) -+ return -EFAULT; -+ -+ if (get_user(k->size, &u->size)) -+ return -EFAULT; -+ if (get_user(data, &u->data)) -+ return -EFAULT; -+ -+ k->data = (void __user *)(unsigned long)data; -+ return 0; -+} -+ -+static int copy_load_driver32(struct load_driver *k, -+ struct load_driver32 __user *u) -+{ -+ int i; -+ -+ if (copy_from_user(&k->name, &u->name, -+ sizeof(u->name) + sizeof(u->conf_file_name))) -+ return -EFAULT; -+ -+ if (get_user(k->num_sys_files, &u->num_sys_files)) -+ return -EFAULT; -+ -+ for (i = 0; i < k->num_sys_files; i++) -+ if (copy_load_driver_file32(&k->sys_files[i], &u->sys_files[i])) -+ return -EFAULT; -+ -+ if (get_user(k->num_settings, &u->num_settings)) -+ return -EFAULT; -+ -+ if (copy_from_user(&k->settings, &u->settings, -+ sizeof(u->settings[0]) * k->num_settings)) -+ return -EFAULT; -+ -+ if (get_user(k->num_bin_files, &u->num_bin_files)) -+ return -EFAULT; -+ -+ for (i = 0; i < k->num_bin_files; i++) -+ if (copy_load_driver_file32(&k->bin_files[i], &u->bin_files[i])) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+static long wrapper_ioctl_compat(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ int ret = 0; -+ void __user *addr = (void __user *)arg; -+ struct load_driver *kdriver; -+ struct load_driver32 __user *udriver = addr; -+ struct load_driver_file kfile; -+ struct load_driver_file32 __user *ufile = addr; -+ -+ ENTER1("cmd: 0x%x", cmd); -+ -+ switch (cmd) { -+ case WRAP_IOCTL_LOAD_DEVICE32: -+ return wrapper_ioctl(file, WRAP_IOCTL_LOAD_DEVICE, arg); -+ case WRAP_IOCTL_LOAD_DRIVER32: -+ TRACE1("loading driver at %p", addr); -+ kdriver = vmalloc(sizeof(*kdriver)); -+ if (!kdriver) { -+ ret = -ENOMEM; -+ break; -+ } -+ -+ ret = copy_load_driver32(kdriver, udriver); -+ if (!ret) -+ ret = load_user_space_driver(kdriver); -+ -+ vfree(kdriver); -+ break; -+ case WRAP_IOCTL_LOAD_BIN_FILE32: -+ ret = copy_load_driver_file32(&kfile, ufile); -+ if (ret) -+ break; -+ -+ ret = add_bin_file(&kfile); -+ break; -+ default: -+ ERROR("unknown ioctl 0x%x", cmd); -+ ret = -EINVAL; -+ break; -+ } -+ complete(&loader_complete); -+ EXIT1(return ret); -+} -+#endif -+ -+static int wrapper_ioctl_release(struct inode *inode, struct file *file) -+{ -+ ENTER1(""); -+ complete(&loader_complete); -+ return 0; -+} -+ -+static struct file_operations wrapper_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = wrapper_ioctl, -+#ifdef CONFIG_COMPAT -+ .compat_ioctl = wrapper_ioctl_compat, -+#endif -+ .release = wrapper_ioctl_release, -+}; -+ -+static struct miscdevice wrapper_misc = { -+ .name = DRIVER_NAME, -+ .minor = MISC_DYNAMIC_MINOR, -+ .fops = &wrapper_fops -+}; -+ -+int loader_init(void) -+{ -+ int err; -+ -+ InitializeListHead(&wrap_drivers); -+ InitializeListHead(&wrap_devices); -+ mutex_init(&loader_mutex); -+ init_completion(&loader_complete); -+ if ((err = misc_register(&wrapper_misc)) < 0) { -+ ERROR("couldn't register module (%d)", err); -+ unregister_devices(); -+ EXIT1(return err); -+ } -+ register_devices(); -+ EXIT1(return 0); -+} -+ -+void loader_exit(void) -+{ -+ struct nt_list *cur, *next; -+ -+ ENTER1(""); -+ misc_deregister(&wrapper_misc); -+ unregister_devices(); -+ mutex_lock(&loader_mutex); -+ nt_list_for_each_safe(cur, next, &wrap_drivers) { -+ struct wrap_driver *driver; -+ driver = container_of(cur, struct wrap_driver, list); -+ unload_wrap_driver(driver); -+ } -+ mutex_unlock(&loader_mutex); -+ EXIT1(return); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/loader.h linux-5.6.11-ndis/3rdparty/ndiswrapper/loader.h ---- linux-5.6.11/3rdparty/ndiswrapper/loader.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/loader.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,108 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _LOADER_H_ -+#define _LOADER_H_ -+ -+#include "ndiswrapper.h" -+ -+#ifndef __KERNEL__ -+#define __user -+#endif -+ -+struct load_driver_file { -+ char driver_name[MAX_DRIVER_NAME_LEN]; -+ char name[MAX_DRIVER_NAME_LEN]; -+ size_t size; -+ void __user *data; -+}; -+ -+struct load_device_setting { -+ char name[MAX_SETTING_NAME_LEN]; -+ char value[MAX_SETTING_VALUE_LEN]; -+}; -+ -+struct load_device { -+ int bus; -+ int vendor; -+ int device; -+ int subvendor; -+ int subdevice; -+ char conf_file_name[MAX_DRIVER_NAME_LEN]; -+ char driver_name[MAX_DRIVER_NAME_LEN]; -+}; -+ -+struct load_driver { -+ char name[MAX_DRIVER_NAME_LEN]; -+ char conf_file_name[MAX_DRIVER_NAME_LEN]; -+ unsigned int num_sys_files; -+ struct load_driver_file sys_files[MAX_DRIVER_PE_IMAGES]; -+ unsigned int num_settings; -+ struct load_device_setting settings[MAX_DEVICE_SETTINGS]; -+ unsigned int num_bin_files; -+ struct load_driver_file bin_files[MAX_DRIVER_BIN_FILES]; -+}; -+ -+#define WRAP_IOCTL_LOAD_DEVICE _IOW(('N' + 'd' + 'i' + 'S'), 0, \ -+ struct load_device *) -+#define WRAP_IOCTL_LOAD_DRIVER _IOW(('N' + 'd' + 'i' + 'S'), 1, \ -+ struct load_driver *) -+#define WRAP_IOCTL_LOAD_BIN_FILE _IOW(('N' + 'd' + 'i' + 'S'), 2, \ -+ struct load_driver_file *) -+ -+#ifdef CONFIG_COMPAT -+struct load_driver_file32 { -+ char driver_name[MAX_DRIVER_NAME_LEN]; -+ char name[MAX_DRIVER_NAME_LEN]; -+ u32 size; -+ u32 data; -+}; -+ -+struct load_driver32 { -+ char name[MAX_DRIVER_NAME_LEN]; -+ char conf_file_name[MAX_DRIVER_NAME_LEN]; -+ u32 num_sys_files; -+ struct load_driver_file32 sys_files[MAX_DRIVER_PE_IMAGES]; -+ u32 num_settings; -+ struct load_device_setting settings[MAX_DEVICE_SETTINGS]; -+ u32 num_bin_files; -+ struct load_driver_file32 bin_files[MAX_DRIVER_BIN_FILES]; -+} __packed; -+ -+#define WRAP_IOCTL_LOAD_DEVICE32 _IOW(('N' + 'd' + 'i' + 'S'), 0, u32) -+#define WRAP_IOCTL_LOAD_DRIVER32 _IOW(('N' + 'd' + 'i' + 'S'), 1, u32) -+#define WRAP_IOCTL_LOAD_BIN_FILE32 _IOW(('N' + 'd' + 'i' + 'S'), 2, u32) -+#endif -+ -+#define WRAP_CMD_LOAD_DEVICE "load_device" -+#define WRAP_CMD_LOAD_DRIVER "load_driver" -+#define WRAP_CMD_LOAD_BIN_FILE "load_bin_file" -+ -+int loader_init(void); -+void loader_exit(void); -+ -+#ifdef __KERNEL__ -+struct wrap_device *load_wrap_device(struct load_device *load_device); -+struct wrap_driver *load_wrap_driver(struct wrap_device *device); -+struct wrap_bin_file *get_bin_file(char *bin_file_name); -+void free_bin_file(struct wrap_bin_file *bin_file); -+void unload_wrap_driver(struct wrap_driver *driver); -+void unload_wrap_device(struct wrap_device *wd); -+struct wrap_device *get_wrap_device(void *dev, int bus_type); -+ -+extern struct mutex loader_mutex; -+#endif -+ -+#endif /* LOADER_H */ -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/longlong.h linux-5.6.11-ndis/3rdparty/ndiswrapper/longlong.h ---- linux-5.6.11/3rdparty/ndiswrapper/longlong.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/longlong.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,1333 @@ -+/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. -+ Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000 -+ Free Software Foundation, Inc. -+ -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library 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 -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, write to the Free -+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -+ 02111-1307 USA. */ -+ -+/* You have to define the following before including this file: -+ -+ UWtype -- An unsigned type, default type for operations (typically a "word") -+ UHWtype -- An unsigned type, at least half the size of UWtype. -+ UDWtype -- An unsigned type, at least twice as large a UWtype -+ W_TYPE_SIZE -- size in bits of UWtype -+ -+ UQItype -- Unsigned 8 bit type. -+ SItype, USItype -- Signed and unsigned 32 bit types. -+ DItype, UDItype -- Signed and unsigned 64 bit types. -+ -+ On a 32 bit machine UWtype should typically be USItype; -+ on a 64 bit machine, UWtype should typically be UDItype. -+*/ -+ -+#define __BITS4 (W_TYPE_SIZE / 4) -+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) -+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) -+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) -+ -+#ifndef W_TYPE_SIZE -+#define W_TYPE_SIZE 32 -+#define UWtype USItype -+#define UHWtype USItype -+#define UDWtype UDItype -+#endif -+ -+/* Define auxiliary asm macros. -+ -+ 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two -+ UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype -+ word product in HIGH_PROD and LOW_PROD. -+ -+ 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a -+ UDWtype product. This is just a variant of umul_ppmm. -+ -+ 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, -+ denominator) divides a UDWtype, composed by the UWtype integers -+ HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient -+ in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less -+ than DENOMINATOR for correct operation. If, in addition, the most -+ significant bit of DENOMINATOR must be 1, then the pre-processor symbol -+ UDIV_NEEDS_NORMALIZATION is defined to 1. -+ -+ 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, -+ denominator). Like udiv_qrnnd but the numbers are signed. The quotient -+ is rounded towards 0. -+ -+ 5) count_leading_zeros(count, x) counts the number of zero-bits from the -+ msb to the first nonzero bit in the UWtype X. This is the number of -+ steps X needs to be shifted left to set the msb. Undefined for X == 0, -+ unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. -+ -+ 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts -+ from the least significant end. -+ -+ 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, -+ high_addend_2, low_addend_2) adds two UWtype integers, composed by -+ HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 -+ respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow -+ (i.e. carry out) is not stored anywhere, and is lost. -+ -+ 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, -+ high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, -+ composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and -+ LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE -+ and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, -+ and is lost. -+ -+ If any of these macros are left undefined for a particular CPU, -+ C macros are used. */ -+ -+/* The CPUs come in alphabetical order below. -+ -+ Please add support for more CPUs here, or improve the current support -+ for the CPUs below! -+ (E.g. WE32100, IBM360.) */ -+ -+#if defined (__GNUC__) && !defined (NO_ASM) -+ -+/* We sometimes need to clobber "cc" with gcc2, but that would not be -+ understood by gcc1. Use cpp to avoid major code duplication. */ -+#if __GNUC__ < 2 -+#define __CLOBBER_CC -+#define __AND_CLOBBER_CC -+#else /* __GNUC__ >= 2 */ -+#define __CLOBBER_CC : "cc" -+#define __AND_CLOBBER_CC , "cc" -+#endif /* __GNUC__ < 2 */ -+ -+#if defined (__alpha) && W_TYPE_SIZE == 64 -+#define umul_ppmm(ph, pl, m0, m1) \ -+ do { \ -+ UDItype __m0 = (m0), __m1 = (m1); \ -+ __asm__ ("umulh %r1,%2,%0" \ -+ : "=r" ((UDItype) ph) \ -+ : "%rJ" (__m0), \ -+ "rI" (__m1)); \ -+ (pl) = __m0 * __m1; \ -+ } while (0) -+#define UMUL_TIME 46 -+#ifndef LONGLONG_STANDALONE -+#define udiv_qrnnd(q, r, n1, n0, d) \ -+ do { UDItype __r; \ -+ (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ -+ (r) = __r; \ -+ } while (0) -+extern UDItype __udiv_qrnnd (UDItype *, UDItype, UDItype, UDItype); -+#define UDIV_TIME 220 -+#endif /* LONGLONG_STANDALONE */ -+#ifdef __alpha_cix__ -+#define count_leading_zeros(COUNT,X) \ -+ __asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X)) -+#define count_trailing_zeros(COUNT,X) \ -+ __asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X)) -+#define COUNT_LEADING_ZEROS_0 64 -+#else -+extern const UQItype __clz_tab[]; -+#define count_leading_zeros(COUNT,X) \ -+ do { \ -+ UDItype __xr = (X), __t, __a; \ -+ __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \ -+ __a = __clz_tab[__t ^ 0xff] - 1; \ -+ __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \ -+ (COUNT) = 64 - (__clz_tab[__t] + __a*8); \ -+ } while (0) -+#define count_trailing_zeros(COUNT,X) \ -+ do { \ -+ UDItype __xr = (X), __t, __a; \ -+ __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \ -+ __t = ~__t & -~__t; \ -+ __a = ((__t & 0xCC) != 0) * 2; \ -+ __a += ((__t & 0xF0) != 0) * 4; \ -+ __a += ((__t & 0xAA) != 0); \ -+ __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \ -+ __a <<= 3; \ -+ __t &= -__t; \ -+ __a += ((__t & 0xCC) != 0) * 2; \ -+ __a += ((__t & 0xF0) != 0) * 4; \ -+ __a += ((__t & 0xAA) != 0); \ -+ (COUNT) = __a; \ -+ } while (0) -+#endif /* __alpha_cix__ */ -+#endif /* __alpha */ -+ -+#if defined (__arc__) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("add.f %1, %4, %5\n\tadc %0, %2, %3" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "%r" ((USItype) (ah)), \ -+ "rIJ" ((USItype) (bh)), \ -+ "%r" ((USItype) (al)), \ -+ "rIJ" ((USItype) (bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("sub.f %1, %4, %5\n\tsbc %0, %2, %3" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "r" ((USItype) (ah)), \ -+ "rIJ" ((USItype) (bh)), \ -+ "r" ((USItype) (al)), \ -+ "rIJ" ((USItype) (bl))) -+/* Call libgcc routine. */ -+#define umul_ppmm(w1, w0, u, v) \ -+do { \ -+ DWunion __w; \ -+ __w.ll = __umulsidi3 (u, v); \ -+ w1 = __w.s.high; \ -+ w0 = __w.s.low; \ -+} while (0) -+#define __umulsidi3 __umulsidi3 -+UDItype __umulsidi3 (USItype, USItype); -+#endif -+ -+#if defined (__arm__) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("adds %1, %4, %5\n\tadc %0, %2, %3" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "%r" ((USItype) (ah)), \ -+ "rI" ((USItype) (bh)), \ -+ "%r" ((USItype) (al)), \ -+ "rI" ((USItype) (bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "r" ((USItype) (ah)), \ -+ "rI" ((USItype) (bh)), \ -+ "r" ((USItype) (al)), \ -+ "rI" ((USItype) (bl))) -+#define umul_ppmm(xh, xl, a, b) \ -+{register USItype __t0, __t1, __t2; \ -+ __asm__ ("%@ Inlined umul_ppmm\n" \ -+ " mov %2, %5, lsr #16\n" \ -+ " mov %0, %6, lsr #16\n" \ -+ " bic %3, %5, %2, lsl #16\n" \ -+ " bic %4, %6, %0, lsl #16\n" \ -+ " mul %1, %3, %4\n" \ -+ " mul %4, %2, %4\n" \ -+ " mul %3, %0, %3\n" \ -+ " mul %0, %2, %0\n" \ -+ " adds %3, %4, %3\n" \ -+ " addcs %0, %0, #65536\n" \ -+ " adds %1, %1, %3, lsl #16\n" \ -+ " adc %0, %0, %3, lsr #16" \ -+ : "=&r" ((USItype) (xh)), \ -+ "=r" ((USItype) (xl)), \ -+ "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ -+ : "r" ((USItype) (a)), \ -+ "r" ((USItype) (b)));} -+#define UMUL_TIME 20 -+#define UDIV_TIME 100 -+#endif /* __arm__ */ -+ -+#if defined (__hppa) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("add %4,%5,%1\n\taddc %2,%3,%0" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "%rM" ((USItype) (ah)), \ -+ "rM" ((USItype) (bh)), \ -+ "%rM" ((USItype) (al)), \ -+ "rM" ((USItype) (bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("sub %4,%5,%1\n\tsubb %2,%3,%0" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "rM" ((USItype) (ah)), \ -+ "rM" ((USItype) (bh)), \ -+ "rM" ((USItype) (al)), \ -+ "rM" ((USItype) (bl))) -+#if defined (_PA_RISC1_1) -+#define umul_ppmm(w1, w0, u, v) \ -+ do { \ -+ union \ -+ { \ -+ UDItype __f; \ -+ struct {USItype __w1, __w0;} __w1w0; \ -+ } __t; \ -+ __asm__ ("xmpyu %1,%2,%0" \ -+ : "=x" (__t.__f) \ -+ : "x" ((USItype) (u)), \ -+ "x" ((USItype) (v))); \ -+ (w1) = __t.__w1w0.__w1; \ -+ (w0) = __t.__w1w0.__w0; \ -+ } while (0) -+#define UMUL_TIME 8 -+#else -+#define UMUL_TIME 30 -+#endif -+#define UDIV_TIME 40 -+#define count_leading_zeros(count, x) \ -+ do { \ -+ USItype __tmp; \ -+ __asm__ ( \ -+ "ldi 1,%0\n" \ -+" extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ -+" extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n"\ -+" ldo 16(%0),%0 ; Yes. Perform add.\n" \ -+" extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ -+" extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n"\ -+" ldo 8(%0),%0 ; Yes. Perform add.\n" \ -+" extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ -+" extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n"\ -+" ldo 4(%0),%0 ; Yes. Perform add.\n" \ -+" extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ -+" extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n"\ -+" ldo 2(%0),%0 ; Yes. Perform add.\n" \ -+" extru %1,30,1,%1 ; Extract bit 1.\n" \ -+" sub %0,%1,%0 ; Subtract it.\n" \ -+ : "=r" (count), "=r" (__tmp) : "1" (x)); \ -+ } while (0) -+#endif -+ -+#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32 -+#define umul_ppmm(xh, xl, m0, m1) \ -+ do { \ -+ union {UDItype __ll; \ -+ struct {USItype __h, __l;} __i; \ -+ } __xx; \ -+ USItype __m0 = (m0), __m1 = (m1); \ -+ __asm__ ("mr %0,%3" \ -+ : "=r" (__xx.__i.__h), \ -+ "=r" (__xx.__i.__l) \ -+ : "%1" (__m0), \ -+ "r" (__m1)); \ -+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ -+ (xh) += ((((SItype) __m0 >> 31) & __m1) \ -+ + (((SItype) __m1 >> 31) & __m0)); \ -+ } while (0) -+#define smul_ppmm(xh, xl, m0, m1) \ -+ do { \ -+ union {DItype __ll; \ -+ struct {USItype __h, __l;} __i; \ -+ } __xx; \ -+ __asm__ ("mr %0,%3" \ -+ : "=r" (__xx.__i.__h), \ -+ "=r" (__xx.__i.__l) \ -+ : "%1" (m0), \ -+ "r" (m1)); \ -+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ -+ } while (0) -+#define sdiv_qrnnd(q, r, n1, n0, d) \ -+ do { \ -+ union {DItype __ll; \ -+ struct {USItype __h, __l;} __i; \ -+ } __xx; \ -+ __xx.__i.__h = n1; __xx.__i.__l = n0; \ -+ __asm__ ("dr %0,%2" \ -+ : "=r" (__xx.__ll) \ -+ : "0" (__xx.__ll), "r" (d)); \ -+ (q) = __xx.__i.__l; (r) = __xx.__i.__h; \ -+ } while (0) -+#endif -+ -+#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("addl %5,%1\n\tadcl %3,%0" \ -+ : "=r" (sh), \ -+ "=&r" (sl) \ -+ : "%0" ((USItype) (ah)), \ -+ "g" ((USItype) (bh)), \ -+ "%1" ((USItype) (al)), \ -+ "g" ((USItype) (bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ -+ : "=r" (sh), \ -+ "=&r" (sl) \ -+ : "0" ((USItype) (ah)), \ -+ "g" ((USItype) (bh)), \ -+ "1" ((USItype) (al)), \ -+ "g" ((USItype) (bl))) -+#define umul_ppmm(w1, w0, u, v) \ -+ __asm__ ("mull %3" \ -+ : "=a" (w0), \ -+ "=d" (w1) \ -+ : "%0" ((USItype) (u)), \ -+ "rm" ((USItype) (v))) -+#define udiv_qrnnd(q, r, n1, n0, dv) \ -+ __asm__ ("divl %4" \ -+ : "=a" (q), \ -+ "=d" (r) \ -+ : "0" ((USItype) (n0)), \ -+ "1" ((USItype) (n1)), \ -+ "rm" ((USItype) (dv))) -+#define count_leading_zeros(count, x) \ -+ do { \ -+ USItype __cbtmp; \ -+ __asm__ ("bsrl %1,%0" \ -+ : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ -+ (count) = __cbtmp ^ 31; \ -+ } while (0) -+#define count_trailing_zeros(count, x) \ -+ __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) -+#define UMUL_TIME 40 -+#define UDIV_TIME 40 -+#endif /* 80x86 */ -+ -+#if defined (__i960__) && W_TYPE_SIZE == 32 -+#define umul_ppmm(w1, w0, u, v) \ -+ ({union {UDItype __ll; \ -+ struct {USItype __l, __h;} __i; \ -+ } __xx; \ -+ __asm__ ("emul %2,%1,%0" \ -+ : "=d" (__xx.__ll) \ -+ : "%dI" ((USItype) (u)), \ -+ "dI" ((USItype) (v))); \ -+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) -+#define __umulsidi3(u, v) \ -+ ({UDItype __w; \ -+ __asm__ ("emul %2,%1,%0" \ -+ : "=d" (__w) \ -+ : "%dI" ((USItype) (u)), \ -+ "dI" ((USItype) (v))); \ -+ __w; }) -+#endif /* __i960__ */ -+ -+#if defined (__M32R__) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ /* The cmp clears the condition bit. */ \ -+ __asm__ ("cmp %0,%0\n\taddx %%5,%1\n\taddx %%3,%0" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "%0" ((USItype) (ah)), \ -+ "r" ((USItype) (bh)), \ -+ "%1" ((USItype) (al)), \ -+ "r" ((USItype) (bl)) \ -+ : "cbit") -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ /* The cmp clears the condition bit. */ \ -+ __asm__ ("cmp %0,%0\n\tsubx %5,%1\n\tsubx %3,%0" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "0" ((USItype) (ah)), \ -+ "r" ((USItype) (bh)), \ -+ "1" ((USItype) (al)), \ -+ "r" ((USItype) (bl)) \ -+ : "cbit") -+#endif /* __M32R__ */ -+ -+#if defined (__mc68000__) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \ -+ : "=d" ((USItype) (sh)), \ -+ "=&d" ((USItype) (sl)) \ -+ : "%0" ((USItype) (ah)), \ -+ "d" ((USItype) (bh)), \ -+ "%1" ((USItype) (al)), \ -+ "g" ((USItype) (bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0" \ -+ : "=d" ((USItype) (sh)), \ -+ "=&d" ((USItype) (sl)) \ -+ : "0" ((USItype) (ah)), \ -+ "d" ((USItype) (bh)), \ -+ "1" ((USItype) (al)), \ -+ "g" ((USItype) (bl))) -+ -+/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r. */ -+#if defined (__mc68020__) || defined(mc68020) \ -+ || defined(__mc68030__) || defined(mc68030) \ -+ || defined(__mc68040__) || defined(mc68040) \ -+ || defined(__mcpu32__) || defined(mcpu32) -+#define umul_ppmm(w1, w0, u, v) \ -+ __asm__ ("mulu%.l %3,%1:%0" \ -+ : "=d" ((USItype) (w0)), \ -+ "=d" ((USItype) (w1)) \ -+ : "%0" ((USItype) (u)), \ -+ "dmi" ((USItype) (v))) -+#define UMUL_TIME 45 -+#define udiv_qrnnd(q, r, n1, n0, d) \ -+ __asm__ ("divu%.l %4,%1:%0" \ -+ : "=d" ((USItype) (q)), \ -+ "=d" ((USItype) (r)) \ -+ : "0" ((USItype) (n0)), \ -+ "1" ((USItype) (n1)), \ -+ "dmi" ((USItype) (d))) -+#define UDIV_TIME 90 -+#define sdiv_qrnnd(q, r, n1, n0, d) \ -+ __asm__ ("divs%.l %4,%1:%0" \ -+ : "=d" ((USItype) (q)), \ -+ "=d" ((USItype) (r)) \ -+ : "0" ((USItype) (n0)), \ -+ "1" ((USItype) (n1)), \ -+ "dmi" ((USItype) (d))) -+ -+#else /* not mc68020 */ -+#if !defined(__mcf5200__) -+/* %/ inserts REGISTER_PREFIX, %# inserts IMMEDIATE_PREFIX. */ -+#define umul_ppmm(xh, xl, a, b) \ -+ __asm__ ("| Inlined umul_ppmm\n" \ -+ " move%.l %2,%/d0\n" \ -+ " move%.l %3,%/d1\n" \ -+ " move%.l %/d0,%/d2\n" \ -+ " swap %/d0\n" \ -+ " move%.l %/d1,%/d3\n" \ -+ " swap %/d1\n" \ -+ " move%.w %/d2,%/d4\n" \ -+ " mulu %/d3,%/d4\n" \ -+ " mulu %/d1,%/d2\n" \ -+ " mulu %/d0,%/d3\n" \ -+ " mulu %/d0,%/d1\n" \ -+ " move%.l %/d4,%/d0\n" \ -+ " eor%.w %/d0,%/d0\n" \ -+ " swap %/d0\n" \ -+ " add%.l %/d0,%/d2\n" \ -+ " add%.l %/d3,%/d2\n" \ -+ " jcc 1f\n" \ -+ " add%.l %#65536,%/d1\n" \ -+ "1: swap %/d2\n" \ -+ " moveq %#0,%/d0\n" \ -+ " move%.w %/d2,%/d0\n" \ -+ " move%.w %/d4,%/d2\n" \ -+ " move%.l %/d2,%1\n" \ -+ " add%.l %/d1,%/d0\n" \ -+ " move%.l %/d0,%0" \ -+ : "=g" ((USItype) (xh)), \ -+ "=g" ((USItype) (xl)) \ -+ : "g" ((USItype) (a)), \ -+ "g" ((USItype) (b)) \ -+ : "d0", "d1", "d2", "d3", "d4") -+#define UMUL_TIME 100 -+#define UDIV_TIME 400 -+#endif /* not mcf5200 */ -+#endif /* not mc68020 */ -+ -+/* The '020, '030, '040 and '060 have bitfield insns. */ -+#if defined (__mc68020__) || defined(mc68020) \ -+ || defined(__mc68030__) || defined(mc68030) \ -+ || defined(__mc68040__) || defined(mc68040) \ -+ || defined(__mc68060__) || defined(mc68060) -+#define count_leading_zeros(count, x) \ -+ __asm__ ("bfffo %1{%b2:%b2},%0" \ -+ : "=d" ((USItype) (count)) \ -+ : "od" ((USItype) (x)), "n" (0)) -+#endif -+#endif /* mc68000 */ -+ -+#if defined (__m88000__) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "%rJ" ((USItype) (ah)), \ -+ "rJ" ((USItype) (bh)), \ -+ "%rJ" ((USItype) (al)), \ -+ "rJ" ((USItype) (bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "rJ" ((USItype) (ah)), \ -+ "rJ" ((USItype) (bh)), \ -+ "rJ" ((USItype) (al)), \ -+ "rJ" ((USItype) (bl))) -+#define count_leading_zeros(count, x) \ -+ do { \ -+ USItype __cbtmp; \ -+ __asm__ ("ff1 %0,%1" \ -+ : "=r" (__cbtmp) \ -+ : "r" ((USItype) (x))); \ -+ (count) = __cbtmp ^ 31; \ -+ } while (0) -+#define COUNT_LEADING_ZEROS_0 63 /* sic */ -+#if defined (__mc88110__) -+#define umul_ppmm(wh, wl, u, v) \ -+ do { \ -+ union {UDItype __ll; \ -+ struct {USItype __h, __l;} __i; \ -+ } __xx; \ -+ __asm__ ("mulu.d %0,%1,%2" \ -+ : "=r" (__xx.__ll) \ -+ : "r" ((USItype) (u)), \ -+ "r" ((USItype) (v))); \ -+ (wh) = __xx.__i.__h; \ -+ (wl) = __xx.__i.__l; \ -+ } while (0) -+#define udiv_qrnnd(q, r, n1, n0, d) \ -+ ({union {UDItype __ll; \ -+ struct {USItype __h, __l;} __i; \ -+ } __xx; \ -+ USItype __q; \ -+ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ -+ __asm__ ("divu.d %0,%1,%2" \ -+ : "=r" (__q) \ -+ : "r" (__xx.__ll), \ -+ "r" ((USItype) (d))); \ -+ (r) = (n0) - __q * (d); (q) = __q; }) -+#define UMUL_TIME 5 -+#define UDIV_TIME 25 -+#else -+#define UMUL_TIME 17 -+#define UDIV_TIME 150 -+#endif /* __mc88110__ */ -+#endif /* __m88000__ */ -+ -+#if defined (__mips__) && W_TYPE_SIZE == 32 -+#define umul_ppmm(w1, w0, u, v) \ -+ __asm__ ("multu %2,%3" \ -+ : "=l" ((USItype) (w0)), \ -+ "=h" ((USItype) (w1)) \ -+ : "d" ((USItype) (u)), \ -+ "d" ((USItype) (v))) -+#define UMUL_TIME 10 -+#define UDIV_TIME 100 -+#endif /* __mips__ */ -+ -+#if defined (__ns32000__) && W_TYPE_SIZE == 32 -+#define umul_ppmm(w1, w0, u, v) \ -+ ({union {UDItype __ll; \ -+ struct {USItype __l, __h;} __i; \ -+ } __xx; \ -+ __asm__ ("meid %2,%0" \ -+ : "=g" (__xx.__ll) \ -+ : "%0" ((USItype) (u)), \ -+ "g" ((USItype) (v))); \ -+ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) -+#define __umulsidi3(u, v) \ -+ ({UDItype __w; \ -+ __asm__ ("meid %2,%0" \ -+ : "=g" (__w) \ -+ : "%0" ((USItype) (u)), \ -+ "g" ((USItype) (v))); \ -+ __w; }) -+#define udiv_qrnnd(q, r, n1, n0, d) \ -+ ({union {UDItype __ll; \ -+ struct {USItype __l, __h;} __i; \ -+ } __xx; \ -+ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ -+ __asm__ ("deid %2,%0" \ -+ : "=g" (__xx.__ll) \ -+ : "0" (__xx.__ll), \ -+ "g" ((USItype) (d))); \ -+ (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) -+#define count_trailing_zeros(count,x) \ -+ do { \ -+ __asm__ ("ffsd %2,%0" \ -+ : "=r" ((USItype) (count)) \ -+ : "0" ((USItype) 0), \ -+ "r" ((USItype) (x))); \ -+ } while (0) -+#endif /* __ns32000__ */ -+ -+/* FIXME: We should test _IBMR2 here when we add assembly support for the -+ system vendor compilers. -+ FIXME: What's needed for gcc PowerPC VxWorks? __vxworks__ is not good -+ enough, since that hits ARM and m68k too. */ -+#if (defined (_ARCH_PPC) /* AIX */ \ -+ || defined (_ARCH_PWR) /* AIX */ \ -+ || defined (_ARCH_COM) /* AIX */ \ -+ || defined (__powerpc__) /* gcc */ \ -+ || defined (__POWERPC__) /* BEOS */ \ -+ || defined (__ppc__) /* Darwin */ \ -+ || defined (PPC) /* GNU/Linux, SysV */ \ -+ ) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ do { \ -+ if (__builtin_constant_p (bh) && (bh) == 0) \ -+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ -+ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ -+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ -+ else \ -+ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ -+ : "=r" (sh), "=&r" (sl) \ -+ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ -+ } while (0) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ do { \ -+ if (__builtin_constant_p (ah) && (ah) == 0) \ -+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ -+ else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \ -+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ -+ else if (__builtin_constant_p (bh) && (bh) == 0) \ -+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ -+ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ -+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ -+ else \ -+ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ -+ : "=r" (sh), "=&r" (sl) \ -+ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ -+ } while (0) -+#define count_leading_zeros(count, x) \ -+ __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x)) -+#define COUNT_LEADING_ZEROS_0 32 -+#if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \ -+ || defined (__ppc__) || defined (PPC) || defined (__vxworks__) -+#define umul_ppmm(ph, pl, m0, m1) \ -+ do { \ -+ USItype __m0 = (m0), __m1 = (m1); \ -+ __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ -+ (pl) = __m0 * __m1; \ -+ } while (0) -+#define UMUL_TIME 15 -+#define smul_ppmm(ph, pl, m0, m1) \ -+ do { \ -+ SItype __m0 = (m0), __m1 = (m1); \ -+ __asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ -+ (pl) = __m0 * __m1; \ -+ } while (0) -+#define SMUL_TIME 14 -+#define UDIV_TIME 120 -+#elif defined (_ARCH_PWR) -+#define UMUL_TIME 8 -+#define smul_ppmm(xh, xl, m0, m1) \ -+ __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1)) -+#define SMUL_TIME 4 -+#define sdiv_qrnnd(q, r, nh, nl, d) \ -+ __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d)) -+#define UDIV_TIME 100 -+#endif -+#endif /* 32-bit POWER architecture variants. */ -+ -+/* We should test _IBMR2 here when we add assembly support for the system -+ vendor compilers. */ -+#if (defined (_ARCH_PPC64) || defined (__powerpc64__)) && W_TYPE_SIZE == 64 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ do { \ -+ if (__builtin_constant_p (bh) && (bh) == 0) \ -+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ -+ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ -+ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ -+ else \ -+ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ -+ : "=r" (sh), "=&r" (sl) \ -+ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ -+ } while (0) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ do { \ -+ if (__builtin_constant_p (ah) && (ah) == 0) \ -+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ -+ else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ -+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ -+ else if (__builtin_constant_p (bh) && (bh) == 0) \ -+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ -+ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ -+ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ -+ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ -+ else \ -+ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ -+ : "=r" (sh), "=&r" (sl) \ -+ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ -+ } while (0) -+#define count_leading_zeros(count, x) \ -+ __asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x)) -+#define COUNT_LEADING_ZEROS_0 64 -+#define umul_ppmm(ph, pl, m0, m1) \ -+ do { \ -+ UDItype __m0 = (m0), __m1 = (m1); \ -+ __asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ -+ (pl) = __m0 * __m1; \ -+ } while (0) -+#define UMUL_TIME 15 -+#define smul_ppmm(ph, pl, m0, m1) \ -+ do { \ -+ DItype __m0 = (m0), __m1 = (m1); \ -+ __asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ -+ (pl) = __m0 * __m1; \ -+ } while (0) -+#define SMUL_TIME 14 /* ??? */ -+#define UDIV_TIME 120 /* ??? */ -+#endif /* 64-bit PowerPC. */ -+ -+#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("a %1,%5\n\tae %0,%3" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "%0" ((USItype) (ah)), \ -+ "r" ((USItype) (bh)), \ -+ "%1" ((USItype) (al)), \ -+ "r" ((USItype) (bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("s %1,%5\n\tse %0,%3" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "0" ((USItype) (ah)), \ -+ "r" ((USItype) (bh)), \ -+ "1" ((USItype) (al)), \ -+ "r" ((USItype) (bl))) -+#define umul_ppmm(ph, pl, m0, m1) \ -+ do { \ -+ USItype __m0 = (m0), __m1 = (m1); \ -+ __asm__ ( \ -+ "s r2,r2\n" \ -+" mts r10,%2\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" m r2,%3\n" \ -+" cas %0,r2,r0\n" \ -+" mfs r10,%1" \ -+ : "=r" ((USItype) (ph)), \ -+ "=r" ((USItype) (pl)) \ -+ : "%r" (__m0), \ -+ "r" (__m1) \ -+ : "r2"); \ -+ (ph) += ((((SItype) __m0 >> 31) & __m1) \ -+ + (((SItype) __m1 >> 31) & __m0)); \ -+ } while (0) -+#define UMUL_TIME 20 -+#define UDIV_TIME 200 -+#define count_leading_zeros(count, x) \ -+ do { \ -+ if ((x) >= 0x10000) \ -+ __asm__ ("clz %0,%1" \ -+ : "=r" ((USItype) (count)) \ -+ : "r" ((USItype) (x) >> 16)); \ -+ else \ -+ { \ -+ __asm__ ("clz %0,%1" \ -+ : "=r" ((USItype) (count)) \ -+ : "r" ((USItype) (x))); \ -+ (count) += 16; \ -+ } \ -+ } while (0) -+#endif -+ -+#if defined (__sh2__) && W_TYPE_SIZE == 32 -+#define umul_ppmm(w1, w0, u, v) \ -+ __asm__ ( \ -+ "dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \ -+ : "=r" ((USItype)(w1)), \ -+ "=r" ((USItype)(w0)) \ -+ : "r" ((USItype)(u)), \ -+ "r" ((USItype)(v)) \ -+ : "macl", "mach") -+#define UMUL_TIME 5 -+#endif -+ -+#if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32 -+#define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v) -+#define count_leading_zeros(count, x) \ -+ do \ -+ { \ -+ UDItype x_ = (USItype)(x); \ -+ SItype c_; \ -+ \ -+ __asm__ ("nsb %1, %0" : "=r" (c_) : "r" (x_)); \ -+ (count) = c_ - 31; \ -+ } \ -+ while (0) -+#define COUNT_LEADING_ZEROS_0 32 -+#endif -+ -+#if defined (__sparc__) && !defined (__arch64__) && !defined (__sparcv9) \ -+ && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "%rJ" ((USItype) (ah)), \ -+ "rI" ((USItype) (bh)), \ -+ "%rJ" ((USItype) (al)), \ -+ "rI" ((USItype) (bl)) \ -+ __CLOBBER_CC) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0" \ -+ : "=r" ((USItype) (sh)), \ -+ "=&r" ((USItype) (sl)) \ -+ : "rJ" ((USItype) (ah)), \ -+ "rI" ((USItype) (bh)), \ -+ "rJ" ((USItype) (al)), \ -+ "rI" ((USItype) (bl)) \ -+ __CLOBBER_CC) -+#if defined (__sparc_v8__) -+#define umul_ppmm(w1, w0, u, v) \ -+ __asm__ ("umul %2,%3,%1;rd %%y,%0" \ -+ : "=r" ((USItype) (w1)), \ -+ "=r" ((USItype) (w0)) \ -+ : "r" ((USItype) (u)), \ -+ "r" ((USItype) (v))) -+#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ -+ __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\ -+ : "=&r" ((USItype) (__q)), \ -+ "=&r" ((USItype) (__r)) \ -+ : "r" ((USItype) (__n1)), \ -+ "r" ((USItype) (__n0)), \ -+ "r" ((USItype) (__d))) -+#else -+#if defined (__sparclite__) -+/* This has hardware multiply but not divide. It also has two additional -+ instructions scan (ffs from high bit) and divscc. */ -+#define umul_ppmm(w1, w0, u, v) \ -+ __asm__ ("umul %2,%3,%1;rd %%y,%0" \ -+ : "=r" ((USItype) (w1)), \ -+ "=r" ((USItype) (w0)) \ -+ : "r" ((USItype) (u)), \ -+ "r" ((USItype) (v))) -+#define udiv_qrnnd(q, r, n1, n0, d) \ -+ __asm__ ("! Inlined udiv_qrnnd\n" \ -+" wr %%g0,%2,%%y ! Not a delayed write for sparclite\n" \ -+" tst %%g0\n" \ -+" divscc %3,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%%g1\n" \ -+" divscc %%g1,%4,%0\n" \ -+" rd %%y,%1\n" \ -+" bl,a 1f\n" \ -+" add %1,%4,%1\n" \ -+"1: ! End of inline udiv_qrnnd" \ -+ : "=r" ((USItype) (q)), \ -+ "=r" ((USItype) (r)) \ -+ : "r" ((USItype) (n1)), \ -+ "r" ((USItype) (n0)), \ -+ "rI" ((USItype) (d)) \ -+ : "g1" __AND_CLOBBER_CC) -+#define UDIV_TIME 37 -+#define count_leading_zeros(count, x) \ -+ do { \ -+ __asm__ ("scan %1,1,%0" \ -+ : "=r" ((USItype) (count)) \ -+ : "r" ((USItype) (x))); \ -+ } while (0) -+/* Early sparclites return 63 for an argument of 0, but they warn that future -+ implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 -+ undefined. */ -+#else -+/* SPARC without integer multiplication and divide instructions. -+ (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */ -+#define umul_ppmm(w1, w0, u, v) \ -+ __asm__ ("! Inlined umul_ppmm\n" \ -+" wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr\n"\ -+" sra %3,31,%%o5 ! Don't move this insn\n" \ -+" and %2,%%o5,%%o5 ! Don't move this insn\n" \ -+" andcc %%g0,0,%%g1 ! Don't move this insn\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,%3,%%g1\n" \ -+" mulscc %%g1,0,%%g1\n" \ -+" add %%g1,%%o5,%0\n" \ -+" rd %%y,%1" \ -+ : "=r" ((USItype) (w1)), \ -+ "=r" ((USItype) (w0)) \ -+ : "%rI" ((USItype) (u)), \ -+ "r" ((USItype) (v)) \ -+ : "g1", "o5" __AND_CLOBBER_CC) -+#define UMUL_TIME 39 /* 39 instructions */ -+/* It's quite necessary to add this much assembler for the sparc. -+ The default udiv_qrnnd (in C) is more than 10 times slower! */ -+#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ -+ __asm__ ("! Inlined udiv_qrnnd\n" \ -+" mov 32,%%g1\n" \ -+" subcc %1,%2,%%g0\n" \ -+"1: bcs 5f\n" \ -+" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ -+" sub %1,%2,%1 ! this kills msb of n\n" \ -+" addx %1,%1,%1 ! so this can't give carry\n" \ -+" subcc %%g1,1,%%g1\n" \ -+"2: bne 1b\n" \ -+" subcc %1,%2,%%g0\n" \ -+" bcs 3f\n" \ -+" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ -+" b 3f\n" \ -+" sub %1,%2,%1 ! this kills msb of n\n" \ -+"4: sub %1,%2,%1\n" \ -+"5: addxcc %1,%1,%1\n" \ -+" bcc 2b\n" \ -+" subcc %%g1,1,%%g1\n" \ -+"! Got carry from n. Subtract next step to cancel this carry.\n" \ -+" bne 4b\n" \ -+" addcc %0,%0,%0 ! shift n1n0 and a 0-bit in lsb\n" \ -+" sub %1,%2,%1\n" \ -+"3: xnor %0,0,%0\n" \ -+" ! End of inline udiv_qrnnd" \ -+ : "=&r" ((USItype) (__q)), \ -+ "=&r" ((USItype) (__r)) \ -+ : "r" ((USItype) (__d)), \ -+ "1" ((USItype) (__n1)), \ -+ "0" ((USItype) (__n0)) : "g1" __AND_CLOBBER_CC) -+#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */ -+#endif /* __sparclite__ */ -+#endif /* __sparc_v8__ */ -+#endif /* sparc32 */ -+ -+#if ((defined (__sparc__) && defined (__arch64__)) || defined (__sparcv9)) \ -+ && W_TYPE_SIZE == 64 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("addcc %r4,%5,%1\n\t" \ -+ "add %r2,%3,%0\n\t" \ -+ "bcs,a,pn %%xcc, 1f\n\t" \ -+ "add %0, 1, %0\n" \ -+ "1:" \ -+ : "=r" ((UDItype)(sh)), \ -+ "=&r" ((UDItype)(sl)) \ -+ : "%rJ" ((UDItype)(ah)), \ -+ "rI" ((UDItype)(bh)), \ -+ "%rJ" ((UDItype)(al)), \ -+ "rI" ((UDItype)(bl)) \ -+ __CLOBBER_CC) -+ -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("subcc %r4,%5,%1\n\t" \ -+ "sub %r2,%3,%0\n\t" \ -+ "bcs,a,pn %%xcc, 1f\n\t" \ -+ "sub %0, 1, %0\n\t" \ -+ "1:" \ -+ : "=r" ((UDItype)(sh)), \ -+ "=&r" ((UDItype)(sl)) \ -+ : "rJ" ((UDItype)(ah)), \ -+ "rI" ((UDItype)(bh)), \ -+ "rJ" ((UDItype)(al)), \ -+ "rI" ((UDItype)(bl)) \ -+ __CLOBBER_CC) -+ -+#define umul_ppmm(wh, wl, u, v) \ -+ do { \ -+ UDItype tmp1, tmp2, tmp3, tmp4; \ -+ __asm__ __volatile__ ( \ -+ "srl %7,0,%3\n\t" \ -+ "mulx %3,%6,%1\n\t" \ -+ "srlx %6,32,%2\n\t" \ -+ "mulx %2,%3,%4\n\t" \ -+ "sllx %4,32,%5\n\t" \ -+ "srl %6,0,%3\n\t" \ -+ "sub %1,%5,%5\n\t" \ -+ "srlx %5,32,%5\n\t" \ -+ "addcc %4,%5,%4\n\t" \ -+ "srlx %7,32,%5\n\t" \ -+ "mulx %3,%5,%3\n\t" \ -+ "mulx %2,%5,%5\n\t" \ -+ "sethi %%hi(0x80000000),%2\n\t" \ -+ "addcc %4,%3,%4\n\t" \ -+ "srlx %4,32,%4\n\t" \ -+ "add %2,%2,%2\n\t" \ -+ "movcc %%xcc,%%g0,%2\n\t" \ -+ "addcc %5,%4,%5\n\t" \ -+ "sllx %3,32,%3\n\t" \ -+ "add %1,%3,%1\n\t" \ -+ "add %5,%2,%0" \ -+ : "=r" ((UDItype)(wh)), \ -+ "=&r" ((UDItype)(wl)), \ -+ "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ -+ : "r" ((UDItype)(u)), \ -+ "r" ((UDItype)(v)) \ -+ __CLOBBER_CC); \ -+ } while (0) -+#define UMUL_TIME 96 -+#define UDIV_TIME 230 -+#endif /* sparc64 */ -+ -+#if defined (__vax__) && W_TYPE_SIZE == 32 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("addl2 %5,%1\n\tadwc %3,%0" \ -+ : "=g" ((USItype) (sh)), \ -+ "=&g" ((USItype) (sl)) \ -+ : "%0" ((USItype) (ah)), \ -+ "g" ((USItype) (bh)), \ -+ "%1" ((USItype) (al)), \ -+ "g" ((USItype) (bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("subl2 %5,%1\n\tsbwc %3,%0" \ -+ : "=g" ((USItype) (sh)), \ -+ "=&g" ((USItype) (sl)) \ -+ : "0" ((USItype) (ah)), \ -+ "g" ((USItype) (bh)), \ -+ "1" ((USItype) (al)), \ -+ "g" ((USItype) (bl))) -+#define umul_ppmm(xh, xl, m0, m1) \ -+ do { \ -+ union { \ -+ UDItype __ll; \ -+ struct {USItype __l, __h;} __i; \ -+ } __xx; \ -+ USItype __m0 = (m0), __m1 = (m1); \ -+ __asm__ ("emul %1,%2,$0,%0" \ -+ : "=r" (__xx.__ll) \ -+ : "g" (__m0), \ -+ "g" (__m1)); \ -+ (xh) = __xx.__i.__h; \ -+ (xl) = __xx.__i.__l; \ -+ (xh) += ((((SItype) __m0 >> 31) & __m1) \ -+ + (((SItype) __m1 >> 31) & __m0)); \ -+ } while (0) -+#define sdiv_qrnnd(q, r, n1, n0, d) \ -+ do { \ -+ union {DItype __ll; \ -+ struct {SItype __l, __h;} __i; \ -+ } __xx; \ -+ __xx.__i.__h = n1; __xx.__i.__l = n0; \ -+ __asm__ ("ediv %3,%2,%0,%1" \ -+ : "=g" (q), "=g" (r) \ -+ : "g" (__xx.__ll), "g" (d)); \ -+ } while (0) -+#endif /* __vax__ */ -+ -+#if defined (__z8000__) && W_TYPE_SIZE == 16 -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \ -+ : "=r" ((unsigned int)(sh)), \ -+ "=&r" ((unsigned int)(sl)) \ -+ : "%0" ((unsigned int)(ah)), \ -+ "r" ((unsigned int)(bh)), \ -+ "%1" ((unsigned int)(al)), \ -+ "rQR" ((unsigned int)(bl))) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \ -+ : "=r" ((unsigned int)(sh)), \ -+ "=&r" ((unsigned int)(sl)) \ -+ : "0" ((unsigned int)(ah)), \ -+ "r" ((unsigned int)(bh)), \ -+ "1" ((unsigned int)(al)), \ -+ "rQR" ((unsigned int)(bl))) -+#define umul_ppmm(xh, xl, m0, m1) \ -+ do { \ -+ union {long int __ll; \ -+ struct {unsigned int __h, __l;} __i; \ -+ } __xx; \ -+ unsigned int __m0 = (m0), __m1 = (m1); \ -+ __asm__ ("mult %S0,%H3" \ -+ : "=r" (__xx.__i.__h), \ -+ "=r" (__xx.__i.__l) \ -+ : "%1" (__m0), \ -+ "rQR" (__m1)); \ -+ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ -+ (xh) += ((((signed int) __m0 >> 15) & __m1) \ -+ + (((signed int) __m1 >> 15) & __m0)); \ -+ } while (0) -+#endif /* __z8000__ */ -+ -+#endif /* __GNUC__ */ -+ -+/* If this machine has no inline assembler, use C macros. */ -+ -+#if !defined (add_ssaaaa) -+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ -+ do { \ -+ UWtype __x; \ -+ __x = (al) + (bl); \ -+ (sh) = (ah) + (bh) + (__x < (al)); \ -+ (sl) = __x; \ -+ } while (0) -+#endif -+ -+#if !defined (sub_ddmmss) -+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ -+ do { \ -+ UWtype __x; \ -+ __x = (al) - (bl); \ -+ (sh) = (ah) - (bh) - (__x > (al)); \ -+ (sl) = __x; \ -+ } while (0) -+#endif -+ -+#if !defined (umul_ppmm) -+#define umul_ppmm(w1, w0, u, v) \ -+ do { \ -+ UWtype __x0, __x1, __x2, __x3; \ -+ UHWtype __ul, __vl, __uh, __vh; \ -+ \ -+ __ul = __ll_lowpart (u); \ -+ __uh = __ll_highpart (u); \ -+ __vl = __ll_lowpart (v); \ -+ __vh = __ll_highpart (v); \ -+ \ -+ __x0 = (UWtype) __ul * __vl; \ -+ __x1 = (UWtype) __ul * __vh; \ -+ __x2 = (UWtype) __uh * __vl; \ -+ __x3 = (UWtype) __uh * __vh; \ -+ \ -+ __x1 += __ll_highpart (__x0);/* this can't give carry */ \ -+ __x1 += __x2; /* but this indeed can */ \ -+ if (__x1 < __x2) /* did we get it? */ \ -+ __x3 += __ll_B; /* yes, add it in the proper pos. */ \ -+ \ -+ (w1) = __x3 + __ll_highpart (__x1); \ -+ (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ -+ } while (0) -+#endif -+ -+#if !defined (__umulsidi3) -+#define __umulsidi3(u, v) \ -+ ({DWunion __w; \ -+ umul_ppmm (__w.s.high, __w.s.low, u, v); \ -+ __w.ll; }) -+#endif -+ -+/* Define this unconditionally, so it can be used for debugging. */ -+#define __udiv_qrnnd_c(q, r, n1, n0, d) \ -+ do { \ -+ UWtype __d1, __d0, __q1, __q0; \ -+ UWtype __r1, __r0, __m; \ -+ __d1 = __ll_highpart (d); \ -+ __d0 = __ll_lowpart (d); \ -+ \ -+ __r1 = (n1) % __d1; \ -+ __q1 = (n1) / __d1; \ -+ __m = (UWtype) __q1 * __d0; \ -+ __r1 = __r1 * __ll_B | __ll_highpart (n0); \ -+ if (__r1 < __m) \ -+ { \ -+ __q1--, __r1 += (d); \ -+ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ -+ if (__r1 < __m) \ -+ __q1--, __r1 += (d); \ -+ } \ -+ __r1 -= __m; \ -+ \ -+ __r0 = __r1 % __d1; \ -+ __q0 = __r1 / __d1; \ -+ __m = (UWtype) __q0 * __d0; \ -+ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ -+ if (__r0 < __m) \ -+ { \ -+ __q0--, __r0 += (d); \ -+ if (__r0 >= (d)) \ -+ if (__r0 < __m) \ -+ __q0--, __r0 += (d); \ -+ } \ -+ __r0 -= __m; \ -+ \ -+ (q) = (UWtype) __q1 * __ll_B | __q0; \ -+ (r) = __r0; \ -+ } while (0) -+ -+/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through -+ __udiv_w_sdiv (defined in libgcc or elsewhere). */ -+#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) -+#define udiv_qrnnd(q, r, nh, nl, d) \ -+ do { \ -+ USItype __r; \ -+ (q) = __udiv_w_sdiv (&__r, nh, nl, d); \ -+ (r) = __r; \ -+ } while (0) -+#endif -+ -+/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ -+#if !defined (udiv_qrnnd) -+#define UDIV_NEEDS_NORMALIZATION 1 -+#define udiv_qrnnd __udiv_qrnnd_c -+#endif -+ -+#if !defined (count_leading_zeros) -+extern const UQItype __clz_tab[]; -+#define count_leading_zeros(count, x) \ -+ do { \ -+ UWtype __xr = (x); \ -+ UWtype __a; \ -+ \ -+ if (W_TYPE_SIZE <= 32) \ -+ { \ -+ __a = __xr < ((UWtype)1<<2*__BITS4) \ -+ ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \ -+ : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ -+ } \ -+ else \ -+ { \ -+ for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ -+ if (((__xr >> __a) & 0xff) != 0) \ -+ break; \ -+ } \ -+ \ -+ (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ -+ } while (0) -+#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE -+#endif -+ -+#if !defined (count_trailing_zeros) -+/* Define count_trailing_zeros using count_leading_zeros. The latter might be -+ defined in asm, but if it is not, the C version above is good enough. */ -+#define count_trailing_zeros(count, x) \ -+ do { \ -+ UWtype __ctz_x = (x); \ -+ UWtype __ctz_c; \ -+ count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ -+ (count) = W_TYPE_SIZE - 1 - __ctz_c; \ -+ } while (0) -+#endif -+ -+#ifndef UDIV_NEEDS_NORMALIZATION -+#define UDIV_NEEDS_NORMALIZATION 0 -+#endif -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/Makefile linux-5.6.11-ndis/3rdparty/ndiswrapper/Makefile ---- linux-5.6.11/3rdparty/ndiswrapper/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/Makefile 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,213 @@ -+# Name of the module -+MODNAME = ndiswrapper -+ -+DISTFILES = \ -+ Makefile crt.c divdi3.c hal.c iw_ndis.c iw_ndis.h lin2win.S lin2win.h \ -+ loader.c loader.h longlong.h mkexport.sh mkstubs.sh ndis.c ndis.h \ -+ ndiswrapper.h ntoskernel.c ntoskernel.h ntoskernel_io.c pe_linker.c \ -+ pe_linker.h pnp.c pnp.h proc.c rtl.c usb.c usb.h win2lin_stubs.S \ -+ winnt_types.h workqueue.c wrapmem.c wrapmem.h wrapndis.c wrapndis.h \ -+ wrapper.c wrapper.h -+ -+# By default, we try to compile the modules for the currently running -+# kernel. But it's the first approximation, as we will re-read the -+# version from the kernel sources. -+KVERS_UNAME ?= $(shell uname -r) -+ -+# KBUILD is the path to the Linux kernel build tree. It is usually the -+# same as the kernel source tree, except when the kernel was compiled in -+# a separate directory. -+KBUILD ?= $(shell readlink -f /lib/modules/$(KVERS_UNAME)/build) -+ -+ifeq (,$(KBUILD)) -+$(error Kernel build tree not found - please set KBUILD to configured kernel) -+endif -+ -+KCONFIG := $(KBUILD)/.config -+ifeq (,$(wildcard $(KCONFIG))) -+$(error No .config found in $(KBUILD), please set KBUILD to configured kernel) -+endif -+ -+ifneq (,$(wildcard $(KBUILD)/include/linux/version.h)) -+ifneq (,$(wildcard $(KBUILD)/include/generated/uapi/linux/version.h)) -+$(error Multiple copies of version.h found, please clean your build tree) -+endif -+endif -+ -+# Kernel Makefile doesn't always know the exact kernel version, so we -+# get it from the kernel headers instead and pass it to make. -+VERSION_H := $(KBUILD)/include/generated/utsrelease.h -+ifeq (,$(wildcard $(VERSION_H))) -+VERSION_H := $(KBUILD)/include/linux/utsrelease.h -+endif -+ifeq (,$(wildcard $(VERSION_H))) -+VERSION_H := $(KBUILD)/include/linux/version.h -+endif -+ifeq (,$(wildcard $(VERSION_H))) -+$(error Please run 'make modules_prepare' in $(KBUILD)) -+endif -+ -+KVERS := $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' $(VERSION_H)) -+ -+ifeq (,$(KVERS)) -+$(error Cannot find UTS_RELEASE in $(VERSION_H), please report) -+endif -+ -+INST_DIR = /lib/modules/$(KVERS)/misc -+ -+SRC_DIR=$(shell pwd) -+ -+include $(KCONFIG) -+ -+# returns of structs and unions in registers when possible, like Windows -+EXTRA_CFLAGS += -freg-struct-return -+ -+# to produce debug trace, add option "DEBUG=" where is 1 to 6 -+ifdef DEBUG -+EXTRA_CFLAGS += -DDEBUG=$(DEBUG) -g -+endif -+ -+# to debug timers, add option "TIMER_DEBUG=1" -+ifdef TIMER_DEBUG -+EXTRA_CFLAGS += -DTIMER_DEBUG -+endif -+ -+# to debug event layer, add option "EVENT_DEBUG=1" -+ifdef EVENT_DEBUG -+EXTRA_CFLAGS += -DEVENT_DEBUG -+endif -+ -+# to debug USB layer, add option "USB_DEBUG=1" -+ifdef USB_DEBUG -+EXTRA_CFLAGS += -DUSB_DEBUG -+endif -+ -+# to debug I/O layer, add option "IO_DEBUG=1" -+ifdef IO_DEBUG -+EXTRA_CFLAGS += -DIO_DEBUG -+endif -+ -+# to debug worker threads, add option "WORK_DEBUG=1" -+ifdef WORK_DEBUG -+EXTRA_CFLAGS += -DWORK_DEBUG -+endif -+ -+# to debug memory allocation, add option "ALLOC_DEBUG=" where is 1 or 2 -+ifdef ALLOC_DEBUG -+EXTRA_CFLAGS += -DALLOC_DEBUG=$(ALLOC_DEBUG) -+endif -+ -+OBJS = crt.o hal.o iw_ndis.o loader.o ndis.o ntoskernel.o ntoskernel_io.o \ -+ pe_linker.o pnp.o proc.o rtl.o wrapmem.o wrapndis.o wrapper.o -+ -+EXPORT_SRCS = crt.c hal.c ndis.c ntoskernel.c ntoskernel_io.c rtl.c -+ -+STUB_SRCS = crt.c hal.c ndis.c ntoskernel.c ntoskernel_io.c \ -+ pnp.c rtl.c wrapndis.c -+ -+ -+# By default, USB layer is compiled in if USB support is in kernel; -+# to disable USB support in ndiswrapper even if USB support is in kernel, -+# add option "DISABLE_USB=1" -+ifndef DISABLE_USB -+ifeq ($(CONFIG_USB),y) -+ENABLE_USB = 1 -+endif -+ifeq ($(CONFIG_USB),m) -+ENABLE_USB = 1 -+endif -+endif -+ -+ifdef ENABLE_USB -+EXPORT_SRCS += usb.c -+STUB_SRCS += usb.c -+OBJS += usb.o -+EXTRA_CFLAGS += -DENABLE_USB -+endif -+ -+ifdef WRAP_WQ -+EXTRA_CFLAGS += -DWRAP_WQ -+OBJS += workqueue.o -+endif -+ -+ -+all: config_check modules -+ -+# generate exports symbol table from C files -+quiet_cmd_mkexport = MKEXPORT $@ -+cmd_mkexport = $(SHELL) $(obj)/mkexport.sh $< $@ -+ -+extra-y += $(EXPORT_SRCS:.c=_exports.h) -+%_exports.h: %.c $(obj)/mkexport.sh FORCE -+ $(call if_changed,mkexport) -+ -+$(addprefix $(obj)/,$(EXPORT_SRCS:.c=.o)): %.o: %_exports.h -+ -+ifeq ($(CONFIG_X86_64),y) -+quiet_cmd_mkstubs = MKSTUBS $@ -+cmd_mkstubs = $(SHELL) $(obj)/mkstubs.sh $(addprefix $(src)/,$(STUB_SRCS)) >$@ -+ -+extra-y += win2lin_stubs.h -+$(obj)/win2lin_stubs.h: $(addprefix $(src)/,$(STUB_SRCS)) FORCE -+ $(call if_changed,mkstubs) -+ -+$(obj)/win2lin_stubs.o: $(obj)/win2lin_stubs.h -+OBJS += win2lin_stubs.o lin2win.o -+else -+OBJS += divdi3.o -+endif -+ -+MODULE := $(MODNAME).ko -+obj-m := $(MODNAME).o -+ -+$(MODNAME)-objs := $(OBJS) -+ -+ -+config_check: -+ @if [ -z "$(CONFIG_WIRELESS_EXT)$(CONFIG_NET_RADIO)" ]; then \ -+ echo; echo; \ -+ echo "*** WARNING: This kernel lacks wireless extensions."; \ -+ echo "Wireless drivers will not work properly."; \ -+ echo; echo; \ -+ fi -+ @if [ -z "$(CONFIG_X86_64)" ] && [ -n "$(CONFIG_4KSTACKS)" ]; then \ -+ echo; echo; \ -+ echo "*** WARNING: This kernel uses 4K stack size option"; \ -+ echo "(CONFIG_4KSTACKS); many Windows drivers will not work"; \ -+ echo "with this option enabled. Disable CONFIG_4KSTACKS"; \ -+ echo "in kernel's .config file, recompile and install kernel"; \ -+ echo; echo; \ -+ fi -+ -+modules: -+ $(MAKE) -C $(KBUILD) M=$(SRC_DIR) -+ -+$(MODULE): -+ $(MAKE) modules -+ -+clean: -+ rm -f *.o *.ko .*.cmd *.mod.c *.symvers modules.order *~ .\#* -+ rm -f *_exports.h win2lin_stubs.h -+ rm -rf .tmp_versions -+ -+install: config_check $(MODULE) -+ @/sbin/modinfo $(MODULE) | grep -q "^vermagic: *$(KVERS) " || \ -+ { echo "$(MODULE)" is not for Linux $(KVERS); exit 1; } -+ mkdir -p -m 755 $(DESTDIR)$(INST_DIR) -+ install -m 0644 $(MODULE) $(DESTDIR)$(INST_DIR) -+ifndef DESTDIR -+ -/sbin/depmod -a $(KVERS) -+endif -+ -+uninstall: -+ rm -f $(DESTDIR)$(INST_DIR)/$(MODULE) -+ifndef DESTDIR -+ -/sbin/depmod -a $(KVERS) -+endif -+ -+dist: -+ @for file in $(DISTFILES); do \ -+ cp $$file $(distdir)/$$file || exit 1; \ -+ done -+ -+.PHONY: all modules clean install config_check dist -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/mkexport.sh linux-5.6.11-ndis/3rdparty/ndiswrapper/mkexport.sh ---- linux-5.6.11/3rdparty/ndiswrapper/mkexport.sh 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/mkexport.sh 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,42 @@ -+#! /bin/sh -+ -+# Generate exports symbol table from C files -+ -+input="$1" -+output="$2" -+exports=$(basename "$output" .h) -+exec >"$output" -+ -+echo "/* automatically generated from src */"; -+ -+sed -n -e '/^\(wstdcall\|wfastcall\|noregparm\|regparm3\|__attribute__\)/{ -+:more -+N -+s/\([^{]\)$/\1/ -+t more -+s/\n{$/;/ -+p -+}' $input -+ -+echo "#ifdef CONFIG_X86_64"; -+ -+sed -n \ -+ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ -+'WIN_FUNC_DECL(\1, \2)/p' \ -+ -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ -+'WIN_FUNC_DECL(\1, \2)/p' $input | sort -u -+ -+echo "#endif" -+echo "extern struct wrap_export $exports[];" -+echo "struct wrap_export $exports[] = {" -+ -+sed -n \ -+ -e 's/.*WIN_FUNC(_win_\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ -+' WIN_WIN_SYMBOL(\1, \2),/p' \ -+ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ -+' WIN_SYMBOL(\1, \2),/p' \ -+ -e 's/.*WIN_SYMBOL_MAP(\("[^"]\+"\)[ ,\n]\+\([^)]\+\)).*/'\ -+' {\1, (generic_func)\2},/p' $input | sort -u -+ -+echo " {NULL, NULL}" -+echo "};" -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/mkstubs.sh linux-5.6.11-ndis/3rdparty/ndiswrapper/mkstubs.sh ---- linux-5.6.11/3rdparty/ndiswrapper/mkstubs.sh 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/mkstubs.sh 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,12 @@ -+#! /bin/sh -+ -+for file in "$@"; do -+ echo -+ echo "# automatically generated from $file" -+ sed -n \ -+ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/\ -+ win2lin(\1, \2)/p' \ -+ -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/\ -+ win2lin(\1, \2)/p' \ -+ $file | sed -e 's/[ \t ]\+//' | sort -u; \ -+done -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/ndis.c linux-5.6.11-ndis/3rdparty/ndiswrapper/ndis.c ---- linux-5.6.11/3rdparty/ndiswrapper/ndis.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/ndis.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,3031 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ndis.h" -+#include "iw_ndis.h" -+#include "wrapndis.h" -+#include "pnp.h" -+#include "loader.h" -+#include -+#include -+#include "ndis_exports.h" -+ -+#define MAX_ALLOCATED_NDIS_PACKETS TX_RING_SIZE -+#define MAX_ALLOCATED_NDIS_BUFFERS TX_RING_SIZE -+ -+static struct work_struct ndis_work; -+static struct nt_list ndis_work_list; -+static spinlock_t ndis_work_list_lock; -+ -+struct workqueue_struct *ndis_wq; -+ -+static void *ndis_get_routine_address(char *name); -+ -+wstdcall void WIN_FUNC(NdisInitializeWrapper,4) -+ (void **driver_handle, struct driver_object *driver, -+ struct unicode_string *reg_path, void *unused) -+{ -+ ENTER1("handle: %p, driver: %p", driver_handle, driver); -+ *driver_handle = driver; -+ EXIT1(return); -+} -+ -+wstdcall void WIN_FUNC(NdisTerminateWrapper,2) -+ (struct device_object *dev_obj, void *system_specific) -+{ -+ EXIT1(return); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterMiniport,3) -+ (struct driver_object *drv_obj, struct miniport *mp, UINT length) -+{ -+ int min_length; -+ struct wrap_driver *wrap_driver; -+ struct ndis_driver *ndis_driver; -+ -+ min_length = ((char *)&mp->co_create_vc) - ((char *)mp); -+ -+ ENTER1("%p %p %d", drv_obj, mp, length); -+ -+ if (mp->major_version < 4) { -+ ERROR("Driver is using ndis version %d which is too old.", -+ mp->major_version); -+ EXIT1(return NDIS_STATUS_BAD_VERSION); -+ } -+ -+ if (length < min_length) { -+ ERROR("Characteristics length %d is too small", length); -+ EXIT1(return NDIS_STATUS_BAD_CHARACTERISTICS); -+ } -+ -+ TRACE1("%d.%d, %d, %u", mp->major_version, mp->minor_version, length, -+ (u32)sizeof(struct miniport)); -+ wrap_driver = IoGetDriverObjectExtension(drv_obj, -+ (void *)WRAP_DRIVER_CLIENT_ID); -+ if (!wrap_driver) { -+ ERROR("couldn't get wrap_driver"); -+ EXIT1(return NDIS_STATUS_RESOURCES); -+ } -+ if (IoAllocateDriverObjectExtension( -+ drv_obj, (void *)NDIS_DRIVER_CLIENT_ID, -+ sizeof(*ndis_driver), (void **)&ndis_driver) != -+ STATUS_SUCCESS) -+ EXIT1(return NDIS_STATUS_RESOURCES); -+ wrap_driver->ndis_driver = ndis_driver; -+ TRACE1("driver: %p", ndis_driver); -+ memcpy(&ndis_driver->mp, mp, min_t(int, sizeof(*mp), length)); -+ -+ DBG_BLOCK(2) { -+ int i; -+ void **func; -+ char *mp_funcs[] = { -+ "queryinfo", "reconfig", "reset", "send", "setinfo", -+ "tx_data", "return_packet", "send_packets", -+ "alloc_complete", "co_create_vc", "co_delete_vc", -+ "co_activate_vc", "co_deactivate_vc", -+ "co_send_packets", "co_request", "cancel_send_packets", -+ "pnp_event_notify", "shutdown", -+ }; -+ func = (void **)&ndis_driver->mp.queryinfo; -+ for (i = 0; i < ARRAY_SIZE(mp_funcs); i++) -+ TRACE0("function '%s' is at %p", mp_funcs[i], func[i]); -+ } -+ EXIT1(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterDevice,6) -+ (struct driver_object *drv_obj, struct unicode_string *dev_name, -+ struct unicode_string *link, void **funcs, -+ struct device_object **dev_obj, void **dev_obj_handle) -+{ -+ NTSTATUS status; -+ struct device_object *tmp; -+ int i; -+ -+ ENTER1("%p, %p, %p", drv_obj, dev_name, link); -+ status = IoCreateDevice(drv_obj, 0, dev_name, FILE_DEVICE_NETWORK, 0, -+ FALSE, &tmp); -+ -+ if (status != STATUS_SUCCESS) -+ EXIT1(return NDIS_STATUS_RESOURCES); -+ if (link) -+ status = IoCreateSymbolicLink(link, dev_name); -+ if (status != STATUS_SUCCESS) { -+ IoDeleteDevice(tmp); -+ EXIT1(return NDIS_STATUS_RESOURCES); -+ } -+ -+ *dev_obj = tmp; -+ *dev_obj_handle = *dev_obj; -+ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) -+ if (funcs[i] && i != IRP_MJ_PNP && i != IRP_MJ_POWER) { -+ drv_obj->major_func[i] = funcs[i]; -+ TRACE1("mj_fn for 0x%x is at %p", i, funcs[i]); -+ } -+ EXIT1(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMDeregisterDevice,1) -+ (struct device_object *dev_obj) -+{ -+ ENTER2("%p", dev_obj); -+ IoDeleteDevice(dev_obj); -+ return NDIS_STATUS_SUCCESS; -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemoryWithTag,3) -+ (void **dest, UINT length, ULONG tag) -+{ -+ void *addr; -+ -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ addr = ExAllocatePoolWithTag(NonPagedPool, length, tag); -+ TRACE4("%p", addr); -+ if (addr) { -+ *dest = addr; -+ EXIT4(return NDIS_STATUS_SUCCESS); -+ } else -+ EXIT4(return NDIS_STATUS_FAILURE); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemory,4) -+ (void **dest, UINT length, UINT flags, NDIS_PHY_ADDRESS highest_address) -+{ -+ return NdisAllocateMemoryWithTag(dest, length, 0); -+} -+ -+/* length_tag is either length or tag, depending on if -+ * NdisAllocateMemory or NdisAllocateMemoryTag is used to allocate -+ * memory */ -+wstdcall void WIN_FUNC(NdisFreeMemory,3) -+ (void *addr, UINT length_tag, UINT flags) -+{ -+ TRACE4("%p", addr); -+ ExFreePool(addr); -+} -+ -+noregparm void WIN_FUNC(NdisWriteErrorLogEntry,12) -+ (struct driver_object *drv_obj, ULONG error, ULONG count, ...) -+{ -+ va_list args; -+ int i; -+ ULONG code; -+ -+ va_start(args, count); -+ ERROR("log: %08X, count: %d, return_address: %p", -+ error, count, __builtin_return_address(0)); -+ for (i = 0; i < count; i++) { -+ code = va_arg(args, ULONG); -+ ERROR("code: 0x%x", code); -+ } -+ va_end(args); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisOpenConfiguration,3) -+ (NDIS_STATUS *status, struct ndis_mp_block **conf_handle, -+ struct ndis_mp_block *handle) -+{ -+ ENTER2("%p", conf_handle); -+ *conf_handle = handle; -+ *status = NDIS_STATUS_SUCCESS; -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisOpenProtocolConfiguration,3) -+ (NDIS_STATUS *status, void **confhandle, -+ struct unicode_string *section) -+{ -+ ENTER2("%p", confhandle); -+ *status = NDIS_STATUS_SUCCESS; -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByName,4) -+ (NDIS_STATUS *status, void *handle, -+ struct unicode_string *key, void **subkeyhandle) -+{ -+ struct ansi_string ansi; -+ ENTER2(""); -+ if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE) == STATUS_SUCCESS) { -+ TRACE2("%s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ *subkeyhandle = handle; -+ *status = NDIS_STATUS_SUCCESS; -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByIndex,5) -+ (NDIS_STATUS *status, void *handle, ULONG index, -+ struct unicode_string *key, void **subkeyhandle) -+{ -+ ENTER2("%u", index); -+// *subkeyhandle = handle; -+ *status = NDIS_STATUS_FAILURE; -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisCloseConfiguration,1) -+ (void *handle) -+{ -+ /* instead of freeing all configuration parameters as we are -+ * supposed to do here, we free them when the device is -+ * removed */ -+ ENTER2("%p", handle); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisOpenFile,5) -+ (NDIS_STATUS *status, struct wrap_bin_file **file, -+ UINT *filelength, struct unicode_string *filename, -+ NDIS_PHY_ADDRESS highest_address) -+{ -+ struct ansi_string ansi; -+ struct wrap_bin_file *bin_file; -+ -+ ENTER2("%p, %d, %llx, %p", status, *filelength, highest_address, *file); -+ if (RtlUnicodeStringToAnsiString(&ansi, filename, TRUE) != -+ STATUS_SUCCESS) { -+ *status = NDIS_STATUS_RESOURCES; -+ EXIT2(return); -+ } -+ TRACE2("%s", ansi.buf); -+ bin_file = get_bin_file(ansi.buf); -+ if (bin_file) { -+ *file = bin_file; -+ *filelength = bin_file->size; -+ *status = NDIS_STATUS_SUCCESS; -+ } else -+ *status = NDIS_STATUS_FILE_NOT_FOUND; -+ -+ RtlFreeAnsiString(&ansi); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMapFile,3) -+ (NDIS_STATUS *status, void **mappedbuffer, struct wrap_bin_file *file) -+{ -+ ENTER2("%p", file); -+ -+ if (!file) { -+ *status = NDIS_STATUS_ALREADY_MAPPED; -+ EXIT2(return); -+ } -+ -+ *status = NDIS_STATUS_SUCCESS; -+ *mappedbuffer = file->data; -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisUnmapFile,1) -+ (struct wrap_bin_file *file) -+{ -+ ENTER2("%p", file); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisCloseFile,1) -+ (struct wrap_bin_file *file) -+{ -+ ENTER2("%p", file); -+ free_bin_file(file); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisGetSystemUpTime,1) -+ (ULONG *ms) -+{ -+ *ms = 1000 * jiffies / HZ; -+ EXIT5(return); -+} -+ -+wstdcall ULONG WIN_FUNC(NDIS_BUFFER_TO_SPAN_PAGES,1) -+ (ndis_buffer *buffer) -+{ -+ ULONG n, length; -+ -+ if (buffer == NULL) -+ EXIT2(return 0); -+ if (MmGetMdlByteCount(buffer) == 0) -+ EXIT2(return 1); -+ -+ length = MmGetMdlByteCount(buffer); -+ n = SPAN_PAGES(MmGetMdlVirtualAddress(buffer), length); -+ TRACE4("%p, %p, %d, %d", buffer->startva, buffer->mappedsystemva, -+ length, n); -+ EXIT3(return n); -+} -+ -+wstdcall void WIN_FUNC(NdisGetBufferPhysicalArraySize,2) -+ (ndis_buffer *buffer, UINT *arraysize) -+{ -+ ENTER3("%p", buffer); -+ *arraysize = NDIS_BUFFER_TO_SPAN_PAGES(buffer); -+ EXIT3(return); -+} -+ -+static struct ndis_configuration_parameter * -+ndis_encode_setting(struct wrap_device_setting *setting, -+ enum ndis_parameter_type type) -+{ -+ struct ansi_string ansi; -+ struct ndis_configuration_parameter *param; -+ -+ param = setting->encoded; -+ if (param) { -+ if (param->type == type) -+ EXIT2(return param); -+ if (param->type == NdisParameterString) -+ RtlFreeUnicodeString(¶m->data.string); -+ setting->encoded = NULL; -+ } else -+ param = ExAllocatePoolWithTag(NonPagedPool, sizeof(*param), 0); -+ if (!param) { -+ ERROR("couldn't allocate memory"); -+ return NULL; -+ } -+ switch (type) { -+ case NdisParameterInteger: -+ param->data.integer = simple_strtol(setting->value, NULL, 0); -+ TRACE2("0x%x", param->data.integer); -+ break; -+ case NdisParameterHexInteger: -+ param->data.integer = simple_strtol(setting->value, NULL, 16); -+ TRACE2("0x%x", param->data.integer); -+ break; -+ case NdisParameterString: -+ RtlInitAnsiString(&ansi, setting->value); -+ TRACE2("'%s'", ansi.buf); -+ if (RtlAnsiStringToUnicodeString(¶m->data.string, -+ &ansi, TRUE)) { -+ ExFreePool(param); -+ EXIT2(return NULL); -+ } -+ break; -+ case NdisParameterBinary: -+ param->data.integer = simple_strtol(setting->value, NULL, 2); -+ TRACE2("0x%x", param->data.integer); -+ break; -+ default: -+ ERROR("unknown type: %d", type); -+ ExFreePool(param); -+ return NULL; -+ } -+ param->type = type; -+ setting->encoded = param; -+ EXIT2(return param); -+} -+ -+static int ndis_decode_setting(struct wrap_device_setting *setting, -+ struct ndis_configuration_parameter *param) -+{ -+ struct ansi_string ansi; -+ struct ndis_configuration_parameter *prev; -+ -+ ENTER2("%p, %p", setting, param); -+ prev = setting->encoded; -+ if (prev && prev->type == NdisParameterString) { -+ RtlFreeUnicodeString(&prev->data.string); -+ setting->encoded = NULL; -+ } -+ switch (param->type) { -+ case NdisParameterInteger: -+ snprintf(setting->value, MAX_SETTING_VALUE_LEN, "%u", -+ param->data.integer); -+ break; -+ case NdisParameterHexInteger: -+ snprintf(setting->value, MAX_SETTING_VALUE_LEN, "%x", -+ param->data.integer); -+ break; -+ case NdisParameterString: -+ ansi.buf = setting->value; -+ ansi.max_length = MAX_SETTING_VALUE_LEN; -+ if ((RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, -+ FALSE) != STATUS_SUCCESS) -+ || ansi.length >= MAX_SETTING_VALUE_LEN) { -+ EXIT1(return -1); -+ } -+ if (ansi.length == ansi.max_length) -+ ansi.length--; -+ setting->value[ansi.length] = 0; -+ break; -+ default: -+ TRACE2("unknown setting type: %d", param->type); -+ return -1; -+ } -+ TRACE2("setting changed %s='%s', %d", setting->name, setting->value, -+ ansi.length); -+ return 0; -+} -+ -+static int read_setting(struct nt_list *setting_list, char *keyname, int length, -+ struct ndis_configuration_parameter **param, -+ enum ndis_parameter_type type) -+{ -+ struct wrap_device_setting *setting; -+ mutex_lock(&loader_mutex); -+ nt_list_for_each_entry(setting, setting_list, list) { -+ if (strncasecmp(keyname, setting->name, length) == 0) { -+ TRACE2("setting %s='%s'", keyname, setting->value); -+ mutex_unlock(&loader_mutex); -+ *param = ndis_encode_setting(setting, type); -+ if (*param) -+ EXIT2(return 0); -+ else -+ EXIT2(return -1); -+ } -+ } -+ mutex_unlock(&loader_mutex); -+ EXIT2(return -1); -+} -+ -+wstdcall void WIN_FUNC(NdisReadConfiguration,5) -+ (NDIS_STATUS *status, struct ndis_configuration_parameter **param, -+ struct ndis_mp_block *nmb, struct unicode_string *key, -+ enum ndis_parameter_type type) -+{ -+ struct ansi_string ansi; -+ int ret; -+ -+ ENTER2("nmb: %p", nmb); -+ ret = RtlUnicodeStringToAnsiString(&ansi, key, TRUE); -+ if (ret != STATUS_SUCCESS || ansi.buf == NULL) { -+ *param = NULL; -+ *status = NDIS_STATUS_FAILURE; -+ RtlFreeAnsiString(&ansi); -+ EXIT2(return); -+ } -+ TRACE2("%d, %s", type, ansi.buf); -+ -+ if (read_setting(&nmb->wnd->wd->settings, ansi.buf, -+ ansi.length, param, type) == 0 || -+ read_setting(&nmb->wnd->wd->driver->settings, ansi.buf, -+ ansi.length, param, type) == 0) -+ *status = NDIS_STATUS_SUCCESS; -+ else { -+ TRACE2("setting %s not found (type:%d)", ansi.buf, type); -+ *status = NDIS_STATUS_FAILURE; -+ } -+ RtlFreeAnsiString(&ansi); -+ EXIT2(return); -+ -+} -+ -+wstdcall void WIN_FUNC(NdisWriteConfiguration,4) -+ (NDIS_STATUS *status, struct ndis_mp_block *nmb, -+ struct unicode_string *key, struct ndis_configuration_parameter *param) -+{ -+ struct ansi_string ansi; -+ char *keyname; -+ struct wrap_device_setting *setting; -+ -+ ENTER2("nmb: %p", nmb); -+ if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE)) { -+ *status = NDIS_STATUS_FAILURE; -+ EXIT2(return); -+ } -+ keyname = ansi.buf; -+ TRACE2("%s", keyname); -+ -+ mutex_lock(&loader_mutex); -+ nt_list_for_each_entry(setting, &nmb->wnd->wd->settings, list) { -+ if (strncasecmp(keyname, setting->name, ansi.length) == 0) { -+ mutex_unlock(&loader_mutex); -+ if (ndis_decode_setting(setting, param)) -+ *status = NDIS_STATUS_FAILURE; -+ else -+ *status = NDIS_STATUS_SUCCESS; -+ RtlFreeAnsiString(&ansi); -+ EXIT2(return); -+ } -+ } -+ mutex_unlock(&loader_mutex); -+ setting = kzalloc(sizeof(*setting), GFP_KERNEL); -+ if (setting) { -+ if (ansi.length == ansi.max_length) -+ ansi.length--; -+ memcpy(setting->name, keyname, ansi.length); -+ setting->name[ansi.length] = 0; -+ if (ndis_decode_setting(setting, param)) -+ *status = NDIS_STATUS_FAILURE; -+ else { -+ *status = NDIS_STATUS_SUCCESS; -+ mutex_lock(&loader_mutex); -+ InsertTailList(&nmb->wnd->wd->settings, &setting->list); -+ mutex_unlock(&loader_mutex); -+ } -+ } else -+ *status = NDIS_STATUS_RESOURCES; -+ -+ RtlFreeAnsiString(&ansi); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisReadNetworkAddress,4) -+ (NDIS_STATUS *status, void **addr, UINT *len, -+ struct ndis_mp_block *nmb) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ struct ndis_configuration_parameter *param; -+ struct unicode_string key; -+ struct ansi_string ansi; -+ typeof(wnd->mac) mac; -+ int i, ret; -+ -+ ENTER2("%p", nmb); -+ RtlInitAnsiString(&ansi, "NetworkAddress"); -+ *status = NDIS_STATUS_FAILURE; -+ if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) -+ EXIT1(return); -+ -+ NdisReadConfiguration(&ret, ¶m, nmb, &key, NdisParameterString); -+ RtlFreeUnicodeString(&key); -+ if (ret != NDIS_STATUS_SUCCESS) -+ EXIT1(return); -+ ret = RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, TRUE); -+ if (ret != STATUS_SUCCESS) -+ EXIT1(return); -+ -+ i = 0; -+ if (ansi.length >= 2 * sizeof(mac)) { -+ for (i = 0; i < sizeof(mac); i++) { -+ char c[3]; -+ int x; -+ c[0] = ansi.buf[i*2]; -+ c[1] = ansi.buf[i*2+1]; -+ c[2] = 0; -+ ret = sscanf(c, "%x", &x); -+ if (ret != 1) -+ break; -+ mac[i] = x; -+ } -+ } -+ TRACE2("%s, %d, " MACSTR, ansi.buf, i, MAC2STR(mac)); -+ RtlFreeAnsiString(&ansi); -+ if (i == sizeof(mac)) { -+ memcpy(wnd->mac, mac, sizeof(wnd->mac)); -+ *len = sizeof(mac); -+ *addr = wnd->mac; -+ *status = NDIS_STATUS_SUCCESS; -+ } -+ EXIT1(return); -+} -+ -+wstdcall void WIN_FUNC(NdisInitializeString,2) -+ (struct unicode_string *dest, UCHAR *src) -+{ -+ struct ansi_string ansi; -+ -+ ENTER2(""); -+ if (src == NULL) { -+ dest->length = dest->max_length = 0; -+ dest->buf = NULL; -+ } else { -+ RtlInitAnsiString(&ansi, src); -+ /* the string is freed with NdisFreeMemory */ -+ RtlAnsiStringToUnicodeString(dest, &ansi, TRUE); -+ } -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisInitAnsiString,2) -+ (struct ansi_string *dst, CHAR *src) -+{ -+ RtlInitAnsiString(dst, src); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisInitUnicodeString,2) -+ (struct unicode_string *dest, const wchar_t *src) -+{ -+ RtlInitUnicodeString(dest, src); -+ return; -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisAnsiStringToUnicodeString,2) -+ (struct unicode_string *dst, struct ansi_string *src) -+{ -+ ENTER2(""); -+ if (dst == NULL || src == NULL) -+ EXIT2(return NDIS_STATUS_FAILURE); -+ if (RtlAnsiStringToUnicodeString(dst, src, FALSE) == STATUS_SUCCESS) -+ return NDIS_STATUS_SUCCESS; -+ else -+ return NDIS_STATUS_FAILURE; -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisUnicodeStringToAnsiString,2) -+ (struct ansi_string *dst, struct unicode_string *src) -+{ -+ ENTER2(""); -+ if (dst == NULL || src == NULL) -+ EXIT2(return NDIS_STATUS_FAILURE); -+ if (RtlUnicodeStringToAnsiString(dst, src, FALSE) == STATUS_SUCCESS) -+ return NDIS_STATUS_SUCCESS; -+ else -+ return NDIS_STATUS_FAILURE; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(NdisUpcaseUnicodeString,2) -+ (struct unicode_string *dst, struct unicode_string *src) -+{ -+ EXIT2(return RtlUpcaseUnicodeString(dst, src, FALSE)); -+} -+ -+wstdcall void WIN_FUNC(NdisMSetAttributesEx,5) -+ (struct ndis_mp_block *nmb, void *mp_ctx, -+ UINT hangcheck_interval, UINT attributes, ULONG adaptertype) -+{ -+ struct ndis_device *wnd; -+ -+ ENTER1("%p, %p, %d, %08x, %d", nmb, mp_ctx, hangcheck_interval, -+ attributes, adaptertype); -+ wnd = nmb->wnd; -+ nmb->mp_ctx = mp_ctx; -+ wnd->attributes = attributes; -+ -+ if ((attributes & NDIS_ATTRIBUTE_BUS_MASTER) && -+ wrap_is_pci_bus(wnd->wd->dev_bus)) -+ pci_set_master(wnd->wd->pci.pdev); -+ -+ if (hangcheck_interval > 0) -+ wnd->hangcheck_interval = 2 * hangcheck_interval * HZ; -+ else -+ wnd->hangcheck_interval = 2 * HZ; -+ -+ EXIT1(return); -+} -+ -+wstdcall ULONG WIN_FUNC(NdisReadPciSlotInformation,5) -+ (struct ndis_mp_block *nmb, ULONG slot, -+ ULONG offset, char *buf, ULONG len) -+{ -+ struct wrap_device *wd = nmb->wnd->wd; -+ ULONG i; -+ if (!wrap_is_pci_bus(wd->dev_bus)) { -+ ERROR("used on a non-PCI device"); -+ return 0; -+ } -+ for (i = 0; i < len; i++) -+ if (pci_read_config_byte(wd->pci.pdev, offset + i, &buf[i]) != -+ PCIBIOS_SUCCESSFUL) -+ break; -+ DBG_BLOCK(2) { -+ if (i != len) -+ WARNING("%u, %u", i, len); -+ } -+ return i; -+} -+ -+wstdcall ULONG WIN_FUNC(NdisImmediateReadPciSlotInformation,5) -+ (struct ndis_mp_block *nmb, ULONG slot, -+ ULONG offset, char *buf, ULONG len) -+{ -+ return NdisReadPciSlotInformation(nmb, slot, offset, buf, len); -+} -+ -+wstdcall ULONG WIN_FUNC(NdisWritePciSlotInformation,5) -+ (struct ndis_mp_block *nmb, ULONG slot, -+ ULONG offset, char *buf, ULONG len) -+{ -+ struct wrap_device *wd = nmb->wnd->wd; -+ ULONG i; -+ if (!wrap_is_pci_bus(wd->dev_bus)) { -+ ERROR("used on a non-PCI device"); -+ return 0; -+ } -+ for (i = 0; i < len; i++) -+ if (pci_write_config_byte(wd->pci.pdev, offset + i, buf[i]) != -+ PCIBIOS_SUCCESSFUL) -+ break; -+ DBG_BLOCK(2) { -+ if (i != len) -+ WARNING("%u, %u", i, len); -+ } -+ return i; -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterIoPortRange,4) -+ (void **virt, struct ndis_mp_block *nmb, UINT start, UINT len) -+{ -+ ENTER3("%08x %08x", start, len); -+ *virt = (void *)(ULONG_PTR)start; -+ return NDIS_STATUS_SUCCESS; -+} -+ -+wstdcall void WIN_FUNC(NdisMDeregisterIoPortRange,4) -+ (struct ndis_mp_block *nmb, UINT start, UINT len, void* virt) -+{ -+ ENTER1("%08x %08x", start, len); -+} -+ -+wstdcall void WIN_FUNC(NdisReadPortUchar,3) -+ (struct ndis_mp_block *nmb, ULONG port, char *data) -+{ -+ *data = inb(port); -+} -+ -+wstdcall void WIN_FUNC(NdisImmediateReadPortUchar,3) -+ (struct ndis_mp_block *nmb, ULONG port, char *data) -+{ -+ *data = inb(port); -+} -+ -+wstdcall void WIN_FUNC(NdisWritePortUchar,3) -+ (struct ndis_mp_block *nmb, ULONG port, char data) -+{ -+ outb(data, port); -+} -+ -+wstdcall void WIN_FUNC(NdisImmediateWritePortUchar,3) -+ (struct ndis_mp_block *nmb, ULONG port, char data) -+{ -+ outb(data, port); -+} -+ -+wstdcall void WIN_FUNC(NdisMQueryAdapterResources,4) -+ (NDIS_STATUS *status, struct ndis_mp_block *nmb, -+ NDIS_RESOURCE_LIST *resource_list, UINT *size) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ NDIS_RESOURCE_LIST *list; -+ UINT resource_length; -+ -+ list = &wnd->wd->resource_list->list->partial_resource_list; -+ resource_length = sizeof(struct cm_partial_resource_list) + -+ sizeof(struct cm_partial_resource_descriptor) * -+ (list->count - 1); -+ TRACE2("%p, %p,%d (%d), %p %d %d", wnd, resource_list, *size, -+ resource_length, &list->partial_descriptors[list->count-1], -+ list->partial_descriptors[list->count-1].u.interrupt.level, -+ list->partial_descriptors[list->count-1].u.interrupt.vector); -+ if (*size < sizeof(*list)) { -+ *size = resource_length; -+ *status = NDIS_STATUS_BUFFER_TOO_SHORT; -+ } else { -+ ULONG count; -+ if (*size >= resource_length) { -+ *size = resource_length; -+ count = list->count; -+ } else { -+ UINT n = sizeof(*list); -+ count = 1; -+ while (count++ < list->count && n < *size) -+ n += sizeof(list->partial_descriptors); -+ *size = n; -+ } -+ memcpy(resource_list, list, *size); -+ resource_list->count = count; -+ *status = NDIS_STATUS_SUCCESS; -+ } -+ EXIT2(return); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMPciAssignResources,3) -+ (struct ndis_mp_block *nmb, ULONG slot_number, -+ NDIS_RESOURCE_LIST **resources) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ -+ ENTER2("%p, %p", wnd, wnd->wd->resource_list); -+ *resources = &wnd->wd->resource_list->list->partial_resource_list; -+ EXIT2(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMMapIoSpace,4) -+ (void __iomem **virt, struct ndis_mp_block *nmb, -+ NDIS_PHY_ADDRESS phy_addr, UINT len) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ -+ ENTER2("%llx, %d", phy_addr, len); -+ *virt = MmMapIoSpace(phy_addr, len, MmCached); -+ if (*virt == NULL) { -+ ERROR("ioremap failed"); -+ EXIT2(return NDIS_STATUS_FAILURE); -+ } -+ wnd->mem_start = phy_addr; -+ wnd->mem_end = phy_addr + len; -+ TRACE2("%p", *virt); -+ EXIT2(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(NdisMUnmapIoSpace,3) -+ (struct ndis_mp_block *nmb, void __iomem *virt, UINT len) -+{ -+ ENTER2("%p, %d", virt, len); -+ MmUnmapIoSpace(virt, len); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisAllocateSpinLock,1) -+ (struct ndis_spinlock *lock) -+{ -+ TRACE4("lock %p, %p", lock, &lock->klock); -+ KeInitializeSpinLock(&lock->klock); -+ lock->irql = PASSIVE_LEVEL; -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisFreeSpinLock,1) -+ (struct ndis_spinlock *lock) -+{ -+ TRACE4("lock %p, %p", lock, &lock->klock); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisAcquireSpinLock,1) -+ (struct ndis_spinlock *lock) -+{ -+ ENTER6("lock %p, %p", lock, &lock->klock); -+// assert_irql(_irql_ <= DISPATCH_LEVEL); -+ lock->irql = nt_spin_lock_irql(&lock->klock, DISPATCH_LEVEL); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisReleaseSpinLock,1) -+ (struct ndis_spinlock *lock) -+{ -+ ENTER6("lock %p, %p", lock, &lock->klock); -+// assert_irql(_irql_ == DISPATCH_LEVEL); -+ nt_spin_unlock_irql(&lock->klock, lock->irql); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisDprAcquireSpinLock,1) -+ (struct ndis_spinlock *lock) -+{ -+ ENTER6("lock %p", &lock->klock); -+// assert_irql(_irql_ == DISPATCH_LEVEL); -+ nt_spin_lock(&lock->klock); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisDprReleaseSpinLock,1) -+ (struct ndis_spinlock *lock) -+{ -+ ENTER6("lock %p", &lock->klock); -+// assert_irql(_irql_ == DISPATCH_LEVEL); -+ nt_spin_unlock(&lock->klock); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisInitializeReadWriteLock,1) -+ (struct ndis_rw_lock *rw_lock) -+{ -+ ENTER3("%p", rw_lock); -+ memset(rw_lock, 0, sizeof(*rw_lock)); -+ KeInitializeSpinLock(&rw_lock->klock); -+ return; -+} -+ -+/* read/write locks are implemented in a rather simplistic way - we -+ * should probably use Linux's rw_lock implementation */ -+ -+wstdcall void WIN_FUNC(NdisAcquireReadWriteLock,3) -+ (struct ndis_rw_lock *rw_lock, BOOLEAN write, -+ struct lock_state *lock_state) -+{ -+ if (write) { -+ while (1) { -+ if (cmpxchg(&rw_lock->count, 0, -1) == 0) -+ return; -+ while (rw_lock->count) -+ cpu_relax(); -+ } -+ return; -+ } -+ while (1) { -+ typeof(rw_lock->count) count; -+ while ((count = rw_lock->count) < 0) -+ cpu_relax(); -+ if (cmpxchg(&rw_lock->count, count, count + 1) == count) -+ return; -+ } -+} -+ -+wstdcall void WIN_FUNC(NdisReleaseReadWriteLock,2) -+ (struct ndis_rw_lock *rw_lock, struct lock_state *lock_state) -+{ -+ if (rw_lock->count > 0) -+ pre_atomic_add(rw_lock->count, -1); -+ else if (rw_lock->count == -1) -+ rw_lock->count = 0; -+ else -+ WARNING("invalid state: %d", rw_lock->count); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateMapRegisters,5) -+ (struct ndis_mp_block *nmb, UINT dmachan, -+ NDIS_DMA_SIZE dmasize, ULONG basemap, ULONG max_buf_size) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ -+ ENTER2("%p, %d %d %d %d", wnd, dmachan, dmasize, basemap, max_buf_size); -+ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { -+ ERROR("used on a non-PCI device"); -+ return NDIS_STATUS_NOT_SUPPORTED; -+ } -+ if (wnd->dma_map_count > 0) { -+ WARNING("%s: map registers already allocated: %u", -+ wnd->net_dev->name, wnd->dma_map_count); -+ EXIT2(return NDIS_STATUS_RESOURCES); -+ } -+ if (dmasize == NDIS_DMA_24BITS) { -+ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(24)) || -+ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, -+ DMA_BIT_MASK(24))) -+ WARNING("setting dma mask failed"); -+ } else if (dmasize == NDIS_DMA_32BITS) { -+ /* consistent dma is in low 32-bits by default */ -+ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32))) -+ WARNING("setting dma mask failed"); -+#ifdef CONFIG_X86_64 -+ } else if (dmasize == NDIS_DMA_64BITS) { -+ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(64)) || -+ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, -+ DMA_BIT_MASK(64))) -+ WARNING("setting dma mask failed"); -+ else -+ wnd->net_dev->features |= NETIF_F_HIGHDMA; -+#endif -+ } else { -+ ERROR("dmasize %d not supported", dmasize); -+ EXIT2(return NDIS_STATUS_NOT_SUPPORTED); -+ } -+ /* since memory for buffer is allocated with kmalloc, buffer -+ * is physically contiguous, so entire map will fit in one -+ * register */ -+ if (basemap > 64) { -+ WARNING("Windows driver %s requesting too many (%u) " -+ "map registers", wnd->wd->driver->name, basemap); -+ /* As per NDIS, NDIS_STATUS_RESOURCES should be -+ * returned, but with that Atheros PCI driver fails - -+ * for now tolerate it */ -+// EXIT2(return NDIS_STATUS_RESOURCES); -+ } -+ -+ wnd->dma_map_addr = kzalloc(basemap * sizeof(*(wnd->dma_map_addr)), -+ GFP_KERNEL); -+ if (!wnd->dma_map_addr) -+ EXIT2(return NDIS_STATUS_RESOURCES); -+ wnd->dma_map_count = basemap; -+ TRACE2("%u", wnd->dma_map_count); -+ EXIT2(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(NdisMFreeMapRegisters,1) -+ (struct ndis_mp_block *nmb) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ int i; -+ -+ ENTER2("wnd: %p", wnd); -+ if (wnd->dma_map_addr) { -+ for (i = 0; i < wnd->dma_map_count; i++) { -+ if (wnd->dma_map_addr[i]) -+ WARNING("%s: dma addr 0x%llx not freed by " -+ "Windows driver", wnd->net_dev->name, -+ (unsigned long long)wnd->dma_map_addr[i]); -+ } -+ kfree(wnd->dma_map_addr); -+ wnd->dma_map_addr = NULL; -+ } else -+ WARNING("map registers already freed?"); -+ wnd->dma_map_count = 0; -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMStartBufferPhysicalMapping,6) -+ (struct ndis_mp_block *nmb, ndis_buffer *buf, -+ ULONG index, BOOLEAN write_to_dev, -+ struct ndis_phy_addr_unit *phy_addr_array, UINT *array_size) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ -+ ENTER3("%p, %p, %u, %u", wnd, buf, index, wnd->dma_map_count); -+ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { -+ ERROR("used on a non-PCI device"); -+ return; -+ } -+ if (unlikely(wnd->sg_dma_size || !write_to_dev || -+ index >= wnd->dma_map_count)) { -+ WARNING("invalid request: %d, %d, %d, %d", wnd->sg_dma_size, -+ write_to_dev, index, wnd->dma_map_count); -+ phy_addr_array[0].phy_addr = 0; -+ phy_addr_array[0].length = 0; -+ *array_size = 0; -+ return; -+ } -+ if (wnd->dma_map_addr[index]) { -+ TRACE2("buffer %p at %d is already mapped: %llx", buf, index, -+ (unsigned long long)wnd->dma_map_addr[index]); -+// *array_size = 1; -+ return; -+ } -+ TRACE3("%p, %p, %u", buf, MmGetSystemAddressForMdl(buf), -+ MmGetMdlByteCount(buf)); -+ DBG_BLOCK(4) { -+ dump_bytes(__func__, MmGetSystemAddressForMdl(buf), -+ MmGetMdlByteCount(buf)); -+ } -+ wnd->dma_map_addr[index] = -+ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, -+ MmGetSystemAddressForMdl(buf), -+ MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); -+ phy_addr_array[0].phy_addr = wnd->dma_map_addr[index]; -+ phy_addr_array[0].length = MmGetMdlByteCount(buf); -+ TRACE4("%llx, %d, %d", phy_addr_array[0].phy_addr, -+ phy_addr_array[0].length, index); -+ *array_size = 1; -+} -+ -+wstdcall void WIN_FUNC(NdisMCompleteBufferPhysicalMapping,3) -+ (struct ndis_mp_block *nmb, ndis_buffer *buf, ULONG index) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ -+ ENTER3("%p, %p %u (%u)", wnd, buf, index, wnd->dma_map_count); -+ -+ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { -+ ERROR("used on a non-PCI device"); -+ return; -+ } -+ if (unlikely(wnd->sg_dma_size)) -+ WARNING("buffer %p may have been unmapped already", buf); -+ if (index >= wnd->dma_map_count) { -+ ERROR("invalid map register (%u >= %u)", -+ index, wnd->dma_map_count); -+ return; -+ } -+ TRACE4("%llx", (unsigned long long)wnd->dma_map_addr[index]); -+ if (wnd->dma_map_addr[index]) { -+ PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, wnd->dma_map_addr[index], -+ MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); -+ wnd->dma_map_addr[index] = 0; -+ } else -+ WARNING("map registers at %u not used", index); -+} -+ -+wstdcall void WIN_FUNC(NdisMAllocateSharedMemory,5) -+ (struct ndis_mp_block *nmb, ULONG size, -+ BOOLEAN cached, void **virt, NDIS_PHY_ADDRESS *phys) -+{ -+ dma_addr_t dma_addr; -+ struct wrap_device *wd = nmb->wnd->wd; -+ -+ ENTER3("size: %u, cached: %d", size, cached); -+ if (!wrap_is_pci_bus(wd->dev_bus)) { -+ ERROR("used on a non-PCI device"); -+ return; -+ } -+ *virt = PCI_DMA_ALLOC_COHERENT(wd->pci.pdev, size, &dma_addr); -+ if (*virt) -+ *phys = dma_addr; -+ else -+ WARNING("couldn't allocate %d bytes of %scached DMA memory", -+ size, cached ? "" : "un-"); -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMFreeSharedMemory,5) -+ (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, -+ void *virt, NDIS_PHY_ADDRESS addr) -+{ -+ struct wrap_device *wd = nmb->wnd->wd; -+ ENTER3("%p, %llx, %u", virt, addr, size); -+ if (!wrap_is_pci_bus(wd->dev_bus)) { -+ ERROR("used on a non-PCI device"); -+ return; -+ } -+ PCI_DMA_FREE_COHERENT(wd->pci.pdev, size, virt, addr); -+ EXIT3(return); -+} -+ -+wstdcall void alloc_shared_memory_async(void *arg1, void *arg2) -+{ -+ struct ndis_device *wnd; -+ struct alloc_shared_mem *alloc_shared_mem; -+ struct miniport *mp; -+ void *virt; -+ NDIS_PHY_ADDRESS phys; -+ KIRQL irql; -+ -+ wnd = arg1; -+ alloc_shared_mem = arg2; -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ NdisMAllocateSharedMemory(wnd->nmb, alloc_shared_mem->size, -+ alloc_shared_mem->cached, &virt, &phys); -+ irql = serialize_lock_irql(wnd); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ LIN2WIN5(mp->alloc_complete, wnd->nmb, virt, -+ &phys, alloc_shared_mem->size, alloc_shared_mem->ctx); -+ serialize_unlock_irql(wnd, irql); -+ kfree(alloc_shared_mem); -+} -+WIN_FUNC_DECL(alloc_shared_memory_async,2) -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateSharedMemoryAsync,4) -+ (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void *ctx) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ struct alloc_shared_mem *alloc_shared_mem; -+ -+ ENTER3("wnd: %p", wnd); -+ alloc_shared_mem = kmalloc(sizeof(*alloc_shared_mem), irql_gfp()); -+ if (!alloc_shared_mem) { -+ WARNING("couldn't allocate memory"); -+ return NDIS_STATUS_FAILURE; -+ } -+ -+ alloc_shared_mem->size = size; -+ alloc_shared_mem->cached = cached; -+ alloc_shared_mem->ctx = ctx; -+ if (schedule_ntos_work_item(WIN_FUNC_PTR(alloc_shared_memory_async,2), -+ wnd, alloc_shared_mem)) -+ EXIT3(return NDIS_STATUS_FAILURE); -+ EXIT3(return NDIS_STATUS_PENDING); -+} -+ -+/* Some drivers allocate NDIS_BUFFER (aka MDL) very often; instead of -+ * allocating and freeing with kernel functions, we chain them into -+ * ndis_buffer_pool. When an MDL is freed, it is added to the list of -+ * free MDLs. When allocated, we first check if there is one in free -+ * list and if so just return it; otherwise, we allocate a new one and -+ * return that. This reduces memory fragmentation. Windows DDK says -+ * that the driver itself shouldn't check what is returned in -+ * pool_handle, presumably because buffer pools are not used in -+ * XP. However, as long as driver follows rest of the semantics - that -+ * it should indicate maximum number of MDLs used with num_descr and -+ * pass the same pool_handle in other buffer functions, this should -+ * work. Sadly, though, NdisFreeBuffer doesn't pass the pool_handle, -+ * so we use 'process' field of MDL to store pool_handle. */ -+ -+wstdcall void WIN_FUNC(NdisAllocateBufferPool,3) -+ (NDIS_STATUS *status, struct ndis_buffer_pool **pool_handle, -+ UINT num_descr) -+{ -+ struct ndis_buffer_pool *pool; -+ -+ ENTER1("buffers: %d", num_descr); -+ pool = kmalloc(sizeof(*pool), irql_gfp()); -+ if (!pool) { -+ *status = NDIS_STATUS_RESOURCES; -+ EXIT3(return); -+ } -+ spin_lock_init(&pool->lock); -+ pool->max_descr = num_descr; -+ pool->num_allocated_descr = 0; -+ pool->free_descr = NULL; -+ *pool_handle = pool; -+ *status = NDIS_STATUS_SUCCESS; -+ TRACE1("pool: %p, num_descr: %d", pool, num_descr); -+ EXIT1(return); -+} -+ -+wstdcall void WIN_FUNC(NdisAllocateBuffer,5) -+ (NDIS_STATUS *status, ndis_buffer **buffer, -+ struct ndis_buffer_pool *pool, void *virt, UINT length) -+{ -+ ndis_buffer *descr; -+ -+ ENTER4("pool: %p (%d)", pool, pool->num_allocated_descr); -+ /* NDIS drivers should call this at DISPATCH_LEVEL, but -+ * alloc_tx_packet calls at SOFT_IRQL */ -+ assert_irql(_irql_ <= SOFT_LEVEL); -+ if (!pool) { -+ *status = NDIS_STATUS_FAILURE; -+ *buffer = NULL; -+ EXIT4(return); -+ } -+ spin_lock_bh(&pool->lock); -+ if ((descr = pool->free_descr)) -+ pool->free_descr = descr->next; -+ spin_unlock_bh(&pool->lock); -+ if (descr) { -+ typeof(descr->flags) flags; -+ flags = descr->flags; -+ memset(descr, 0, sizeof(*descr)); -+ MmInitializeMdl(descr, virt, length); -+ if (flags & MDL_CACHE_ALLOCATED) -+ descr->flags |= MDL_CACHE_ALLOCATED; -+ } else { -+ if (pool->num_allocated_descr > pool->max_descr) { -+ TRACE2("pool %p is full: %d(%d)", pool, -+ pool->num_allocated_descr, pool->max_descr); -+#ifndef ALLOW_POOL_OVERFLOW -+ *status = NDIS_STATUS_FAILURE; -+ *buffer = NULL; -+ return; -+#endif -+ } -+ descr = allocate_init_mdl(virt, length); -+ if (!descr) { -+ WARNING("couldn't allocate buffer"); -+ *status = NDIS_STATUS_FAILURE; -+ *buffer = NULL; -+ EXIT4(return); -+ } -+ TRACE4("buffer %p for %p, %d", descr, virt, length); -+ atomic_inc_var(pool->num_allocated_descr); -+ } -+ /* TODO: make sure this mdl can map given buffer */ -+ MmBuildMdlForNonPagedPool(descr); -+// descr->flags |= MDL_ALLOCATED_FIXED_SIZE | -+// MDL_MAPPED_TO_SYSTEM_VA | MDL_PAGES_LOCKED; -+ descr->pool = pool; -+ *buffer = descr; -+ *status = NDIS_STATUS_SUCCESS; -+ TRACE4("buffer: %p", descr); -+ EXIT4(return); -+} -+ -+wstdcall void WIN_FUNC(NdisFreeBuffer,1) -+ (ndis_buffer *buffer) -+{ -+ struct ndis_buffer_pool *pool; -+ -+ ENTER4("%p", buffer); -+ if (!buffer || !buffer->pool) { -+ ERROR("invalid buffer"); -+ EXIT4(return); -+ } -+ pool = buffer->pool; -+ if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_BUFFERS) { -+ /* NB NB NB: set mdl's 'pool' field to NULL before -+ * calling free_mdl; otherwise free_mdl calls -+ * NdisFreeBuffer back */ -+ atomic_dec_var(pool->num_allocated_descr); -+ buffer->pool = NULL; -+ free_mdl(buffer); -+ } else { -+ spin_lock_bh(&pool->lock); -+ buffer->next = pool->free_descr; -+ pool->free_descr = buffer; -+ spin_unlock_bh(&pool->lock); -+ } -+ EXIT4(return); -+} -+ -+wstdcall void WIN_FUNC(NdisFreeBufferPool,1) -+ (struct ndis_buffer_pool *pool) -+{ -+ ndis_buffer *cur, *next; -+ -+ TRACE3("pool: %p", pool); -+ if (!pool) { -+ WARNING("invalid pool"); -+ EXIT3(return); -+ } -+ spin_lock_bh(&pool->lock); -+ cur = pool->free_descr; -+ while (cur) { -+ next = cur->next; -+ cur->pool = NULL; -+ free_mdl(cur); -+ cur = next; -+ } -+ spin_unlock_bh(&pool->lock); -+ kfree(pool); -+ pool = NULL; -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisAdjustBufferLength,2) -+ (ndis_buffer *buffer, UINT length) -+{ -+ ENTER4("%p, %d", buffer, length); -+ buffer->bytecount = length; -+} -+ -+wstdcall void WIN_FUNC(NdisQueryBuffer,3) -+ (ndis_buffer *buffer, void **virt, UINT *length) -+{ -+ ENTER4("buffer: %p", buffer); -+ if (virt) -+ *virt = MmGetSystemAddressForMdl(buffer); -+ *length = MmGetMdlByteCount(buffer); -+ TRACE4("%p, %u", virt ? *virt : NULL, *length); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisQueryBufferSafe,4) -+ (ndis_buffer *buffer, void **virt, UINT *length, -+ enum mm_page_priority priority) -+{ -+ ENTER4("%p, %p, %p, %d", buffer, virt, length, priority); -+ if (virt) -+ *virt = MmGetSystemAddressForMdlSafe(buffer, priority); -+ *length = MmGetMdlByteCount(buffer); -+ TRACE4("%p, %u", virt ? *virt : NULL, *length); -+} -+ -+wstdcall void *WIN_FUNC(NdisBufferVirtualAddress,1) -+ (ndis_buffer *buffer) -+{ -+ ENTER3("%p", buffer); -+ return MmGetSystemAddressForMdl(buffer); -+} -+ -+wstdcall ULONG WIN_FUNC(NdisBufferLength,1) -+ (ndis_buffer *buffer) -+{ -+ ENTER3("%p", buffer); -+ return MmGetMdlByteCount(buffer); -+} -+ -+wstdcall void WIN_FUNC(NdisQueryBufferOffset,3) -+ (ndis_buffer *buffer, UINT *offset, UINT *length) -+{ -+ ENTER3("%p", buffer); -+ *offset = MmGetMdlByteOffset(buffer); -+ *length = MmGetMdlByteCount(buffer); -+ TRACE3("%d, %d", *offset, *length); -+} -+ -+wstdcall void WIN_FUNC(NdisUnchainBufferAtBack,2) -+ (struct ndis_packet *packet, ndis_buffer **buffer) -+{ -+ ndis_buffer *b, *btail; -+ -+ ENTER3("%p", packet); -+ b = packet->private.buffer_head; -+ if (!b) { -+ /* no buffer in packet */ -+ *buffer = NULL; -+ EXIT3(return); -+ } -+ btail = packet->private.buffer_tail; -+ *buffer = btail; -+ if (b == btail) { -+ /* one buffer in packet */ -+ packet->private.buffer_head = NULL; -+ packet->private.buffer_tail = NULL; -+ } else { -+ while (b->next != btail) -+ b = b->next; -+ packet->private.buffer_tail = b; -+ b->next = NULL; -+ } -+ packet->private.valid_counts = FALSE; -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisUnchainBufferAtFront,2) -+ (struct ndis_packet *packet, ndis_buffer **buffer) -+{ -+ ENTER3("%p", packet); -+ if (packet->private.buffer_head == NULL) { -+ /* no buffer in packet */ -+ *buffer = NULL; -+ EXIT3(return); -+ } -+ -+ *buffer = packet->private.buffer_head; -+ if (packet->private.buffer_head == packet->private.buffer_tail) { -+ /* one buffer in packet */ -+ packet->private.buffer_head = NULL; -+ packet->private.buffer_tail = NULL; -+ } else -+ packet->private.buffer_head = (*buffer)->next; -+ -+ packet->private.valid_counts = FALSE; -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacketSafe,6) -+ (struct ndis_packet *packet, ndis_buffer **first_buffer, -+ void **first_buffer_va, UINT *first_buffer_length, -+ UINT *total_buffer_length, enum mm_page_priority priority) -+{ -+ ndis_buffer *b = packet->private.buffer_head; -+ -+ ENTER3("%p(%p)", packet, b); -+ *first_buffer = b; -+ if (b) { -+ *first_buffer_va = MmGetSystemAddressForMdlSafe(b, priority); -+ *first_buffer_length = *total_buffer_length = -+ MmGetMdlByteCount(b); -+ for (b = b->next; b; b = b->next) -+ *total_buffer_length += MmGetMdlByteCount(b); -+ } else { -+ *first_buffer_va = NULL; -+ *first_buffer_length = 0; -+ *total_buffer_length = 0; -+ } -+ TRACE3("%p, %d, %d", *first_buffer_va, *first_buffer_length, -+ *total_buffer_length); -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacket,6) -+ (struct ndis_packet *packet, ndis_buffer **first_buffer, -+ void **first_buffer_va, UINT *first_buffer_length, -+ UINT *total_buffer_length, enum mm_page_priority priority) -+{ -+ NdisGetFirstBufferFromPacketSafe(packet, first_buffer, -+ first_buffer_va, first_buffer_length, -+ total_buffer_length, -+ NormalPagePriority); -+} -+ -+wstdcall void WIN_FUNC(NdisAllocatePacketPoolEx,5) -+ (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle, -+ UINT num_descr, UINT overflowsize, UINT proto_rsvd_length) -+{ -+ struct ndis_packet_pool *pool; -+ -+ ENTER3("buffers: %d, length: %d", num_descr, proto_rsvd_length); -+ pool = kzalloc(sizeof(*pool), irql_gfp()); -+ if (!pool) { -+ *status = NDIS_STATUS_RESOURCES; -+ EXIT3(return); -+ } -+ spin_lock_init(&pool->lock); -+ pool->max_descr = num_descr; -+ pool->num_allocated_descr = 0; -+ pool->num_used_descr = 0; -+ pool->free_descr = NULL; -+ pool->proto_rsvd_length = proto_rsvd_length; -+ *pool_handle = pool; -+ *status = NDIS_STATUS_SUCCESS; -+ TRACE3("pool: %p", pool); -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisAllocatePacketPool,4) -+ (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle, -+ UINT num_descr, UINT proto_rsvd_length) -+{ -+ NdisAllocatePacketPoolEx(status, pool_handle, num_descr, 0, -+ proto_rsvd_length); -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisFreePacketPool,1) -+ (struct ndis_packet_pool *pool) -+{ -+ struct ndis_packet *packet, *next; -+ -+ ENTER3("pool: %p", pool); -+ if (!pool) { -+ WARNING("invalid pool"); -+ EXIT3(return); -+ } -+ spin_lock_bh(&pool->lock); -+ packet = pool->free_descr; -+ while (packet) { -+ next = (struct ndis_packet *)packet->reserved[0]; -+ kfree(packet); -+ packet = next; -+ } -+ pool->num_allocated_descr = 0; -+ pool->num_used_descr = 0; -+ pool->free_descr = NULL; -+ spin_unlock_bh(&pool->lock); -+ kfree(pool); -+ EXIT3(return); -+} -+ -+wstdcall UINT WIN_FUNC(NdisPacketPoolUsage,1) -+ (struct ndis_packet_pool *pool) -+{ -+ EXIT4(return pool->num_used_descr); -+} -+ -+wstdcall void WIN_FUNC(NdisAllocatePacket,3) -+ (NDIS_STATUS *status, struct ndis_packet **ndis_packet, -+ struct ndis_packet_pool *pool) -+{ -+ struct ndis_packet *packet; -+ int packet_length; -+ -+ ENTER4("pool: %p", pool); -+ if (!pool) { -+ *status = NDIS_STATUS_RESOURCES; -+ *ndis_packet = NULL; -+ EXIT4(return); -+ } -+ assert_irql(_irql_ <= SOFT_LEVEL); -+ if (pool->num_used_descr > pool->max_descr) { -+ TRACE3("pool %p is full: %d(%d)", pool, -+ pool->num_used_descr, pool->max_descr); -+#ifndef ALLOW_POOL_OVERFLOW -+ *status = NDIS_STATUS_RESOURCES; -+ *ndis_packet = NULL; -+ return; -+#endif -+ } -+ /* packet has space for 1 byte in protocol_reserved field */ -+ packet_length = sizeof(*packet) - 1 + pool->proto_rsvd_length + -+ sizeof(struct ndis_packet_oob_data); -+ spin_lock_bh(&pool->lock); -+ if ((packet = pool->free_descr)) -+ pool->free_descr = (void *)packet->reserved[0]; -+ spin_unlock_bh(&pool->lock); -+ if (!packet) { -+ packet = kmalloc(packet_length, irql_gfp()); -+ if (!packet) { -+ WARNING("couldn't allocate packet"); -+ *status = NDIS_STATUS_RESOURCES; -+ *ndis_packet = NULL; -+ return; -+ } -+ atomic_inc_var(pool->num_allocated_descr); -+ } -+ TRACE4("%p, %p", pool, packet); -+ atomic_inc_var(pool->num_used_descr); -+ memset(packet, 0, packet_length); -+ packet->private.oob_offset = -+ packet_length - sizeof(struct ndis_packet_oob_data); -+ packet->private.packet_flags = fPACKET_ALLOCATED_BY_NDIS; -+ packet->private.pool = pool; -+ *ndis_packet = packet; -+ *status = NDIS_STATUS_SUCCESS; -+ EXIT4(return); -+} -+ -+wstdcall void WIN_FUNC(NdisDprAllocatePacket,3) -+ (NDIS_STATUS *status, struct ndis_packet **packet, -+ struct ndis_packet_pool *pool) -+{ -+ NdisAllocatePacket(status, packet, pool); -+} -+ -+wstdcall void WIN_FUNC(NdisFreePacket,1) -+ (struct ndis_packet *packet) -+{ -+ struct ndis_packet_pool *pool; -+ -+ ENTER4("%p, %p", packet, packet->private.pool); -+ pool = packet->private.pool; -+ if (!pool) { -+ ERROR("invalid pool %p", packet); -+ EXIT4(return); -+ } -+ assert((int)pool->num_used_descr > 0); -+ atomic_dec_var(pool->num_used_descr); -+ if (packet->reserved[1]) { -+ TRACE3("%p, %p", packet, (void *)packet->reserved[1]); -+ kfree((void *)packet->reserved[1]); -+ packet->reserved[1] = 0; -+ } -+ if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_PACKETS) { -+ TRACE3("%p", pool); -+ atomic_dec_var(pool->num_allocated_descr); -+ kfree(packet); -+ } else { -+ TRACE4("%p, %p, %p", pool, packet, pool->free_descr); -+ spin_lock_bh(&pool->lock); -+ packet->reserved[0] = -+ (typeof(packet->reserved[0]))pool->free_descr; -+ pool->free_descr = packet; -+ spin_unlock_bh(&pool->lock); -+ } -+ EXIT4(return); -+} -+ -+wstdcall struct ndis_packet_stack *WIN_FUNC(NdisIMGetCurrentPacketStack,2) -+ (struct ndis_packet *packet, BOOLEAN *stacks_remain) -+{ -+ struct ndis_packet_stack *stack; -+ -+ if (!packet->reserved[1]) { -+ stack = kzalloc(2 * sizeof(*stack), irql_gfp()); -+ TRACE3("%p, %p", packet, stack); -+ packet->reserved[1] = (typeof(packet->reserved[1]))stack; -+ } else { -+ stack = (void *)packet->reserved[1];; -+ if (xchg(&stack->ndis_reserved[0], 1)) { -+ stack++; -+ if (xchg(&stack->ndis_reserved[0], 1)) -+ stack = NULL; -+ } -+ TRACE3("%p", stack); -+ } -+ if (stack) -+ *stacks_remain = TRUE; -+ else -+ *stacks_remain = FALSE; -+ -+ EXIT3(return stack); -+} -+ -+wstdcall void WIN_FUNC(NdisCopyFromPacketToPacketSafe,7) -+ (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy, -+ struct ndis_packet *src, UINT src_offset, UINT *num_copied, -+ enum mm_page_priority priority) -+{ -+ UINT dst_n, src_n, n, left; -+ ndis_buffer *dst_buf; -+ ndis_buffer *src_buf; -+ -+ ENTER4(""); -+ if (!dst || !src) { -+ *num_copied = 0; -+ EXIT4(return); -+ } -+ -+ dst_buf = dst->private.buffer_head; -+ src_buf = src->private.buffer_head; -+ -+ if (!dst_buf || !src_buf) { -+ *num_copied = 0; -+ EXIT4(return); -+ } -+ dst_n = MmGetMdlByteCount(dst_buf) - dst_offset; -+ src_n = MmGetMdlByteCount(src_buf) - src_offset; -+ -+ n = min(src_n, dst_n); -+ n = min(n, num_to_copy); -+ memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset, -+ MmGetSystemAddressForMdl(src_buf) + src_offset, n); -+ -+ left = num_to_copy - n; -+ while (left > 0) { -+ src_offset += n; -+ dst_offset += n; -+ dst_n -= n; -+ src_n -= n; -+ if (dst_n == 0) { -+ dst_buf = dst_buf->next; -+ if (!dst_buf) -+ break; -+ dst_n = MmGetMdlByteCount(dst_buf); -+ dst_offset = 0; -+ } -+ if (src_n == 0) { -+ src_buf = src_buf->next; -+ if (!src_buf) -+ break; -+ src_n = MmGetMdlByteCount(src_buf); -+ src_offset = 0; -+ } -+ -+ n = min(src_n, dst_n); -+ n = min(n, left); -+ memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset, -+ MmGetSystemAddressForMdl(src_buf) + src_offset, n); -+ left -= n; -+ } -+ *num_copied = num_to_copy - left; -+ EXIT4(return); -+} -+ -+wstdcall void WIN_FUNC(NdisCopyFromPacketToPacket,6) -+ (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy, -+ struct ndis_packet *src, UINT src_offset, UINT *num_copied) -+{ -+ NdisCopyFromPacketToPacketSafe(dst, dst_offset, num_to_copy, -+ src, src_offset, num_copied, -+ NormalPagePriority); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisIMCopySendPerPacketInfo,2) -+ (struct ndis_packet *dst, struct ndis_packet *src) -+{ -+ struct ndis_packet_oob_data *dst_oob, *src_oob; -+ dst_oob = NDIS_PACKET_OOB_DATA(dst); -+ src_oob = NDIS_PACKET_OOB_DATA(src); -+ memcpy(&dst_oob->ext, &src_oob->ext, sizeof(dst_oob->ext)); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisSend,3) -+ (NDIS_STATUS *status, struct ndis_mp_block *nmb, -+ struct ndis_packet *packet) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ struct miniport *mp; -+ KIRQL irql; -+ -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ if (mp->send_packets) { -+ irql = serialize_lock_irql(wnd); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, &packet, 1); -+ serialize_unlock_irql(wnd, irql); -+ if (deserialized_driver(wnd)) -+ *status = NDIS_STATUS_PENDING; -+ else { -+ struct ndis_packet_oob_data *oob_data; -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ *status = oob_data->status; -+ switch (*status) { -+ case NDIS_STATUS_SUCCESS: -+ free_tx_packet(wnd, packet, *status); -+ break; -+ case NDIS_STATUS_PENDING: -+ break; -+ case NDIS_STATUS_RESOURCES: -+ wnd->tx_ok = 0; -+ break; -+ case NDIS_STATUS_FAILURE: -+ default: -+ free_tx_packet(wnd, packet, *status); -+ break; -+ } -+ } -+ } else { -+ irql = serialize_lock_irql(wnd); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ *status = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, packet, 0); -+ serialize_unlock_irql(wnd, irql); -+ switch (*status) { -+ case NDIS_STATUS_SUCCESS: -+ free_tx_packet(wnd, packet, *status); -+ break; -+ case NDIS_STATUS_PENDING: -+ break; -+ case NDIS_STATUS_RESOURCES: -+ wnd->tx_ok = 0; -+ break; -+ case NDIS_STATUS_FAILURE: -+ default: -+ free_tx_packet(wnd, packet, *status); -+ break; -+ } -+ } -+ EXIT3(return); -+} -+ -+/* called for serialized drivers only */ -+wstdcall void mp_timer_dpc(struct kdpc *kdpc, void *ctx, void *arg1, void *arg2) -+{ -+ struct ndis_mp_timer *timer; -+ struct ndis_mp_block *nmb; -+ -+ timer = ctx; -+ TIMERENTER("%p, %p, %p, %p", timer, timer->func, timer->ctx, timer->nmb); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ nmb = timer->nmb; -+ serialize_lock(nmb->wnd); -+ LIN2WIN4(timer->func, NULL, timer->ctx, NULL, NULL); -+ serialize_unlock(nmb->wnd); -+ TIMEREXIT(return); -+} -+WIN_FUNC_DECL(mp_timer_dpc,4) -+ -+wstdcall void WIN_FUNC(NdisMInitializeTimer,4) -+ (struct ndis_mp_timer *timer, struct ndis_mp_block *nmb, -+ DPC func, void *ctx) -+{ -+ TIMERENTER("%p, %p, %p, %p", timer, func, ctx, nmb); -+ assert_irql(_irql_ == PASSIVE_LEVEL); -+ timer->func = func; -+ timer->ctx = ctx; -+ timer->nmb = nmb; -+ if (deserialized_driver(nmb->wnd)) -+ KeInitializeDpc(&timer->kdpc, func, ctx); -+ else -+ KeInitializeDpc(&timer->kdpc, WIN_FUNC_PTR(mp_timer_dpc,4), -+ timer); -+ wrap_init_timer(&timer->nt_timer, NotificationTimer, nmb); -+ TIMEREXIT(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMSetPeriodicTimer,2) -+ (struct ndis_mp_timer *timer, UINT period_ms) -+{ -+ unsigned long expires = MSEC_TO_HZ(period_ms); -+ -+ TIMERENTER("%p, %u, %ld", timer, period_ms, expires); -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ wrap_set_timer(&timer->nt_timer, expires, expires, &timer->kdpc); -+ TIMEREXIT(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMCancelTimer,2) -+ (struct ndis_mp_timer *timer, BOOLEAN *canceled) -+{ -+ TIMERENTER("%p", timer); -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ *canceled = KeCancelTimer(&timer->nt_timer); -+ TIMERTRACE("%d", *canceled); -+ return; -+} -+ -+wstdcall void WIN_FUNC(NdisInitializeTimer,3) -+ (struct ndis_timer *timer, void *func, void *ctx) -+{ -+ TIMERENTER("%p, %p, %p", timer, func, ctx); -+ assert_irql(_irql_ == PASSIVE_LEVEL); -+ KeInitializeDpc(&timer->kdpc, func, ctx); -+ wrap_init_timer(&timer->nt_timer, NotificationTimer, NULL); -+ TIMEREXIT(return); -+} -+ -+/* NdisMSetTimer is a macro that calls NdisSetTimer with -+ * ndis_mp_timer typecast to ndis_timer */ -+ -+wstdcall void WIN_FUNC(NdisSetTimer,2) -+ (struct ndis_timer *timer, UINT duetime_ms) -+{ -+ unsigned long expires = MSEC_TO_HZ(duetime_ms); -+ -+ TIMERENTER("%p, %p, %u, %ld", timer, timer->nt_timer.wrap_timer, -+ duetime_ms, expires); -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ wrap_set_timer(&timer->nt_timer, expires, 0, &timer->kdpc); -+ TIMEREXIT(return); -+} -+ -+wstdcall void WIN_FUNC(NdisCancelTimer,2) -+ (struct ndis_timer *timer, BOOLEAN *canceled) -+{ -+ TIMERENTER("%p", timer); -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ *canceled = KeCancelTimer(&timer->nt_timer); -+ TIMEREXIT(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMRegisterAdapterShutdownHandler,3) -+ (struct ndis_mp_block *nmb, void *ctx, void *func) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ ENTER1("%p", func); -+ wnd->wd->driver->ndis_driver->mp.shutdown = func; -+ wnd->shutdown_ctx = ctx; -+} -+ -+wstdcall void WIN_FUNC(NdisMDeregisterAdapterShutdownHandler,1) -+ (struct ndis_mp_block *nmb) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ wnd->wd->driver->ndis_driver->mp.shutdown = NULL; -+ wnd->shutdown_ctx = NULL; -+} -+ -+/* TODO: rt61 (serialized) driver doesn't want MiniportEnableInterrupt -+ * to be called in irq handler, but mrv800c (deserialized) driver -+ * wants. NDIS is confusing about when to call MiniportEnableInterrupt -+ * For now, handle these cases with two separate irq handlers based on -+ * observation of these two drivers. However, it is likely not -+ * correct. */ -+wstdcall void deserialized_irq_handler(struct kdpc *kdpc, void *ctx, -+ void *arg1, void *arg2) -+{ -+ struct ndis_device *wnd = ctx; -+ ndis_interrupt_handler irq_handler = arg1; -+ struct miniport *mp = arg2; -+ -+ TRACE6("%p", irq_handler); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ LIN2WIN1(irq_handler, wnd->nmb->mp_ctx); -+ if (mp->enable_interrupt) -+ LIN2WIN1(mp->enable_interrupt, wnd->nmb->mp_ctx); -+ EXIT6(return); -+} -+WIN_FUNC_DECL(deserialized_irq_handler,4) -+ -+wstdcall void serialized_irq_handler(struct kdpc *kdpc, void *ctx, -+ void *arg1, void *arg2) -+{ -+ struct ndis_device *wnd = ctx; -+ ndis_interrupt_handler irq_handler = arg1; -+ -+ TRACE6("%p, %p, %p", wnd, irq_handler, arg2); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ serialize_lock(wnd); -+ LIN2WIN1(irq_handler, arg2); -+ serialize_unlock(wnd); -+ EXIT6(return); -+} -+WIN_FUNC_DECL(serialized_irq_handler,4) -+ -+wstdcall BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) -+{ -+ struct ndis_mp_interrupt *mp_interrupt = ctx; -+ struct ndis_device *wnd = mp_interrupt->nmb->wnd; -+ BOOLEAN recognized = TRUE, queue_handler = TRUE; -+ -+ TRACE6("%p", wnd); -+ /* kernel may call ISR when registering interrupt, in -+ * the same context if DEBUG_SHIRQ is enabled */ -+ assert_irql(_irql_ == DIRQL || _irql_ == PASSIVE_LEVEL); -+ if (mp_interrupt->shared) -+ LIN2WIN3(mp_interrupt->isr, &recognized, &queue_handler, -+ wnd->nmb->mp_ctx); -+ else { -+ struct miniport *mp; -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ LIN2WIN1(mp->disable_interrupt, wnd->nmb->mp_ctx); -+ /* it is not shared interrupt, so handler must be called */ -+ recognized = queue_handler = TRUE; -+ } -+ if (recognized) { -+ if (queue_handler) { -+ TRACE5("%p", &wnd->irq_kdpc); -+ queue_kdpc(&wnd->irq_kdpc); -+ } -+ EXIT6(return TRUE); -+ } -+ EXIT6(return FALSE); -+} -+WIN_FUNC_DECL(ndis_isr,2) -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterInterrupt,7) -+ (struct ndis_mp_interrupt *mp_interrupt, -+ struct ndis_mp_block *nmb, UINT vector, UINT level, -+ BOOLEAN req_isr, BOOLEAN shared, enum kinterrupt_mode mode) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ struct miniport *mp; -+ -+ ENTER1("%p, vector:%d, level:%d, req_isr:%d, shared:%d, mode:%d", -+ mp_interrupt, vector, level, req_isr, shared, mode); -+ -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ nt_spin_lock_init(&mp_interrupt->lock); -+ mp_interrupt->irq = vector; -+ mp_interrupt->isr = mp->isr; -+ mp_interrupt->mp_dpc = mp->handle_interrupt; -+ mp_interrupt->nmb = nmb; -+ mp_interrupt->req_isr = req_isr; -+ if (shared && !req_isr) -+ WARNING("shared but dynamic interrupt!"); -+ mp_interrupt->shared = shared; -+ wnd->mp_interrupt = mp_interrupt; -+ if (mp->enable_interrupt) -+ mp_interrupt->enable = TRUE; -+ else -+ mp_interrupt->enable = FALSE; -+ -+ if (deserialized_driver(wnd)) { -+ KeInitializeDpc(&wnd->irq_kdpc, -+ WIN_FUNC_PTR(deserialized_irq_handler,4), -+ nmb->wnd); -+ wnd->irq_kdpc.arg1 = mp->handle_interrupt; -+ wnd->irq_kdpc.arg2 = mp; -+ TRACE2("%p, %p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, -+ nmb->wnd, nmb->mp_ctx); -+ } else { -+ KeInitializeDpc(&wnd->irq_kdpc, -+ WIN_FUNC_PTR(serialized_irq_handler,4), -+ nmb->wnd); -+ wnd->irq_kdpc.arg1 = mp->handle_interrupt; -+ wnd->irq_kdpc.arg2 = nmb->mp_ctx; -+ TRACE2("%p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, -+ nmb->wnd); -+ } -+ -+ if (IoConnectInterrupt(&mp_interrupt->kinterrupt, -+ WIN_FUNC_PTR(ndis_isr,2), mp_interrupt, NULL, -+ vector, DIRQL, DIRQL, mode, shared, 0, FALSE) != -+ STATUS_SUCCESS) { -+ printk(KERN_WARNING "%s: request for IRQ %d failed\n", -+ DRIVER_NAME, vector); -+ return NDIS_STATUS_RESOURCES; -+ } -+ printk(KERN_INFO "%s: using IRQ %d\n", DRIVER_NAME, vector); -+ EXIT1(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(NdisMDeregisterInterrupt,1) -+ (struct ndis_mp_interrupt *mp_interrupt) -+{ -+ struct ndis_mp_block *nmb; -+ -+ ENTER1("%p", mp_interrupt); -+ nmb = xchg(&mp_interrupt->nmb, NULL); -+ TRACE1("%p", nmb); -+ if (!nmb) { -+ WARNING("interrupt already freed?"); -+ return; -+ } -+ nmb->wnd->mp_interrupt = NULL; -+ if (dequeue_kdpc(&nmb->wnd->irq_kdpc)) -+ TRACE2("interrupt kdpc was pending"); -+ flush_workqueue(wrapndis_wq); -+ IoDisconnectInterrupt(mp_interrupt->kinterrupt); -+ EXIT1(return); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(NdisMSynchronizeWithInterrupt,3) -+ (struct ndis_mp_interrupt *mp_interrupt, -+ PKSYNCHRONIZE_ROUTINE sync_func, void *ctx) -+{ -+ return KeSynchronizeExecution(mp_interrupt->kinterrupt, sync_func, ctx); -+} -+ -+/* called via function pointer; but 64-bit RNDIS driver calls directly */ -+wstdcall void WIN_FUNC(NdisMIndicateStatus,4) -+ (struct ndis_mp_block *nmb, NDIS_STATUS status, void *buf, UINT len) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ struct ndis_status_indication *si; -+ -+ ENTER2("status=0x%x len=%d", status, len); -+ switch (status) { -+ case NDIS_STATUS_MEDIA_CONNECT: -+ set_media_state(wnd, NdisMediaStateConnected); -+ break; -+ case NDIS_STATUS_MEDIA_DISCONNECT: -+ set_media_state(wnd, NdisMediaStateDisconnected); -+ break; -+ case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION: -+ if (!buf) -+ break; -+ si = buf; -+ TRACE2("status_type=%d", si->status_type); -+ switch (si->status_type) { -+ case Ndis802_11StatusType_MediaStreamMode: -+ break; -+#ifdef CONFIG_WIRELESS_EXT -+ case Ndis802_11StatusType_Authentication: -+ buf = (char *)buf + sizeof(*si); -+ len -= sizeof(*si); -+ while (len > 0) { -+ int pairwise_error = 0, group_error = 0; -+ struct ndis_auth_req *auth_req = -+ (struct ndis_auth_req *)buf; -+ TRACE1(MACSTRSEP, MAC2STR(auth_req->bssid)); -+ if (auth_req->flags & 0x01) -+ TRACE2("reauth request"); -+ if (auth_req->flags & 0x02) -+ TRACE2("key update request"); -+ if (auth_req->flags & 0x06) { -+ pairwise_error = 1; -+ TRACE2("pairwise_error"); -+ } -+ if (auth_req->flags & 0x0E) { -+ group_error = 1; -+ TRACE2("group_error"); -+ } -+ if (pairwise_error || group_error) { -+ union iwreq_data wrqu; -+ struct iw_michaelmicfailure micfailure; -+ -+ memset(&micfailure, 0, sizeof(micfailure)); -+ if (pairwise_error) -+ micfailure.flags |= -+ IW_MICFAILURE_PAIRWISE; -+ if (group_error) -+ micfailure.flags |= -+ IW_MICFAILURE_GROUP; -+ memcpy(micfailure.src_addr.sa_data, -+ auth_req->bssid, ETH_ALEN); -+ memset(&wrqu, 0, sizeof(wrqu)); -+ wrqu.data.length = sizeof(micfailure); -+ wireless_send_event(wnd->net_dev, -+ IWEVMICHAELMICFAILURE, -+ &wrqu, (u8 *)&micfailure); -+ } -+ len -= auth_req->length; -+ buf = (char *)buf + auth_req->length; -+ } -+ break; -+ case Ndis802_11StatusType_PMKID_CandidateList: -+ { -+ u8 *end; -+ unsigned long i; -+ struct ndis_pmkid_candidate_list *cand; -+ -+ cand = buf + sizeof(struct ndis_status_indication); -+ if (len < sizeof(struct ndis_status_indication) + -+ sizeof(struct ndis_pmkid_candidate_list) || -+ cand->version != 1) { -+ WARNING("unrecognized PMKID ignored"); -+ EXIT1(return); -+ } -+ -+ end = (u8 *)buf + len; -+ TRACE2("PMKID ver %d num_cand %d", -+ cand->version, cand->num_candidates); -+ for (i = 0; i < cand->num_candidates; i++) { -+ struct iw_pmkid_cand pcand; -+ union iwreq_data wrqu; -+ struct ndis_pmkid_candidate *c = -+ &cand->candidates[i]; -+ if ((u8 *)(c + 1) > end) { -+ TRACE2("truncated PMKID"); -+ break; -+ } -+ TRACE2("%ld: " MACSTRSEP " 0x%x", -+ i, MAC2STR(c->bssid), c->flags); -+ memset(&pcand, 0, sizeof(pcand)); -+ if (c->flags & 0x01) -+ pcand.flags |= IW_PMKID_CAND_PREAUTH; -+ pcand.index = i; -+ memcpy(pcand.bssid.sa_data, c->bssid, ETH_ALEN); -+ -+ memset(&wrqu, 0, sizeof(wrqu)); -+ wrqu.data.length = sizeof(pcand); -+ wireless_send_event(wnd->net_dev, IWEVPMKIDCAND, -+ &wrqu, (u8 *)&pcand); -+ } -+ break; -+ } -+ case Ndis802_11StatusType_RadioState: -+ { -+ struct ndis_radio_status_indication *radio_status = buf; -+ if (radio_status->radio_state == -+ Ndis802_11RadioStatusOn) -+ INFO("radio is turned on"); -+ else if (radio_status->radio_state == -+ Ndis802_11RadioStatusHardwareOff) -+ INFO("radio is turned off by hardware"); -+ else if (radio_status->radio_state == -+ Ndis802_11RadioStatusSoftwareOff) -+ INFO("radio is turned off by software"); -+ break; -+ } -+#endif -+ default: -+ /* is this RSSI indication? */ -+ TRACE2("unknown indication: %x", si->status_type); -+ break; -+ } -+ break; -+ default: -+ TRACE2("unknown status: %08X", status); -+ break; -+ } -+ -+ EXIT2(return); -+} -+ -+/* called via function pointer; but 64-bit RNDIS driver calls directly */ -+wstdcall void WIN_FUNC(NdisMIndicateStatusComplete,1) -+ (struct ndis_mp_block *nmb) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ ENTER2("%p", wnd); -+ if (wnd->tx_ok) -+ queue_work(wrapndis_wq, &wnd->tx_work); -+} -+ -+/* called via function pointer */ -+wstdcall void NdisMSendComplete(struct ndis_mp_block *nmb, -+ struct ndis_packet *packet, NDIS_STATUS status) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ ENTER4("%p, %08X", packet, status); -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ if (deserialized_driver(wnd)) -+ free_tx_packet(wnd, packet, status); -+ else { -+ struct ndis_packet_oob_data *oob_data; -+ NDIS_STATUS pkt_status; -+ TRACE3("%p, %08x", packet, status); -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ switch ((pkt_status = xchg(&oob_data->status, status))) { -+ case NDIS_STATUS_NOT_RECOGNIZED: -+ free_tx_packet(wnd, packet, status); -+ break; -+ case NDIS_STATUS_PENDING: -+ case 0: -+ break; -+ default: -+ WARNING("%p: invalid status: %08X", packet, pkt_status); -+ break; -+ } -+ /* In case a serialized driver has earlier requested a -+ * pause by returning NDIS_STATUS_RESOURCES during -+ * MiniportSend(Packets), wakeup tx worker now. -+ */ -+ if (xchg(&wnd->tx_ok, 1) == 0) { -+ TRACE3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); -+ queue_work(wrapndis_wq, &wnd->tx_work); -+ } -+ } -+ EXIT3(return); -+} -+ -+/* called via function pointer */ -+wstdcall void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ ENTER3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); -+ wnd->tx_ok = 1; -+ queue_work(wrapndis_wq, &wnd->tx_work); -+ EXIT3(return); -+} -+ -+wstdcall void return_packet(void *arg1, void *arg2) -+{ -+ struct ndis_device *wnd; -+ struct ndis_packet *packet; -+ struct miniport *mp; -+ KIRQL irql; -+ -+ wnd = arg1; -+ packet = arg2; -+ ENTER4("%p, %p", wnd, packet); -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ irql = serialize_lock_irql(wnd); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ LIN2WIN2(mp->return_packet, wnd->nmb->mp_ctx, packet); -+ serialize_unlock_irql(wnd, irql); -+ EXIT4(return); -+} -+WIN_FUNC_DECL(return_packet,2) -+ -+/* called via function pointer */ -+wstdcall void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb, -+ struct ndis_packet **packets, -+ UINT nr_packets) -+{ -+ struct ndis_device *wnd; -+ ndis_buffer *buffer; -+ struct ndis_packet *packet; -+ struct sk_buff *skb; -+ ULONG i, length, total_length; -+ struct ndis_packet_oob_data *oob_data; -+ void *virt; -+ struct ndis_tcp_ip_checksum_packet_info csum; -+ -+ ENTER3("%p, %d", nmb, nr_packets); -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ wnd = nmb->wnd; -+ for (i = 0; i < nr_packets; i++) { -+ packet = packets[i]; -+ if (!packet) { -+ WARNING("empty packet ignored"); -+ continue; -+ } -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,11,0) -+ wnd->net_dev->last_rx = jiffies; -+#endif -+ /* get total number of bytes in packet */ -+ NdisGetFirstBufferFromPacketSafe(packet, &buffer, &virt, -+ &length, &total_length, -+ NormalPagePriority); -+ TRACE3("%d, %d", length, total_length); -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ TRACE3("0x%x, 0x%x, %llu", packet->private.flags, -+ packet->private.packet_flags, oob_data->time_rxed); -+ skb = dev_alloc_skb(total_length); -+ if (skb) { -+ while (buffer) { -+ memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), -+ MmGetMdlByteCount(buffer)); -+ buffer = buffer->next; -+ } -+ skb->dev = wnd->net_dev; -+ skb->protocol = eth_type_trans(skb, wnd->net_dev); -+ pre_atomic_add(wnd->net_stats.rx_bytes, total_length); -+ atomic_inc_var(wnd->net_stats.rx_packets); -+ csum.value = (typeof(csum.value))(ULONG_PTR) -+ oob_data->ext.info[TcpIpChecksumPacketInfo]; -+ TRACE3("0x%05x", csum.value); -+ if (wnd->rx_csum.value && -+ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded || -+ csum.rx.ip_succeeded)) -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ else -+ skb->ip_summed = CHECKSUM_NONE; -+ -+ if (in_interrupt()) -+ netif_rx(skb); -+ else -+ netif_rx_ni(skb); -+ } else { -+ WARNING("couldn't allocate skb; packet dropped"); -+ atomic_inc_var(wnd->net_stats.rx_dropped); -+ } -+ -+ /* serialized drivers check the status upon return -+ * from this function */ -+ if (!deserialized_driver(wnd)) { -+ oob_data->status = NDIS_STATUS_SUCCESS; -+ continue; -+ } -+ -+ /* if a deserialized driver sets -+ * NDIS_STATUS_RESOURCES, then it reclaims the packet -+ * upon return from this function */ -+ if (oob_data->status == NDIS_STATUS_RESOURCES) -+ continue; -+ -+ assert(oob_data->status == NDIS_STATUS_SUCCESS); -+ /* deserialized driver doesn't check the status upon -+ * return from this function; we need to call -+ * MiniportReturnPacket later for this packet. Calling -+ * MiniportReturnPacket from here is not correct - the -+ * driver doesn't expect it (at least Centrino driver -+ * crashes) */ -+ schedule_ntos_work_item(WIN_FUNC_PTR(return_packet,2), -+ wnd, packet); -+ } -+ EXIT3(return); -+} -+ -+/* called via function pointer (by NdisMEthIndicateReceive macro); the -+ * first argument is nmb->eth_db */ -+wstdcall void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx, -+ char *header1, char *header, UINT header_size, -+ void *look_ahead, UINT look_ahead_size, -+ UINT packet_size) -+{ -+ struct sk_buff *skb = NULL; -+ struct ndis_device *wnd; -+ unsigned int skb_size = 0; -+ KIRQL irql; -+ struct ndis_packet_oob_data *oob_data; -+ -+ ENTER3("nmb = %p, rx_ctx = %p, buf = %p, size = %d, buf = %p, " -+ "size = %d, packet = %d", nmb, rx_ctx, header, header_size, -+ look_ahead, look_ahead_size, packet_size); -+ -+ wnd = nmb->wnd; -+ TRACE3("wnd = %p", wnd); -+ if (!wnd) { -+ ERROR("nmb is NULL"); -+ EXIT3(return); -+ } -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,11,0) -+ wnd->net_dev->last_rx = jiffies; -+#endif -+ -+ if (look_ahead_size < packet_size) { -+ struct ndis_packet *packet; -+ struct miniport *mp; -+ unsigned int bytes_txed; -+ NDIS_STATUS res; -+ -+ NdisAllocatePacket(&res, &packet, wnd->tx_packet_pool); -+ if (res != NDIS_STATUS_SUCCESS) { -+ atomic_inc_var(wnd->net_stats.rx_dropped); -+ EXIT3(return); -+ } -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ irql = serialize_lock_irql(wnd); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ res = LIN2WIN6(mp->tx_data, packet, &bytes_txed, nmb, -+ rx_ctx, look_ahead_size, packet_size); -+ serialize_unlock_irql(wnd, irql); -+ TRACE3("%d, %d, %d", header_size, look_ahead_size, bytes_txed); -+ if (res == NDIS_STATUS_SUCCESS) { -+ ndis_buffer *buffer; -+ struct ndis_tcp_ip_checksum_packet_info csum; -+ skb = dev_alloc_skb(header_size + look_ahead_size + -+ bytes_txed); -+ if (!skb) { -+ ERROR("couldn't allocate skb; packet dropped"); -+ atomic_inc_var(wnd->net_stats.rx_dropped); -+ NdisFreePacket(packet); -+ return; -+ } -+ memcpy_skb(skb, header, header_size); -+ memcpy_skb(skb, look_ahead, look_ahead_size); -+ buffer = packet->private.buffer_head; -+ while (buffer) { -+ memcpy_skb(skb, -+ MmGetSystemAddressForMdl(buffer), -+ MmGetMdlByteCount(buffer)); -+ buffer = buffer->next; -+ } -+ skb_size = header_size + look_ahead_size + bytes_txed; -+ csum.value = (typeof(csum.value))(ULONG_PTR) -+ oob_data->ext.info[TcpIpChecksumPacketInfo]; -+ TRACE3("0x%05x", csum.value); -+ if (wnd->rx_csum.value && -+ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ else -+ skb->ip_summed = CHECKSUM_NONE; -+ NdisFreePacket(packet); -+ } else if (res == NDIS_STATUS_PENDING) { -+ /* driver will call td_complete */ -+ oob_data->look_ahead = kmalloc(look_ahead_size, -+ GFP_ATOMIC); -+ if (!oob_data->look_ahead) { -+ NdisFreePacket(packet); -+ ERROR("packet dropped"); -+ atomic_inc_var(wnd->net_stats.rx_dropped); -+ EXIT3(return); -+ } -+ assert(sizeof(oob_data->header) == header_size); -+ memcpy(oob_data->header, header, -+ sizeof(oob_data->header)); -+ memcpy(oob_data->look_ahead, look_ahead, -+ look_ahead_size); -+ oob_data->look_ahead_size = look_ahead_size; -+ EXIT3(return); -+ } else { -+ WARNING("packet dropped: %08X", res); -+ atomic_inc_var(wnd->net_stats.rx_dropped); -+ NdisFreePacket(packet); -+ EXIT3(return); -+ } -+ } else { -+ skb_size = header_size + packet_size; -+ skb = dev_alloc_skb(skb_size); -+ if (skb) { -+ memcpy_skb(skb, header, header_size); -+ memcpy_skb(skb, look_ahead, packet_size); -+ } -+ } -+ -+ if (skb) { -+ skb->dev = wnd->net_dev; -+ skb->protocol = eth_type_trans(skb, wnd->net_dev); -+ pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); -+ atomic_inc_var(wnd->net_stats.rx_packets); -+ if (in_interrupt()) -+ netif_rx(skb); -+ else -+ netif_rx_ni(skb); -+ } -+ -+ EXIT3(return); -+} -+ -+/* called via function pointer */ -+wstdcall void NdisMTransferDataComplete(struct ndis_mp_block *nmb, -+ struct ndis_packet *packet, -+ NDIS_STATUS status, UINT bytes_txed) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ struct sk_buff *skb; -+ unsigned int skb_size; -+ struct ndis_packet_oob_data *oob_data; -+ ndis_buffer *buffer; -+ struct ndis_tcp_ip_checksum_packet_info csum; -+ -+ ENTER3("wnd = %p, packet = %p, bytes_txed = %d", -+ wnd, packet, bytes_txed); -+ if (!packet) { -+ WARNING("illegal packet"); -+ EXIT3(return); -+ } -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,11,0) -+ wnd->net_dev->last_rx = jiffies; -+#endif -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ skb_size = sizeof(oob_data->header) + oob_data->look_ahead_size + -+ bytes_txed; -+ skb = dev_alloc_skb(skb_size); -+ if (!skb) { -+ kfree(oob_data->look_ahead); -+ NdisFreePacket(packet); -+ ERROR("couldn't allocate skb; packet dropped"); -+ atomic_inc_var(wnd->net_stats.rx_dropped); -+ EXIT3(return); -+ } -+ memcpy_skb(skb, oob_data->header, sizeof(oob_data->header)); -+ memcpy_skb(skb, oob_data->look_ahead, oob_data->look_ahead_size); -+ buffer = packet->private.buffer_head; -+ while (buffer) { -+ memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), -+ MmGetMdlByteCount(buffer)); -+ buffer = buffer->next; -+ } -+ kfree(oob_data->look_ahead); -+ NdisFreePacket(packet); -+ skb->dev = wnd->net_dev; -+ skb->protocol = eth_type_trans(skb, wnd->net_dev); -+ pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); -+ atomic_inc_var(wnd->net_stats.rx_packets); -+ -+ csum.value = (typeof(csum.value))(ULONG_PTR) -+ oob_data->ext.info[TcpIpChecksumPacketInfo]; -+ TRACE3("0x%05x", csum.value); -+ if (wnd->rx_csum.value && -+ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) -+ skb->ip_summed = CHECKSUM_UNNECESSARY; -+ else -+ skb->ip_summed = CHECKSUM_NONE; -+ -+ if (in_interrupt()) -+ netif_rx(skb); -+ else -+ netif_rx_ni(skb); -+} -+ -+/* called via function pointer */ -+wstdcall void EthRxComplete(struct ndis_mp_block *nmb) -+{ -+ TRACE3(""); -+} -+ -+/* called via function pointer */ -+wstdcall void NdisMQueryInformationComplete(struct ndis_mp_block *nmb, -+ NDIS_STATUS status) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ typeof(wnd->ndis_req_task) task; -+ -+ ENTER2("nmb: %p, wnd: %p, %08X", nmb, wnd, status); -+ wnd->ndis_req_status = status; -+ wnd->ndis_req_done = 1; -+ if ((task = xchg(&wnd->ndis_req_task, NULL))) -+ wake_up_process(task); -+ else -+ WARNING("invalid task"); -+ EXIT2(return); -+} -+ -+/* called via function pointer */ -+wstdcall void NdisMSetInformationComplete(struct ndis_mp_block *nmb, -+ NDIS_STATUS status) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ typeof(wnd->ndis_req_task) task; -+ -+ ENTER2("status = %08X", status); -+ wnd->ndis_req_status = status; -+ wnd->ndis_req_done = 1; -+ if ((task = xchg(&wnd->ndis_req_task, NULL))) -+ wake_up_process(task); -+ else -+ WARNING("invalid task"); -+ EXIT2(return); -+} -+ -+/* called via function pointer */ -+wstdcall void NdisMResetComplete(struct ndis_mp_block *nmb, -+ NDIS_STATUS status, BOOLEAN address_reset) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ typeof(wnd->ndis_req_task) task; -+ -+ ENTER2("status: %08X, %u", status, address_reset); -+ wnd->ndis_req_status = status; -+ wnd->ndis_req_done = address_reset + 1; -+ if ((task = xchg(&wnd->ndis_req_task, NULL))) -+ wake_up_process(task); -+ else -+ WARNING("invalid task"); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMSleep,1) -+ (ULONG us) -+{ -+ unsigned long delay; -+ -+ ENTER4("%p: us: %u", current, us); -+ delay = USEC_TO_HZ(us); -+ sleep_hz(delay); -+ TRACE4("%p: done", current); -+} -+ -+wstdcall void WIN_FUNC(NdisGetCurrentSystemTime,1) -+ (LARGE_INTEGER *time) -+{ -+ *time = ticks_1601(); -+ TRACE5("%llu, %lu", *time, jiffies); -+} -+ -+wstdcall LONG WIN_FUNC(NdisInterlockedDecrement,1) -+ (LONG *val) -+{ -+ return InterlockedDecrement(val); -+} -+ -+wstdcall LONG WIN_FUNC(NdisInterlockedIncrement,1) -+ (LONG *val) -+{ -+ return InterlockedIncrement(val); -+} -+ -+wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertHeadList,3) -+ (struct nt_list *head, struct nt_list *entry, -+ struct ndis_spinlock *lock) -+{ -+ return ExInterlockedInsertHeadList(head, entry, &lock->klock); -+} -+ -+wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertTailList,3) -+ (struct nt_list *head, struct nt_list *entry, -+ struct ndis_spinlock *lock) -+{ -+ return ExInterlockedInsertTailList(head, entry, &lock->klock); -+} -+ -+wstdcall struct nt_list *WIN_FUNC(NdisInterlockedRemoveHeadList,2) -+ (struct nt_list *head, struct ndis_spinlock *lock) -+{ -+ return ExInterlockedRemoveHeadList(head, &lock->klock); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMInitializeScatterGatherDma,3) -+ (struct ndis_mp_block *nmb, BOOLEAN dma64_supported, ULONG max_phy_map) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ ENTER2("dma64_supported=%d, maxtransfer=%u", dma64_supported, -+ max_phy_map); -+ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { -+ ERROR("used on a non-PCI device"); -+ return NDIS_STATUS_NOT_SUPPORTED; -+ } -+#ifdef CONFIG_X86_64 -+ if (!dma64_supported) { -+ TRACE1("64-bit DMA size is not supported"); -+ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32)) || -+ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, -+ DMA_BIT_MASK(32))) -+ WARNING("setting dma mask failed"); -+ } -+#endif -+ if ((wnd->attributes & NDIS_ATTRIBUTE_BUS_MASTER) && -+ wrap_is_pci_bus(wnd->wd->dev_bus)) { -+ wnd->sg_dma_size = max_phy_map; -+ return NDIS_STATUS_SUCCESS; -+ } else -+ EXIT1(return NDIS_STATUS_NOT_SUPPORTED); -+} -+ -+wstdcall ULONG WIN_FUNC(NdisMGetDmaAlignment,1) -+ (struct ndis_mp_block *nmb) -+{ -+ ENTER3(""); -+ return dma_get_cache_alignment(); -+} -+ -+wstdcall CHAR WIN_FUNC(NdisSystemProcessorCount,0) -+ (void) -+{ -+ return num_online_cpus(); -+} -+ -+wstdcall void WIN_FUNC(NdisGetCurrentProcessorCounts,3) -+ (ULONG *idle, ULONG *kernel_user, ULONG *index) -+{ -+ int cpu = smp_processor_id(); -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) -+ *idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; -+ *kernel_user = kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM] + -+ kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; -+#else -+ *idle = kstat_cpu(cpu).cpustat.idle; -+ *kernel_user = kstat_cpu(cpu).cpustat.system + -+ kstat_cpu(cpu).cpustat.user; -+#endif -+ *index = cpu; -+} -+ -+wstdcall void WIN_FUNC(NdisInitializeEvent,1) -+ (struct ndis_event *ndis_event) -+{ -+ EVENTENTER("%p", ndis_event); -+ KeInitializeEvent(&ndis_event->nt_event, NotificationEvent, 0); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(NdisWaitEvent,2) -+ (struct ndis_event *ndis_event, UINT ms) -+{ -+ LARGE_INTEGER ticks; -+ NTSTATUS res; -+ -+ EVENTENTER("%p %u", ndis_event, ms); -+ ticks = -((LARGE_INTEGER)ms * TICKSPERMSEC); -+ res = KeWaitForSingleObject(&ndis_event->nt_event, 0, 0, TRUE, -+ ms == 0 ? NULL : &ticks); -+ if (res == STATUS_SUCCESS) -+ EXIT3(return TRUE); -+ else -+ EXIT3(return FALSE); -+} -+ -+wstdcall void WIN_FUNC(NdisSetEvent,1) -+ (struct ndis_event *ndis_event) -+{ -+ EVENTENTER("%p", ndis_event); -+ KeSetEvent(&ndis_event->nt_event, 0, 0); -+} -+ -+wstdcall void WIN_FUNC(NdisResetEvent,1) -+ (struct ndis_event *ndis_event) -+{ -+ EVENTENTER("%p", ndis_event); -+ KeResetEvent(&ndis_event->nt_event); -+} -+ -+static void ndis_worker(struct work_struct *dummy) -+{ -+ struct nt_list *ent; -+ struct ndis_work_item *ndis_work_item; -+ -+ WORKENTER(""); -+ while (1) { -+ spin_lock_bh(&ndis_work_list_lock); -+ ent = RemoveHeadList(&ndis_work_list); -+ spin_unlock_bh(&ndis_work_list_lock); -+ if (!ent) -+ break; -+ ndis_work_item = container_of(ent, struct ndis_work_item, list); -+ WORKTRACE("%p: %p, %p", ndis_work_item, -+ ndis_work_item->func, ndis_work_item->ctx); -+ LIN2WIN2(ndis_work_item->func, ndis_work_item, -+ ndis_work_item->ctx); -+ WORKTRACE("%p done", ndis_work_item); -+ } -+ WORKEXIT(return); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisScheduleWorkItem,1) -+ (struct ndis_work_item *ndis_work_item) -+{ -+ ENTER3("%p", ndis_work_item); -+ spin_lock_bh(&ndis_work_list_lock); -+ InsertTailList(&ndis_work_list, &ndis_work_item->list); -+ spin_unlock_bh(&ndis_work_list_lock); -+ WORKTRACE("scheduling %p", ndis_work_item); -+ queue_work(ndis_wq, &ndis_work); -+ EXIT3(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(NdisMGetDeviceProperty,6) -+ (struct ndis_mp_block *nmb, void **phy_dev, void **func_dev, -+ void **next_dev, void **alloc_res, void**trans_res) -+{ -+ ENTER2("nmb: %p, phy_dev = %p, func_dev = %p, next_dev = %p, " -+ "alloc_res = %p, trans_res = %p", nmb, phy_dev, func_dev, -+ next_dev, alloc_res, trans_res); -+ if (phy_dev) -+ *phy_dev = nmb->pdo; -+ if (func_dev) -+ *func_dev = nmb->fdo; -+ if (next_dev) -+ *next_dev = nmb->next_device; -+} -+ -+wstdcall void WIN_FUNC(NdisMRegisterUnloadHandler,2) -+ (struct driver_object *drv_obj, void *unload) -+{ -+ if (drv_obj) -+ drv_obj->unload = unload; -+ return; -+} -+ -+wstdcall UINT WIN_FUNC(NdisGetVersion,0) -+ (void) -+{ -+ return 0x00050001; -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMQueryAdapterInstanceName,2) -+ (struct unicode_string *name, struct ndis_mp_block *nmb) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ struct ansi_string ansi; -+ -+ if (wrap_is_pci_bus(wnd->wd->dev_bus)) -+ RtlInitAnsiString(&ansi, "PCI Ethernet Adapter"); -+ else -+ RtlInitAnsiString(&ansi, "USB Ethernet Adapter"); -+ -+ if (RtlAnsiStringToUnicodeString(name, &ansi, TRUE)) -+ EXIT2(return NDIS_STATUS_RESOURCES); -+ else -+ EXIT2(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisWriteEventLogEntry,7) -+ (void *handle, NDIS_STATUS code, ULONG value, USHORT n, -+ void *strings, ULONG datasize, void *data) -+{ -+ TRACE1("0x%x, 0x%x, %u, %u", code, value, n, datasize); -+ return NDIS_STATUS_SUCCESS; -+} -+ -+wstdcall void *WIN_FUNC(NdisGetRoutineAddress,1) -+ (struct unicode_string *unicode_string) -+{ -+ struct ansi_string ansi_string; -+ void *address; -+ -+ if (RtlUnicodeStringToAnsiString(&ansi_string, unicode_string, TRUE) != -+ STATUS_SUCCESS) -+ EXIT1(return NULL); -+ INFO("%s", ansi_string.buf); -+ address = ndis_get_routine_address(ansi_string.buf); -+ RtlFreeAnsiString(&ansi_string); -+ return address; -+} -+ -+wstdcall ULONG WIN_FUNC(NdisReadPcmciaAttributeMemory,4) -+ (struct ndis_mp_block *nmb, ULONG offset, void *buffer, -+ ULONG length) -+{ -+ TODO(); -+ return 0; -+} -+ -+wstdcall ULONG WIN_FUNC(NdisWritePcmciaAttributeMemory,4) -+ (struct ndis_mp_block *nmb, ULONG offset, void *buffer, -+ ULONG length) -+{ -+ TODO(); -+ return 0; -+} -+ -+wstdcall void WIN_FUNC(NdisMCoIndicateReceivePacket,3) -+ (struct ndis_mp_block *nmb, struct ndis_packet **packets, -+ UINT nr_packets) -+{ -+ ENTER3("nmb = %p", nmb); -+ NdisMIndicateReceivePacket(nmb, packets, nr_packets); -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMCoSendComplete,3) -+ (NDIS_STATUS status, struct ndis_mp_block *nmb, -+ struct ndis_packet *packet) -+{ -+ ENTER3("%08x", status); -+ NdisMSendComplete(nmb, packet, status); -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(NdisMCoRequestComplete,3) -+ (NDIS_STATUS status, struct ndis_mp_block *nmb, -+ struct ndis_request *ndis_request) -+{ -+ struct ndis_device *wnd = nmb->wnd; -+ typeof(wnd->ndis_req_task) task; -+ -+ ENTER3("%08X", status); -+ wnd->ndis_req_status = status; -+ wnd->ndis_req_done = 1; -+ if ((task = xchg(&wnd->ndis_req_task, NULL))) -+ wake_up_process(task); -+ else -+ WARNING("invalid task"); -+ EXIT3(return); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisIMNotifiyPnPEvent,2) -+ (struct ndis_mp_block *nmb, struct net_pnp_event *event) -+{ -+ ENTER2("%p, %d", nmb, event->code); -+ /* NdisWrapper never calls protocol's pnp event notifier, so -+ * nothing to do here */ -+ EXIT2(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(NdisCompletePnPEvent,3) -+ (NDIS_STATUS status, void *handle, struct net_pnp_event *event) -+{ -+ ENTER2("%d, %p, %d", status, handle, event->code); -+ /* NdisWrapper never calls protocol's pnp event notifier, so -+ * nothing to do here */ -+ EXIT2(return); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMSetMiniportSecondary,2) -+ (struct ndis_mp_block *nmb2, struct ndis_mp_block *nmb1) -+{ -+ ENTER3("%p, %p", nmb1, nmb2); -+ TODO(); -+ EXIT3(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMPromoteMiniport,1) -+ (struct ndis_mp_block *nmb) -+{ -+ ENTER3("%p", nmb); -+ TODO(); -+ EXIT3(return NDIS_STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(NdisMCoActivateVcComplete,3) -+ (NDIS_STATUS status, void *handle, void *params) -+{ -+ TODO(); -+} -+ -+wstdcall void WIN_FUNC(NdisMCoDeactivateVcComplete,2) -+ (NDIS_STATUS status, void *handle) -+{ -+ TODO(); -+} -+ -+wstdcall void WIN_FUNC(NdisMRemoveMiniport,1) -+ (void *handle) -+{ -+ TODO(); -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMOpenLog,3) -+ (struct ndis_device *wnd, UINT size, void *handle) -+{ -+ if (size >= sizeof(int)) -+ *((int *)handle) = 42; -+ return NDIS_STATUS_SUCCESS; -+} -+ -+wstdcall NDIS_STATUS WIN_FUNC(NdisMWriteLogData,3) -+ (void *handle, char *buffer, UINT buffer_size) -+{ -+ TODO(); -+ return NDIS_STATUS_SUCCESS; -+} -+ -+wstdcall void WIN_FUNC(NdisMFlushLog,1) -+ (void *handle) -+{ -+ TODO(); -+} -+ -+wstdcall void WIN_FUNC(NdisMCloseLog,1) -+ (void *handle) -+{ -+ TODO(); -+} -+ -+static void *ndis_get_routine_address(char *name) -+{ -+ int i; -+ ENTER2("%p", name); -+ for (i = 0; i < ARRAY_SIZE(ndis_exports); i++) { -+ if (strcmp(name, ndis_exports[i].name) == 0) { -+ TRACE2("%p", ndis_exports[i].func); -+ return ndis_exports[i].func; -+ } -+ } -+ EXIT2(return NULL); -+} -+ -+/* ndis_init_device is called for each device */ -+int ndis_init_device(struct ndis_device *wnd) -+{ -+ struct ndis_mp_block *nmb = wnd->nmb; -+ -+ KeInitializeSpinLock(&nmb->lock); -+ wnd->mp_interrupt = NULL; -+ wnd->wrap_timer_slist.next = NULL; -+ if (wnd->wd->driver->ndis_driver) -+ wnd->wd->driver->ndis_driver->mp.shutdown = NULL; -+ -+ nmb->filterdbs.eth_db = nmb; -+ nmb->filterdbs.tr_db = nmb; -+ nmb->filterdbs.fddi_db = nmb; -+ nmb->filterdbs.arc_db = nmb; -+ -+ nmb->rx_packet = WIN_FUNC_PTR(NdisMIndicateReceivePacket,3); -+ nmb->send_complete = WIN_FUNC_PTR(NdisMSendComplete,3); -+ nmb->send_resource_avail = WIN_FUNC_PTR(NdisMSendResourcesAvailable,1); -+ nmb->status = WIN_FUNC_PTR(NdisMIndicateStatus,4); -+ nmb->status_complete = WIN_FUNC_PTR(NdisMIndicateStatusComplete,1); -+ nmb->queryinfo_complete = WIN_FUNC_PTR(NdisMQueryInformationComplete,2); -+ nmb->setinfo_complete = WIN_FUNC_PTR(NdisMSetInformationComplete,2); -+ nmb->reset_complete = WIN_FUNC_PTR(NdisMResetComplete,3); -+ nmb->eth_rx_indicate = WIN_FUNC_PTR(EthRxIndicateHandler,8); -+ nmb->eth_rx_complete = WIN_FUNC_PTR(EthRxComplete,1); -+ nmb->td_complete = WIN_FUNC_PTR(NdisMTransferDataComplete,4); -+ return 0; -+} -+ -+/* ndis_exit_device is called for each device */ -+void ndis_exit_device(struct ndis_device *wnd) -+{ -+ struct wrap_device_setting *setting; -+ ENTER2("%p", wnd); -+ mutex_lock(&loader_mutex); -+ nt_list_for_each_entry(setting, &wnd->wd->settings, list) { -+ struct ndis_configuration_parameter *param; -+ param = setting->encoded; -+ if (param) { -+ if (param->type == NdisParameterString) -+ RtlFreeUnicodeString(¶m->data.string); -+ ExFreePool(param); -+ setting->encoded = NULL; -+ } -+ } -+ mutex_unlock(&loader_mutex); -+} -+ -+/* ndis_init is called once when module is loaded */ -+int ndis_init(void) -+{ -+ InitializeListHead(&ndis_work_list); -+ spin_lock_init(&ndis_work_list_lock); -+ INIT_WORK(&ndis_work, ndis_worker); -+ -+ ndis_wq = create_singlethread_workqueue("ndis_wq"); -+ if (!ndis_wq) { -+ WARNING("couldn't create worker thread"); -+ EXIT1(return -ENOMEM); -+ } -+ -+ TRACE1("ndis_wq: %p", ndis_wq); -+ return 0; -+} -+ -+/* ndis_exit is called once when module is removed */ -+void ndis_exit(void) -+{ -+ ENTER1(""); -+ if (ndis_wq) -+ destroy_workqueue(ndis_wq); -+ EXIT1(return); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/ndis.h linux-5.6.11-ndis/3rdparty/ndiswrapper/ndis.h ---- linux-5.6.11/3rdparty/ndiswrapper/ndis.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/ndis.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,1309 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _NDIS_H_ -+#define _NDIS_H_ -+ -+#include "ntoskernel.h" -+ -+//#define ALLOW_POOL_OVERFLOW 1 -+ -+#define NDIS_DMA_24BITS 0 -+#define NDIS_DMA_32BITS 1 -+#define NDIS_DMA_64BITS 2 -+ -+#ifdef CONFIG_X86_64 -+#define MAXIMUM_PROCESSORS 64 -+#else -+#define MAXIMUM_PROCESSORS 32 -+#endif -+ -+typedef UINT NDIS_STATUS; -+typedef UCHAR NDIS_DMA_SIZE; -+typedef LONG ndis_rssi; -+typedef ULONG ndis_key_index; -+typedef ULONG ndis_tx_power_level; -+typedef ULONGULONG ndis_key_rsc; -+typedef UCHAR mac_address[ETH_ALEN]; -+typedef ULONG ndis_fragmentation_threshold; -+typedef ULONG ndis_rts_threshold; -+typedef ULONG ndis_antenna; -+typedef ULONG ndis_oid; -+ -+typedef uint64_t NDIS_PHY_ADDRESS; -+ -+struct ndis_sg_element { -+ PHYSICAL_ADDRESS address; -+ ULONG length; -+ ULONG_PTR reserved; -+}; -+ -+struct ndis_sg_list { -+ ULONG nent; -+ ULONG_PTR reserved; -+ struct ndis_sg_element elements[]; -+}; -+ -+/* when sending packets, ndiswrapper associates exactly one sg element -+ * in sg list */ -+struct wrap_tx_sg_list { -+ ULONG nent; -+ ULONG_PTR reserved; -+ struct ndis_sg_element elements[1]; -+}; -+ -+struct ndis_phy_addr_unit { -+ NDIS_PHY_ADDRESS phy_addr; -+ UINT length; -+}; -+ -+typedef struct mdl ndis_buffer; -+ -+struct ndis_buffer_pool { -+ ndis_buffer *free_descr; -+// NT_SPIN_LOCK lock; -+ spinlock_t lock; -+ UINT max_descr; -+ UINT num_allocated_descr; -+}; -+ -+#define NDIS_PROTOCOL_ID_DEFAULT 0x00 -+#define NDIS_PROTOCOL_ID_TCP_IP 0x02 -+#define NDIS_PROTOCOL_ID_IPX 0x06 -+#define NDIS_PROTOCOL_ID_NBF 0x07 -+#define NDIS_PROTOCOL_ID_MAX 0x0F -+#define NDIS_PROTOCOL_ID_MASK 0x0F -+ -+#define fPACKET_WRAPPER_RESERVED 0x3F -+#define fPACKET_CONTAINS_MEDIA_SPECIFIC_INFO 0x40 -+#define fPACKET_ALLOCATED_BY_NDIS 0x80 -+ -+#define PROTOCOL_RESERVED_SIZE_IN_PACKET (4 * sizeof(void *)) -+ -+struct transport_header_offset { -+ USHORT protocol_type; -+ USHORT header_offset; -+}; -+ -+struct ndis_network_address { -+ USHORT length; -+ USHORT type; -+ UCHAR address[1]; -+}; -+ -+struct ndis_network_address_list { -+ LONG count; -+ USHORT type; -+ struct ndis_network_address address[1]; -+}; -+ -+struct ndis_tcp_ip_checksum_packet_info { -+ union { -+ struct { -+ ULONG v4:1; -+ ULONG v6:1; -+ ULONG tcp:1; -+ ULONG udp:1; -+ ULONG ip:1; -+ } tx; -+ struct { -+ ULONG tcp_failed:1; -+ ULONG udp_failed:1; -+ ULONG ip_failed:1; -+ ULONG tcp_succeeded:1; -+ ULONG udp_succeeded:1; -+ ULONG ip_succeeded:1; -+ ULONG loopback:1; -+ } rx; -+ ULONG value; -+ }; -+}; -+ -+enum ndis_task { -+ TcpIpChecksumNdisTask, IpSecNdisTask, TcpLargeSendNdisTask, MaxNdisTask -+}; -+ -+enum ndis_encapsulation { -+ UNSPECIFIED_Encapsulation, NULL_Encapsulation, -+ IEEE_802_3_Encapsulation, IEEE_802_5_Encapsulation, -+ LLC_SNAP_ROUTED_Encapsulation, LLC_SNAP_BRIDGED_Encapsulation -+}; -+ -+#define NDIS_TASK_OFFLOAD_VERSION 1 -+ -+struct ndis_encapsulation_format { -+ enum ndis_encapsulation encap; -+ struct { -+ ULONG fixed_header_size:1; -+ ULONG reserved:31; -+ } flags; -+ ULONG header_size; -+}; -+ -+struct ndis_task_offload_header { -+ ULONG version; -+ ULONG size; -+ ULONG reserved; -+ ULONG offset_first_task; -+ struct ndis_encapsulation_format encap_format; -+}; -+ -+struct ndis_task_offload { -+ ULONG version; -+ ULONG size; -+ enum ndis_task task; -+ ULONG offset_next_task; -+ ULONG task_buf_length; -+ UCHAR task_buf[1]; -+}; -+ -+struct v4_checksum { -+ union { -+ struct { -+ ULONG ip_opts:1; -+ ULONG tcp_opts:1; -+ ULONG tcp_csum:1; -+ ULONG udp_csum:1; -+ ULONG ip_csum:1; -+ }; -+ ULONG value; -+ }; -+}; -+ -+struct v6_checksum { -+ ULONG ip_supported:1; -+ ULONG tcp_supported:1; -+ ULONG tcp_csum:1; -+ ULONG udp_csum:1; -+}; -+ -+struct ndis_task_tcp_ip_checksum { -+ struct v4_checksum v4_tx; -+ struct v4_checksum v4_rx; -+ struct v6_checksum v6_tx; -+ struct v6_checksum v6_rx; -+}; -+ -+struct ndis_task_tcp_large_send { -+ ULONG version; -+ ULONG max_size; -+ ULONG min_seg_count; -+ BOOLEAN tcp_opts; -+ BOOLEAN ip_opts; -+}; -+ -+struct ndis_packet; -+ -+struct ndis_packet_pool { -+ struct ndis_packet *free_descr; -+// NT_SPIN_LOCK lock; -+ spinlock_t lock; -+ UINT max_descr; -+ UINT num_allocated_descr; -+ UINT num_used_descr; -+ UINT proto_rsvd_length; -+}; -+ -+struct ndis_packet_stack { -+ ULONG_PTR IM_reserved[2]; -+ ULONG_PTR ndis_reserved[4]; -+}; -+ -+enum ndis_per_packet_info { -+ TcpIpChecksumPacketInfo, IpSecPacketInfo, TcpLargeSendPacketInfo, -+ ClassificationHandlePacketInfo, NdisReserved, -+ ScatterGatherListPacketInfo, Ieee8021QInfo, OriginalPacketInfo, -+ PacketCancelId, MaxPerPacketInfo -+}; -+ -+struct ndis_packet_extension { -+ void *info[MaxPerPacketInfo]; -+}; -+ -+struct ndis_packet_private { -+ UINT nr_pages; -+ UINT len; -+ ndis_buffer *buffer_head; -+ ndis_buffer *buffer_tail; -+ struct ndis_packet_pool *pool; -+ UINT count; -+ ULONG flags; -+ BOOLEAN valid_counts; -+ UCHAR packet_flags; -+ USHORT oob_offset; -+}; -+ -+struct ndis_packet { -+ struct ndis_packet_private private; -+ /* for use by miniport */ -+ union { -+ /* for connectionless mininports */ -+ struct { -+ UCHAR miniport_reserved[2 * sizeof(void *)]; -+ UCHAR wrapper_reserved[2 * sizeof(void *)]; -+ } cl_reserved; -+ /* for deserialized miniports */ -+ struct { -+ UCHAR miniport_reserved_ex[3 * sizeof(void *)]; -+ UCHAR wrapper_reserved_ex[sizeof(void *)]; -+ } deserialized_reserved; -+ struct { -+ UCHAR mac_reserved[4 * sizeof(void *)]; -+ } mac_reserved; -+ }; -+ ULONG_PTR reserved[2]; -+ UCHAR protocol_reserved[1]; -+}; -+ -+/* OOB data */ -+struct ndis_packet_oob_data { -+ union { -+ ULONGLONG time_to_tx; -+ ULONGLONG time_txed; -+ }; -+ ULONGLONG time_rxed; -+ UINT header_size; -+ UINT media_size; -+ void *media; -+ NDIS_STATUS status; -+ -+ /* ndiswrapper specific info; extension should be right after -+ * ndis's oob_data */ -+ struct ndis_packet_extension ext; -+ union { -+ /* used for tx only */ -+ struct { -+ struct sk_buff *tx_skb; -+ union { -+ struct wrap_tx_sg_list wrap_tx_sg_list; -+ struct ndis_sg_list *tx_sg_list; -+ }; -+ }; -+ /* used for rx only */ -+ struct { -+ unsigned char header[ETH_HLEN]; -+ unsigned char *look_ahead; -+ UINT look_ahead_size; -+ }; -+ }; -+}; -+ -+#define NDIS_PACKET_OOB_DATA(packet) \ -+ (struct ndis_packet_oob_data *)(((void *)(packet)) + \ -+ (packet)->private.oob_offset) -+ -+enum ndis_device_pnp_event { -+ NdisDevicePnPEventQueryRemoved, NdisDevicePnPEventRemoved, -+ NdisDevicePnPEventSurpriseRemoved, NdisDevicePnPEventQueryStopped, -+ NdisDevicePnPEventStopped, NdisDevicePnPEventPowerProfileChanged, -+ NdisDevicePnPEventMaximum -+}; -+ -+enum ndis_request_type { -+ NdisRequestQueryInformation, NdisRequestSetInformation, -+ NdisRequestQueryStatistics, NdisRequestOpen, NdisRequestClose, -+ NdisRequestSend, NdisRequestTransferData, NdisRequestReset, -+ NdisRequestGeneric1, NdisRequestGeneric2, NdisRequestGeneric3, -+ NdisRequestGeneric4 -+}; -+ -+struct ndis_request { -+ mac_address mac; -+ enum ndis_request_type request_type; -+ union data { -+ struct query_info { -+ UINT oid; -+ void *buf; -+ UINT buf_len; -+ UINT written; -+ UINT needed; -+ } query_info; -+ struct set_info { -+ UINT oid; -+ void *buf; -+ UINT buf_len; -+ UINT written; -+ UINT needed; -+ } set_info; -+ } data; -+}; -+ -+enum ndis_medium { -+ NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumWan, -+ NdisMediumLocalTalk, NdisMediumDix, NdisMediumArcnetRaw, -+ NdisMediumArcnet878_2, NdisMediumAtm, NdisMediumWirelessWan, -+ NdisMediumIrda, NdisMediumBpc, NdisMediumCoWan, -+ NdisMedium1394, NdisMediumMax -+}; -+ -+enum ndis_physical_medium { -+ NdisPhysicalMediumUnspecified, NdisPhysicalMediumWirelessLan, -+ NdisPhysicalMediumCableModem, NdisPhysicalMediumPhoneLine, -+ NdisPhysicalMediumPowerLine, NdisPhysicalMediumDSL, -+ NdisPhysicalMediumFibreChannel, NdisPhysicalMedium1394, -+ NdisPhysicalMediumWirelessWan, NdisPhysicalMediumMax -+}; -+ -+enum ndis_power_state { -+ NdisDeviceStateUnspecified = 0, -+ NdisDeviceStateD0, NdisDeviceStateD1, NdisDeviceStateD2, -+ NdisDeviceStateD3, NdisDeviceStateMaximum -+}; -+ -+enum ndis_power_profile { -+ NdisPowerProfileBattery, NdisPowerProfileAcOnLine -+}; -+ -+struct ndis_pm_wakeup_capabilities { -+ enum ndis_power_state min_magic_packet_wakeup; -+ enum ndis_power_state min_pattern_wakeup; -+ enum ndis_power_state min_link_change_wakeup; -+}; -+ -+#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 -+#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 -+#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 -+ -+enum net_pnp_event_code { -+ NetEventSetPower, NetEventQueryPower, NetEventQueryRemoveDevice, -+ NetEventCancelRemoveDevice, NetEventReconfigure, NetEventBindList, -+ NetEventBindsComplete, NetEventPnPCapabilities, NetEventMaximum -+}; -+ -+struct net_pnp_event { -+ enum net_pnp_event_code code; -+ void *buf; -+ ULONG buf_length; -+ ULONG_PTR ndis_reserved[4]; -+ ULONG_PTR transport_reserved[4]; -+ ULONG_PTR tdi_reserved[4]; -+ ULONG_PTR tdi_client_reserved[4]; -+}; -+ -+struct ndis_pnp_capabilities { -+ ULONG flags; -+ struct ndis_pm_wakeup_capabilities wakeup; -+}; -+ -+typedef void (*ndis_isr_handler)(BOOLEAN *recognized, BOOLEAN *queue_handler, -+ void *handle) wstdcall; -+typedef void (*ndis_interrupt_handler)(void *ctx) wstdcall; -+ -+struct miniport { -+ /* NDIS 3.0 */ -+ UCHAR major_version; -+ UCHAR minor_version; -+ USHORT filler; -+ UINT reserved; -+ BOOLEAN (*hangcheck)(void *ctx) wstdcall; -+ void (*disable_interrupt)(void *ctx) wstdcall; -+ void (*enable_interrupt)(void *ctx) wstdcall; -+ void (*mp_halt)(void *ctx) wstdcall; -+ ndis_interrupt_handler handle_interrupt; -+ NDIS_STATUS (*init)(NDIS_STATUS *error_status, UINT *medium_index, -+ enum ndis_medium medium[], UINT medium_array_size, -+ void *handle, void *conf_handle) wstdcall; -+ ndis_isr_handler isr; -+ NDIS_STATUS (*queryinfo)(void *ctx, ndis_oid oid, void *buffer, -+ ULONG buflen, ULONG *written, -+ ULONG *needed) wstdcall; -+ void *reconfig; -+ NDIS_STATUS (*reset)(BOOLEAN *reset_address, void *ctx) wstdcall; -+ NDIS_STATUS (*send)(void *ctx, struct ndis_packet *packet, -+ UINT flags) wstdcall; -+ NDIS_STATUS (*setinfo)(void *ctx, ndis_oid oid, void *buffer, -+ ULONG buflen, ULONG *written, -+ ULONG *needed) wstdcall; -+ NDIS_STATUS (*tx_data)(struct ndis_packet *ndis_packet, -+ UINT *bytes_txed, void *mp_ctx, void *rx_ctx, -+ UINT offset, UINT bytes_to_tx) wstdcall; -+ /* NDIS 4.0 extensions */ -+ void (*return_packet)(void *ctx, void *packet) wstdcall; -+ void (*send_packets)(void *ctx, struct ndis_packet **packets, -+ INT nr_of_packets) wstdcall; -+ void (*alloc_complete)(void *handle, void *virt, -+ NDIS_PHY_ADDRESS *phys, -+ ULONG size, void *ctx) wstdcall; -+ /* NDIS 5.0 extensions */ -+ NDIS_STATUS (*co_create_vc)(void *ctx, void *vc_handle, -+ void *vc_ctx) wstdcall; -+ NDIS_STATUS (*co_delete_vc)(void *vc_ctx) wstdcall; -+ NDIS_STATUS (*co_activate_vc)(void *vc_ctx, void *call_params) wstdcall; -+ NDIS_STATUS (*co_deactivate_vc)(void *vc_ctx) wstdcall; -+ NDIS_STATUS (*co_send_packets)(void *vc_ctx, void **packets, -+ UINT nr_of_packets) wstdcall; -+ NDIS_STATUS (*co_request)(void *ctx, void *vc_ctx, UINT *req) wstdcall; -+ /* NDIS 5.1 extensions */ -+ void (*cancel_send_packets)(void *ctx, void *id) wstdcall; -+ void (*pnp_event_notify)(void *ctx, enum ndis_device_pnp_event event, -+ void *inf_buf, ULONG inf_buf_len) wstdcall; -+ void (*shutdown)(void *ctx) wstdcall; -+ void *reserved1; -+ void *reserved2; -+ void *reserved3; -+ void *reserved4; -+}; -+ -+struct ndis_spinlock { -+ NT_SPIN_LOCK klock; -+ KIRQL irql; -+}; -+ -+union ndis_rw_lock_refcount { -+ UCHAR cache_line[16]; -+}; -+ -+struct ndis_rw_lock { -+ union { -+ struct { -+ NT_SPIN_LOCK klock; -+ void *context; -+ }; -+ UCHAR reserved[16]; -+ }; -+ union { -+ union ndis_rw_lock_refcount ref_count[MAXIMUM_PROCESSORS]; -+ /* ndiswrapper specific */ -+ volatile int count; -+ }; -+}; -+ -+struct lock_state { -+ USHORT state; -+ KIRQL irql; -+}; -+ -+struct ndis_work_item; -+typedef void (*NDIS_PROC)(struct ndis_work_item *, void *) wstdcall; -+ -+struct ndis_work_item { -+ void *ctx; -+ NDIS_PROC func; -+ union { -+ UCHAR reserved[8 * sizeof(void *)]; -+ /* ndiswrapper specific */ -+ struct nt_list list; -+ }; -+}; -+ -+struct alloc_shared_mem { -+ void *ctx; -+ ULONG size; -+ BOOLEAN cached; -+}; -+ -+struct ndis_mp_block; -+ -+/* this is opaque to drivers, so we can use it as we please */ -+struct ndis_mp_interrupt { -+ struct kinterrupt *kinterrupt; -+ NT_SPIN_LOCK lock; -+ union { -+ void *reserved; -+ unsigned int irq; -+ }; -+ ndis_isr_handler isr; -+ ndis_interrupt_handler mp_dpc; -+ struct kdpc intr_dpc; -+ struct ndis_mp_block *nmb; -+ UCHAR dpc_count; -+ BOOLEAN enable; -+ struct nt_event dpc_completed_event; -+ BOOLEAN shared; -+ BOOLEAN req_isr; -+}; -+ -+struct ndis_binary_data { -+ USHORT len; -+ void *buf; -+}; -+ -+enum ndis_parameter_type { -+ NdisParameterInteger, NdisParameterHexInteger, -+ NdisParameterString, NdisParameterMultiString, NdisParameterBinary, -+}; -+ -+typedef struct unicode_string NDIS_STRING; -+ -+struct ndis_configuration_parameter { -+ enum ndis_parameter_type type; -+ union { -+ ULONG integer; -+ NDIS_STRING string; -+ } data; -+}; -+ -+struct ndis_driver { -+ struct miniport mp; -+}; -+ -+/* IDs used to store extensions in driver_object's custom extension */ -+#define NDIS_DRIVER_CLIENT_ID 10 -+ -+struct ndis_wireless_stats { -+ ULONG length; -+ LARGE_INTEGER tx_frag; -+ LARGE_INTEGER tx_multi_frag; -+ LARGE_INTEGER failed; -+ LARGE_INTEGER retry; -+ LARGE_INTEGER multi_retry; -+ LARGE_INTEGER rtss_succ; -+ LARGE_INTEGER rtss_fail; -+ LARGE_INTEGER ack_fail; -+ LARGE_INTEGER frame_dup; -+ LARGE_INTEGER rx_frag; -+ LARGE_INTEGER rx_multi_frag; -+ LARGE_INTEGER fcs_err; -+ LARGE_INTEGER tkip_local_mic_failures; -+ LARGE_INTEGER tkip_icv_errors; -+ LARGE_INTEGER tkip_counter_measures_invoked; -+ LARGE_INTEGER tkip_replays; -+ LARGE_INTEGER ccmp_format_errors; -+ LARGE_INTEGER ccmp_replays; -+ LARGE_INTEGER ccmp_decrypt_errors; -+ LARGE_INTEGER fourway_handshake_failures; -+ LARGE_INTEGER wep_undecryptable_count; -+ LARGE_INTEGER wep_icv_errorcount; -+ LARGE_INTEGER decrypt_success_count; -+ LARGE_INTEGER decrypt_failure_count; -+}; -+ -+enum ndis_status_type { -+ Ndis802_11StatusType_Authentication, -+ Ndis802_11StatusType_MediaStreamMode, -+ Ndis802_11StatusType_PMKID_CandidateList, -+ Ndis802_11StatusType_RadioState, -+}; -+ -+struct ndis_status_indication { -+ enum ndis_status_type status_type; -+}; -+ -+enum ndis_radio_status { -+ Ndis802_11RadioStatusOn, Ndis802_11RadioStatusHardwareOff, -+ Ndis802_11RadioStatusSoftwareOff, -+}; -+ -+struct ndis_radio_status_indication -+{ -+ enum ndis_status_type status_type; -+ enum ndis_radio_status radio_state; -+}; -+ -+enum ndis_media_state { -+ NdisMediaStateConnected, -+ NdisMediaStateDisconnected, -+}; -+ -+enum ndis_media_stream_mode { -+ Ndis802_11MediaStreamOff, Ndis802_11MediaStreamOn -+}; -+ -+enum wrapper_work { -+ LINK_STATUS_OFF, LINK_STATUS_ON, SET_MULTICAST_LIST, COLLECT_IW_STATS, -+ HANGCHECK, NETIF_WAKEQ, -+}; -+ -+struct encr_info { -+ struct encr_key { -+ ULONG length; -+ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; -+ } keys[MAX_ENCR_KEYS]; -+ unsigned short tx_key_index; -+}; -+ -+struct ndis_essid { -+ ULONG length; -+ UCHAR essid[NDIS_ESSID_MAX_SIZE]; -+}; -+ -+enum ndis_infrastructure_mode { -+ Ndis802_11IBSS, Ndis802_11Infrastructure, Ndis802_11AutoUnknown, -+ Ndis802_11InfrastructureMax -+}; -+ -+enum authentication_mode { -+ Ndis802_11AuthModeOpen, Ndis802_11AuthModeShared, -+ Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA, -+ Ndis802_11AuthModeWPAPSK, Ndis802_11AuthModeWPANone, -+ Ndis802_11AuthModeWPA2, Ndis802_11AuthModeWPA2PSK, -+ Ndis802_11AuthModeMax -+}; -+ -+enum encryption_status { -+ Ndis802_11WEPEnabled, -+ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, -+ Ndis802_11WEPDisabled, -+ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, -+ Ndis802_11WEPKeyAbsent, -+ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, -+ Ndis802_11WEPNotSupported, -+ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, -+ Ndis802_11Encryption2Enabled, Ndis802_11Encryption2KeyAbsent, -+ Ndis802_11Encryption3Enabled, Ndis802_11Encryption3KeyAbsent -+}; -+ -+struct ndis_auth_encr_pair { -+ enum authentication_mode auth_mode; -+ enum encryption_status encr_mode; -+}; -+ -+struct ndis_capability { -+ ULONG length; -+ ULONG version; -+ ULONG num_PMKIDs; -+ ULONG num_auth_encr_pair; -+ struct ndis_auth_encr_pair auth_encr_pair[1]; -+}; -+ -+struct ndis_guid { -+ struct guid guid; -+ union { -+ ndis_oid oid; -+ NDIS_STATUS status; -+ }; -+ ULONG size; -+ ULONG flags; -+}; -+ -+struct ndis_timer { -+ struct nt_timer nt_timer; -+ struct kdpc kdpc; -+}; -+ -+struct ndis_mp_timer { -+ struct nt_timer nt_timer; -+ struct kdpc kdpc; -+ DPC func; -+ void *ctx; -+ struct ndis_mp_block *nmb; -+ struct ndis_mp_timer *next; -+}; -+ -+typedef struct cm_partial_resource_list NDIS_RESOURCE_LIST; -+ -+struct ndis_event { -+ struct nt_event nt_event; -+}; -+ -+struct ndis_bind_paths { -+ UINT number; -+ struct unicode_string paths[1]; -+}; -+ -+struct ndis_reference { -+ NT_SPIN_LOCK lock; -+ USHORT ref_count; -+ BOOLEAN closing; -+}; -+ -+struct ndis_filterdbs { -+ union { -+ void *eth_db; -+ void *null_db; -+ }; -+ void *tr_db; -+ void *fddi_db; -+ void *arc_db; -+}; -+ -+enum ndis_interface_type { -+ NdisInterfaceInternal, NdisInterfaceIsa, NdisInterfaceEisa, -+ NdisInterfaceMca, NdisInterfaceTurboChannel, NdisInterfacePci, -+ NdisInterfacePcMcia, -+}; -+ -+struct auth_encr_capa { -+ unsigned long auth; -+ unsigned long encr; -+}; -+ -+struct ndis_pmkid_candidate { -+ mac_address bssid; -+ DWORD flags; -+}; -+ -+struct ndis_pmkid_candidate_list { -+ ULONG version; -+ ULONG num_candidates; -+ struct ndis_pmkid_candidate candidates[1]; -+}; -+ -+/* -+ * This struct contains function pointers that the drivers references -+ * directly via macros, so it's important that they are at the correct -+ * position. -+ */ -+struct ndis_mp_block { -+ void *signature; -+ struct ndis_mp_block *next; -+ struct driver_object *drv_obj; -+ void *mp_ctx; -+ struct unicode_string name; -+ struct ndis_bind_paths *bindpaths; -+ void *openqueue; -+ struct ndis_reference reference; -+ void *device_ctx; -+ UCHAR padding; -+ UCHAR lock_acquired; -+ UCHAR pmode_opens; -+ UCHAR assigned_cpu; -+ NT_SPIN_LOCK lock; -+ enum ndis_request_type *mediarequest; -+ struct ndis_mp_interrupt *interrupt; -+ ULONG flags; -+ ULONG pnp_flags; -+ struct nt_list packet_list; -+ struct ndis_packet *first_pending_tx_packet; -+ struct ndis_packet *return_packet_queue; -+ ULONG request_buffer; -+ void *set_mcast_buffer; -+ struct ndis_mp_block *primary_mp; -+ void *wrapper_ctx; -+ void *bus_data_ctx; -+ ULONG pnp_capa; -+ void *resources; -+ struct ndis_timer wakeup_dpc_timer; -+ struct unicode_string basename; -+ struct unicode_string symlink_name; -+ ULONG ndis_hangcheck_interval; -+ USHORT hangcheck_ticks; -+ USHORT hangcheck_tick; -+ NDIS_STATUS ndis_reset_status; -+ void *resetopen; -+ struct ndis_filterdbs filterdbs; -+ void *rx_packet; -+ void *send_complete; -+ void *send_resource_avail; -+ void *reset_complete; -+ -+ enum ndis_medium media_type; -+ ULONG bus_number; -+ enum ndis_interface_type bus_type; -+ enum ndis_interface_type adapter_type; -+ struct device_object *fdo; -+ struct device_object *pdo; -+ struct device_object *next_device; -+ void *mapreg; -+ void *call_mgraflist; -+ void *mp_thread; -+ void *setinfobuf; -+ USHORT setinfo_buf_len; -+ USHORT max_send_pkts; -+ NDIS_STATUS fake_status; -+ void *lock_handler; -+ struct unicode_string *adapter_instance_name; -+ void *timer_queue; -+ UINT mac_options; -+ void *pending_req; -+ UINT max_long_addrs; -+ UINT max_short_addrs; -+ UINT cur_lookahead; -+ UINT max_lookahead; -+ -+ ndis_interrupt_handler irq_bh; -+ void *disable_intr; -+ void *enable_intr; -+ void *send_pkts; -+ void *deferred_send; -+ void *eth_rx_indicate; -+ void *tr_rx_indicate; -+ void *fddi_rx_indicate; -+ void *eth_rx_complete; -+ void *tr_rx_complete; -+ void *fddi_rx_complete; -+ -+ void *status; -+ void *status_complete; -+ void *td_complete; -+ -+ void *queryinfo_complete; -+ void *setinfo_complete; -+ void *wan_tx_complete; -+ void *wan_rx; -+ void *wan_rx_complete; -+ /* ndiswrapper specific */ -+ struct ndis_device *wnd; -+}; -+ -+struct ndis_device { -+ struct ndis_mp_block *nmb; -+ struct wrap_device *wd; -+ struct net_device *net_dev; -+ void *shutdown_ctx; -+ struct ndis_mp_interrupt *mp_interrupt; -+ struct kdpc irq_kdpc; -+ unsigned long mem_start; -+ unsigned long mem_end; -+ -+ struct net_device_stats net_stats; -+ struct iw_statistics iw_stats; -+ BOOLEAN iw_stats_enabled; -+ struct ndis_wireless_stats ndis_stats; -+ -+ struct work_struct tx_work; -+ struct ndis_packet *tx_ring[TX_RING_SIZE]; -+ u8 tx_ring_start; -+ u8 tx_ring_end; -+ u8 is_tx_ring_full; -+ u8 tx_ok; -+ spinlock_t tx_ring_lock; -+ struct mutex tx_ring_mutex; -+ unsigned int max_tx_packets; -+ struct mutex ndis_req_mutex; -+ struct task_struct *ndis_req_task; -+ int ndis_req_done; -+ NDIS_STATUS ndis_req_status; -+ ULONG packet_filter; -+ -+ ULONG sg_dma_size; -+ ULONG dma_map_count; -+ dma_addr_t *dma_map_addr; -+ -+ int hangcheck_interval; -+ struct timer_list hangcheck_timer; -+ int iw_stats_interval; -+ struct timer_list iw_stats_timer; -+ unsigned long scan_timestamp; -+ struct encr_info encr_info; -+ char nick[IW_ESSID_MAX_SIZE + 1]; -+ struct ndis_essid essid; -+ struct auth_encr_capa capa; -+ enum ndis_infrastructure_mode infrastructure_mode; -+ int max_pmkids; -+ int num_pmkids; -+ struct ndis_pmkid *pmkids; -+ mac_address mac; -+ struct proc_dir_entry *procfs_iface; -+ -+ struct work_struct ndis_work; -+ unsigned long ndis_pending_work; -+ UINT attributes; -+ int iw_auth_wpa_version; -+ int iw_auth_cipher_pairwise; -+ int iw_auth_cipher_group; -+ int iw_auth_key_mgmt; -+ int iw_auth_80211_alg; -+ struct ndis_packet_pool *tx_packet_pool; -+ struct ndis_buffer_pool *tx_buffer_pool; -+ int multicast_size; -+ struct v4_checksum rx_csum; -+ struct v4_checksum tx_csum; -+ enum ndis_physical_medium physical_medium; -+ ULONG ndis_wolopts; -+ struct nt_slist wrap_timer_slist; -+ int drv_ndis_version; -+ struct ndis_pnp_capabilities pnp_capa; -+}; -+ -+BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) wstdcall; -+ -+int ndis_init(void); -+void ndis_exit(void); -+int ndis_init_device(struct ndis_device *wnd); -+void ndis_exit_device(struct ndis_device *wnd); -+ -+int wrap_procfs_add_ndis_device(struct ndis_device *wnd); -+void wrap_procfs_remove_ndis_device(struct ndis_device *wnd); -+ -+void NdisAllocatePacketPoolEx(NDIS_STATUS *status, -+ struct ndis_packet_pool **pool_handle, -+ UINT num_descr, UINT overflowsize, -+ UINT proto_rsvd_length) wstdcall; -+void NdisFreePacketPool(struct ndis_packet_pool *pool) wstdcall; -+void NdisAllocatePacket(NDIS_STATUS *status, struct ndis_packet **packet, -+ struct ndis_packet_pool *pool) wstdcall; -+void NdisFreePacket(struct ndis_packet *descr) wstdcall; -+void NdisAllocateBufferPool(NDIS_STATUS *status, -+ struct ndis_buffer_pool **pool_handle, -+ UINT num_descr) wstdcall; -+void NdisFreeBufferPool(struct ndis_buffer_pool *pool) wstdcall; -+void NdisAllocateBuffer(NDIS_STATUS *status, ndis_buffer **buffer, -+ struct ndis_buffer_pool *pool, void *virt, -+ UINT length) wstdcall; -+void NdisFreeBuffer(ndis_buffer *descr) wstdcall; -+void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb, -+ struct ndis_packet **packets, -+ UINT nr_packets) wstdcall; -+void NdisMSendComplete(struct ndis_mp_block *nmb, struct ndis_packet *packet, -+ NDIS_STATUS status) wstdcall; -+void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) wstdcall; -+void NdisMIndicateStatus(struct ndis_mp_block *nmb, -+ NDIS_STATUS status, void *buf, UINT len) wstdcall; -+void NdisMIndicateStatusComplete(struct ndis_mp_block *nmb) wstdcall; -+void NdisMQueryInformationComplete(struct ndis_mp_block *nmb, -+ NDIS_STATUS status) wstdcall; -+void NdisMSetInformationComplete(struct ndis_mp_block *nmb, -+ NDIS_STATUS status) wstdcall; -+void NdisMResetComplete(struct ndis_mp_block *nmb, NDIS_STATUS status, -+ BOOLEAN address_reset) wstdcall; -+ULONG NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *buffer) wstdcall; -+BOOLEAN NdisWaitEvent(struct ndis_event *event, UINT timeout) wstdcall; -+void NdisSetEvent(struct ndis_event *event) wstdcall; -+void NdisMDeregisterInterrupt(struct ndis_mp_interrupt *mp_interrupt) wstdcall; -+void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx, -+ char *header1, char *header, UINT header_size, -+ void *look_ahead, UINT look_ahead_size, -+ UINT packet_size) wstdcall; -+void EthRxComplete(struct ndis_mp_block *nmb) wstdcall; -+void NdisMTransferDataComplete(struct ndis_mp_block *nmb, -+ struct ndis_packet *packet, NDIS_STATUS status, -+ UINT bytes_txed) wstdcall; -+void NdisWriteConfiguration(NDIS_STATUS *status, struct ndis_mp_block *nmb, -+ struct unicode_string *key, -+ struct ndis_configuration_parameter *param) wstdcall; -+void NdisReadConfiguration(NDIS_STATUS *status, -+ struct ndis_configuration_parameter **param, -+ struct ndis_mp_block *nmb, -+ struct unicode_string *key, -+ enum ndis_parameter_type type) wstdcall; -+ -+/* Required OIDs */ -+#define OID_GEN_SUPPORTED_LIST 0x00010101 -+#define OID_GEN_HARDWARE_STATUS 0x00010102 -+#define OID_GEN_MEDIA_SUPPORTED 0x00010103 -+#define OID_GEN_MEDIA_IN_USE 0x00010104 -+#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 -+#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 -+#define OID_GEN_LINK_SPEED 0x00010107 -+#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 -+#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 -+#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A -+#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B -+#define OID_GEN_VENDOR_ID 0x0001010C -+#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D -+#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E -+#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F -+#define OID_GEN_DRIVER_VERSION 0x00010110 -+#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 -+#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 -+#define OID_GEN_MAC_OPTIONS 0x00010113 -+#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 -+#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 -+#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 -+#define OID_GEN_SUPPORTED_GUIDS 0x00010117 -+#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 /* Set only */ -+#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 /* Set only */ -+#define OID_GEN_MACHINE_NAME 0x0001021A -+#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B /* Set only */ -+#define OID_GEN_VLAN_ID 0x0001021C -+ -+/* Optional OIDs. */ -+#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 -+#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 -+ -+/* Required statistics OIDs. */ -+#define OID_GEN_XMIT_OK 0x00020101 -+#define OID_GEN_RCV_OK 0x00020102 -+#define OID_GEN_XMIT_ERROR 0x00020103 -+#define OID_GEN_RCV_ERROR 0x00020104 -+#define OID_GEN_RCV_NO_BUFFER 0x00020105 -+ -+/* Optional OID statistics */ -+#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 -+#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 -+#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 -+#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 -+#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 -+#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 -+#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 -+#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 -+#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 -+#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A -+#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B -+#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C -+#define OID_GEN_RCV_CRC_ERROR 0x0002020D -+#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E -+#define OID_GEN_GET_TIME_CAPS 0x0002020F -+#define OID_GEN_GET_NETCARD_TIME 0x00020210 -+#define OID_GEN_NETCARD_LOAD 0x00020211 -+#define OID_GEN_DEVICE_PROFILE 0x00020212 -+ -+/* 802.3 (ethernet) OIDs */ -+#define OID_802_3_PERMANENT_ADDRESS 0x01010101 -+#define OID_802_3_CURRENT_ADDRESS 0x01010102 -+#define OID_802_3_MULTICAST_LIST 0x01010103 -+#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 -+#define OID_802_3_MAC_OPTIONS 0x01010105 -+#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 -+#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 -+#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 -+#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 -+#define OID_802_3_XMIT_DEFERRED 0x01020201 -+#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 -+#define OID_802_3_RCV_OVERRUN 0x01020203 -+#define OID_802_3_XMIT_UNDERRUN 0x01020204 -+#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 -+#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 -+#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 -+ -+/* PnP and power management OIDs */ -+#define OID_PNP_CAPABILITIES 0xFD010100 -+#define OID_PNP_SET_POWER 0xFD010101 -+#define OID_PNP_QUERY_POWER 0xFD010102 -+#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 -+#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 -+#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105 -+#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 -+ -+/* PnP/PM Statistics (Optional). */ -+#define OID_PNP_WAKE_UP_OK 0xFD020200 -+#define OID_PNP_WAKE_UP_ERROR 0xFD020201 -+ -+/* The following bits are defined for OID_PNP_ENABLE_WAKE_UP */ -+#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 -+#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 -+#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 -+ -+/* 802.11 OIDs */ -+#define OID_802_11_BSSID 0x0D010101 -+#define OID_802_11_SSID 0x0D010102 -+#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0D010203 -+#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 -+#define OID_802_11_TX_POWER_LEVEL 0x0D010205 -+#define OID_802_11_RSSI 0x0D010206 -+#define OID_802_11_RSSI_TRIGGER 0x0D010207 -+#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 -+#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0D010209 -+#define OID_802_11_RTS_THRESHOLD 0x0D01020A -+#define OID_802_11_NUMBER_OF_ANTENNAS 0x0D01020B -+#define OID_802_11_RX_ANTENNA_SELECTED 0x0D01020C -+#define OID_802_11_TX_ANTENNA_SELECTED 0x0D01020D -+#define OID_802_11_SUPPORTED_RATES 0x0D01020E -+#define OID_802_11_DESIRED_RATES 0x0D010210 -+#define OID_802_11_CONFIGURATION 0x0D010211 -+#define OID_802_11_STATISTICS 0x0D020212 -+#define OID_802_11_ADD_WEP 0x0D010113 -+#define OID_802_11_REMOVE_WEP 0x0D010114 -+#define OID_802_11_DISASSOCIATE 0x0D010115 -+#define OID_802_11_POWER_MODE 0x0D010216 -+#define OID_802_11_BSSID_LIST 0x0D010217 -+#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 -+#define OID_802_11_PRIVACY_FILTER 0x0D010119 -+#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A -+#define OID_802_11_WEP_STATUS 0x0D01011B -+#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS -+#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C -+#define OID_802_11_ADD_KEY 0x0D01011D -+#define OID_802_11_REMOVE_KEY 0x0D01011E -+#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F -+#define OID_802_11_TEST 0x0D010120 -+#define OID_802_11_MEDIA_STREAM_MODE 0x0D010121 -+#define OID_802_11_CAPABILITY 0x0D010122 -+#define OID_802_11_PMKID 0x0D010123 -+ -+#define NDIS_STATUS_SUCCESS 0 -+#define NDIS_STATUS_PENDING 0x00000103 -+#define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 -+#define NDIS_STATUS_NOT_COPIED 0x00010002 -+#define NDIS_STATUS_NOT_ACCEPTED 0x00010003 -+#define NDIS_STATUS_CALL_ACTIVE 0x00010007 -+#define NDIS_STATUS_ONLINE 0x40010003 -+#define NDIS_STATUS_RESET_START 0x40010004 -+#define NDIS_STATUS_RESET_END 0x40010005 -+#define NDIS_STATUS_RING_STATUS 0x40010006 -+#define NDIS_STATUS_CLOSED 0x40010007 -+#define NDIS_STATUS_WAN_LINE_UP 0x40010008 -+#define NDIS_STATUS_WAN_LINE_DOWN 0x40010009 -+#define NDIS_STATUS_WAN_FRAGMENT 0x4001000A -+#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B -+#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C -+#define NDIS_STATUS_HARDWARE_LINE_UP 0x4001000D -+#define NDIS_STATUS_HARDWARE_LINE_DOWN 0x4001000E -+#define NDIS_STATUS_INTERFACE_UP 0x4001000F -+#define NDIS_STATUS_INTERFACE_DOWN 0x40010010 -+#define NDIS_STATUS_MEDIA_BUSY 0x40010011 -+#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 -+#define NDIS_STATUS_WW_INDICATION NDIS_STATUS_MEDIA_SPECIFIC_INDICATION -+#define NDIS_STATUS_LINK_SPEED_CHANGE 0x40010013 -+#define NDIS_STATUS_WAN_GET_STATS 0x40010014 -+#define NDIS_STATUS_WAN_CO_FRAGMENT 0x40010015 -+#define NDIS_STATUS_WAN_CO_LINKPARAMS 0x40010016 -+#define NDIS_STATUS_NOT_RESETTABLE 0x80010001 -+#define NDIS_STATUS_SOFT_ERRORS 0x80010003 -+#define NDIS_STATUS_HARD_ERRORS 0x80010004 -+#define NDIS_STATUS_BUFFER_OVERFLOW 0x80000005 -+#define NDIS_STATUS_FAILURE 0xC0000001 -+#define NDIS_STATUS_INVALID_PARAMETER 0xC000000D -+#define NDIS_STATUS_RESOURCES 0xC000009A -+#define NDIS_STATUS_CLOSING 0xC0010002 -+#define NDIS_STATUS_BAD_VERSION 0xC0010004 -+#define NDIS_STATUS_BAD_CHARACTERISTICS 0xC0010005 -+#define NDIS_STATUS_ADAPTER_NOT_FOUND 0xC0010006 -+#define NDIS_STATUS_OPEN_FAILED 0xC0010007 -+#define NDIS_STATUS_DEVICE_FAILED 0xC0010008 -+#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 -+#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A -+#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B -+#define NDIS_STATUS_REQUEST_ABORTED 0xC001000C -+#define NDIS_STATUS_RESET_IN_PROGRESS 0xC001000D -+#define NDIS_STATUS_CLOSING_INDICATING 0xC001000E -+#define NDIS_STATUS_BAD_VERSION 0xC0010004 -+#define NDIS_STATUS_NOT_SUPPORTED 0xC00000BB -+#define NDIS_STATUS_INVALID_PACKET 0xC001000F -+#define NDIS_STATUS_OPEN_LIST_FULL 0xC0010010 -+#define NDIS_STATUS_ADAPTER_NOT_READY 0xC0010011 -+#define NDIS_STATUS_ADAPTER_NOT_OPEN 0xC0010012 -+#define NDIS_STATUS_NOT_INDICATING 0xC0010013 -+#define NDIS_STATUS_INVALID_LENGTH 0xC0010014 -+#define NDIS_STATUS_INVALID_DATA 0xC0010015 -+#define NDIS_STATUS_BUFFER_TOO_SHORT 0xC0010016 -+#define NDIS_STATUS_INVALID_OID 0xC0010017 -+#define NDIS_STATUS_ADAPTER_REMOVED 0xC0010018 -+#define NDIS_STATUS_UNSUPPORTED_MEDIA 0xC0010019 -+#define NDIS_STATUS_GROUP_ADDRESS_IN_USE 0xC001001A -+#define NDIS_STATUS_FILE_NOT_FOUND 0xC001001B -+#define NDIS_STATUS_ERROR_READING_FILE 0xC001001C -+#define NDIS_STATUS_ALREADY_MAPPED 0xC001001D -+#define NDIS_STATUS_RESOURCE_CONFLICT 0xC001001E -+#define NDIS_STATUS_NO_CABLE 0xC001001F -+#define NDIS_STATUS_INVALID_SAP 0xC0010020 -+#define NDIS_STATUS_SAP_IN_USE 0xC0010021 -+#define NDIS_STATUS_INVALID_ADDRESS 0xC0010022 -+#define NDIS_STATUS_VC_NOT_ACTIVATED 0xC0010023 -+#define NDIS_STATUS_DEST_OUT_OF_ORDER 0xC0010024 -+#define NDIS_STATUS_VC_NOT_AVAILABLE 0xC0010025 -+#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE 0xC0010026 -+#define NDIS_STATUS_INCOMPATABLE_QOS 0xC0010027 -+#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED 0xC0010028 -+#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION 0xC0010029 -+#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR 0xC0011000 -+#define NDIS_STATUS_INVALID_DEVICE_REQUEST 0xC0000010 -+#define NDIS_STATUS_NETWORK_UNREACHABLE 0xC000023C -+ -+/* Event codes */ -+ -+#define EVENT_NDIS_RESOURCE_CONFLICT 0xC0001388 -+#define EVENT_NDIS_OUT_OF_RESOURCE 0xC0001389 -+#define EVENT_NDIS_HARDWARE_FAILURE 0xC000138A -+#define EVENT_NDIS_ADAPTER_NOT_FOUND 0xC000138B -+#define EVENT_NDIS_INTERRUPT_CONNECT 0xC000138C -+#define EVENT_NDIS_DRIVER_FAILURE 0xC000138D -+#define EVENT_NDIS_BAD_VERSION 0xC000138E -+#define EVENT_NDIS_TIMEOUT 0x8000138F -+#define EVENT_NDIS_NETWORK_ADDRESS 0xC0001390 -+#define EVENT_NDIS_UNSUPPORTED_CONFIGURATION 0xC0001391 -+#define EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER 0xC0001392 -+#define EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER 0xC0001393 -+#define EVENT_NDIS_BAD_IO_BASE_ADDRESS 0xC0001394 -+#define EVENT_NDIS_RECEIVE_SPACE_SMALL 0x40001395 -+#define EVENT_NDIS_ADAPTER_DISABLED 0x80001396 -+#define EVENT_NDIS_IO_PORT_CONFLICT 0x80001397 -+#define EVENT_NDIS_PORT_OR_DMA_CONFLICT 0x80001398 -+#define EVENT_NDIS_MEMORY_CONFLICT 0x80001399 -+#define EVENT_NDIS_INTERRUPT_CONFLICT 0x8000139A -+#define EVENT_NDIS_DMA_CONFLICT 0x8000139B -+#define EVENT_NDIS_INVALID_DOWNLOAD_FILE_ERROR 0xC000139C -+#define EVENT_NDIS_MAXRECEIVES_ERROR 0x8000139D -+#define EVENT_NDIS_MAXTRANSMITS_ERROR 0x8000139E -+#define EVENT_NDIS_MAXFRAMESIZE_ERROR 0x8000139F -+#define EVENT_NDIS_MAXINTERNALBUFS_ERROR 0x800013A0 -+#define EVENT_NDIS_MAXMULTICAST_ERROR 0x800013A1 -+#define EVENT_NDIS_PRODUCTID_ERROR 0x800013A2 -+#define EVENT_NDIS_LOBE_FAILUE_ERROR 0x800013A3 -+#define EVENT_NDIS_SIGNAL_LOSS_ERROR 0x800013A4 -+#define EVENT_NDIS_REMOVE_RECEIVED_ERROR 0x800013A5 -+#define EVENT_NDIS_TOKEN_RING_CORRECTION 0x400013A6 -+#define EVENT_NDIS_ADAPTER_CHECK_ERROR 0xC00013A7 -+#define EVENT_NDIS_RESET_FAILURE_ERROR 0x800013A8 -+#define EVENT_NDIS_CABLE_DISCONNECTED_ERROR 0x800013A9 -+#define EVENT_NDIS_RESET_FAILURE_CORRECTION 0x800013AA -+ -+/* packet filter bits used by NDIS_OID_PACKET_FILTER */ -+#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 -+#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 -+#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 -+#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 -+#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 -+#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 -+#define NDIS_PACKET_TYPE_SMT 0x00000040 -+#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 -+#define NDIS_PACKET_TYPE_GROUP 0x00001000 -+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00002000 -+#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00004000 -+#define NDIS_PACKET_TYPE_MAC_FRAME 0x00008000 -+ -+/* memory allocation flags */ -+#define NDIS_MEMORY_CONTIGUOUS 0x00000001 -+#define NDIS_MEMORY_NONCACHED 0x00000002 -+ -+/* Attribute flags to NdisMSetAtrributesEx */ -+#define NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT 0x00000001 -+#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002 -+#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004 -+#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008 -+#define NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER 0x00000010 -+#define NDIS_ATTRIBUTE_DESERIALIZE 0x00000020 -+#define NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND 0x00000040 -+#define NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK 0x00000080 -+#define NDIS_ATTRIBUTE_NOT_CO_NDIS 0x00000100 -+#define NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS 0x00000200 -+ -+#define OID_TCP_TASK_OFFLOAD 0xFC010201 -+ -+#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 -+#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 -+#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 -+#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 -+#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 -+#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 -+#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 -+#define NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00000080 -+#define NDIS_MAC_OPTION_RECEIVE_AT_DPC 0x00000100 -+#define NDIS_MAC_OPTION_8021Q_VLAN 0x00000200 -+#define NDIS_MAC_OPTION_RESERVED 0x80000000 -+ -+#define deserialized_driver(wnd) (wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE) -+ -+static inline void serialize_lock(struct ndis_device *wnd) -+{ -+ nt_spin_lock(&wnd->nmb->lock); -+} -+ -+static inline void serialize_unlock(struct ndis_device *wnd) -+{ -+ nt_spin_unlock(&wnd->nmb->lock); -+} -+ -+static inline KIRQL serialize_lock_irql(struct ndis_device *wnd) -+{ -+ if (deserialized_driver(wnd)) -+ return raise_irql(DISPATCH_LEVEL); -+ else -+ return nt_spin_lock_irql(&wnd->nmb->lock, DISPATCH_LEVEL); -+} -+ -+static inline void serialize_unlock_irql(struct ndis_device *wnd, -+ KIRQL irql) -+{ -+ if (deserialized_driver(wnd)) -+ lower_irql(irql); -+ else -+ nt_spin_unlock_irql(&wnd->nmb->lock, irql); -+} -+ -+static inline void if_serialize_lock(struct ndis_device *wnd) -+{ -+ if (!deserialized_driver(wnd)) -+ nt_spin_lock(&wnd->nmb->lock); -+} -+ -+static inline void if_serialize_unlock(struct ndis_device *wnd) -+{ -+ if (!deserialized_driver(wnd)) -+ nt_spin_unlock(&wnd->nmb->lock); -+} -+ -+#endif /* NDIS_H */ -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/ndiswrapper.h linux-5.6.11-ndis/3rdparty/ndiswrapper/ndiswrapper.h ---- linux-5.6.11/3rdparty/ndiswrapper/ndiswrapper.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/ndiswrapper.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,219 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _NDISWRAPPER_H_ -+#define _NDISWRAPPER_H_ -+ -+#define DRIVER_VERSION "1.63" -+#define UTILS_VERSION "1.9" -+ -+#define DRIVER_NAME "ndiswrapper" -+#define DRIVER_CONFIG_DIR "/etc/ndiswrapper" -+ -+#define NDIS_ESSID_MAX_SIZE 32 -+#define NDIS_ENCODING_TOKEN_MAX 32 -+#define MAX_ENCR_KEYS 4 -+#define TX_RING_SIZE 16 -+#define NDIS_MAX_RATES 8 -+#define NDIS_MAX_RATES_EX 16 -+ -+#define WRAP_PCI_BUS 5 -+#define WRAP_PCMCIA_BUS 8 -+/* some USB devices, e.g., DWL-G120 have BusType as 0 */ -+#define WRAP_INTERNAL_BUS 0 -+/* documentation at msdn says 15 is PNP bus, but inf files from all -+ * vendors say 15 is USB; which is correct? */ -+#define WRAP_USB_BUS 15 -+ -+/* NDIS device must be 0, for compatibility with old versions of -+ * ndiswrapper where device type for NDIS drivers is 0 */ -+#define WRAP_NDIS_DEVICE 0 -+#define WRAP_USB_DEVICE 1 -+#define WRAP_BLUETOOTH_DEVICE1 2 -+#define WRAP_BLUETOOTH_DEVICE2 3 -+ -+#define WRAP_DEVICE_BUS(dev, bus) ((dev) << 8 | (bus)) -+#define WRAP_BUS(dev_bus) ((dev_bus) & 0x000FF) -+#define WRAP_DEVICE(dev_bus) ((dev_bus) >> 8) -+ -+#define MAX_DRIVER_NAME_LEN 32 -+#define MAX_VERSION_STRING_LEN 64 -+#define MAX_SETTING_NAME_LEN 128 -+#define MAX_SETTING_VALUE_LEN 256 -+ -+#define MAX_DRIVER_PE_IMAGES 4 -+#define MAX_DRIVER_BIN_FILES 5 -+#define MAX_DEVICE_SETTINGS 512 -+ -+#define MAX_ALLOCATED_URBS 15 -+ -+#define DEV_ANY_ID -1 -+ -+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] -+#define MACSTRSEP "%02x:%02x:%02x:%02x:%02x:%02x" -+#define MACSTR "%02x%02x%02x%02x%02x%02x" -+#define MACINTADR(a) (int*)&((a)[0]), (int*)&((a)[1]), (int*)&((a)[2]), \ -+ (int*)&((a)[3]), (int*)&((a)[4]), (int*)&((a)[5]) -+ -+#ifdef __KERNEL__ -+/* DEBUG macros */ -+ -+#define MSG(level, fmt, ...) \ -+ printk(level DRIVER_NAME " (%s:%d): " fmt "\n", \ -+ __func__, __LINE__ , ## __VA_ARGS__) -+ -+#define WARNING(fmt, ...) MSG(KERN_WARNING, fmt, ## __VA_ARGS__) -+#define ERROR(fmt, ...) MSG(KERN_ERR, fmt , ## __VA_ARGS__) -+#define INFO(fmt, ...) MSG(KERN_INFO, fmt , ## __VA_ARGS__) -+#define TODO() WARNING("not fully implemented (yet)") -+ -+#define TRACE(level, fmt, ...) \ -+do { \ -+ if (debug >= level) \ -+ printk(KERN_INFO "%s (%s:%d): " fmt "\n", DRIVER_NAME, \ -+ __func__, __LINE__ , ## __VA_ARGS__); \ -+} while (0) -+#define TRACE0(fmt, ...) TRACE(0, fmt , ## __VA_ARGS__) -+ -+extern int debug; -+ -+#ifndef DEBUG -+#define DEBUG 0 -+#endif -+ -+/* for a block of code */ -+#if DEBUG >= 1 -+#define DBG_BLOCK(level) if (debug >= level) -+#else -+#define DBG_BLOCK(level) while (0) -+#endif -+ -+#if DEBUG >= 1 -+#define TRACE1(fmt, ...) TRACE(1, fmt , ## __VA_ARGS__) -+#else -+#define TRACE1(fmt, ...) do { } while (0) -+#endif -+ -+#if DEBUG >= 2 -+#define TRACE2(fmt, ...) TRACE(2, fmt , ## __VA_ARGS__) -+#else -+#define TRACE2(fmt, ...) do { } while (0) -+#endif -+ -+#if DEBUG >= 3 -+#define TRACE3(fmt, ...) TRACE(3, fmt , ## __VA_ARGS__) -+#else -+#define TRACE3(fmt, ...) do { } while (0) -+#endif -+ -+#if DEBUG >= 4 -+#define TRACE4(fmt, ...) TRACE(4, fmt , ## __VA_ARGS__) -+#else -+#define TRACE4(fmt, ...) do { } while (0) -+#endif -+ -+#if DEBUG >= 5 -+#define TRACE5(fmt, ...) TRACE(5, fmt , ## __VA_ARGS__) -+#else -+#define TRACE5(fmt, ...) do { } while (0) -+#endif -+ -+#if DEBUG >= 6 -+#define TRACE6(fmt, ...) TRACE(6, fmt , ## __VA_ARGS__) -+#else -+#define TRACE6(fmt, ...) do { } while (0) -+#endif -+ -+#define ENTER0(fmt, ...) TRACE0("Enter " fmt , ## __VA_ARGS__) -+#define ENTER1(fmt, ...) TRACE1("Enter " fmt , ## __VA_ARGS__) -+#define ENTER2(fmt, ...) TRACE2("Enter " fmt , ## __VA_ARGS__) -+#define ENTER3(fmt, ...) TRACE3("Enter " fmt , ## __VA_ARGS__) -+#define ENTER4(fmt, ...) TRACE4("Enter " fmt , ## __VA_ARGS__) -+#define ENTER5(fmt, ...) TRACE5("Enter " fmt , ## __VA_ARGS__) -+#define ENTER6(fmt, ...) TRACE6("Enter " fmt , ## __VA_ARGS__) -+ -+#define EXIT0(stmt) do { TRACE0("Exit"); stmt; } while (0) -+#define EXIT1(stmt) do { TRACE1("Exit"); stmt; } while (0) -+#define EXIT2(stmt) do { TRACE2("Exit"); stmt; } while (0) -+#define EXIT3(stmt) do { TRACE3("Exit"); stmt; } while (0) -+#define EXIT4(stmt) do { TRACE4("Exit"); stmt; } while (0) -+#define EXIT5(stmt) do { TRACE5("Exit"); stmt; } while (0) -+#define EXIT6(stmt) do { TRACE6("Exit"); stmt; } while (0) -+ -+#if defined(USB_DEBUG) -+#define USBTRACE TRACE0 -+#define USBENTER ENTER0 -+#define USBEXIT EXIT0 -+#else -+#define USBTRACE(fmt, ...) do { } while (0) -+#define USBENTER(fmt, ...) -+#define USBEXIT(stmt) stmt -+#endif -+ -+#if defined(EVENT_DEBUG) -+#define EVENTTRACE TRACE0 -+#define EVENTENTER ENTER0 -+#define EVENTEXIT EXIT0 -+#else -+#define EVENTTRACE(fmt, ...) do { } while (0) -+#define EVENTENTER(fmt, ...) -+#define EVENTEXIT(stmt) stmt -+#endif -+ -+#if defined(TIMER_DEBUG) -+#define TIMERTRACE TRACE0 -+#define TIMERENTER ENTER0 -+#define TIMEREXIT EXIT0 -+#else -+#define TIMERTRACE(fmt, ...) do { } while (0) -+#define TIMERENTER(fmt, ...) -+#define TIMEREXIT(stmt) stmt -+#endif -+ -+#if defined(IO_DEBUG) -+#define IOTRACE TRACE0 -+#define IOENTER ENTER0 -+#define IOEXIT EXIT0 -+#else -+#define IOTRACE(fmt, ...) do { } while (0) -+#define IOENTER(fmt, ...) -+#define IOEXIT(stmt) stmt -+#endif -+ -+#if defined(WORK_DEBUG) -+#define WORKTRACE TRACE0 -+#define WORKENTER ENTER0 -+#define WORKEXIT EXIT0 -+#else -+#define WORKTRACE(fmt, ...) do { } while (0) -+#define WORKENTER(fmt, ...) -+#define WORKEXIT(stmt) stmt -+#endif -+ -+#if DEBUG >= 1 -+#define assert(expr) \ -+do { \ -+ if (!(expr)) { \ -+ ERROR("assertion '%s' failed", #expr); \ -+ dump_stack(); \ -+ } \ -+} while (0) -+#else -+#define assert(expr) do { } while (0) -+#endif -+ -+#endif // __KERNEL__ -+ -+#endif // NDISWRAPPER_H -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/ntoskernel.c linux-5.6.11-ndis/3rdparty/ndiswrapper/ntoskernel.c ---- linux-5.6.11/3rdparty/ndiswrapper/ntoskernel.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/ntoskernel.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,2716 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ntoskernel.h" -+#include "ndis.h" -+#include "usb.h" -+#include "pnp.h" -+#include "loader.h" -+#include "ntoskernel_exports.h" -+ -+/* MDLs describe a range of virtual address with an array of physical -+ * pages right after the header. For different ranges of virtual -+ * addresses, the number of entries of physical pages may be different -+ * (depending on number of entries required). If we want to allocate -+ * MDLs from a pool, the size has to be constant. So we assume that -+ * maximum range used by a driver is MDL_CACHE_PAGES; if a driver -+ * requests an MDL for a bigger region, we allocate it with kmalloc; -+ * otherwise, we allocate from the pool */ -+ -+#define MDL_CACHE_PAGES 3 -+#define MDL_CACHE_SIZE (sizeof(struct mdl) + \ -+ (sizeof(PFN_NUMBER) * MDL_CACHE_PAGES)) -+struct wrap_mdl { -+ struct nt_list list; -+ struct mdl mdl[0]; -+}; -+ -+/* everything here is for all drivers/devices - not per driver/device */ -+static spinlock_t dispatcher_lock; -+spinlock_t ntoskernel_lock; -+static void *mdl_cache; -+static struct nt_list wrap_mdl_list; -+ -+static struct work_struct kdpc_work; -+static void kdpc_worker(struct work_struct *dummy); -+ -+static struct nt_list kdpc_list; -+static spinlock_t kdpc_list_lock; -+ -+static struct nt_list callback_objects; -+ -+struct nt_list object_list; -+ -+struct bus_driver { -+ struct nt_list list; -+ char name[MAX_DRIVER_NAME_LEN]; -+ struct driver_object drv_obj; -+}; -+ -+static struct nt_list bus_driver_list; -+ -+static struct work_struct ntos_work; -+static struct nt_list ntos_work_list; -+static spinlock_t ntos_work_lock; -+static void ntos_work_worker(struct work_struct *dummy); -+spinlock_t irp_cancel_lock; -+static NT_SPIN_LOCK nt_list_lock; -+static struct nt_slist wrap_timer_slist; -+CCHAR cpu_count; -+ -+/* compute ticks (100ns) since 1601 until when system booted into -+ * wrap_ticks_to_boot */ -+u64 wrap_ticks_to_boot; -+ -+#if defined(CONFIG_X86_64) -+static struct timer_list shared_data_timer; -+struct kuser_shared_data kuser_shared_data; -+#endif -+ -+WIN_SYMBOL_MAP("KeTickCount", &jiffies) -+WIN_SYMBOL_MAP("KeNumberProcessors", &cpu_count) -+WIN_SYMBOL_MAP("NlsMbCodePageTag", FALSE) -+ -+struct workqueue_struct *ntos_wq; -+ -+#ifdef WRAP_PREEMPT -+DEFINE_PER_CPU(struct irql_info, irql_info); -+#endif -+ -+#if defined(CONFIG_X86_64) -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+static void update_user_shared_data_proc(struct timer_list *tl) -+#else -+static void update_user_shared_data_proc(unsigned long data) -+#endif -+{ -+ /* timer is supposed to be scheduled every 10ms, but bigger -+ * intervals seem to work (tried up to 50ms) */ -+ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); -+ *((ULONG64 *)&kuser_shared_data.interrupt_time) = -+ jiffies * TICKSPERSEC / HZ; -+ *((ULONG64 *)&kuser_shared_data.tick) = jiffies; -+ -+ mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30)); -+} -+#endif -+ -+void *allocate_object(ULONG size, enum common_object_type type, -+ struct unicode_string *name) -+{ -+ struct common_object_header *hdr; -+ void *body; -+ -+ /* we pad header as prefix to body */ -+ hdr = ExAllocatePoolWithTag(NonPagedPool, OBJECT_SIZE(size), 0); -+ if (!hdr) { -+ WARNING("couldn't allocate memory"); -+ return NULL; -+ } -+ memset(hdr, 0, OBJECT_SIZE(size)); -+ if (name) { -+ hdr->name.buf = ExAllocatePoolWithTag(NonPagedPool, -+ name->max_length, 0); -+ if (!hdr->name.buf) { -+ ExFreePool(hdr); -+ return NULL; -+ } -+ memcpy(hdr->name.buf, name->buf, name->max_length); -+ hdr->name.length = name->length; -+ hdr->name.max_length = name->max_length; -+ } -+ hdr->type = type; -+ hdr->ref_count = 1; -+ spin_lock_bh(&ntoskernel_lock); -+ /* threads are looked up often (in KeWaitForXXX), so optimize -+ * for fast lookups of threads */ -+ if (type == OBJECT_TYPE_NT_THREAD) -+ InsertHeadList(&object_list, &hdr->list); -+ else -+ InsertTailList(&object_list, &hdr->list); -+ spin_unlock_bh(&ntoskernel_lock); -+ body = HEADER_TO_OBJECT(hdr); -+ TRACE3("allocated hdr: %p, body: %p", hdr, body); -+ return body; -+} -+ -+static void free_object(void *object) -+{ -+ struct common_object_header *hdr; -+ -+ hdr = OBJECT_TO_HEADER(object); -+ spin_lock_bh(&ntoskernel_lock); -+ RemoveEntryList(&hdr->list); -+ spin_unlock_bh(&ntoskernel_lock); -+ TRACE3("freed hdr: %p, body: %p", hdr, object); -+ if (hdr->name.buf) -+ ExFreePool(hdr->name.buf); -+ ExFreePool(hdr); -+} -+ -+static int add_bus_driver(const char *name) -+{ -+ struct bus_driver *bus_driver; -+ -+ bus_driver = kzalloc(sizeof(*bus_driver), GFP_KERNEL); -+ if (!bus_driver) { -+ ERROR("couldn't allocate memory"); -+ return -ENOMEM; -+ } -+ strncpy(bus_driver->name, name, sizeof(bus_driver->name)); -+ bus_driver->name[sizeof(bus_driver->name)-1] = 0; -+ spin_lock_bh(&ntoskernel_lock); -+ InsertTailList(&bus_driver_list, &bus_driver->list); -+ spin_unlock_bh(&ntoskernel_lock); -+ TRACE1("bus driver %s is at %p", name, &bus_driver->drv_obj); -+ return STATUS_SUCCESS; -+} -+ -+struct driver_object *find_bus_driver(const char *name) -+{ -+ struct bus_driver *bus_driver; -+ struct driver_object *drv_obj; -+ -+ spin_lock_bh(&ntoskernel_lock); -+ drv_obj = NULL; -+ nt_list_for_each_entry(bus_driver, &bus_driver_list, list) { -+ if (strcmp(bus_driver->name, name) == 0) { -+ drv_obj = &bus_driver->drv_obj; -+ break; -+ } -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ return drv_obj; -+} -+ -+wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertHeadList,3) -+ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) -+{ -+ struct nt_list *first; -+ unsigned long flags; -+ -+ ENTER5("head = %p, entry = %p", head, entry); -+ nt_spin_lock_irqsave(lock, flags); -+ first = InsertHeadList(head, entry); -+ nt_spin_unlock_irqrestore(lock, flags); -+ TRACE5("head = %p, old = %p", head, first); -+ return first; -+} -+ -+wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertHeadList,3) -+ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) -+{ -+ ENTER5("%p", head); -+ return ExfInterlockedInsertHeadList(head, entry, lock); -+} -+ -+wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertTailList,3) -+ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) -+{ -+ struct nt_list *last; -+ unsigned long flags; -+ -+ ENTER5("head = %p, entry = %p", head, entry); -+ nt_spin_lock_irqsave(lock, flags); -+ last = InsertTailList(head, entry); -+ nt_spin_unlock_irqrestore(lock, flags); -+ TRACE5("head = %p, old = %p", head, last); -+ return last; -+} -+ -+wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertTailList,3) -+ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) -+{ -+ ENTER5("%p", head); -+ return ExfInterlockedInsertTailList(head, entry, lock); -+} -+ -+wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveHeadList,2) -+ (struct nt_list *head, NT_SPIN_LOCK *lock) -+{ -+ struct nt_list *ret; -+ unsigned long flags; -+ -+ ENTER5("head = %p", head); -+ nt_spin_lock_irqsave(lock, flags); -+ ret = RemoveHeadList(head); -+ nt_spin_unlock_irqrestore(lock, flags); -+ TRACE5("head = %p, ret = %p", head, ret); -+ return ret; -+} -+ -+wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveHeadList,2) -+ (struct nt_list *head, NT_SPIN_LOCK *lock) -+{ -+ ENTER5("%p", head); -+ return ExfInterlockedRemoveHeadList(head, lock); -+} -+ -+wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveTailList,2) -+ (struct nt_list *head, NT_SPIN_LOCK *lock) -+{ -+ struct nt_list *ret; -+ unsigned long flags; -+ -+ ENTER5("head = %p", head); -+ nt_spin_lock_irqsave(lock, flags); -+ ret = RemoveTailList(head); -+ nt_spin_unlock_irqrestore(lock, flags); -+ TRACE5("head = %p, ret = %p", head, ret); -+ return ret; -+} -+ -+wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveTailList,2) -+ (struct nt_list *head, NT_SPIN_LOCK *lock) -+{ -+ ENTER5("%p", head); -+ return ExfInterlockedRemoveTailList(head, lock); -+} -+ -+wfastcall void WIN_FUNC(InitializeSListHead,1) -+ (nt_slist_header *head) -+{ -+ memset(head, 0, sizeof(*head)); -+} -+ -+wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPushEntrySList,3) -+ (nt_slist_header *head, struct nt_slist *entry, NT_SPIN_LOCK *lock) -+{ -+ struct nt_slist *ret; -+ -+ ret = PushEntrySList(head, entry, lock); -+ return ret; -+} -+ -+wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPushEntrySList,2) -+ (nt_slist_header *head, struct nt_slist *entry) -+{ -+ struct nt_slist *ret; -+ -+ ret = PushEntrySList(head, entry, &nt_list_lock); -+ return ret; -+} -+ -+wfastcall struct nt_slist *WIN_FUNC(InterlockedPushEntrySList,2) -+ (nt_slist_header *head, struct nt_slist *entry) -+{ -+ struct nt_slist *ret; -+ -+ ret = PushEntrySList(head, entry, &nt_list_lock); -+ return ret; -+} -+ -+wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPopEntrySList,2) -+ (nt_slist_header *head, NT_SPIN_LOCK *lock) -+{ -+ struct nt_slist *ret; -+ -+ ret = PopEntrySList(head, lock); -+ return ret; -+} -+ -+wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPopEntrySList,1) -+ (nt_slist_header *head) -+{ -+ struct nt_slist *ret; -+ -+ ret = PopEntrySList(head, &nt_list_lock); -+ return ret; -+} -+ -+wfastcall struct nt_slist *WIN_FUNC(InterlockedPopEntrySList,1) -+ (nt_slist_header *head) -+{ -+ struct nt_slist *ret; -+ -+ ret = PopEntrySList(head, &nt_list_lock); -+ return ret; -+} -+ -+wstdcall USHORT WIN_FUNC(ExQueryDepthSList,1) -+ (nt_slist_header *head) -+{ -+ USHORT depth; -+ ENTER5("%p", head); -+ depth = head->depth; -+ TRACE5("%d, %p", depth, head->next); -+ return depth; -+} -+ -+wfastcall LONG WIN_FUNC(InterlockedIncrement,1) -+ (LONG volatile *val) -+{ -+ return post_atomic_add(*val, 1); -+} -+ -+wfastcall LONG WIN_FUNC(InterlockedDecrement,1) -+ (LONG volatile *val) -+{ -+ return post_atomic_add(*val, -1); -+} -+ -+wfastcall LONG WIN_FUNC(InterlockedExchange,2) -+ (LONG volatile *target, LONG val) -+{ -+ return xchg(target, val); -+} -+ -+wfastcall LONG WIN_FUNC(InterlockedCompareExchange,3) -+ (LONG volatile *dest, LONG new, LONG old) -+{ -+ return cmpxchg(dest, old, new); -+} -+ -+wfastcall void WIN_FUNC(ExInterlockedAddLargeStatistic,2) -+ (LARGE_INTEGER volatile *plint, ULONG n) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+#ifdef CONFIG_X86_64 -+ __asm__ __volatile__( -+ "\n" -+ LOCK_PREFIX "add %1, %0\n\t" -+ : "+m" (*plint) -+ : "r" (n)); -+#else -+ __asm__ __volatile__( -+ "1:\t" -+ " movl %1, %%ebx\n\t" -+ " movl %%edx, %%ecx\n\t" -+ " addl %%eax, %%ebx\n\t" -+ " adcl $0, %%ecx\n\t" -+ LOCK_PREFIX "cmpxchg8b %0\n\t" -+ " jnz 1b\n\t" -+ : "+m" (*plint) -+ : "m" (n), "A" (*plint) -+ : "ebx", "ecx"); -+#endif -+ local_irq_restore(flags); -+} -+ -+static void initialize_object(struct dispatcher_header *dh, enum dh_type type, -+ int state) -+{ -+ memset(dh, 0, sizeof(*dh)); -+ set_object_type(dh, type); -+ dh->signal_state = state; -+ InitializeListHead(&dh->wait_blocks); -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+static void timer_proc(struct timer_list *tl) -+#else -+static void timer_proc(unsigned long data) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+ struct wrap_timer *wrap_timer = from_timer(wrap_timer, tl, timer); -+#else -+ struct wrap_timer *wrap_timer = (struct wrap_timer *)data; -+#endif -+ struct nt_timer *nt_timer; -+ struct kdpc *kdpc; -+ -+ nt_timer = wrap_timer->nt_timer; -+ TIMERENTER("%p(%p), %lu", wrap_timer, nt_timer, jiffies); -+#ifdef TIMER_DEBUG -+ BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); -+ BUG_ON(nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); -+#endif -+ KeSetEvent((struct nt_event *)nt_timer, 0, FALSE); -+ if (wrap_timer->repeat) -+ mod_timer(&wrap_timer->timer, jiffies + wrap_timer->repeat); -+ kdpc = nt_timer->kdpc; -+ if (kdpc) -+ queue_kdpc(kdpc); -+ TIMEREXIT(return); -+} -+ -+void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, -+ struct ndis_mp_block *nmb) -+{ -+ struct wrap_timer *wrap_timer; -+ -+ /* TODO: if a timer is initialized more than once, we allocate -+ * memory for wrap_timer more than once for the same nt_timer, -+ * wasting memory. We can check if nt_timer->wrap_timer_magic is -+ * set and not allocate, but it is not guaranteed always to be -+ * safe */ -+ TIMERENTER("%p", nt_timer); -+ /* we allocate memory for wrap_timer behind driver's back and -+ * there is no NDIS/DDK function where this memory can be -+ * freed, so we use slack_kmalloc so it gets freed when driver -+ * is unloaded */ -+ if (nmb) -+ wrap_timer = kzalloc(sizeof(*wrap_timer), irql_gfp()); -+ else -+ wrap_timer = slack_kzalloc(sizeof(*wrap_timer)); -+ if (!wrap_timer) { -+ ERROR("couldn't allocate memory for timer"); -+ return; -+ } -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) -+ init_timer(&wrap_timer->timer); -+ wrap_timer->timer.function = timer_proc; -+ wrap_timer->timer.data = (unsigned long)wrap_timer; -+#else -+ timer_setup(&wrap_timer->timer, timer_proc, 0); -+#endif -+ wrap_timer->nt_timer = nt_timer; -+#ifdef TIMER_DEBUG -+ wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; -+#endif -+ nt_timer->wrap_timer = wrap_timer; -+ nt_timer->kdpc = NULL; -+ initialize_object(&nt_timer->dh, (enum dh_type)type, 0); -+ nt_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; -+ TIMERTRACE("timer %p (%p)", wrap_timer, nt_timer); -+ spin_lock_bh(&ntoskernel_lock); -+ if (nmb) { -+ wrap_timer->slist.next = nmb->wnd->wrap_timer_slist.next; -+ nmb->wnd->wrap_timer_slist.next = &wrap_timer->slist; -+ } else { -+ wrap_timer->slist.next = wrap_timer_slist.next; -+ wrap_timer_slist.next = &wrap_timer->slist; -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ TIMEREXIT(return); -+} -+ -+wstdcall void WIN_FUNC(KeInitializeTimerEx,2) -+ (struct nt_timer *nt_timer, enum timer_type type) -+{ -+ TIMERENTER("%p", nt_timer); -+ wrap_init_timer(nt_timer, type, NULL); -+} -+ -+wstdcall void WIN_FUNC(KeInitializeTimer,1) -+ (struct nt_timer *nt_timer) -+{ -+ TIMERENTER("%p", nt_timer); -+ wrap_init_timer(nt_timer, NotificationTimer, NULL); -+} -+ -+/* expires and repeat are in HZ */ -+BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz, -+ unsigned long repeat_hz, struct kdpc *kdpc) -+{ -+ struct wrap_timer *wrap_timer; -+ -+ TIMERENTER("%p, %lu, %lu, %p, %lu", -+ nt_timer, expires_hz, repeat_hz, kdpc, jiffies); -+ -+ wrap_timer = nt_timer->wrap_timer; -+ TIMERTRACE("%p", wrap_timer); -+#ifdef TIMER_DEBUG -+ if (wrap_timer->nt_timer != nt_timer) -+ WARNING("bad timers: %p, %p, %p", wrap_timer, nt_timer, -+ wrap_timer->nt_timer); -+ if (nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) { -+ WARNING("buggy Windows timer didn't initialize timer %p", -+ nt_timer); -+ return FALSE; -+ } -+ if (wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) { -+ WARNING("timer %p is not initialized (%lx)?", -+ wrap_timer, wrap_timer->wrap_timer_magic); -+ wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; -+ } -+#endif -+ KeClearEvent((struct nt_event *)nt_timer); -+ nt_timer->kdpc = kdpc; -+ wrap_timer->repeat = repeat_hz; -+ if (mod_timer(&wrap_timer->timer, jiffies + expires_hz)) -+ TIMEREXIT(return TRUE); -+ else -+ TIMEREXIT(return FALSE); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeSetTimerEx,4) -+ (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, -+ LONG period_ms, struct kdpc *kdpc) -+{ -+ unsigned long expires_hz, repeat_hz; -+ -+ TIMERENTER("%p, %lld, %d", nt_timer, duetime_ticks, period_ms); -+ expires_hz = SYSTEM_TIME_TO_HZ(duetime_ticks); -+ repeat_hz = MSEC_TO_HZ(period_ms); -+ return wrap_set_timer(nt_timer, expires_hz, repeat_hz, kdpc); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeSetTimer,3) -+ (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, -+ struct kdpc *kdpc) -+{ -+ TIMERENTER("%p, %lld, %p", nt_timer, duetime_ticks, kdpc); -+ return KeSetTimerEx(nt_timer, duetime_ticks, 0, kdpc); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeCancelTimer,1) -+ (struct nt_timer *nt_timer) -+{ -+ struct wrap_timer *wrap_timer; -+ int ret; -+ -+ TIMERENTER("%p", nt_timer); -+ wrap_timer = nt_timer->wrap_timer; -+ if (!wrap_timer) { -+ ERROR("invalid wrap_timer"); -+ return TRUE; -+ } -+#ifdef TIMER_DEBUG -+ BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); -+#endif -+ /* disable timer before deleting so if it is periodic timer, it -+ * won't be re-armed after deleting */ -+ wrap_timer->repeat = 0; -+ ret = del_timer_sync(&wrap_timer->timer); -+ /* the documentation for KeCancelTimer suggests the DPC is -+ * deqeued, but actually DPC is left to run */ -+ if (ret) -+ TIMEREXIT(return TRUE); -+ else -+ TIMEREXIT(return FALSE); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeReadStateTimer,1) -+ (struct nt_timer *nt_timer) -+{ -+ if (nt_timer->dh.signal_state) -+ return TRUE; -+ else -+ return FALSE; -+} -+ -+wstdcall void WIN_FUNC(KeInitializeDpc,3) -+ (struct kdpc *kdpc, void *func, void *ctx) -+{ -+ ENTER3("%p, %p, %p", kdpc, func, ctx); -+ memset(kdpc, 0, sizeof(*kdpc)); -+ kdpc->func = func; -+ kdpc->ctx = ctx; -+ InitializeListHead(&kdpc->list); -+} -+ -+static void kdpc_worker(struct work_struct *dummy) -+{ -+ struct nt_list *entry; -+ struct kdpc *kdpc; -+ unsigned long flags; -+ KIRQL irql; -+ -+ WORKENTER(""); -+ irql = raise_irql(DISPATCH_LEVEL); -+ while (1) { -+ spin_lock_irqsave(&kdpc_list_lock, flags); -+ entry = RemoveHeadList(&kdpc_list); -+ if (entry) { -+ kdpc = container_of(entry, struct kdpc, list); -+ assert(kdpc->queued); -+ kdpc->queued = 0; -+ } else -+ kdpc = NULL; -+ spin_unlock_irqrestore(&kdpc_list_lock, flags); -+ if (!kdpc) -+ break; -+ WORKTRACE("%p, %p, %p, %p, %p", kdpc, kdpc->func, kdpc->ctx, -+ kdpc->arg1, kdpc->arg2); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ LIN2WIN4(kdpc->func, kdpc, kdpc->ctx, kdpc->arg1, kdpc->arg2); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ } -+ lower_irql(irql); -+ WORKEXIT(return); -+} -+ -+wstdcall void WIN_FUNC(KeFlushQueuedDpcs,0) -+ (void) -+{ -+ kdpc_worker(NULL); -+} -+ -+BOOLEAN queue_kdpc(struct kdpc *kdpc) -+{ -+ BOOLEAN ret; -+ unsigned long flags; -+ -+ WORKENTER("%p", kdpc); -+ spin_lock_irqsave(&kdpc_list_lock, flags); -+ if (kdpc->queued) -+ ret = FALSE; -+ else { -+ if (unlikely(kdpc->importance == HighImportance)) -+ InsertHeadList(&kdpc_list, &kdpc->list); -+ else -+ InsertTailList(&kdpc_list, &kdpc->list); -+ kdpc->queued = 1; -+ ret = TRUE; -+ } -+ spin_unlock_irqrestore(&kdpc_list_lock, flags); -+ if (ret == TRUE) -+ queue_work(ntos_wq, &kdpc_work); -+ WORKTRACE("%d", ret); -+ return ret; -+} -+ -+BOOLEAN dequeue_kdpc(struct kdpc *kdpc) -+{ -+ BOOLEAN ret; -+ unsigned long flags; -+ -+ WORKENTER("%p", kdpc); -+ spin_lock_irqsave(&kdpc_list_lock, flags); -+ if (kdpc->queued) { -+ RemoveEntryList(&kdpc->list); -+ kdpc->queued = 0; -+ ret = TRUE; -+ } else -+ ret = FALSE; -+ spin_unlock_irqrestore(&kdpc_list_lock, flags); -+ WORKTRACE("%d", ret); -+ return ret; -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeInsertQueueDpc,3) -+ (struct kdpc *kdpc, void *arg1, void *arg2) -+{ -+ WORKENTER("%p, %p, %p", kdpc, arg1, arg2); -+ kdpc->arg1 = arg1; -+ kdpc->arg2 = arg2; -+ return queue_kdpc(kdpc); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeRemoveQueueDpc,1) -+ (struct kdpc *kdpc) -+{ -+ return dequeue_kdpc(kdpc); -+} -+ -+wstdcall void WIN_FUNC(KeSetImportanceDpc,2) -+ (struct kdpc *kdpc, enum kdpc_importance importance) -+{ -+ kdpc->importance = importance; -+} -+ -+static void ntos_work_worker(struct work_struct *dummy) -+{ -+ struct ntos_work_item *ntos_work_item; -+ struct nt_list *cur; -+ -+ while (1) { -+ spin_lock_bh(&ntos_work_lock); -+ cur = RemoveHeadList(&ntos_work_list); -+ spin_unlock_bh(&ntos_work_lock); -+ if (!cur) -+ break; -+ ntos_work_item = container_of(cur, struct ntos_work_item, list); -+ WORKTRACE("%p: executing %p, %p, %p", current, -+ ntos_work_item->func, ntos_work_item->arg1, -+ ntos_work_item->arg2); -+ LIN2WIN2(ntos_work_item->func, ntos_work_item->arg1, -+ ntos_work_item->arg2); -+ kfree(ntos_work_item); -+ } -+ WORKEXIT(return); -+} -+ -+int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2) -+{ -+ struct ntos_work_item *ntos_work_item; -+ -+ WORKENTER("adding work: %p, %p, %p", func, arg1, arg2); -+ ntos_work_item = kmalloc(sizeof(*ntos_work_item), irql_gfp()); -+ if (!ntos_work_item) { -+ ERROR("couldn't allocate memory"); -+ return -ENOMEM; -+ } -+ ntos_work_item->func = func; -+ ntos_work_item->arg1 = arg1; -+ ntos_work_item->arg2 = arg2; -+ spin_lock_bh(&ntos_work_lock); -+ InsertTailList(&ntos_work_list, &ntos_work_item->list); -+ spin_unlock_bh(&ntos_work_lock); -+ queue_work(ntos_wq, &ntos_work); -+ WORKEXIT(return 0); -+} -+ -+wstdcall void WIN_FUNC(KeInitializeSpinLock,1) -+ (NT_SPIN_LOCK *lock) -+{ -+ ENTER6("%p", lock); -+ nt_spin_lock_init(lock); -+} -+ -+wstdcall void WIN_FUNC(KeAcquireSpinLock,2) -+ (NT_SPIN_LOCK *lock, KIRQL *irql) -+{ -+ ENTER6("%p", lock); -+ *irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); -+} -+ -+wstdcall void WIN_FUNC(KeReleaseSpinLock,2) -+ (NT_SPIN_LOCK *lock, KIRQL oldirql) -+{ -+ ENTER6("%p", lock); -+ nt_spin_unlock_irql(lock, oldirql); -+} -+ -+wstdcall void WIN_FUNC(KeAcquireSpinLockAtDpcLevel,1) -+ (NT_SPIN_LOCK *lock) -+{ -+ ENTER6("%p", lock); -+ nt_spin_lock(lock); -+} -+ -+wstdcall void WIN_FUNC(KeReleaseSpinLockFromDpcLevel,1) -+ (NT_SPIN_LOCK *lock) -+{ -+ ENTER6("%p", lock); -+ nt_spin_unlock(lock); -+} -+ -+wstdcall void WIN_FUNC(KeRaiseIrql,2) -+ (KIRQL newirql, KIRQL *oldirql) -+{ -+ ENTER6("%d", newirql); -+ *oldirql = raise_irql(newirql); -+} -+ -+wstdcall KIRQL WIN_FUNC(KeRaiseIrqlToDpcLevel,0) -+ (void) -+{ -+ return raise_irql(DISPATCH_LEVEL); -+} -+ -+wstdcall void WIN_FUNC(KeLowerIrql,1) -+ (KIRQL irql) -+{ -+ ENTER6("%d", irql); -+ lower_irql(irql); -+} -+ -+wstdcall KIRQL WIN_FUNC(KeAcquireSpinLockRaiseToDpc,1) -+ (NT_SPIN_LOCK *lock) -+{ -+ ENTER6("%p", lock); -+ return nt_spin_lock_irql(lock, DISPATCH_LEVEL); -+} -+ -+wstdcall void *WIN_FUNC(ExAllocatePoolWithTag,3) -+ (enum pool_type pool_type, SIZE_T size, ULONG tag) -+{ -+ void *addr; -+ -+ ENTER4("pool_type: %d, size: %zu, tag: 0x%x", pool_type, size, tag); -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ if (size < PAGE_SIZE) -+ addr = kmalloc(size, irql_gfp()); -+ else { -+ if (irql_gfp() & GFP_ATOMIC) { -+ addr = __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM -+ ); -+ TRACE1("%p, %zu", addr, size); -+ } else { -+ addr = vmalloc(size); -+ TRACE1("%p, %zu", addr, size); -+ } -+ } -+ DBG_BLOCK(1) { -+ if (addr) -+ TRACE4("addr: %p, %zu", addr, size); -+ else -+ TRACE1("failed: %zu", size); -+ } -+ return addr; -+} -+WIN_FUNC_DECL(ExAllocatePoolWithTag,3) -+ -+wstdcall void WIN_FUNC(ExFreePoolWithTag,2) -+ (void *addr, ULONG tag) -+{ -+ TRACE4("%p", addr); -+ if ((unsigned long)addr < VMALLOC_START || -+ (unsigned long)addr >= VMALLOC_END) -+ kfree(addr); -+ else -+ vfree(addr); -+ -+ EXIT4(return); -+} -+ -+wstdcall void WIN_FUNC(ExFreePool,1) -+ (void *addr) -+{ -+ ExFreePoolWithTag(addr, 0); -+} -+WIN_FUNC_DECL(ExFreePool,1) -+ -+wstdcall void WIN_FUNC(ExInitializeNPagedLookasideList,7) -+ (struct npaged_lookaside_list *lookaside, -+ LOOKASIDE_ALLOC_FUNC *alloc_func, LOOKASIDE_FREE_FUNC *free_func, -+ ULONG flags, SIZE_T size, ULONG tag, USHORT depth) -+{ -+ ENTER3("lookaside: %p, size: %zu, flags: %u, head: %p, " -+ "alloc: %p, free: %p", lookaside, size, flags, -+ lookaside, alloc_func, free_func); -+ -+ memset(lookaside, 0, sizeof(*lookaside)); -+ -+ lookaside->size = size; -+ lookaside->tag = tag; -+ lookaside->depth = 4; -+ lookaside->maxdepth = 256; -+ lookaside->pool_type = NonPagedPool; -+ -+ if (alloc_func) -+ lookaside->alloc_func = alloc_func; -+ else -+ lookaside->alloc_func = WIN_FUNC_PTR(ExAllocatePoolWithTag,3); -+ if (free_func) -+ lookaside->free_func = free_func; -+ else -+ lookaside->free_func = WIN_FUNC_PTR(ExFreePool,1); -+ -+#ifndef CONFIG_X86_64 -+ nt_spin_lock_init(&lookaside->obsolete); -+#endif -+ EXIT3(return); -+} -+ -+wstdcall void WIN_FUNC(ExDeleteNPagedLookasideList,1) -+ (struct npaged_lookaside_list *lookaside) -+{ -+ struct nt_slist *entry; -+ -+ ENTER3("lookaside = %p", lookaside); -+ while ((entry = ExpInterlockedPopEntrySList(&lookaside->head))) -+ LIN2WIN1(lookaside->free_func, entry); -+ EXIT3(return); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ExCreateCallback,4) -+ (struct callback_object **object, struct object_attributes *attributes, -+ BOOLEAN create, BOOLEAN allow_multiple_callbacks) -+{ -+ struct callback_object *obj; -+ -+ ENTER2(""); -+ spin_lock_bh(&ntoskernel_lock); -+ nt_list_for_each_entry(obj, &callback_objects, callback_funcs) { -+ if (obj->attributes == attributes) { -+ spin_unlock_bh(&ntoskernel_lock); -+ *object = obj; -+ return STATUS_SUCCESS; -+ } -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ obj = allocate_object(sizeof(struct callback_object), -+ OBJECT_TYPE_CALLBACK, NULL); -+ if (!obj) -+ EXIT2(return STATUS_INSUFFICIENT_RESOURCES); -+ InitializeListHead(&obj->callback_funcs); -+ nt_spin_lock_init(&obj->lock); -+ obj->allow_multiple_callbacks = allow_multiple_callbacks; -+ obj->attributes = attributes; -+ *object = obj; -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall void *WIN_FUNC(ExRegisterCallback,3) -+ (struct callback_object *object, PCALLBACK_FUNCTION func, void *context) -+{ -+ struct callback_func *callback; -+ KIRQL irql; -+ -+ ENTER2(""); -+ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); -+ if (object->allow_multiple_callbacks == FALSE && -+ !IsListEmpty(&object->callback_funcs)) { -+ nt_spin_unlock_irql(&object->lock, irql); -+ EXIT2(return NULL); -+ } -+ nt_spin_unlock_irql(&object->lock, irql); -+ callback = kmalloc(sizeof(*callback), GFP_KERNEL); -+ if (!callback) { -+ ERROR("couldn't allocate memory"); -+ return NULL; -+ } -+ callback->func = func; -+ callback->context = context; -+ callback->object = object; -+ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); -+ InsertTailList(&object->callback_funcs, &callback->list); -+ nt_spin_unlock_irql(&object->lock, irql); -+ EXIT2(return callback); -+} -+ -+wstdcall void WIN_FUNC(ExUnregisterCallback,1) -+ (struct callback_func *callback) -+{ -+ struct callback_object *object; -+ KIRQL irql; -+ -+ ENTER3("%p", callback); -+ if (!callback) -+ return; -+ object = callback->object; -+ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); -+ RemoveEntryList(&callback->list); -+ nt_spin_unlock_irql(&object->lock, irql); -+ kfree(callback); -+ return; -+} -+ -+wstdcall void WIN_FUNC(ExNotifyCallback,3) -+ (struct callback_object *object, void *arg1, void *arg2) -+{ -+ struct callback_func *callback; -+ KIRQL irql; -+ -+ ENTER3("%p", object); -+ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); -+ nt_list_for_each_entry(callback, &object->callback_funcs, list) { -+ LIN2WIN3(callback->func, callback->context, arg1, arg2); -+ } -+ nt_spin_unlock_irql(&object->lock, irql); -+ return; -+} -+ -+/* check and set signaled state; should be called with dispatcher_lock held */ -+/* @grab indicates if the event should be grabbed or checked -+ * - note that a semaphore may stay in signaled state for multiple -+ * 'grabs' if the count is > 1 */ -+static int grab_object(struct dispatcher_header *dh, -+ struct task_struct *thread, int grab) -+{ -+ EVENTTRACE("%p, %p, %d, %d", dh, thread, grab, dh->signal_state); -+ if (unlikely(is_mutex_object(dh))) { -+ struct nt_mutex *nt_mutex; -+ nt_mutex = container_of(dh, struct nt_mutex, dh); -+ EVENTTRACE("%p, %p, %d, %p, %d", nt_mutex, -+ nt_mutex->owner_thread, dh->signal_state, -+ thread, grab); -+ /* either no thread owns the mutex or this thread owns -+ * it */ -+ assert(dh->signal_state == 1 && nt_mutex->owner_thread == NULL); -+ assert(dh->signal_state < 1 && nt_mutex->owner_thread != NULL); -+ if ((dh->signal_state == 1 && nt_mutex->owner_thread == NULL) || -+ nt_mutex->owner_thread == thread) { -+ if (grab) { -+ dh->signal_state--; -+ nt_mutex->owner_thread = thread; -+ } -+ EVENTEXIT(return 1); -+ } -+ } else if (dh->signal_state > 0) { -+ /* to grab, decrement signal_state for synchronization -+ * or semaphore objects */ -+ if (grab && (is_synch_object(dh) || is_semaphore_object(dh))) -+ dh->signal_state--; -+ EVENTEXIT(return 1); -+ } -+ EVENTEXIT(return 0); -+} -+ -+/* this function should be called holding dispatcher_lock */ -+static void object_signaled(struct dispatcher_header *dh) -+{ -+ struct nt_list *cur, *next; -+ struct wait_block *wb; -+ -+ EVENTENTER("%p", dh); -+ nt_list_for_each_safe(cur, next, &dh->wait_blocks) { -+ wb = container_of(cur, struct wait_block, list); -+ assert(wb->thread != NULL); -+ assert(wb->object == NULL); -+ if (!grab_object(dh, wb->thread, 1)) -+ continue; -+ EVENTTRACE("%p (%p): waking %p", dh, wb, wb->thread); -+ RemoveEntryList(cur); -+ wb->object = dh; -+ *(wb->wait_done) = 1; -+ wake_up_process(wb->thread); -+ } -+ EVENTEXIT(return); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(KeWaitForMultipleObjects,8) -+ (ULONG count, void *object[], enum wait_type wait_type, -+ KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode, -+ BOOLEAN alertable, LARGE_INTEGER *timeout, -+ struct wait_block *wait_block_array) -+{ -+ int i, res = 0, wait_count, wait_done; -+ typeof(jiffies) wait_hz = 0; -+ struct wait_block *wb, wb_array[THREAD_WAIT_OBJECTS]; -+ struct dispatcher_header *dh; -+ KIRQL irql = current_irql(); -+ -+ EVENTENTER("%p, %d, %u, %p", current, count, wait_type, timeout); -+ -+ if (count > MAX_WAIT_OBJECTS || -+ (count > THREAD_WAIT_OBJECTS && wait_block_array == NULL)) -+ EVENTEXIT(return STATUS_INVALID_PARAMETER); -+ -+ if (wait_block_array == NULL) -+ wb = wb_array; -+ else -+ wb = wait_block_array; -+ -+ /* If *timeout == 0: In the case of WaitAny, if an object can -+ * be grabbed (object is in signaled state), grab and -+ * return. In the case of WaitAll, we have to first make sure -+ * all objects can be grabbed. If any/some of them can't be -+ * grabbed, either we return STATUS_TIMEOUT or wait for them, -+ * depending on how to satisfy wait. If all of them can be -+ * grabbed, we will grab them in the next loop below */ -+ -+ spin_lock_bh(&dispatcher_lock); -+ for (i = wait_count = 0; i < count; i++) { -+ dh = object[i]; -+ EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state); -+ /* wait_type == 1 for WaitAny, 0 for WaitAll */ -+ if (grab_object(dh, current, wait_type)) { -+ if (wait_type == WaitAny) { -+ spin_unlock_bh(&dispatcher_lock); -+ EVENTEXIT(return STATUS_WAIT_0 + i); -+ } -+ } else { -+ EVENTTRACE("%p: wait for %p", current, dh); -+ wait_count++; -+ } -+ } -+ -+ if (timeout && *timeout == 0 && wait_count) { -+ spin_unlock_bh(&dispatcher_lock); -+ EVENTEXIT(return STATUS_TIMEOUT); -+ } -+ -+ /* get the list of objects the thread needs to wait on and add -+ * the thread on the wait list for each such object */ -+ /* if *timeout == 0, this step will grab all the objects */ -+ wait_done = 0; -+ for (i = 0; i < count; i++) { -+ dh = object[i]; -+ EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state); -+ wb[i].object = NULL; -+ if (grab_object(dh, current, 1)) { -+ EVENTTRACE("%p: no wait for %p (%d)", -+ current, dh, dh->signal_state); -+ /* mark that we are not waiting on this object */ -+ wb[i].thread = NULL; -+ } else { -+ wb[i].wait_done = &wait_done; -+ wb[i].thread = current; -+ EVENTTRACE("%p: wait for %p", current, dh); -+ InsertTailList(&dh->wait_blocks, &wb[i].list); -+ } -+ } -+ spin_unlock_bh(&dispatcher_lock); -+ if (wait_count == 0) -+ EVENTEXIT(return STATUS_SUCCESS); -+ -+ assert(timeout == NULL || *timeout != 0); -+ if (timeout == NULL) -+ wait_hz = 0; -+ else -+ wait_hz = SYSTEM_TIME_TO_HZ(*timeout); -+ -+ if (irql >= DISPATCH_LEVEL) { -+ WARNING("attempt to wait with irql %d", irql); -+ EVENTEXIT(return STATUS_INVALID_PARAMETER); -+ } -+ EVENTTRACE("%p: sleep for %ld on %p", current, wait_hz, &wait_done); -+ /* we don't honor 'alertable' - according to description for -+ * this, even if waiting in non-alertable state, thread may be -+ * alerted in some circumstances */ -+ while (wait_count) { -+ res = wait_condition(wait_done, wait_hz, TASK_INTERRUPTIBLE); -+ spin_lock_bh(&dispatcher_lock); -+ EVENTTRACE("%p woke up: %d, %d", current, res, wait_done); -+ /* the event may have been set by the time -+ * wrap_wait_event returned and spinlock obtained, so -+ * don't rely on value of 'res' - check event status */ -+ if (!wait_done) { -+ assert(res <= 0); -+ /* timed out or interrupted; remove from wait list */ -+ for (i = 0; i < count; i++) { -+ if (!wb[i].thread) -+ continue; -+ EVENTTRACE("%p: timedout, dequeue %p (%p)", -+ current, object[i], wb[i].object); -+ assert(wb[i].object == NULL); -+ RemoveEntryList(&wb[i].list); -+ } -+ spin_unlock_bh(&dispatcher_lock); -+ if (res < 0) -+ EVENTEXIT(return STATUS_ALERTED); -+ else -+ EVENTEXIT(return STATUS_TIMEOUT); -+ } -+ assert(res > 0); -+ /* woken because object(s) signaled */ -+ for (i = 0; wait_count && i < count; i++) { -+ if (!wb[i].thread || !wb[i].object) -+ continue; -+ DBG_BLOCK(1) { -+ if (wb[i].object != object[i]) { -+ EVENTTRACE("oops %p != %p", -+ wb[i].object, object[i]); -+ continue; -+ } -+ } -+ wait_count--; -+ if (wait_type == WaitAny) { -+ int j; -+ /* done; remove from rest of wait list */ -+ for (j = i + 1; j < count; j++) { -+ if (wb[j].thread && !wb[j].object) -+ RemoveEntryList(&wb[j].list); -+ } -+ spin_unlock_bh(&dispatcher_lock); -+ EVENTEXIT(return STATUS_WAIT_0 + i); -+ } -+ } -+ wait_done = 0; -+ spin_unlock_bh(&dispatcher_lock); -+ if (wait_count == 0) -+ EVENTEXIT(return STATUS_SUCCESS); -+ -+ /* this thread is still waiting for more objects, so -+ * let it wait for remaining time and those objects */ -+ if (timeout) -+ wait_hz = res; -+ else -+ wait_hz = 0; -+ } -+ /* should never reach here, but compiler wants return value */ -+ ERROR("%p: wait_hz: %ld", current, wait_hz); -+ EVENTEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(KeWaitForSingleObject,5) -+ (void *object, KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode, -+ BOOLEAN alertable, LARGE_INTEGER *timeout) -+{ -+ return KeWaitForMultipleObjects(1, &object, WaitAny, wait_reason, -+ wait_mode, alertable, timeout, NULL); -+} -+ -+wstdcall void WIN_FUNC(KeInitializeEvent,3) -+ (struct nt_event *nt_event, enum event_type type, BOOLEAN state) -+{ -+ EVENTENTER("event = %p, type = %d, state = %d", nt_event, type, state); -+ initialize_object(&nt_event->dh, (enum dh_type)type, state); -+ EVENTEXIT(return); -+} -+ -+wstdcall LONG WIN_FUNC(KeSetEvent,3) -+ (struct nt_event *nt_event, KPRIORITY incr, BOOLEAN wait) -+{ -+ LONG old_state; -+ -+ EVENTENTER("%p, %d", nt_event, nt_event->dh.type); -+ if (wait == TRUE) -+ WARNING("wait = %d, not yet implemented", wait); -+ spin_lock_bh(&dispatcher_lock); -+ old_state = nt_event->dh.signal_state; -+ nt_event->dh.signal_state = 1; -+ if (old_state == 0) -+ object_signaled(&nt_event->dh); -+ spin_unlock_bh(&dispatcher_lock); -+ EVENTEXIT(return old_state); -+} -+ -+wstdcall void WIN_FUNC(KeClearEvent,1) -+ (struct nt_event *nt_event) -+{ -+ EVENTENTER("%p", nt_event); -+ nt_event->dh.signal_state = 0; -+ EVENTEXIT(return); -+} -+ -+wstdcall LONG WIN_FUNC(KeResetEvent,1) -+ (struct nt_event *nt_event) -+{ -+ LONG old_state; -+ -+ EVENTENTER("%p", nt_event); -+ old_state = xchg(&nt_event->dh.signal_state, 0); -+ EVENTEXIT(return old_state); -+} -+ -+wstdcall LONG WIN_FUNC(KeReadStateEvent,1) -+ (struct nt_event *nt_event) -+{ -+ LONG state; -+ -+ state = nt_event->dh.signal_state; -+ EVENTTRACE("%d", state); -+ return state; -+} -+ -+wstdcall void WIN_FUNC(KeInitializeMutex,2) -+ (struct nt_mutex *mutex, ULONG level) -+{ -+ EVENTENTER("%p", mutex); -+ initialize_object(&mutex->dh, MutexObject, 1); -+ mutex->dh.size = sizeof(*mutex); -+ InitializeListHead(&mutex->list); -+ mutex->abandoned = FALSE; -+ mutex->apc_disable = 1; -+ mutex->owner_thread = NULL; -+ EVENTEXIT(return); -+} -+ -+wstdcall LONG WIN_FUNC(KeReleaseMutex,2) -+ (struct nt_mutex *mutex, BOOLEAN wait) -+{ -+ LONG ret; -+ struct task_struct *thread; -+ -+ EVENTENTER("%p, %d, %p", mutex, wait, current); -+ if (wait == TRUE) -+ WARNING("wait: %d", wait); -+ thread = current; -+ spin_lock_bh(&dispatcher_lock); -+ EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread, -+ mutex->dh.signal_state); -+ if ((mutex->owner_thread == thread) && (mutex->dh.signal_state <= 0)) { -+ ret = mutex->dh.signal_state++; -+ if (ret == 0) { -+ mutex->owner_thread = NULL; -+ object_signaled(&mutex->dh); -+ } -+ } else { -+ ret = STATUS_MUTANT_NOT_OWNED; -+ WARNING("invalid mutex: %p, %p, %p", mutex, mutex->owner_thread, -+ thread); -+ } -+ EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread, -+ mutex->dh.signal_state); -+ spin_unlock_bh(&dispatcher_lock); -+ EVENTEXIT(return ret); -+} -+ -+wstdcall void WIN_FUNC(KeInitializeSemaphore,3) -+ (struct nt_semaphore *semaphore, LONG count, LONG limit) -+{ -+ EVENTENTER("%p: %d", semaphore, count); -+ /* if limit > 1, we need to satisfy as many waits (until count -+ * becomes 0); so we keep decrementing count every time a wait -+ * is satisfied */ -+ initialize_object(&semaphore->dh, SemaphoreObject, count); -+ semaphore->dh.size = sizeof(*semaphore); -+ semaphore->limit = limit; -+ EVENTEXIT(return); -+} -+ -+wstdcall LONG WIN_FUNC(KeReleaseSemaphore,4) -+ (struct nt_semaphore *semaphore, KPRIORITY incr, LONG adjustment, -+ BOOLEAN wait) -+{ -+ LONG ret; -+ -+ EVENTENTER("%p", semaphore); -+ spin_lock_bh(&dispatcher_lock); -+ ret = semaphore->dh.signal_state; -+ assert(ret >= 0); -+ if (semaphore->dh.signal_state + adjustment <= semaphore->limit) -+ semaphore->dh.signal_state += adjustment; -+ else { -+ WARNING("releasing %d over limit %d", adjustment, -+ semaphore->limit); -+ semaphore->dh.signal_state = semaphore->limit; -+ } -+ if (semaphore->dh.signal_state > 0) -+ object_signaled(&semaphore->dh); -+ spin_unlock_bh(&dispatcher_lock); -+ EVENTEXIT(return ret); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(KeDelayExecutionThread,3) -+ (KPROCESSOR_MODE wait_mode, BOOLEAN alertable, LARGE_INTEGER *interval) -+{ -+ int res; -+ long timeout; -+ -+ if (wait_mode != 0) -+ ERROR("invalid wait_mode %d", wait_mode); -+ -+ timeout = SYSTEM_TIME_TO_HZ(*interval); -+ EVENTTRACE("%p, %lld, %ld", current, *interval, timeout); -+ if (timeout <= 0) -+ EVENTEXIT(return STATUS_SUCCESS); -+ -+ if (alertable) -+ set_current_state(TASK_INTERRUPTIBLE); -+ else -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ -+ res = schedule_timeout(timeout); -+ EVENTTRACE("%p, %d", current, res); -+ if (res == 0) -+ EVENTEXIT(return STATUS_SUCCESS); -+ else -+ EVENTEXIT(return STATUS_ALERTED); -+} -+ -+wstdcall ULONGLONG WIN_FUNC(KeQueryInterruptTime,0) -+ (void) -+{ -+ EXIT5(return jiffies * TICKSPERJIFFY); -+} -+ -+wstdcall ULONG WIN_FUNC(KeQueryTimeIncrement,0) -+ (void) -+{ -+ EXIT5(return TICKSPERSEC / HZ); -+} -+ -+wstdcall void WIN_FUNC(KeQuerySystemTime,1) -+ (LARGE_INTEGER *time) -+{ -+ *time = ticks_1601(); -+ TRACE5("%llu, %lu", *time, jiffies); -+} -+ -+wstdcall void WIN_FUNC(KeQueryTickCount,1) -+ (LARGE_INTEGER *count) -+{ -+ *count = jiffies; -+} -+ -+wstdcall LARGE_INTEGER WIN_FUNC(KeQueryPerformanceCounter,1) -+ (LARGE_INTEGER *counter) -+{ -+ if (counter) -+ *counter = HZ; -+ return jiffies; -+} -+ -+wstdcall KAFFINITY WIN_FUNC(KeQueryActiveProcessors,0) -+ (void) -+{ -+ int i, n; -+ KAFFINITY bits = 0; -+ n = num_online_cpus(); -+ for (i = 0; i < n; i++) -+ bits = (bits << 1) | 1; -+ return bits; -+} -+ -+struct nt_thread *get_current_nt_thread(void) -+{ -+ struct task_struct *task = current; -+ struct nt_thread *thread; -+ struct common_object_header *header; -+ -+ TRACE6("task: %p", task); -+ thread = NULL; -+ spin_lock_bh(&ntoskernel_lock); -+ nt_list_for_each_entry(header, &object_list, list) { -+ TRACE6("%p, %d", header, header->type); -+ if (header->type != OBJECT_TYPE_NT_THREAD) -+ break; -+ thread = HEADER_TO_OBJECT(header); -+ TRACE6("%p, %p", thread, thread->task); -+ if (thread->task == task) -+ break; -+ else -+ thread = NULL; -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ if (thread == NULL) -+ TRACE4("couldn't find thread for task %p, %d", task, task->pid); -+ TRACE6("%p", thread); -+ return thread; -+} -+ -+static struct task_struct *get_nt_thread_task(struct nt_thread *thread) -+{ -+ struct task_struct *task; -+ struct common_object_header *header; -+ -+ TRACE6("%p", thread); -+ task = NULL; -+ spin_lock_bh(&ntoskernel_lock); -+ nt_list_for_each_entry(header, &object_list, list) { -+ TRACE6("%p, %d", header, header->type); -+ if (header->type != OBJECT_TYPE_NT_THREAD) -+ break; -+ if (thread == HEADER_TO_OBJECT(header)) { -+ task = thread->task; -+ break; -+ } -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ if (task == NULL) -+ TRACE2("%p: couldn't find task for %p", current, thread); -+ return task; -+} -+ -+static struct nt_thread *create_nt_thread(struct task_struct *task) -+{ -+ struct nt_thread *thread; -+ thread = allocate_object(sizeof(*thread), OBJECT_TYPE_NT_THREAD, NULL); -+ if (!thread) { -+ ERROR("couldn't allocate thread object"); -+ EXIT2(return NULL); -+ } -+ thread->task = task; -+ if (task) -+ thread->pid = task->pid; -+ else -+ thread->pid = 0; -+ nt_spin_lock_init(&thread->lock); -+ InitializeListHead(&thread->irps); -+ initialize_object(&thread->dh, ThreadObject, 0); -+ thread->dh.size = sizeof(*thread); -+ thread->prio = LOW_PRIORITY; -+ return thread; -+} -+ -+wstdcall struct nt_thread *WIN_FUNC(KeGetCurrentThread,0) -+ (void) -+{ -+ struct nt_thread *thread = get_current_nt_thread(); -+ TRACE2("%p, %p", thread, current); -+ return thread; -+} -+ -+wstdcall KPRIORITY WIN_FUNC(KeQueryPriorityThread,1) -+ (struct nt_thread *thread) -+{ -+ KPRIORITY prio; -+ struct task_struct *task; -+ -+ TRACE2("%p", thread); -+#ifdef CONFIG_X86_64 -+ /* sis163u driver for amd64 passes 0x1f from thread created by -+ * PsCreateSystemThread - no idea what is 0x1f */ -+ if (thread == (void *)0x1f) -+ thread = get_current_nt_thread(); -+#endif -+ if (!thread) { -+ TRACE2("invalid thread"); -+ EXIT2(return LOW_REALTIME_PRIORITY); -+ } -+ task = get_nt_thread_task(thread); -+ if (!task) { -+ TRACE2("couldn't find task for thread: %p", thread); -+ EXIT2(return LOW_REALTIME_PRIORITY); -+ } -+ -+ prio = thread->prio; -+ -+ TRACE2("%d", prio); -+ return prio; -+} -+ -+wstdcall KPRIORITY WIN_FUNC(KeSetPriorityThread,2) -+ (struct nt_thread *thread, KPRIORITY prio) -+{ -+ KPRIORITY old_prio; -+ struct task_struct *task; -+ -+ TRACE2("thread: %p, priority = %u", thread, prio); -+#ifdef CONFIG_X86_64 -+ if (thread == (void *)0x1f) -+ thread = get_current_nt_thread(); -+#endif -+ if (!thread) { -+ TRACE2("invalid thread"); -+ EXIT2(return LOW_REALTIME_PRIORITY); -+ } -+ task = get_nt_thread_task(thread); -+ if (!task) { -+ TRACE2("couldn't find task for thread: %p", thread); -+ EXIT2(return LOW_REALTIME_PRIORITY); -+ } -+ -+ old_prio = thread->prio; -+ thread->prio = prio; -+ -+ TRACE2("%d, %d", old_prio, thread->prio); -+ return old_prio; -+} -+ -+struct thread_trampoline { -+ void (*func)(void *) wstdcall; -+ void *ctx; -+ struct nt_thread *thread; -+ struct completion started; -+}; -+ -+static int ntdriver_thread(void *data) -+{ -+ struct thread_trampoline *thread_tramp = data; -+ /* yes, a tramp! */ -+ typeof(thread_tramp->func) func = thread_tramp->func; -+ typeof(thread_tramp->ctx) ctx = thread_tramp->ctx; -+ -+ thread_tramp->thread->task = current; -+ thread_tramp->thread->pid = current->pid; -+ TRACE2("thread: %p, task: %p (%d)", thread_tramp->thread, -+ current, current->pid); -+ complete(&thread_tramp->started); -+ -+#ifdef PF_NOFREEZE -+ current->flags |= PF_NOFREEZE; -+#endif -+ strncpy(current->comm, "ntdriver", sizeof(current->comm)); -+ current->comm[sizeof(current->comm)-1] = 0; -+ LIN2WIN1(func, ctx); -+ ERROR("task: %p", current); -+ return 0; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(PsCreateSystemThread,7) -+ (void **handle, ULONG access, void *obj_attr, void *process, -+ void *client_id, void (*func)(void *) wstdcall, void *ctx) -+{ -+ struct thread_trampoline thread_tramp; -+ -+ ENTER2("handle = %p, access = %u, obj_attr = %p, process = %p, " -+ "client_id = %p, func = %p, context = %p", handle, access, -+ obj_attr, process, client_id, func, ctx); -+ -+ thread_tramp.thread = create_nt_thread(NULL); -+ if (!thread_tramp.thread) { -+ ERROR("couldn't allocate thread object"); -+ EXIT2(return STATUS_RESOURCES); -+ } -+ TRACE2("thread: %p", thread_tramp.thread); -+ thread_tramp.func = func; -+ thread_tramp.ctx = ctx; -+ init_completion(&thread_tramp.started); -+ -+ thread_tramp.thread->task = kthread_run(ntdriver_thread, -+ &thread_tramp, "ntdriver"); -+ if (IS_ERR(thread_tramp.thread->task)) { -+ free_object(thread_tramp.thread); -+ EXIT2(return STATUS_FAILURE); -+ } -+ TRACE2("created task: %p", thread_tramp.thread->task); -+ -+ wait_for_completion(&thread_tramp.started); -+ *handle = OBJECT_TO_HEADER(thread_tramp.thread); -+ TRACE2("created thread: %p, %p", thread_tramp.thread, *handle); -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(PsTerminateSystemThread,1) -+ (NTSTATUS status) -+{ -+ struct nt_thread *thread; -+ -+ TRACE2("%p, %08X", current, status); -+ thread = get_current_nt_thread(); -+ TRACE2("%p", thread); -+ if (thread) { -+ KeSetEvent((struct nt_event *)&thread->dh, 0, FALSE); -+ while (1) { -+ struct nt_list *ent; -+ struct irp *irp; -+ KIRQL irql; -+ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); -+ ent = RemoveHeadList(&thread->irps); -+ nt_spin_unlock_irql(&thread->lock, irql); -+ if (!ent) -+ break; -+ irp = container_of(ent, struct irp, thread_list); -+ IOTRACE("%p", irp); -+ IoCancelIrp(irp); -+ } -+ /* the driver may later query this status with -+ * ZwQueryInformationThread */ -+ thread->status = status; -+ } else -+ ERROR("couldn't find thread for task: %p", current); -+ -+ complete_and_exit(NULL, status); -+ ERROR("oops: %p, %d", thread->task, thread->pid); -+ return STATUS_FAILURE; -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeRemoveEntryDeviceQueue,2) -+ (struct kdevice_queue *dev_queue, struct kdevice_queue_entry *entry) -+{ -+ struct kdevice_queue_entry *e; -+ KIRQL irql; -+ -+ irql = nt_spin_lock_irql(&dev_queue->lock, DISPATCH_LEVEL); -+ nt_list_for_each_entry(e, &dev_queue->list, list) { -+ if (e == entry) { -+ RemoveEntryList(&e->list); -+ nt_spin_unlock_irql(&dev_queue->lock, irql); -+ return TRUE; -+ } -+ } -+ nt_spin_unlock_irql(&dev_queue->lock, irql); -+ return FALSE; -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeSynchronizeExecution,3) -+ (struct kinterrupt *interrupt, PKSYNCHRONIZE_ROUTINE synch_routine, -+ void *ctx) -+{ -+ BOOLEAN ret; -+ unsigned long flags; -+ -+ nt_spin_lock_irqsave(interrupt->actual_lock, flags); -+ ret = LIN2WIN1(synch_routine, ctx); -+ nt_spin_unlock_irqrestore(interrupt->actual_lock, flags); -+ TRACE6("%d", ret); -+ return ret; -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeRegisterBugCheckReasonCallback,4) -+ (void *callback_record, void *callback_routine, UINT reason, -+ char *component) -+{ -+ TRACE1("callback_record: %p, callback_routine: %p, reason: %d, " -+ "component: %s", callback_record, callback_routine, reason, -+ component); -+ TODO(); -+ return FALSE; -+} -+ -+wstdcall BOOLEAN WIN_FUNC(KeDeregisterBugCheckReasonCallback,1) -+ (void *callback_record) -+{ -+ TRACE1("callback_record: %p", callback_record); -+ TODO(); -+ return TRUE; -+} -+ -+wstdcall void *WIN_FUNC(MmAllocateContiguousMemorySpecifyCache,5) -+ (SIZE_T size, PHYSICAL_ADDRESS lowest, PHYSICAL_ADDRESS highest, -+ PHYSICAL_ADDRESS boundary, enum memory_caching_type cache_type) -+{ -+ void *addr; -+ gfp_t flags; -+ -+ ENTER2("%zu, 0x%llx, 0x%llx, 0x%llx, %d", size, lowest, -+ highest, boundary, cache_type); -+ flags = irql_gfp(); -+ addr = wrap_get_free_pages(flags, size); -+ TRACE2("%p, %zu, 0x%x", addr, size, flags); -+ if (addr && ((virt_to_phys(addr) + size) <= highest)) -+ EXIT2(return addr); -+#ifdef CONFIG_X86_64 -+ /* GFP_DMA is really only 16MB even on x86-64, but there is no -+ * other zone available */ -+ if (highest <= DMA_BIT_MASK(31)) -+ flags |= __GFP_DMA; -+ else if (highest <= DMA_BIT_MASK(32)) -+ flags |= __GFP_DMA32; -+#else -+ if (highest <= DMA_BIT_MASK(24)) -+ flags |= __GFP_DMA; -+ else if (highest > DMA_BIT_MASK(30)) -+ flags |= __GFP_HIGHMEM; -+#endif -+ if (addr) -+ free_pages((unsigned long)addr, get_order(size)); -+ addr = wrap_get_free_pages(flags, size); -+ TRACE2("%p, %zu, 0x%x", addr, size, flags); -+ return addr; -+} -+ -+wstdcall void WIN_FUNC(MmFreeContiguousMemorySpecifyCache,3) -+ (void *base, SIZE_T size, enum memory_caching_type cache_type) -+{ -+ TRACE2("%p, %zu", base, size); -+ free_pages((unsigned long)base, get_order(size)); -+} -+ -+wstdcall PHYSICAL_ADDRESS WIN_FUNC(MmGetPhysicalAddress,1) -+ (void *base) -+{ -+ unsigned long phy = virt_to_phys(base); -+ TRACE2("%p, %p", base, (void *)phy); -+ return phy; -+} -+ -+/* Atheros card with pciid 168C:0014 calls this function with 0xf0000 -+ * and 0xf6ef0 address, and then check for things that seem to be -+ * related to ACPI: "_SM_" and "_DMI_". This may be the hack they do -+ * to check if this card is installed in IBM thinkpads; we can -+ * probably get this device to work if we create a buffer with the -+ * strings as required by the driver and return virtual address for -+ * that address instead */ -+wstdcall void __iomem *WIN_FUNC(MmMapIoSpace,3) -+ (PHYSICAL_ADDRESS phys_addr, SIZE_T size, -+ enum memory_caching_type cache) -+{ -+ void __iomem *virt; -+ ENTER1("cache type: %d", cache); -+ if (cache == MmCached) { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) -+ virt = ioremap_cache(phys_addr, size); -+#else -+ virt = ioremap(phys_addr, size); -+#endif -+ } else { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) -+ virt = ioremap(phys_addr, size); -+#else -+ virt = ioremap_nocache(phys_addr, size); -+#endif -+ } -+ TRACE1("%llx, %zu, %p", phys_addr, size, virt); -+ return virt; -+} -+ -+wstdcall void WIN_FUNC(MmUnmapIoSpace,2) -+ (void __iomem *addr, SIZE_T size) -+{ -+ ENTER1("%p, %zu", addr, size); -+ iounmap(addr); -+ return; -+} -+ -+wstdcall ULONG WIN_FUNC(MmSizeOfMdl,2) -+ (void *base, ULONG length) -+{ -+ return sizeof(struct mdl) + -+ (sizeof(PFN_NUMBER) * SPAN_PAGES(base, length)); -+} -+ -+struct mdl *allocate_init_mdl(void *virt, ULONG length) -+{ -+ struct wrap_mdl *wrap_mdl; -+ struct mdl *mdl; -+ int mdl_size = MmSizeOfMdl(virt, length); -+ -+ if (mdl_size <= MDL_CACHE_SIZE) { -+ wrap_mdl = kmem_cache_alloc(mdl_cache, irql_gfp()); -+ if (!wrap_mdl) -+ return NULL; -+ spin_lock_bh(&dispatcher_lock); -+ InsertHeadList(&wrap_mdl_list, &wrap_mdl->list); -+ spin_unlock_bh(&dispatcher_lock); -+ mdl = wrap_mdl->mdl; -+ TRACE3("allocated mdl from cache: %p(%p), %p(%d)", -+ wrap_mdl, mdl, virt, length); -+ memset(mdl, 0, MDL_CACHE_SIZE); -+ MmInitializeMdl(mdl, virt, length); -+ /* mark the MDL as allocated from cache pool so when -+ * it is freed, we free it back to the pool */ -+ mdl->flags = MDL_ALLOCATED_FIXED_SIZE | MDL_CACHE_ALLOCATED; -+ } else { -+ wrap_mdl = -+ kmalloc(sizeof(*wrap_mdl) + mdl_size, irql_gfp()); -+ if (!wrap_mdl) -+ return NULL; -+ mdl = wrap_mdl->mdl; -+ TRACE3("allocated mdl from memory: %p(%p), %p(%d)", -+ wrap_mdl, mdl, virt, length); -+ spin_lock_bh(&dispatcher_lock); -+ InsertHeadList(&wrap_mdl_list, &wrap_mdl->list); -+ spin_unlock_bh(&dispatcher_lock); -+ memset(mdl, 0, mdl_size); -+ MmInitializeMdl(mdl, virt, length); -+ mdl->flags = MDL_ALLOCATED_FIXED_SIZE; -+ } -+ return mdl; -+} -+ -+void free_mdl(struct mdl *mdl) -+{ -+ /* A driver may allocate Mdl with NdisAllocateBuffer and free -+ * with IoFreeMdl (e.g., 64-bit Broadcom). Since we need to -+ * treat buffers allocated with Ndis calls differently, we -+ * must call NdisFreeBuffer if it is allocated with Ndis -+ * function. We set 'pool' field in Ndis functions. */ -+ if (!mdl) -+ return; -+ if (mdl->pool) -+ NdisFreeBuffer(mdl); -+ else { -+ struct wrap_mdl *wrap_mdl = (struct wrap_mdl *) -+ ((char *)mdl - offsetof(struct wrap_mdl, mdl)); -+ spin_lock_bh(&dispatcher_lock); -+ RemoveEntryList(&wrap_mdl->list); -+ spin_unlock_bh(&dispatcher_lock); -+ -+ if (mdl->flags & MDL_CACHE_ALLOCATED) { -+ TRACE3("freeing mdl cache: %p, %p, %p", -+ wrap_mdl, mdl, mdl->mappedsystemva); -+ kmem_cache_free(mdl_cache, wrap_mdl); -+ } else { -+ TRACE3("freeing mdl: %p, %p, %p", -+ wrap_mdl, mdl, mdl->mappedsystemva); -+ kfree(wrap_mdl); -+ } -+ } -+ return; -+} -+ -+wstdcall void WIN_FUNC(IoBuildPartialMdl,4) -+ (struct mdl *source, struct mdl *target, void *virt, ULONG length) -+{ -+ MmInitializeMdl(target, virt, length); -+ target->flags |= MDL_PARTIAL; -+} -+ -+wstdcall void WIN_FUNC(MmBuildMdlForNonPagedPool,1) -+ (struct mdl *mdl) -+{ -+ PFN_NUMBER *mdl_pages; -+ int i, n; -+ -+ ENTER4("%p", mdl); -+ /* already mapped */ -+// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl); -+ mdl->flags |= MDL_SOURCE_IS_NONPAGED_POOL; -+ TRACE4("%p, %p, %p, %d, %d", mdl, mdl->mappedsystemva, mdl->startva, -+ mdl->byteoffset, mdl->bytecount); -+ n = SPAN_PAGES(MmGetSystemAddressForMdl(mdl), MmGetMdlByteCount(mdl)); -+ if (n > MDL_CACHE_PAGES) -+ WARNING("%p, %d, %d", MmGetSystemAddressForMdl(mdl), -+ MmGetMdlByteCount(mdl), n); -+ mdl_pages = MmGetMdlPfnArray(mdl); -+ for (i = 0; i < n; i++) -+ mdl_pages[i] = (ULONG_PTR)mdl->startva + (i * PAGE_SIZE); -+ EXIT4(return); -+} -+ -+wstdcall void *WIN_FUNC(MmMapLockedPages,2) -+ (struct mdl *mdl, KPROCESSOR_MODE access_mode) -+{ -+ /* already mapped */ -+// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl); -+ mdl->flags |= MDL_MAPPED_TO_SYSTEM_VA; -+ /* what is the need for MDL_PARTIAL_HAS_BEEN_MAPPED? */ -+ if (mdl->flags & MDL_PARTIAL) -+ mdl->flags |= MDL_PARTIAL_HAS_BEEN_MAPPED; -+ return mdl->mappedsystemva; -+} -+ -+wstdcall void *WIN_FUNC(MmMapLockedPagesSpecifyCache,6) -+ (struct mdl *mdl, KPROCESSOR_MODE access_mode, -+ enum memory_caching_type cache_type, void *base_address, -+ ULONG bug_check, enum mm_page_priority priority) -+{ -+ return MmMapLockedPages(mdl, access_mode); -+} -+ -+wstdcall void WIN_FUNC(MmUnmapLockedPages,2) -+ (void *base, struct mdl *mdl) -+{ -+ mdl->flags &= ~MDL_MAPPED_TO_SYSTEM_VA; -+ return; -+} -+ -+wstdcall void WIN_FUNC(MmProbeAndLockPages,3) -+ (struct mdl *mdl, KPROCESSOR_MODE access_mode, -+ enum lock_operation operation) -+{ -+ /* already locked */ -+ mdl->flags |= MDL_PAGES_LOCKED; -+ return; -+} -+ -+wstdcall void WIN_FUNC(MmUnlockPages,1) -+ (struct mdl *mdl) -+{ -+ mdl->flags &= ~MDL_PAGES_LOCKED; -+ return; -+} -+ -+wstdcall BOOLEAN WIN_FUNC(MmIsAddressValid,1) -+ (void *virt_addr) -+{ -+ if (virt_addr_valid(virt_addr)) -+ return TRUE; -+ else -+ return FALSE; -+} -+ -+wstdcall void *WIN_FUNC(MmLockPagableDataSection,1) -+ (void *address) -+{ -+ return address; -+} -+ -+wstdcall void WIN_FUNC(MmUnlockPagableImageSection,1) -+ (void *handle) -+{ -+ return; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ObReferenceObjectByHandle,6) -+ (void *handle, ACCESS_MASK desired_access, void *obj_type, -+ KPROCESSOR_MODE access_mode, void **object, void *handle_info) -+{ -+ struct common_object_header *hdr; -+ -+ TRACE2("%p", handle); -+ hdr = HANDLE_TO_HEADER(handle); -+ atomic_inc_var(hdr->ref_count); -+ *object = HEADER_TO_OBJECT(hdr); -+ TRACE2("%p, %p, %d, %p", hdr, object, hdr->ref_count, *object); -+ return STATUS_SUCCESS; -+} -+ -+/* DDK doesn't say if return value should be before incrementing or -+ * after incrementing reference count, but according to #reactos -+ * developers, it should be return value after incrementing */ -+wfastcall LONG WIN_FUNC(ObfReferenceObject,1) -+ (void *object) -+{ -+ struct common_object_header *hdr; -+ LONG ret; -+ -+ hdr = OBJECT_TO_HEADER(object); -+ ret = post_atomic_add(hdr->ref_count, 1); -+ TRACE2("%p, %d, %p", hdr, hdr->ref_count, object); -+ return ret; -+} -+ -+static int dereference_object(void *object) -+{ -+ struct common_object_header *hdr; -+ int ref_count; -+ -+ ENTER2("object: %p", object); -+ hdr = OBJECT_TO_HEADER(object); -+ TRACE2("hdr: %p", hdr); -+ ref_count = post_atomic_add(hdr->ref_count, -1); -+ TRACE2("object: %p, %d", object, ref_count); -+ if (ref_count < 0) -+ ERROR("invalid object: %p (%d)", object, ref_count); -+ if (ref_count <= 0) { -+ free_object(object); -+ return 1; -+ } else -+ return 0; -+} -+ -+wfastcall void WIN_FUNC(ObfDereferenceObject,1) -+ (void *object) -+{ -+ TRACE2("%p", object); -+ dereference_object(object); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwCreateFile,11) -+ (void **handle, ACCESS_MASK access_mask, -+ struct object_attributes *obj_attr, struct io_status_block *iosb, -+ LARGE_INTEGER *size, ULONG file_attr, ULONG share_access, -+ ULONG create_disposition, ULONG create_options, void *ea_buffer, -+ ULONG ea_length) -+{ -+ struct common_object_header *coh; -+ struct file_object *fo; -+ struct ansi_string ansi; -+ struct wrap_bin_file *bin_file; -+ char *file_basename; -+ NTSTATUS status; -+ -+ spin_lock_bh(&ntoskernel_lock); -+ nt_list_for_each_entry(coh, &object_list, list) { -+ if (coh->type != OBJECT_TYPE_FILE) -+ continue; -+ /* TODO: check if file is opened in shared mode */ -+ if (!RtlCompareUnicodeString(&coh->name, obj_attr->name, TRUE)) { -+ fo = HEADER_TO_OBJECT(coh); -+ bin_file = fo->wrap_bin_file; -+ *handle = coh; -+ spin_unlock_bh(&ntoskernel_lock); -+ ObReferenceObject(fo); -+ iosb->status = FILE_OPENED; -+ iosb->info = bin_file->size; -+ EXIT2(return STATUS_SUCCESS); -+ } -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ -+ if (RtlUnicodeStringToAnsiString(&ansi, obj_attr->name, TRUE) != -+ STATUS_SUCCESS) -+ EXIT2(return STATUS_INSUFFICIENT_RESOURCES); -+ -+ file_basename = strrchr(ansi.buf, '\\'); -+ if (file_basename) -+ file_basename++; -+ else -+ file_basename = ansi.buf; -+ TRACE2("file: '%s', '%s'", ansi.buf, file_basename); -+ -+ fo = allocate_object(sizeof(struct file_object), OBJECT_TYPE_FILE, -+ obj_attr->name); -+ if (!fo) { -+ RtlFreeAnsiString(&ansi); -+ iosb->status = STATUS_INSUFFICIENT_RESOURCES; -+ iosb->info = 0; -+ EXIT2(return STATUS_FAILURE); -+ } -+ coh = OBJECT_TO_HEADER(fo); -+ bin_file = get_bin_file(file_basename); -+ if (bin_file) { -+ TRACE2("%s, %s", bin_file->name, file_basename); -+ fo->flags = FILE_OPENED; -+ } else if (access_mask & FILE_WRITE_DATA) { -+ bin_file = kzalloc(sizeof(*bin_file), GFP_KERNEL); -+ if (bin_file) { -+ strncpy(bin_file->name, file_basename, -+ sizeof(bin_file->name)); -+ bin_file->name[sizeof(bin_file->name)-1] = 0; -+ bin_file->data = vmalloc(*size); -+ if (bin_file->data) { -+ memset(bin_file->data, 0, *size); -+ bin_file->size = *size; -+ fo->flags = FILE_CREATED; -+ } else { -+ kfree(bin_file); -+ bin_file = NULL; -+ } -+ } -+ } else -+ bin_file = NULL; -+ -+ RtlFreeAnsiString(&ansi); -+ if (!bin_file) { -+ iosb->status = FILE_DOES_NOT_EXIST; -+ iosb->info = 0; -+ free_object(fo); -+ EXIT2(return STATUS_FAILURE); -+ } -+ -+ fo->wrap_bin_file = bin_file; -+ fo->current_byte_offset = 0; -+ if (access_mask & FILE_READ_DATA) -+ fo->read_access = TRUE; -+ if (access_mask & FILE_WRITE_DATA) -+ fo->write_access = TRUE; -+ iosb->status = FILE_OPENED; -+ iosb->info = bin_file->size; -+ *handle = coh; -+ TRACE2("handle: %p", *handle); -+ status = STATUS_SUCCESS; -+ EXIT2(return status); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwOpenFile,6) -+ (void **handle, ACCESS_MASK access_mask, -+ struct object_attributes *obj_attr, struct io_status_block *iosb, -+ ULONG share_access, ULONG open_options) -+{ -+ LARGE_INTEGER size; -+ return ZwCreateFile(handle, access_mask, obj_attr, iosb, &size, 0, -+ share_access, 0, open_options, NULL, 0); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwReadFile,9) -+ (void *handle, struct nt_event *event, void *apc_routine, -+ void *apc_context, struct io_status_block *iosb, void *buffer, -+ ULONG length, LARGE_INTEGER *byte_offset, ULONG *key) -+{ -+ struct file_object *fo; -+ struct common_object_header *coh; -+ ULONG count; -+ size_t offset; -+ struct wrap_bin_file *file; -+ -+ TRACE2("%p", handle); -+ coh = handle; -+ if (coh->type != OBJECT_TYPE_FILE) { -+ ERROR("handle %p is invalid: %d", handle, coh->type); -+ EXIT2(return STATUS_FAILURE); -+ } -+ fo = HANDLE_TO_OBJECT(coh); -+ file = fo->wrap_bin_file; -+ TRACE2("file: %s (%zu)", file->name, file->size); -+ spin_lock_bh(&ntoskernel_lock); -+ if (byte_offset) -+ offset = *byte_offset; -+ else -+ offset = fo->current_byte_offset; -+ count = min((size_t)length, file->size - offset); -+ TRACE2("count: %u, offset: %zu, length: %u", count, offset, length); -+ memcpy(buffer, ((void *)file->data) + offset, count); -+ fo->current_byte_offset = offset + count; -+ spin_unlock_bh(&ntoskernel_lock); -+ iosb->status = STATUS_SUCCESS; -+ iosb->info = count; -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwWriteFile,9) -+ (void *handle, struct nt_event *event, void *apc_routine, -+ void *apc_context, struct io_status_block *iosb, void *buffer, -+ ULONG length, LARGE_INTEGER *byte_offset, ULONG *key) -+{ -+ struct file_object *fo; -+ struct common_object_header *coh; -+ struct wrap_bin_file *file; -+ unsigned long offset; -+ -+ TRACE2("%p", handle); -+ coh = handle; -+ if (coh->type != OBJECT_TYPE_FILE) { -+ ERROR("handle %p is invalid: %d", handle, coh->type); -+ EXIT2(return STATUS_FAILURE); -+ } -+ fo = HANDLE_TO_OBJECT(coh); -+ file = fo->wrap_bin_file; -+ TRACE2("file: %zu, %u", file->size, length); -+ spin_lock_bh(&ntoskernel_lock); -+ if (byte_offset) -+ offset = *byte_offset; -+ else -+ offset = fo->current_byte_offset; -+ if (length + offset > file->size) { -+ WARNING("%lu, %zu", length + offset, file->size); -+ /* TODO: implement writing past end of current size */ -+ iosb->status = STATUS_FAILURE; -+ iosb->info = 0; -+ } else { -+ memcpy(file->data + offset, buffer, length); -+ iosb->status = STATUS_SUCCESS; -+ iosb->info = length; -+ fo->current_byte_offset = offset + length; -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ EXIT2(return iosb->status); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwClose,1) -+ (void *handle) -+{ -+ struct common_object_header *coh; -+ -+ TRACE2("%p", handle); -+ if (handle == NULL) { -+ TRACE1(""); -+ EXIT2(return STATUS_SUCCESS); -+ } -+ coh = handle; -+ if (coh->type == OBJECT_TYPE_FILE) { -+ struct file_object *fo; -+ struct wrap_bin_file *bin_file; -+ typeof(fo->flags) flags; -+ -+ fo = HANDLE_TO_OBJECT(handle); -+ flags = fo->flags; -+ bin_file = fo->wrap_bin_file; -+ if (dereference_object(fo)) { -+ if (flags == FILE_CREATED) { -+ vfree(bin_file->data); -+ kfree(bin_file); -+ } else -+ free_bin_file(bin_file); -+ } -+ } else if (coh->type == OBJECT_TYPE_NT_THREAD) { -+ struct nt_thread *thread = HANDLE_TO_OBJECT(handle); -+ TRACE2("thread: %p (%p)", thread, handle); -+ ObDereferenceObject(thread); -+ } else { -+ /* TODO: can we just dereference object here? */ -+ WARNING("closing handle 0x%x not implemented", coh->type); -+ } -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwQueryInformationFile,5) -+ (void *handle, struct io_status_block *iosb, void *info, -+ ULONG length, enum file_info_class class) -+{ -+ struct file_object *fo; -+ struct file_name_info *fni; -+ struct file_std_info *fsi; -+ struct wrap_bin_file *file; -+ struct common_object_header *coh; -+ -+ ENTER2("%p", handle); -+ coh = handle; -+ if (coh->type != OBJECT_TYPE_FILE) { -+ ERROR("handle %p is invalid: %d", coh, coh->type); -+ EXIT2(return STATUS_FAILURE); -+ } -+ fo = HANDLE_TO_OBJECT(handle); -+ TRACE2("fo: %p, %d", fo, class); -+ switch (class) { -+ case FileNameInformation: -+ fni = info; -+ fni->length = min(length, (typeof(length))coh->name.length); -+ memcpy(fni->name, coh->name.buf, fni->length); -+ iosb->status = STATUS_SUCCESS; -+ iosb->info = fni->length; -+ break; -+ case FileStandardInformation: -+ fsi = info; -+ file = fo->wrap_bin_file; -+ fsi->alloc_size = file->size; -+ fsi->eof = file->size; -+ fsi->num_links = 1; -+ fsi->delete_pending = FALSE; -+ fsi->dir = FALSE; -+ iosb->status = STATUS_SUCCESS; -+ iosb->info = 0; -+ break; -+ default: -+ WARNING("type %d not implemented yet", class); -+ iosb->status = STATUS_FAILURE; -+ iosb->info = 0; -+ break; -+ } -+ EXIT2(return iosb->status); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwOpenSection,3) -+ (void **handle, ACCESS_MASK access, struct object_attributes *obj_attrs) -+{ -+ INFO("%p, 0x%x, %d", obj_attrs, obj_attrs->attributes, access); -+ TODO(); -+ *handle = obj_attrs; -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwMapViewOfSection,10) -+ (void *secn_handle, void *process_handle, void **base_address, -+ ULONG zero_bits, SIZE_T commit_size, LARGE_INTEGER *secn_offset, -+ SIZE_T *view_size, enum section_inherit inherit, ULONG alloc_type, -+ ULONG protect) -+{ -+ INFO("%p, %p, %p", secn_handle, process_handle, base_address); -+ TODO(); -+ *base_address = (void *)0xdeadbeef; -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwUnmapViewOfSection,2) -+ (void *process_handle, void *base_address) -+{ -+ INFO("%p, %p", process_handle, base_address); -+ TODO(); -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwCreateKey,7) -+ (void **handle, ACCESS_MASK desired_access, -+ struct object_attributes *attr, ULONG title_index, -+ struct unicode_string *class, ULONG create_options, -+ ULONG *disposition) -+{ -+ struct ansi_string ansi; -+ if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) == -+ STATUS_SUCCESS) { -+ TRACE1("key: %s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ *handle = NULL; -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwOpenKey,3) -+ (void **handle, ACCESS_MASK desired_access, -+ struct object_attributes *attr) -+{ -+ struct ansi_string ansi; -+ if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) == -+ STATUS_SUCCESS) { -+ TRACE1("key: %s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ *handle = NULL; -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwSetValueKey,6) -+ (void *handle, struct unicode_string *name, ULONG title_index, -+ ULONG type, void *data, ULONG data_size) -+{ -+ struct ansi_string ansi; -+ if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == -+ STATUS_SUCCESS) { -+ TRACE1("key: %s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwQueryValueKey,6) -+ (void *handle, struct unicode_string *name, -+ enum key_value_information_class class, void *info, -+ ULONG length, ULONG *res_length) -+{ -+ struct ansi_string ansi; -+ if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == STATUS_SUCCESS) { -+ TRACE1("key: %s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ TODO(); -+ return STATUS_INVALID_PARAMETER; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwDeleteKey,1) -+ (void *handle) -+{ -+ ENTER2("%p", handle); -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(ZwPowerInformation,5) -+ (INT info_level, void *in_buf, ULONG in_buf_len, void *out_buf, -+ ULONG out_buf_len) -+{ -+ INFO("%d, %u, %u", info_level, in_buf_len, out_buf_len); -+ TODO(); -+ return STATUS_ACCESS_DENIED; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(WmiSystemControl,4) -+ (struct wmilib_context *info, struct device_object *dev_obj, -+ struct irp *irp, void *irp_disposition) -+{ -+ TODO(); -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(WmiCompleteRequest,5) -+ (struct device_object *dev_obj, struct irp *irp, NTSTATUS status, -+ ULONG buffer_used, CCHAR priority_boost) -+{ -+ TODO(); -+ return STATUS_SUCCESS; -+} -+ -+noregparm NTSTATUS WIN_FUNC(WmiTraceMessage,12) -+ (void *tracehandle, ULONG message_flags, -+ void *message_guid, USHORT message_no, ...) -+{ -+ TODO(); -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(WmiQueryTraceInformation,4) -+ (enum trace_information_class trace_info_class, void *trace_info, -+ ULONG *req_length, void *buf) -+{ -+ TODO(); -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+/* this function can't be wstdcall as it takes variable number of args */ -+__attribute__((format(printf, 1, 2))) -+noregparm ULONG WIN_FUNC(DbgPrint,12) -+ (char *format, ...) -+{ -+#if DEBUG >= 1 -+ va_list args; -+ static char buf[100]; -+ -+ va_start(args, format); -+ vsnprintf(buf, sizeof(buf), format, args); -+ printk(KERN_DEBUG "%s (%s): %s", DRIVER_NAME, __func__, buf); -+ va_end(args); -+#endif -+ return STATUS_SUCCESS; -+} -+ -+__attribute__((format(printf, 3, 4))) -+noregparm ULONG WIN_FUNC(DbgPrintEx,12) -+ (ULONG component_id, ULONG severity, char *format, ...) -+{ -+#if DEBUG >= 1 -+ va_list args; -+ static char buf[100]; -+ -+ va_start(args, format); -+ vsnprintf(buf, sizeof(buf), format, args); -+ TRACE1("component_id: %d, severity: %d\n", component_id, severity); -+ printk(KERN_DEBUG "%s (%s): %s", DRIVER_NAME, __func__, buf); -+ va_end(args); -+#endif -+ return STATUS_SUCCESS; -+} -+ -+wstdcall void WIN_FUNC(KeBugCheck,1) -+ (ULONG code) -+{ -+ ERROR("Unrecoverable error reported by the driver"); -+ ERROR("code: 0x%x\n", code); -+ dump_stack(); -+ return; -+} -+ -+wstdcall void WIN_FUNC(KeBugCheckEx,5) -+ (ULONG code, ULONG_PTR param1, ULONG_PTR param2, -+ ULONG_PTR param3, ULONG_PTR param4) -+{ -+ ERROR("Unrecoverable error reported by the driver"); -+ ERROR("code: 0x%x, params: 0x%lx 0x%lx 0x%lx 0x%lx\n", code, param1, -+ param2, param3, param4); -+ dump_stack(); -+ return; -+} -+ -+wstdcall void WIN_FUNC(ExSystemTimeToLocalTime,2) -+ (LARGE_INTEGER *system_time, LARGE_INTEGER *local_time) -+{ -+ *local_time = *system_time; -+} -+ -+wstdcall ULONG WIN_FUNC(ExSetTimerResolution,2) -+ (ULONG time, BOOLEAN set) -+{ -+ /* why a driver should change system wide timer resolution is -+ * beyond me */ -+ return time; -+} -+ -+wstdcall void WIN_FUNC(DbgBreakPoint,0) -+ (void) -+{ -+ TODO(); -+} -+ -+wstdcall void WIN_FUNC(_except_handler3,0) -+ (void) -+{ -+ TODO(); -+} -+ -+wstdcall void WIN_FUNC(__C_specific_handler,0) -+ (void) -+{ -+ TODO(); -+} -+ -+wstdcall void WIN_FUNC(_purecall,0) -+ (void) -+{ -+ TODO(); -+} -+ -+struct worker_init_struct { -+ struct work_struct work; -+ struct completion completion; -+ struct nt_thread *nt_thread; -+}; -+ -+int ntoskernel_init(void) -+{ -+ spin_lock_init(&dispatcher_lock); -+ spin_lock_init(&ntoskernel_lock); -+ spin_lock_init(&ntos_work_lock); -+ spin_lock_init(&kdpc_list_lock); -+ spin_lock_init(&irp_cancel_lock); -+ InitializeListHead(&wrap_mdl_list); -+ InitializeListHead(&kdpc_list); -+ InitializeListHead(&callback_objects); -+ InitializeListHead(&bus_driver_list); -+ InitializeListHead(&object_list); -+ InitializeListHead(&ntos_work_list); -+ -+ nt_spin_lock_init(&nt_list_lock); -+ -+ INIT_WORK(&kdpc_work, kdpc_worker); -+ INIT_WORK(&ntos_work, ntos_work_worker); -+ wrap_timer_slist.next = NULL; -+ -+ wrap_ticks_to_boot = TICKS_1601_TO_1970; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) -+ do { -+ u64 now; -+ now = ktime_get_real_ns(); -+ wrap_ticks_to_boot += now * 10; -+ } while (0); -+#else -+ do { -+ struct timeval now; -+ -+ do_gettimeofday(&now); -+ wrap_ticks_to_boot += (u64)now.tv_sec * TICKSPERSEC; -+ wrap_ticks_to_boot += now.tv_usec * 10; -+ } while (0); -+#endif -+ TRACE2("%llu", wrap_ticks_to_boot); -+ wrap_ticks_to_boot -= jiffies * TICKSPERJIFFY; -+ TRACE2("%llu", wrap_ticks_to_boot); -+ -+ cpu_count = num_online_cpus(); -+ -+#ifdef WRAP_PREEMPT -+ do { -+ int cpu; -+ for_each_possible_cpu(cpu) { -+ struct irql_info *info; -+ info = &per_cpu(irql_info, cpu); -+ mutex_init(&(info->lock)); -+ info->task = NULL; -+ info->count = 0; -+#ifdef CONFIG_SMP -+ cpumask_setall(tsk_cpus_allowed(info)); -+#endif -+ } -+ } while (0); -+#endif -+ -+ ntos_wq = create_singlethread_workqueue("ntos_wq"); -+ if (!ntos_wq) { -+ WARNING("couldn't create ntos_wq thread"); -+ return -ENOMEM; -+ } -+ TRACE1("ntos_wq: %p", ntos_wq); -+ -+ if (add_bus_driver("PCI") -+#ifdef ENABLE_USB -+ || add_bus_driver("USB") -+#endif -+ ) { -+ ntoskernel_exit(); -+ return -ENOMEM; -+ } -+ mdl_cache = -+ wrap_kmem_cache_create(DRIVER_NAME "_mdl", -+ sizeof(struct wrap_mdl) + MDL_CACHE_SIZE, -+ 0, 0); -+ TRACE2("%p", mdl_cache); -+ if (!mdl_cache) { -+ ERROR("couldn't allocate MDL cache"); -+ ntoskernel_exit(); -+ return -ENOMEM; -+ } -+ -+#if defined(CONFIG_X86_64) -+ memset(&kuser_shared_data, 0, sizeof(kuser_shared_data)); -+ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) -+ init_timer(&shared_data_timer); -+ shared_data_timer.function = update_user_shared_data_proc; -+ shared_data_timer.data = 0; -+#else -+ timer_setup(&shared_data_timer, update_user_shared_data_proc, 0); -+#endif -+#endif -+ return 0; -+} -+ -+int ntoskernel_init_device(struct wrap_device *wd) -+{ -+#if defined(CONFIG_X86_64) -+ if (kuser_shared_data.reserved1) -+ mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30)); -+#endif -+ return 0; -+} -+ -+void ntoskernel_exit_device(struct wrap_device *wd) -+{ -+ ENTER2(""); -+ -+ KeFlushQueuedDpcs(); -+ EXIT2(return); -+} -+ -+void ntoskernel_exit(void) -+{ -+ struct nt_list *cur; -+ -+ ENTER2(""); -+ -+ /* free kernel (Ke) timers */ -+ TRACE2("freeing timers"); -+ while (1) { -+ struct wrap_timer *wrap_timer; -+ struct nt_slist *slist; -+ -+ spin_lock_bh(&ntoskernel_lock); -+ if ((slist = wrap_timer_slist.next)) -+ wrap_timer_slist.next = slist->next; -+ spin_unlock_bh(&ntoskernel_lock); -+ TIMERTRACE("%p", slist); -+ if (!slist) -+ break; -+ wrap_timer = container_of(slist, struct wrap_timer, slist); -+ if (del_timer_sync(&wrap_timer->timer)) -+ WARNING("Buggy Windows driver left timer %p running", -+ wrap_timer->nt_timer); -+ memset(wrap_timer, 0, sizeof(*wrap_timer)); -+ slack_kfree(wrap_timer); -+ } -+ -+ TRACE2("freeing MDLs"); -+ if (mdl_cache) { -+ spin_lock_bh(&ntoskernel_lock); -+ if (!IsListEmpty(&wrap_mdl_list)) -+ ERROR("Windows driver didn't free all MDLs; " -+ "freeing them now"); -+ while ((cur = RemoveHeadList(&wrap_mdl_list))) { -+ struct wrap_mdl *wrap_mdl; -+ wrap_mdl = container_of(cur, struct wrap_mdl, list); -+ if (wrap_mdl->mdl->flags & MDL_CACHE_ALLOCATED) -+ kmem_cache_free(mdl_cache, wrap_mdl); -+ else -+ kfree(wrap_mdl); -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ kmem_cache_destroy(mdl_cache); -+ mdl_cache = NULL; -+ } -+ -+ TRACE2("freeing callbacks"); -+ spin_lock_bh(&ntoskernel_lock); -+ while ((cur = RemoveHeadList(&callback_objects))) { -+ struct callback_object *object; -+ struct nt_list *ent; -+ object = container_of(cur, struct callback_object, list); -+ while ((ent = RemoveHeadList(&object->callback_funcs))) { -+ struct callback_func *f; -+ f = container_of(ent, struct callback_func, list); -+ kfree(f); -+ } -+ kfree(object); -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ -+ spin_lock_bh(&ntoskernel_lock); -+ while ((cur = RemoveHeadList(&bus_driver_list))) { -+ struct bus_driver *bus_driver; -+ bus_driver = container_of(cur, struct bus_driver, list); -+ /* TODO: make sure all all drivers are shutdown/removed */ -+ kfree(bus_driver); -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ -+#if defined(CONFIG_X86_64) -+ del_timer_sync(&shared_data_timer); -+#endif -+ if (ntos_wq) -+ destroy_workqueue(ntos_wq); -+ ENTER2("freeing objects"); -+ spin_lock_bh(&ntoskernel_lock); -+ while ((cur = RemoveHeadList(&object_list))) { -+ struct common_object_header *hdr; -+ hdr = container_of(cur, struct common_object_header, list); -+ if (hdr->type == OBJECT_TYPE_NT_THREAD) -+ TRACE1("object %p(%d) was not freed, freeing it now", -+ HEADER_TO_OBJECT(hdr), hdr->type); -+ else -+ WARNING("object %p(%d) was not freed, freeing it now", -+ HEADER_TO_OBJECT(hdr), hdr->type); -+ ExFreePool(hdr); -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ -+ EXIT2(return); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/ntoskernel.h linux-5.6.11-ndis/3rdparty/ndiswrapper/ntoskernel.h ---- linux-5.6.11/3rdparty/ndiswrapper/ntoskernel.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/ntoskernel.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,1117 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _NTOSKERNEL_H_ -+#define _NTOSKERNEL_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 -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(4,11,0) -+#include -+#endif -+ -+#if !defined(CONFIG_X86) && !defined(CONFIG_X86_64) -+#error "this module is for x86 or x86_64 architectures only" -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) -+#define gfp_t unsigned int __nocast -+ -+static inline void *_kzalloc(size_t size, gfp_t flags) -+{ -+ void *p = kmalloc(size, flags); -+ if (likely(p != NULL)) -+ memset(p, 0, size); -+ return p; -+} -+ -+#define kzalloc(size, flags) _kzalloc(size, flags) -+#endif -+ -+/* Interrupt backwards compatibility stuff */ -+#include -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) -+#ifndef IRQ_HANDLED -+#define IRQ_HANDLED -+#define IRQ_NONE -+#define irqreturn_t void -+#endif -+#endif /* Linux < 2.6.29 */ -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) -+#ifndef mutex_init -+#define mutex semaphore -+#define mutex_init(m) sema_init(m, 1) -+#define mutex_lock(m) down(m) -+#define mutex_trylock(m) (!down_trylock(m)) -+#define mutex_unlock(m) up(m) -+#define mutex_is_locked(m) (atomic_read(m.count) == 0) -+#endif -+#endif /* Linux < 2.6.16 */ -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) -+#define set_cpus_allowed_ptr(task, mask) set_cpus_allowed(task, *mask) -+#endif /* Linux < 2.6.26 */ -+ -+#ifdef CONFIG_SMP -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -+#define cpumask_copy(dst, src) do { *dst = *src; } while (0) -+#define cpumask_equal(mask1, mask2) cpus_equal(*mask1, *mask2) -+#define cpumask_setall(mask) cpus_setall(*mask) -+static cpumask_t cpumasks[NR_CPUS]; -+#define cpumask_of(cpu) \ -+({ \ -+ cpumasks[cpu] = cpumask_of_cpu(cpu); \ -+ &cpumasks[cpu]; \ -+}) -+#endif /* Linux < 2.6.28 */ -+#endif /* CONFIG_SMP */ -+ -+#ifndef tsk_cpus_allowed -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,3,0) -+#define tsk_cpus_allowed(tsk) (&(tsk)->cpus_mask) -+#else -+#define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed) -+#endif -+#endif -+ -+#ifndef __packed -+#define __packed __attribute__((packed)) -+#endif -+ -+/* pci functions in 2.6 kernels have problems allocating dma buffers, -+ * but seem to work fine with dma functions -+ */ -+#include -+ -+#ifndef ___GFP_RETRY_MAYFAIL -+#define ___GFP_RETRY_MAYFAIL __GFP_REPEAT -+#endif -+ -+#define PCI_DMA_ALLOC_COHERENT(pci_dev,size,dma_handle) \ -+ dma_alloc_coherent(&pci_dev->dev,size,dma_handle, \ -+ GFP_KERNEL | ___GFP_RETRY_MAYFAIL) -+#define PCI_DMA_FREE_COHERENT(pci_dev,size,cpu_addr,dma_handle) \ -+ dma_free_coherent(&pci_dev->dev,size,cpu_addr,dma_handle) -+#define PCI_DMA_MAP_SINGLE(pci_dev,addr,size,direction) \ -+ dma_map_single(&pci_dev->dev,addr,size,direction) -+#define PCI_DMA_UNMAP_SINGLE(pci_dev,dma_handle,size,direction) \ -+ dma_unmap_single(&pci_dev->dev,dma_handle,size,direction) -+#define MAP_SG(pci_dev, sglist, nents, direction) \ -+ dma_map_sg(&pci_dev->dev, sglist, nents, direction) -+#define UNMAP_SG(pci_dev, sglist, nents, direction) \ -+ dma_unmap_sg(&pci_dev->dev, sglist, nents, direction) -+#define PCI_DMA_MAP_ERROR(dma_addr) dma_mapping_error(dma_addr) -+ -+ -+#if defined(CONFIG_NET_RADIO) && !defined(CONFIG_WIRELESS_EXT) -+#define CONFIG_WIRELESS_EXT -+#endif -+ -+#define prepare_wait_condition(task, var, value) \ -+do { \ -+ var = value; \ -+ task = current; \ -+ barrier(); \ -+} while (0) -+ -+/* Wait in wait_state (e.g., TASK_INTERRUPTIBLE) for condition to -+ * become true; timeout is either jiffies (> 0) to wait or 0 to wait -+ * forever. -+ * When timeout == 0, return value is -+ * > 0 if condition becomes true, or -+ * < 0 if signal is pending on the thread. -+ * When timeout > 0, return value is -+ * > 0 if condition becomes true before timeout, -+ * < 0 if signal is pending on the thread before timeout, or -+ * 0 if timedout (condition may have become true at the same time) -+ */ -+ -+#define wait_condition(condition, timeout, wait_state) \ -+({ \ -+ long ret = timeout ? timeout : 1; \ -+ while (1) { \ -+ if (signal_pending(current)) { \ -+ ret = -ERESTARTSYS; \ -+ break; \ -+ } \ -+ set_current_state(wait_state); \ -+ if (condition) { \ -+ __set_current_state(TASK_RUNNING); \ -+ break; \ -+ } \ -+ if (timeout) { \ -+ ret = schedule_timeout(ret); \ -+ if (!ret) \ -+ break; \ -+ } else \ -+ schedule(); \ -+ } \ -+ ret; \ -+}) -+ -+#ifdef WRAP_WQ -+ -+struct wrap_workqueue_struct; -+ -+struct wrap_work_struct { -+ struct list_head list; -+ void (*func)(struct wrap_work_struct *data); -+ void *data; -+ /* whether/on which thread scheduled */ -+ struct workqueue_thread *thread; -+}; -+ -+#define work_struct wrap_work_struct -+#define workqueue_struct wrap_workqueue_struct -+ -+#undef INIT_WORK -+#define INIT_WORK(work, pfunc) \ -+ do { \ -+ (work)->func = (pfunc); \ -+ (work)->data = (work); \ -+ (work)->thread = NULL; \ -+ } while (0) -+ -+#undef create_singlethread_workqueue -+#define create_singlethread_workqueue(wq) wrap_create_wq(wq, 1, 0) -+#undef create_workqueue -+#define create_workqueue(wq) wrap_create_wq(wq, 0, 0) -+#undef destroy_workqueue -+#define destroy_workqueue(wq) wrap_destroy_wq(wq) -+#undef queue_work -+#define queue_work(wq, work) wrap_queue_work(wq, work) -+#undef flush_workqueue -+#define flush_workqueue(wq) wrap_flush_wq(wq) -+ -+struct workqueue_struct *wrap_create_wq(const char *name, u8 singlethread, -+ u8 freeze); -+void wrap_destroy_wq(struct workqueue_struct *workq); -+int wrap_queue_work(struct workqueue_struct *workq, struct work_struct *work); -+void wrap_cancel_work(struct work_struct *work); -+void wrap_flush_wq(struct workqueue_struct *workq); -+ -+#else // WRAP_WQ -+ -+/* Compatibility for Linux before 2.6.20 where INIT_WORK takes 3 arguments */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && \ -+ !defined(INIT_WORK_NAR) && \ -+ !defined(INIT_DELAYED_WORK_DEFERRABLE) -+typedef void (*compat_work_func_t)(void *work); -+typedef void (*work_func_t)(struct work_struct *work); -+static inline void (INIT_WORK)(struct work_struct *work, work_func_t func) -+{ -+ INIT_WORK(work, (compat_work_func_t)func, work); -+} -+#undef INIT_WORK -+#endif -+ -+#endif // WRAP_WQ -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) -+#define ISR_PT_REGS_PARAM_DECL -+#else -+#define ISR_PT_REGS_PARAM_DECL , struct pt_regs *regs -+#endif -+ -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) -+#define for_each_possible_cpu(_cpu) for_each_cpu(_cpu) -+#endif -+ -+#ifndef CHECKSUM_PARTIAL -+#define CHECKSUM_PARTIAL CHECKSUM_HW -+#endif -+ -+#ifndef IRQF_SHARED -+#define IRQF_SHARED SA_SHIRQ -+#endif -+ -+#ifndef UMH_WAIT_PROC -+#define UMH_WAIT_PROC 1 -+#endif -+ -+#define memcpy_skb(skb, from, length) \ -+ memcpy(skb_put(skb, length), from, length) -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) -+#ifndef DMA_BIT_MASK -+#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) -+#endif -+#endif -+ -+#ifndef __GFP_DMA32 -+#define __GFP_DMA32 GFP_DMA -+#endif -+ -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) -+#define wrap_kmem_cache_create(name, size, align, flags) \ -+ kmem_cache_create(name, size, align, flags, NULL, NULL) -+#else -+#define wrap_kmem_cache_create(name, size, align, flags) \ -+ kmem_cache_create(name, size, align, flags, NULL) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) -+#define netdev_mc_count(dev) ((dev)->mc_count) -+#define usb_alloc_coherent(dev, size, mem_flags, dma) (usb_buffer_alloc((dev), (size), (mem_flags), (dma))) -+#define usb_free_coherent(dev, size, addr, dma) (usb_buffer_free((dev), (size), (addr), (dma))) -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0) -+#define daemonize(name, ...) do {} while (0) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) -+#define add_taint(flag, lockdep_ok) add_taint(flag) -+#endif -+ -+#include "winnt_types.h" -+#include "ndiswrapper.h" -+#include "pe_linker.h" -+#include "wrapmem.h" -+#include "lin2win.h" -+#include "loader.h" -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) -+static inline void netif_tx_lock(struct net_device *dev) -+{ -+ spin_lock(&dev->xmit_lock); -+} -+static inline void netif_tx_unlock(struct net_device *dev) -+{ -+ spin_unlock(&dev->xmit_lock); -+} -+static inline void netif_tx_lock_bh(struct net_device *dev) -+{ -+ spin_lock_bh(&dev->xmit_lock); -+} -+static inline void netif_tx_unlock_bh(struct net_device *dev) -+{ -+ spin_unlock_bh(&dev->xmit_lock); -+} -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) -+static inline void netif_poll_enable(struct net_device *dev) -+{ -+} -+static inline void netif_poll_disable(struct net_device *dev) -+{ -+} -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) -+#define proc_net_root init_net.proc_net -+#else -+#define proc_net_root proc_net -+#endif -+ -+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)) && \ -+ (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0))) || \ -+ (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,42)) -+#ifndef skb_frag_page -+#define skb_frag_page(frag) ((frag)->page) -+#endif -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) -+#define netdev_notifier_info_to_dev(x) ((struct net_device *)(x)) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) -+static inline void reinit_completion(struct completion *x) -+{ -+ INIT_COMPLETION(*x); -+} -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) -+#define prandom_seed(seed) net_srandom(seed) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) -+static int strncasecmp(const char *s1, const char *s2, size_t n) -+{ -+ strnicmp(s1, s2, n); -+} -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) -+static inline void netif_trans_update(struct net_device *dev) -+{ -+ dev->trans_start = jiffies; -+} -+#endif -+ -+/* TICK is 100ns */ -+#define TICKSPERSEC 10000000 -+#define TICKSPERMSEC 10000 -+#define SECSPERDAY 86400 -+#define TICKSPERJIFFY ((TICKSPERSEC + HZ - 1) / HZ) -+ -+#define int_div_round(x, y) (((x) + (y - 1)) / (y)) -+ -+/* 1601 to 1970 is 369 years plus 89 leap days */ -+#define SECS_1601_TO_1970 ((369 * 365 + 89) * (u64)SECSPERDAY) -+#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC) -+ -+/* 100ns units to HZ; if sys_time is negative, relative to current -+ * clock, otherwise from year 1601 */ -+#define SYSTEM_TIME_TO_HZ(sys_time) \ -+ (((sys_time) <= 0) ? \ -+ int_div_round(((u64)HZ * (-(sys_time))), TICKSPERSEC) : \ -+ int_div_round(((s64)HZ * ((sys_time) - ticks_1601())), TICKSPERSEC)) -+ -+#define MSEC_TO_HZ(ms) int_div_round((ms * HZ), 1000) -+#define USEC_TO_HZ(us) int_div_round((us * HZ), 1000000) -+ -+extern u64 wrap_ticks_to_boot; -+ -+static inline u64 ticks_1601(void) -+{ -+ return wrap_ticks_to_boot + (u64)jiffies * TICKSPERJIFFY; -+} -+ -+typedef void (*generic_func)(void); -+ -+struct wrap_export { -+ const char *name; -+ generic_func func; -+}; -+ -+#ifdef CONFIG_X86_64 -+ -+#define WIN_SYMBOL(name, argc) \ -+ {#name, (generic_func) win2lin_ ## name ## _ ## argc} -+#define WIN_WIN_SYMBOL(name, argc) \ -+ {#name, (generic_func) win2lin__win_ ## name ## _ ## argc} -+#define WIN_FUNC_DECL(name, argc) \ -+ extern typeof(name) win2lin_ ## name ## _ ## argc; -+#define WIN_FUNC_PTR(name, argc) win2lin_ ## name ## _ ## argc -+ -+#else -+ -+#define WIN_SYMBOL(name, argc) {#name, (generic_func)name} -+#define WIN_WIN_SYMBOL(name, argc) {#name, (generic_func)_win_ ## name} -+#define WIN_FUNC_DECL(name, argc) -+#define WIN_FUNC_PTR(name, argc) name -+ -+#endif -+ -+#define WIN_FUNC(name, argc) (name) -+/* map name s to f - if f is different from s */ -+#define WIN_SYMBOL_MAP(s, f) -+ -+#define POOL_TAG(A, B, C, D) \ -+ ((ULONG)((A) + ((B) << 8) + ((C) << 16) + ((D) << 24))) -+ -+struct pe_image { -+ char name[MAX_DRIVER_NAME_LEN]; -+ UINT (*entry)(struct driver_object *, struct unicode_string *) wstdcall; -+ void *image; -+ int size; -+ int type; -+ -+ IMAGE_NT_HEADERS *nt_hdr; -+ IMAGE_OPTIONAL_HEADER *opt_hdr; -+}; -+ -+struct ndis_mp_block; -+ -+struct wrap_timer { -+ struct nt_slist slist; -+ struct timer_list timer; -+ struct nt_timer *nt_timer; -+ long repeat; -+#ifdef TIMER_DEBUG -+ unsigned long wrap_timer_magic; -+#endif -+}; -+ -+struct ntos_work_item { -+ struct nt_list list; -+ void *arg1; -+ void *arg2; -+ NTOS_WORK_FUNC func; -+}; -+ -+struct wrap_device_setting { -+ struct nt_list list; -+ char name[MAX_SETTING_NAME_LEN]; -+ char value[MAX_SETTING_VALUE_LEN]; -+ void *encoded; -+}; -+ -+struct wrap_bin_file { -+ char name[MAX_DRIVER_NAME_LEN]; -+ size_t size; -+ void *data; -+}; -+ -+#define WRAP_DRIVER_CLIENT_ID 1 -+ -+struct wrap_driver { -+ struct nt_list list; -+ struct driver_object *drv_obj; -+ char name[MAX_DRIVER_NAME_LEN]; -+ char version[MAX_SETTING_VALUE_LEN]; -+ unsigned short num_pe_images; -+ struct pe_image pe_images[MAX_DRIVER_PE_IMAGES]; -+ unsigned short num_bin_files; -+ struct wrap_bin_file *bin_files; -+ struct nt_list settings; -+ int dev_type; -+ struct ndis_driver *ndis_driver; -+}; -+ -+enum hw_status { -+ HW_INITIALIZED = 1, HW_SUSPENDED, HW_HALTED, HW_DISABLED, -+}; -+ -+struct wrap_device { -+ /* first part is (de)initialized once by loader */ -+ struct nt_list list; -+ int dev_bus; -+ int vendor; -+ int device; -+ int subvendor; -+ int subdevice; -+ char conf_file_name[MAX_DRIVER_NAME_LEN]; -+ char driver_name[MAX_DRIVER_NAME_LEN]; -+ struct wrap_driver *driver; -+ struct nt_list settings; -+ -+ /* rest should be (de)initialized when a device is -+ * (un)plugged */ -+ struct cm_resource_list *resource_list; -+ unsigned long hw_status; -+ struct device_object *pdo; -+ union { -+ struct { -+ struct pci_dev *pdev; -+ enum device_power_state wake_state; -+ } pci; -+ struct { -+ struct usb_device *udev; -+ struct usb_interface *intf; -+ int num_alloc_urbs; -+ struct nt_list wrap_urb_list; -+ } usb; -+ }; -+}; -+ -+#define wrap_is_pci_bus(dev_bus) \ -+ (WRAP_BUS(dev_bus) == WRAP_PCI_BUS || \ -+ WRAP_BUS(dev_bus) == WRAP_PCMCIA_BUS) -+#ifdef ENABLE_USB -+/* earlier versions of ndiswrapper used 0 as USB_BUS */ -+#define wrap_is_usb_bus(dev_bus) \ -+ (WRAP_BUS(dev_bus) == WRAP_USB_BUS || \ -+ WRAP_BUS(dev_bus) == WRAP_INTERNAL_BUS) -+#else -+#define wrap_is_usb_bus(dev_bus) 0 -+#endif -+#define wrap_is_bluetooth_device(dev_bus) \ -+ (WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE1 || \ -+ WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE2) -+ -+extern struct workqueue_struct *ntos_wq; -+extern struct workqueue_struct *ndis_wq; -+extern struct workqueue_struct *wrapndis_wq; -+ -+#define atomic_unary_op(var, size, oper) \ -+do { \ -+ if (size == 1) \ -+ __asm__ __volatile__( \ -+ LOCK_PREFIX oper "b %b0\n\t" : "+m" (var)); \ -+ else if (size == 2) \ -+ __asm__ __volatile__( \ -+ LOCK_PREFIX oper "w %w0\n\t" : "+m" (var)); \ -+ else if (size == 4) \ -+ __asm__ __volatile__( \ -+ LOCK_PREFIX oper "l %0\n\t" : "+m" (var)); \ -+ else if (size == 8) \ -+ __asm__ __volatile__( \ -+ LOCK_PREFIX oper "q %q0\n\t" : "+m" (var)); \ -+ else { \ -+ extern void _invalid_op_size_(void); \ -+ _invalid_op_size_(); \ -+ } \ -+} while (0) -+ -+#define atomic_inc_var_size(var, size) atomic_unary_op(var, size, "inc") -+ -+#define atomic_inc_var(var) atomic_inc_var_size(var, sizeof(var)) -+ -+#define atomic_dec_var_size(var, size) atomic_unary_op(var, size, "dec") -+ -+#define atomic_dec_var(var) atomic_dec_var_size(var, sizeof(var)) -+ -+#define pre_atomic_add(var, i) \ -+({ \ -+ typeof(var) pre; \ -+ __asm__ __volatile__( \ -+ LOCK_PREFIX "xadd %0, %1\n\t" \ -+ : "=r"(pre), "+m"(var) \ -+ : "0"(i)); \ -+ pre; \ -+}) -+ -+#define post_atomic_add(var, i) (pre_atomic_add(var, i) + i) -+ -+//#define DEBUG_IRQL 1 -+ -+#ifdef DEBUG_IRQL -+#define assert_irql(cond) \ -+do { \ -+ KIRQL _irql_ = current_irql(); \ -+ if (!(cond)) { \ -+ WARNING("assertion '%s' failed: %d", #cond, _irql_); \ -+ DBG_BLOCK(4) { \ -+ dump_stack(); \ -+ } \ -+ } \ -+} while (0) -+#else -+#define assert_irql(cond) do { } while (0) -+#endif -+ -+/* When preempt is enabled, we should preempt_disable to raise IRQL to -+ * DISPATCH_LEVEL, to be consistent with the semantics. However, using -+ * a mutex instead, so that only ndiswrapper threads run one at a time -+ * on a processor when at DISPATCH_LEVEL seems to be enough. So that -+ * is what we will use until we learn otherwise. If -+ * preempt_(en|dis)able is required for some reason, comment out -+ * following #define. */ -+ -+#define WRAP_PREEMPT 1 -+ -+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PREEMPT_RT) -+#ifndef WRAP_PREEMPT -+#define WRAP_PREEMPT 1 -+#endif -+#endif -+ -+//#undef WRAP_PREEMPT -+ -+#ifdef WRAP_PREEMPT -+ -+struct irql_info { -+ int count; -+ struct mutex lock; -+#ifdef CONFIG_SMP -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,3,0) -+ cpumask_t cpus_mask; -+#else -+ cpumask_t cpus_allowed; -+#endif -+#endif -+ struct task_struct *task; -+}; -+ -+DECLARE_PER_CPU(struct irql_info, irql_info); -+ -+static inline KIRQL raise_irql(KIRQL newirql) -+{ -+ struct irql_info *info; -+ -+ assert(newirql == DISPATCH_LEVEL); -+ info = &get_cpu_var(irql_info); -+ if (info->task == current) { -+ assert(info->count > 0); -+ assert(mutex_is_locked(&info->lock)); -+#if defined(CONFIG_SMP) && DEBUG >= 1 -+ assert(cpumask_equal(tsk_cpus_allowed(current), -+ cpumask_of(smp_processor_id()))); -+#endif -+ info->count++; -+ put_cpu_var(irql_info); -+ return DISPATCH_LEVEL; -+ } -+ /* TODO: is this enough to pin down to current cpu? */ -+#ifdef CONFIG_SMP -+ assert(task_cpu(current) == smp_processor_id()); -+ cpumask_copy(tsk_cpus_allowed(info), tsk_cpus_allowed(current)); -+ set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id())); -+#endif -+ put_cpu_var(irql_info); -+ mutex_lock(&info->lock); -+ assert(info->count == 0); -+ assert(info->task == NULL); -+ info->count = 1; -+ info->task = current; -+ return PASSIVE_LEVEL; -+} -+ -+static inline void lower_irql(KIRQL oldirql) -+{ -+ struct irql_info *info; -+ -+ assert(oldirql <= DISPATCH_LEVEL); -+ info = &get_cpu_var(irql_info); -+ assert(info->task == current); -+ assert(mutex_is_locked(&info->lock)); -+ assert(info->count > 0); -+ if (--info->count == 0) { -+ info->task = NULL; -+#ifdef CONFIG_SMP -+ set_cpus_allowed_ptr(current, tsk_cpus_allowed(info)); -+#endif -+ mutex_unlock(&info->lock); -+ } -+ put_cpu_var(irql_info); -+} -+ -+static inline KIRQL current_irql(void) -+{ -+ int count; -+ if (in_irq() || irqs_disabled()) -+ EXIT4(return DIRQL); -+ if (in_atomic() || in_interrupt()) -+ EXIT4(return SOFT_IRQL); -+ count = get_cpu_var(irql_info).count; -+ put_cpu_var(irql_info); -+ if (count) -+ EXIT6(return DISPATCH_LEVEL); -+ else -+ EXIT6(return PASSIVE_LEVEL); -+} -+ -+#else -+ -+static inline KIRQL current_irql(void) -+{ -+ if (in_irq() || irqs_disabled()) -+ EXIT4(return DIRQL); -+ if (in_interrupt()) -+ EXIT4(return SOFT_IRQL); -+ if (in_atomic()) -+ EXIT6(return DISPATCH_LEVEL); -+ else -+ EXIT6(return PASSIVE_LEVEL); -+} -+ -+static inline KIRQL raise_irql(KIRQL newirql) -+{ -+ KIRQL ret = in_atomic() ? DISPATCH_LEVEL : PASSIVE_LEVEL; -+ assert(newirql == DISPATCH_LEVEL); -+ assert(current_irql() <= DISPATCH_LEVEL); -+ preempt_disable(); -+ return ret; -+} -+ -+static inline void lower_irql(KIRQL oldirql) -+{ -+ assert(current_irql() == DISPATCH_LEVEL); -+ preempt_enable(); -+} -+ -+#endif -+ -+#define irql_gfp() (in_atomic() ? GFP_ATOMIC : GFP_KERNEL) -+ -+/* Windows spinlocks are of type ULONG_PTR which is not big enough to -+ * store Linux spinlocks; so we implement Windows spinlocks using -+ * ULONG_PTR space with our own functions/macros */ -+ -+/* Windows seems to use 0 for unlocked state of spinlock - if Linux -+ * convention of 1 for unlocked state is used, at least prism54 driver -+ * crashes */ -+ -+#define NT_SPIN_LOCK_UNLOCKED 0 -+#define NT_SPIN_LOCK_LOCKED 1 -+ -+static inline void nt_spin_lock_init(NT_SPIN_LOCK *lock) -+{ -+ *lock = NT_SPIN_LOCK_UNLOCKED; -+} -+ -+#ifdef CONFIG_SMP -+ -+static inline void nt_spin_lock(NT_SPIN_LOCK *lock) -+{ -+ while (1) { -+ unsigned long lockval = xchg(lock, NT_SPIN_LOCK_LOCKED); -+ -+ if (likely(lockval == NT_SPIN_LOCK_UNLOCKED)) -+ break; -+ if (unlikely(lockval > NT_SPIN_LOCK_LOCKED)) { -+ ERROR("bad spinlock: 0x%lx at %p", lockval, lock); -+ return; -+ } -+ /* "rep; nop" doesn't change cx register, it's a "pause" */ -+ __asm__ __volatile__("rep; nop"); -+ } -+} -+ -+static inline void nt_spin_unlock(NT_SPIN_LOCK *lock) -+{ -+ unsigned long lockval = xchg(lock, NT_SPIN_LOCK_UNLOCKED); -+ -+ if (likely(lockval == NT_SPIN_LOCK_LOCKED)) -+ return; -+ WARNING("unlocking unlocked spinlock: 0x%lx at %p", lockval, lock); -+} -+ -+#else // CONFIG_SMP -+ -+#define nt_spin_lock(lock) do { } while (0) -+ -+#define nt_spin_unlock(lock) do { } while (0) -+ -+#endif // CONFIG_SMP -+ -+/* When kernel would've disabled preempt (e.g., in interrupt -+ * handlers), we need to fake preempt so driver thinks it is running -+ * at right IRQL */ -+ -+/* raise IRQL to given (higher) IRQL if necessary before locking */ -+static inline KIRQL nt_spin_lock_irql(NT_SPIN_LOCK *lock, KIRQL newirql) -+{ -+ KIRQL oldirql = raise_irql(newirql); -+ nt_spin_lock(lock); -+ return oldirql; -+} -+ -+/* lower IRQL to given (lower) IRQL if necessary after unlocking */ -+static inline void nt_spin_unlock_irql(NT_SPIN_LOCK *lock, KIRQL oldirql) -+{ -+ nt_spin_unlock(lock); -+ lower_irql(oldirql); -+} -+ -+#define nt_spin_lock_irqsave(lock, flags) \ -+do { \ -+ local_irq_save(flags); \ -+ preempt_disable(); \ -+ nt_spin_lock(lock); \ -+} while (0) -+ -+#define nt_spin_unlock_irqrestore(lock, flags) \ -+do { \ -+ nt_spin_unlock(lock); \ -+ preempt_enable(); \ -+ local_irq_restore(flags); \ -+} while (0) -+ -+static inline ULONG SPAN_PAGES(void *ptr, SIZE_T length) -+{ -+ return PAGE_ALIGN(((unsigned long)ptr & (PAGE_SIZE - 1)) + length) -+ >> PAGE_SHIFT; -+} -+ -+#ifdef CONFIG_X86_64 -+ -+/* TODO: can these be implemented without using spinlock? */ -+ -+static inline struct nt_slist *PushEntrySList(nt_slist_header *head, -+ struct nt_slist *entry, -+ NT_SPIN_LOCK *lock) -+{ -+ KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); -+ entry->next = head->next; -+ head->next = entry; -+ head->depth++; -+ nt_spin_unlock_irql(lock, irql); -+ TRACE4("%p, %p, %p", head, entry, entry->next); -+ return entry->next; -+} -+ -+static inline struct nt_slist *PopEntrySList(nt_slist_header *head, -+ NT_SPIN_LOCK *lock) -+{ -+ struct nt_slist *entry; -+ KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); -+ entry = head->next; -+ if (entry) { -+ head->next = entry->next; -+ head->depth--; -+ } -+ nt_spin_unlock_irql(lock, irql); -+ TRACE4("%p, %p", head, entry); -+ return entry; -+} -+ -+#else -+ -+#define u64_low_32(x) ((u32)x) -+#define u64_high_32(x) ((u32)(x >> 32)) -+ -+static inline u64 nt_cmpxchg8b(volatile u64 *ptr, u64 old, u64 new) -+{ -+ u64 prev; -+ -+ __asm__ __volatile__( -+ "\n" -+ LOCK_PREFIX "cmpxchg8b %0\n" -+ : "+m" (*ptr), "=A" (prev) -+ : "A" (old), "b" (u64_low_32(new)), "c" (u64_high_32(new))); -+ return prev; -+} -+ -+/* slist routines below update slist atomically - no need for -+ * spinlocks */ -+ -+static inline struct nt_slist *PushEntrySList(nt_slist_header *head, -+ struct nt_slist *entry, -+ NT_SPIN_LOCK *lock) -+{ -+ nt_slist_header old, new; -+ do { -+ old.align = head->align; -+ entry->next = old.next; -+ new.next = entry; -+ new.depth = old.depth + 1; -+ } while (nt_cmpxchg8b(&head->align, old.align, new.align) != old.align); -+ TRACE4("%p, %p, %p", head, entry, old.next); -+ return old.next; -+} -+ -+static inline struct nt_slist *PopEntrySList(nt_slist_header *head, -+ NT_SPIN_LOCK *lock) -+{ -+ struct nt_slist *entry; -+ nt_slist_header old, new; -+ do { -+ old.align = head->align; -+ entry = old.next; -+ if (!entry) -+ break; -+ new.next = entry->next; -+ new.depth = old.depth - 1; -+ } while (nt_cmpxchg8b(&head->align, old.align, new.align) != old.align); -+ TRACE4("%p, %p", head, entry); -+ return entry; -+} -+ -+#endif -+ -+#define sleep_hz(n) \ -+do { \ -+ set_current_state(TASK_INTERRUPTIBLE); \ -+ schedule_timeout(n); \ -+} while (0) -+ -+int ntoskernel_init(void); -+void ntoskernel_exit(void); -+int ntoskernel_init_device(struct wrap_device *wd); -+void ntoskernel_exit_device(struct wrap_device *wd); -+void *allocate_object(ULONG size, enum common_object_type type, -+ struct unicode_string *name); -+ -+#ifdef ENABLE_USB -+int usb_init(void); -+void usb_exit(void); -+#else -+static inline int usb_init(void) { return 0; } -+static inline void usb_exit(void) {} -+#endif -+int usb_init_device(struct wrap_device *wd); -+void usb_exit_device(struct wrap_device *wd); -+ -+int wrap_procfs_init(void); -+void wrap_procfs_remove(void); -+ -+int link_pe_images(struct pe_image *pe_image, unsigned short n); -+ -+int stricmp(const char *s1, const char *s2); -+void dump_bytes(const char *name, const u8 *from, int len); -+struct mdl *allocate_init_mdl(void *virt, ULONG length); -+void free_mdl(struct mdl *mdl); -+struct driver_object *find_bus_driver(const char *name); -+void free_custom_extensions(struct driver_extension *drv_obj_ext); -+struct nt_thread *get_current_nt_thread(void); -+u64 ticks_1601(void); -+int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2); -+void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, -+ struct ndis_mp_block *nmb); -+BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz, -+ unsigned long repeat_hz, struct kdpc *kdpc); -+ -+LONG InterlockedDecrement(LONG volatile *val) wfastcall; -+LONG InterlockedIncrement(LONG volatile *val) wfastcall; -+struct nt_list *ExInterlockedInsertHeadList -+ (struct nt_list *head, struct nt_list *entry, -+ NT_SPIN_LOCK *lock) wfastcall; -+struct nt_list *ExInterlockedInsertTailList -+ (struct nt_list *head, struct nt_list *entry, -+ NT_SPIN_LOCK *lock) wfastcall; -+struct nt_list *ExInterlockedRemoveHeadList -+ (struct nt_list *head, NT_SPIN_LOCK *lock) wfastcall; -+NTSTATUS IofCallDriver(struct device_object *dev_obj, struct irp *irp) wfastcall; -+KIRQL KfRaiseIrql(KIRQL newirql) wfastcall; -+void KfLowerIrql(KIRQL oldirql) wfastcall; -+KIRQL KfAcquireSpinLock(NT_SPIN_LOCK *lock) wfastcall; -+void KfReleaseSpinLock(NT_SPIN_LOCK *lock, KIRQL oldirql) wfastcall; -+void IofCompleteRequest(struct irp *irp, CHAR prio_boost) wfastcall; -+void KefReleaseSpinLockFromDpcLevel(NT_SPIN_LOCK *lock) wfastcall; -+ -+LONG ObfReferenceObject(void *object) wfastcall; -+void ObfDereferenceObject(void *object) wfastcall; -+ -+#define ObReferenceObject(object) ObfReferenceObject(object) -+#define ObDereferenceObject(object) ObfDereferenceObject(object) -+ -+/* prevent expansion of ExAllocatePoolWithTag macro */ -+void *(ExAllocatePoolWithTag)(enum pool_type pool_type, SIZE_T size, -+ ULONG tag) wstdcall; -+ -+void ExFreePool(void *p) wstdcall; -+ULONG MmSizeOfMdl(void *base, ULONG length) wstdcall; -+void __iomem *MmMapIoSpace(PHYSICAL_ADDRESS phys_addr, SIZE_T size, -+ enum memory_caching_type cache) wstdcall; -+void MmUnmapIoSpace(void __iomem *addr, SIZE_T size) wstdcall; -+void MmProbeAndLockPages(struct mdl *mdl, KPROCESSOR_MODE access_mode, -+ enum lock_operation operation) wstdcall; -+void MmUnlockPages(struct mdl *mdl) wstdcall; -+void KeInitializeEvent(struct nt_event *nt_event, -+ enum event_type type, BOOLEAN state) wstdcall; -+LONG KeSetEvent(struct nt_event *nt_event, KPRIORITY incr, -+ BOOLEAN wait) wstdcall; -+LONG KeResetEvent(struct nt_event *nt_event) wstdcall; -+BOOLEAN queue_kdpc(struct kdpc *kdpc); -+BOOLEAN dequeue_kdpc(struct kdpc *kdpc); -+ -+NTSTATUS IoConnectInterrupt(struct kinterrupt **kinterrupt, -+ PKSERVICE_ROUTINE service_routine, -+ void *service_context, NT_SPIN_LOCK *lock, -+ ULONG vector, KIRQL irql, KIRQL synch_irql, -+ enum kinterrupt_mode interrupt_mode, -+ BOOLEAN shareable, KAFFINITY processor_enable_mask, -+ BOOLEAN floating_save) wstdcall; -+void IoDisconnectInterrupt(struct kinterrupt *interrupt) wstdcall; -+BOOLEAN KeSynchronizeExecution(struct kinterrupt *interrupt, -+ PKSYNCHRONIZE_ROUTINE synch_routine, -+ void *ctx) wstdcall; -+ -+NTSTATUS KeWaitForSingleObject(void *object, KWAIT_REASON reason, -+ KPROCESSOR_MODE waitmode, BOOLEAN alertable, -+ LARGE_INTEGER *timeout) wstdcall; -+void MmBuildMdlForNonPagedPool(struct mdl *mdl) wstdcall; -+NTSTATUS IoCreateDevice(struct driver_object *driver, ULONG dev_ext_length, -+ struct unicode_string *dev_name, DEVICE_TYPE dev_type, -+ ULONG dev_chars, BOOLEAN exclusive, -+ struct device_object **dev_obj) wstdcall; -+NTSTATUS IoCreateSymbolicLink(struct unicode_string *link, -+ struct unicode_string *dev_name) wstdcall; -+void IoDeleteDevice(struct device_object *dev) wstdcall; -+void IoDetachDevice(struct device_object *topdev) wstdcall; -+struct device_object *IoGetAttachedDevice(struct device_object *dev) wstdcall; -+struct device_object *IoGetAttachedDeviceReference -+ (struct device_object *dev) wstdcall; -+NTSTATUS IoAllocateDriverObjectExtension -+ (struct driver_object *drv_obj, void *client_id, ULONG extlen, -+ void **ext) wstdcall; -+void *IoGetDriverObjectExtension(struct driver_object *drv, -+ void *client_id) wstdcall; -+struct device_object *IoAttachDeviceToDeviceStack -+ (struct device_object *src, struct device_object *dst) wstdcall; -+BOOLEAN IoCancelIrp(struct irp *irp) wstdcall; -+struct irp *IoBuildSynchronousFsdRequest -+ (ULONG major_func, struct device_object *dev_obj, void *buf, -+ ULONG length, LARGE_INTEGER *offset, struct nt_event *event, -+ struct io_status_block *status) wstdcall; -+ -+NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) wstdcall; -+WIN_FUNC_DECL(IoPassIrpDown,2); -+NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, -+ struct irp *irp) wstdcall; -+NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, -+ struct irp *irp) wstdcall; -+NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, -+ struct irp *irp) wstdcall; -+ -+void KeInitializeSpinLock(NT_SPIN_LOCK *lock) wstdcall; -+void IoAcquireCancelSpinLock(KIRQL *irql) wstdcall; -+void IoReleaseCancelSpinLock(KIRQL irql) wstdcall; -+ -+NTSTATUS RtlUnicodeStringToAnsiString -+ (struct ansi_string *dst, const struct unicode_string *src, -+ BOOLEAN dup) wstdcall; -+NTSTATUS RtlAnsiStringToUnicodeString -+ (struct unicode_string *dst, const struct ansi_string *src, -+ BOOLEAN dup) wstdcall; -+void RtlInitAnsiString(struct ansi_string *dst, const char *src) wstdcall; -+void RtlInitUnicodeString(struct unicode_string *dest, -+ const wchar_t *src) wstdcall; -+void RtlFreeUnicodeString(struct unicode_string *string) wstdcall; -+void RtlFreeAnsiString(struct ansi_string *string) wstdcall; -+LONG RtlCompareUnicodeString(const struct unicode_string *s1, -+ const struct unicode_string *s2, -+ BOOLEAN case_insensitive) wstdcall; -+NTSTATUS RtlUpcaseUnicodeString(struct unicode_string *dst, -+ struct unicode_string *src, -+ BOOLEAN alloc) wstdcall; -+BOOLEAN KeCancelTimer(struct nt_timer *nt_timer) wstdcall; -+void KeInitializeDpc(struct kdpc *kdpc, void *func, void *ctx) wstdcall; -+ -+extern spinlock_t ntoskernel_lock; -+extern spinlock_t irp_cancel_lock; -+extern struct nt_list object_list; -+extern CCHAR cpu_count; -+#ifdef CONFIG_X86_64 -+extern struct kuser_shared_data kuser_shared_data; -+#endif -+ -+#define IoCompleteRequest(irp, prio) IofCompleteRequest(irp, prio) -+#define IoCallDriver(dev, irp) IofCallDriver(dev, irp) -+ -+#if defined(IO_DEBUG) -+#define DUMP_IRP(_irp) \ -+do { \ -+ struct io_stack_location *_irp_sl; \ -+ _irp_sl = IoGetCurrentIrpStackLocation(_irp); \ -+ IOTRACE("irp: %p, stack size: %d, cl: %d, sl: %p, dev_obj: %p, " \ -+ "mj_fn: %d, minor_fn: %d, nt_urb: %p, event: %p", \ -+ _irp, _irp->stack_count, (_irp)->current_location, \ -+ _irp_sl, _irp_sl->dev_obj, _irp_sl->major_fn, \ -+ _irp_sl->minor_fn, IRP_URB(_irp), \ -+ (_irp)->user_event); \ -+} while (0) -+#else -+#define DUMP_IRP(_irp) do { } while (0) -+#endif -+ -+#endif // _NTOSKERNEL_H_ -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/ntoskernel_io.c linux-5.6.11-ndis/3rdparty/ndiswrapper/ntoskernel_io.c ---- linux-5.6.11/3rdparty/ndiswrapper/ntoskernel_io.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/ntoskernel_io.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,1161 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ntoskernel.h" -+#include "ndis.h" -+#include "wrapndis.h" -+#include "usb.h" -+#include "loader.h" -+#include "ntoskernel_io_exports.h" -+ -+wstdcall void WIN_FUNC(IoAcquireCancelSpinLock,1) -+ (KIRQL *irql) __acquires(irql) -+{ -+ spin_lock_bh(&irp_cancel_lock); -+ *irql = 0; -+} -+ -+wstdcall void WIN_FUNC(IoReleaseCancelSpinLock,1) -+ (KIRQL irql) __releases(irql) -+{ -+ spin_unlock_bh(&irp_cancel_lock); -+} -+ -+wstdcall int WIN_FUNC(IoIsWdmVersionAvailable,2) -+ (UCHAR major, UCHAR minor) -+{ -+ IOENTER("%d, %x", major, minor); -+ if (major == 1 && -+ (minor == 0x30 || // Windows 2003 -+ minor == 0x20 || // Windows XP -+ minor == 0x10)) // Windows 2000 -+ IOEXIT(return TRUE); -+ IOEXIT(return FALSE); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(IoIs32bitProcess,1) -+ (struct irp *irp) -+{ -+#ifdef CONFIG_X86_64 -+ return FALSE; -+#else -+ return TRUE; -+#endif -+} -+ -+wstdcall void WIN_FUNC(IoInitializeIrp,3) -+ (struct irp *irp, USHORT size, CCHAR stack_count) -+{ -+ IOENTER("irp: %p, %d, %d", irp, size, stack_count); -+ -+ memset(irp, 0, size); -+ irp->size = size; -+ irp->stack_count = stack_count; -+ irp->current_location = stack_count; -+ IoGetCurrentIrpStackLocation(irp) = IRP_SL(irp, stack_count); -+ IOEXIT(return); -+} -+ -+wstdcall void WIN_FUNC(IoReuseIrp,2) -+ (struct irp *irp, NTSTATUS status) -+{ -+ IOENTER("%p, %d", irp, status); -+ if (irp) { -+ UCHAR alloc_flags; -+ -+ alloc_flags = irp->alloc_flags; -+ IoInitializeIrp(irp, irp->size, irp->stack_count); -+ irp->alloc_flags = alloc_flags; -+ irp->io_status.status = status; -+ } -+ IOEXIT(return); -+} -+ -+wstdcall struct irp *WIN_FUNC(IoAllocateIrp,2) -+ (char stack_count, BOOLEAN charge_quota) -+{ -+ struct irp *irp; -+ int irp_size; -+ -+ IOENTER("count: %d", stack_count); -+ stack_count++; -+ irp_size = IoSizeOfIrp(stack_count); -+ irp = kmalloc(irp_size, irql_gfp()); -+ if (irp) -+ IoInitializeIrp(irp, irp_size, stack_count); -+ IOTRACE("irp %p", irp); -+ IOEXIT(return irp); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(IoCancelIrp,1) -+ (struct irp *irp) -+{ -+ typeof(irp->cancel_routine) cancel_routine; -+ -+ /* NB: this function may be called at DISPATCH_LEVEL */ -+ IOTRACE("irp: %p", irp); -+ if (!irp) -+ return FALSE; -+ DUMP_IRP(irp); -+ IoAcquireCancelSpinLock(&irp->cancel_irql); -+ cancel_routine = xchg(&irp->cancel_routine, NULL); -+ IOTRACE("%p", cancel_routine); -+ irp->cancel = TRUE; -+ if (cancel_routine) { -+ struct device_object *dev_obj; -+ -+ if (irp->current_location >= 0 && -+ irp->current_location < irp->stack_count) -+ dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj; -+ else -+ dev_obj = NULL; -+ IOTRACE("current_location: %d, dev_obj: %p", -+ irp->current_location, dev_obj); -+ /* cancel_routine will release the spin lock */ -+ __release(irp->cancel_irql); -+ LIN2WIN2(cancel_routine, dev_obj, irp); -+ /* in usb's cancel, irp->cancel is set to indicate -+ * status of cancel */ -+ IOEXIT(return xchg(&irp->cancel, TRUE)); -+ } else { -+ IOTRACE("irp %p already canceled", irp); -+ IoReleaseCancelSpinLock(irp->cancel_irql); -+ IOEXIT(return FALSE); -+ } -+} -+ -+wstdcall void IoQueueThreadIrp(struct irp *irp) -+{ -+ struct nt_thread *thread; -+ KIRQL irql; -+ -+ thread = get_current_nt_thread(); -+ if (thread) { -+ IOTRACE("thread: %p, task: %p", thread, thread->task); -+ irp->flags |= IRP_SYNCHRONOUS_API; -+ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); -+ InsertTailList(&thread->irps, &irp->thread_list); -+ IoIrpThread(irp) = thread; -+ nt_spin_unlock_irql(&thread->lock, irql); -+ } else -+ IoIrpThread(irp) = NULL; -+} -+ -+wstdcall void IoDequeueThreadIrp(struct irp *irp) -+{ -+ struct nt_thread *thread; -+ KIRQL irql; -+ -+ thread = IoIrpThread(irp); -+ if (thread) { -+ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); -+ RemoveEntryList(&irp->thread_list); -+ nt_spin_unlock_irql(&thread->lock, irql); -+ } -+} -+ -+wstdcall void WIN_FUNC(IoFreeIrp,1) -+ (struct irp *irp) -+{ -+ IOENTER("irp = %p", irp); -+ if (!irp) { -+ WARNING("irp is NULL"); -+ return; -+ } -+ -+ if (irp->flags & IRP_SYNCHRONOUS_API) -+ IoDequeueThreadIrp(irp); -+ IoCancelIrp(irp); -+ kfree(irp); -+ -+ IOEXIT(return); -+} -+ -+wstdcall struct irp *WIN_FUNC(IoBuildAsynchronousFsdRequest,6) -+ (ULONG major_fn, struct device_object *dev_obj, void *buffer, -+ ULONG length, LARGE_INTEGER *offset, -+ struct io_status_block *user_status) -+{ -+ struct irp *irp; -+ struct io_stack_location *irp_sl; -+ -+ IOENTER("%p", dev_obj); -+ if (!dev_obj) -+ IOEXIT(return NULL); -+ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); -+ if (irp == NULL) { -+ WARNING("couldn't allocate irp"); -+ IOEXIT(return NULL); -+ } -+ -+ irp_sl = IoGetNextIrpStackLocation(irp); -+ irp_sl->major_fn = major_fn; -+ IOTRACE("major_fn: %d", major_fn); -+ irp_sl->minor_fn = 0; -+ irp_sl->flags = 0; -+ irp_sl->control = 0; -+ irp_sl->dev_obj = dev_obj; -+ irp_sl->file_obj = NULL; -+ irp_sl->completion_routine = NULL; -+ -+ if (dev_obj->flags & DO_DIRECT_IO) { -+ irp->mdl = IoAllocateMdl(buffer, length, FALSE, FALSE, irp); -+ if (irp->mdl == NULL) { -+ IoFreeIrp(irp); -+ return NULL; -+ } -+ MmProbeAndLockPages(irp->mdl, KernelMode, -+ major_fn == IRP_MJ_WRITE ? -+ IoReadAccess : IoWriteAccess); -+ IOTRACE("mdl: %p", irp->mdl); -+ } else if (dev_obj->flags & DO_BUFFERED_IO) { -+ irp->associated_irp.system_buffer = buffer; -+ irp->flags = IRP_BUFFERED_IO; -+ irp->mdl = NULL; -+ IOTRACE("buffer: %p", buffer); -+ } -+ if (major_fn == IRP_MJ_READ) { -+ irp_sl->params.read.length = length; -+ irp_sl->params.read.byte_offset = *offset; -+ } else if (major_fn == IRP_MJ_WRITE) { -+ irp_sl->params.write.length = length; -+ irp_sl->params.write.byte_offset = *offset; -+ } -+ irp->user_status = user_status; -+ IOTRACE("irp: %p", irp); -+ return irp; -+} -+ -+wstdcall struct irp *WIN_FUNC(IoBuildSynchronousFsdRequest,7) -+ (ULONG major_fn, struct device_object *dev_obj, void *buf, -+ ULONG length, LARGE_INTEGER *offset, struct nt_event *event, -+ struct io_status_block *user_status) -+{ -+ struct irp *irp; -+ -+ irp = IoBuildAsynchronousFsdRequest(major_fn, dev_obj, buf, length, -+ offset, user_status); -+ if (irp == NULL) -+ return NULL; -+ irp->user_event = event; -+ IoQueueThreadIrp(irp); -+ return irp; -+} -+ -+wstdcall struct irp *WIN_FUNC(IoBuildDeviceIoControlRequest,9) -+ (ULONG ioctl, struct device_object *dev_obj, -+ void *input_buf, ULONG input_buf_len, void *output_buf, -+ ULONG output_buf_len, BOOLEAN internal_ioctl, -+ struct nt_event *event, struct io_status_block *io_status) -+{ -+ struct irp *irp; -+ struct io_stack_location *irp_sl; -+ ULONG buf_len; -+ -+ IOENTER("%p, 0x%08x, %d", dev_obj, ioctl, internal_ioctl); -+ if (!dev_obj) -+ IOEXIT(return NULL); -+ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); -+ if (irp == NULL) { -+ WARNING("couldn't allocate irp"); -+ return NULL; -+ } -+ irp_sl = IoGetNextIrpStackLocation(irp); -+ irp_sl->params.dev_ioctl.code = ioctl; -+ irp_sl->params.dev_ioctl.input_buf_len = input_buf_len; -+ irp_sl->params.dev_ioctl.output_buf_len = output_buf_len; -+ irp_sl->major_fn = (internal_ioctl) ? -+ IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; -+ IOTRACE("%d", IO_METHOD_FROM_CTL_CODE(ioctl)); -+ -+ switch (IO_METHOD_FROM_CTL_CODE(ioctl)) { -+ case METHOD_BUFFERED: -+ buf_len = max(input_buf_len, output_buf_len); -+ if (buf_len) { -+ irp->associated_irp.system_buffer = -+ ExAllocatePoolWithTag(NonPagedPool, buf_len, 0); -+ if (!irp->associated_irp.system_buffer) { -+ IoFreeIrp(irp); -+ IOEXIT(return NULL); -+ } -+ irp->associated_irp.system_buffer = input_buf; -+ if (input_buf) -+ memcpy(irp->associated_irp.system_buffer, -+ input_buf, input_buf_len); -+ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; -+ if (output_buf) -+ irp->flags = IRP_INPUT_OPERATION; -+ irp->user_buf = output_buf; -+ } else -+ irp->user_buf = NULL; -+ break; -+ case METHOD_IN_DIRECT: -+ case METHOD_OUT_DIRECT: -+ if (input_buf) { -+ irp->associated_irp.system_buffer = -+ ExAllocatePoolWithTag(NonPagedPool, -+ input_buf_len, 0); -+ if (!irp->associated_irp.system_buffer) { -+ IoFreeIrp(irp); -+ IOEXIT(return NULL); -+ } -+ memcpy(irp->associated_irp.system_buffer, -+ input_buf, input_buf_len); -+ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; -+ } -+ /* TODO: we are supposed to setup MDL, but USB layer -+ * doesn't use MDLs. Moreover, USB layer mirrors -+ * non-DMAable buffers, so no need to allocate -+ * DMAable buffer here */ -+ if (output_buf) { -+ irp->associated_irp.system_buffer = -+ ExAllocatePoolWithTag(NonPagedPool, -+ output_buf_len, 0); -+ if (!irp->associated_irp.system_buffer) { -+ IoFreeIrp(irp); -+ IOEXIT(return NULL); -+ } -+ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; -+ } -+ break; -+ case METHOD_NEITHER: -+ irp->user_buf = output_buf; -+ irp_sl->params.dev_ioctl.type3_input_buf = input_buf; -+ break; -+ } -+ -+ irp->user_status = io_status; -+ irp->user_event = event; -+ IoQueueThreadIrp(irp); -+ -+ IOTRACE("irp: %p", irp); -+ IOEXIT(return irp); -+} -+ -+wfastcall NTSTATUS WIN_FUNC(IofCallDriver,2) -+ (struct device_object *dev_obj, struct irp *irp) -+{ -+ struct io_stack_location *irp_sl; -+ NTSTATUS status; -+ driver_dispatch_t *major_func; -+ struct driver_object *drv_obj; -+ -+ if (irp->current_location <= 0) { -+ ERROR("invalid irp: %p, %d", irp, irp->current_location); -+ return STATUS_INVALID_PARAMETER; -+ } -+ IOTRACE("%p, %p, %p, %d, %d, %p", dev_obj, irp, dev_obj->drv_obj, -+ irp->current_location, irp->stack_count, -+ IoGetCurrentIrpStackLocation(irp)); -+ IoSetNextIrpStackLocation(irp); -+ DUMP_IRP(irp); -+ irp_sl = IoGetCurrentIrpStackLocation(irp); -+ drv_obj = dev_obj->drv_obj; -+ irp_sl->dev_obj = dev_obj; -+ major_func = drv_obj->major_func[irp_sl->major_fn]; -+ IOTRACE("major_func: %p, dev_obj: %p", major_func, dev_obj); -+ if (major_func) -+ status = LIN2WIN2(major_func, dev_obj, irp); -+ else { -+ ERROR("major_function %d is not implemented", -+ irp_sl->major_fn); -+ status = STATUS_NOT_SUPPORTED; -+ } -+ IOEXIT(return status); -+} -+ -+wfastcall void WIN_FUNC(IofCompleteRequest,2) -+ (struct irp *irp, CHAR prio_boost) -+{ -+ struct io_stack_location *irp_sl; -+ -+#ifdef IO_DEBUG -+ DUMP_IRP(irp); -+ if (irp->io_status.status == STATUS_PENDING) { -+ ERROR("invalid irp: %p, STATUS_PENDING", irp); -+ return; -+ } -+ if (irp->current_location < 0 || -+ irp->current_location >= irp->stack_count) { -+ ERROR("invalid irp: %p, %d", irp, irp->current_location); -+ return; -+ } -+#endif -+ for (irp_sl = IoGetCurrentIrpStackLocation(irp); -+ irp->current_location < irp->stack_count; irp_sl++) { -+ struct device_object *dev_obj; -+ NTSTATUS status; -+ -+ DUMP_IRP(irp); -+ if (irp_sl->control & SL_PENDING_RETURNED) -+ irp->pending_returned = TRUE; -+ -+ /* current_location and dev_obj must be same as when -+ * driver called IoSetCompletionRoutine, which sets -+ * completion routine at next (lower) location, which -+ * is what we are going to call below; so we set -+ * current_location and dev_obj for the previous -+ * (higher) location */ -+ IoSkipCurrentIrpStackLocation(irp); -+ if (irp->current_location < irp->stack_count) -+ dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj; -+ else -+ dev_obj = NULL; -+ -+ IOTRACE("%d, %d, %p", irp->current_location, irp->stack_count, -+ dev_obj); -+ if (irp_sl->completion_routine && -+ ((irp->io_status.status == STATUS_SUCCESS && -+ irp_sl->control & SL_INVOKE_ON_SUCCESS) || -+ (irp->io_status.status != STATUS_SUCCESS && -+ irp_sl->control & SL_INVOKE_ON_ERROR) || -+ (irp->cancel == TRUE && -+ irp_sl->control & SL_INVOKE_ON_CANCEL))) { -+ IOTRACE("calling completion_routine at: %p, %p", -+ irp_sl->completion_routine, irp_sl->context); -+ status = LIN2WIN3(irp_sl->completion_routine, -+ dev_obj, irp, irp_sl->context); -+ IOTRACE("status: %08X", status); -+ if (status == STATUS_MORE_PROCESSING_REQUIRED) -+ IOEXIT(return); -+ } else { -+ /* propagate pending status to next irp_sl */ -+ if (irp->pending_returned && -+ irp->current_location < irp->stack_count) -+ IoMarkIrpPending(irp); -+ } -+ } -+ -+ if (irp->user_status) { -+ irp->user_status->status = irp->io_status.status; -+ irp->user_status->info = irp->io_status.info; -+ } -+ -+ if (irp->user_event) { -+ IOTRACE("setting event %p", irp->user_event); -+ KeSetEvent(irp->user_event, prio_boost, FALSE); -+ } -+ -+ if (irp->associated_irp.system_buffer && -+ (irp->flags & IRP_DEALLOCATE_BUFFER)) -+ ExFreePool(irp->associated_irp.system_buffer); -+ else { -+ struct mdl *mdl; -+ while ((mdl = irp->mdl)) { -+ irp->mdl = mdl->next; -+ MmUnlockPages(mdl); -+ IoFreeMdl(mdl); -+ } -+ } -+ IOTRACE("freeing irp %p", irp); -+ IoFreeIrp(irp); -+ IOEXIT(return); -+} -+ -+wstdcall NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) -+{ -+ IoSkipCurrentIrpStackLocation(irp); -+ IOEXIT(return IoCallDriver(dev_obj, irp)); -+} -+ -+wstdcall NTSTATUS IoIrpSyncComplete(struct device_object *dev_obj, -+ struct irp *irp, void *context) -+{ -+ if (irp->pending_returned == TRUE) -+ KeSetEvent(context, IO_NO_INCREMENT, FALSE); -+ IOEXIT(return STATUS_MORE_PROCESSING_REQUIRED); -+} -+WIN_FUNC_DECL(IoIrpSyncComplete,3) -+ -+wstdcall NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, -+ struct irp *irp) -+{ -+ struct nt_event event; -+ NTSTATUS status; -+ -+ IoCopyCurrentIrpStackLocationToNext(irp); -+ KeInitializeEvent(&event, SynchronizationEvent, FALSE); -+ /* completion function is called as Windows function */ -+ IoSetCompletionRoutine(irp, WIN_FUNC_PTR(IoIrpSyncComplete,3), &event, -+ TRUE, TRUE, TRUE); -+ status = IoCallDriver(dev_obj, irp); -+ IOTRACE("%08X", status); -+ if (status == STATUS_PENDING) { -+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, -+ NULL); -+ status = irp->io_status.status; -+ } -+ IOTRACE("%08X", status); -+ IOEXIT(return status); -+} -+WIN_FUNC_DECL(IoSyncForwardIrp,2) -+ -+wstdcall NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, -+ struct irp *irp) -+{ -+ NTSTATUS status; -+ -+ IoCopyCurrentIrpStackLocationToNext(irp); -+ status = IoCallDriver(dev_obj, irp); -+ IOEXIT(return status); -+} -+WIN_FUNC_DECL(IoAsyncForwardIrp,2) -+ -+wstdcall NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, -+ struct irp *irp) -+{ -+ struct io_stack_location *irp_sl; -+ NTSTATUS status; -+ -+ irp_sl = IoGetCurrentIrpStackLocation(irp); -+ WARNING("%d:%d not implemented", irp_sl->major_fn, irp_sl->minor_fn); -+ irp->io_status.status = STATUS_SUCCESS; -+ irp->io_status.info = 0; -+ status = irp->io_status.status; -+ IoCompleteRequest(irp, IO_NO_INCREMENT); -+ IOEXIT(return status); -+} -+WIN_FUNC_DECL(IoInvalidDeviceRequest,2) -+ -+static irqreturn_t io_irq_isr(int irq, void *data ISR_PT_REGS_PARAM_DECL) -+{ -+ struct kinterrupt *interrupt = data; -+ BOOLEAN ret; -+ -+#ifdef CONFIG_DEBUG_SHIRQ -+ if (!interrupt->u.enabled) -+ EXIT1(return IRQ_NONE); -+#endif -+ TRACE6("%p", interrupt); -+ nt_spin_lock(interrupt->actual_lock); -+ ret = LIN2WIN2(interrupt->isr, interrupt, interrupt->isr_ctx); -+ nt_spin_unlock(interrupt->actual_lock); -+ if (ret == TRUE) -+ EXIT6(return IRQ_HANDLED); -+ else -+ EXIT6(return IRQ_NONE); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoConnectInterrupt,11) -+ (struct kinterrupt **kinterrupt, PKSERVICE_ROUTINE isr, void *isr_ctx, -+ NT_SPIN_LOCK *lock, ULONG vector, KIRQL irql, KIRQL synch_irql, -+ enum kinterrupt_mode mode, BOOLEAN shared, KAFFINITY cpu_mask, -+ BOOLEAN save_fp) -+{ -+ struct kinterrupt *interrupt; -+ IOENTER(""); -+ interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL); -+ if (!interrupt) -+ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); -+ interrupt->vector = vector; -+ interrupt->cpu_mask = cpu_mask; -+ nt_spin_lock_init(&interrupt->lock); -+ if (lock) -+ interrupt->actual_lock = lock; -+ else -+ interrupt->actual_lock = &interrupt->lock; -+ interrupt->shared = shared; -+ interrupt->save_fp = save_fp; -+ interrupt->isr = isr; -+ interrupt->isr_ctx = isr_ctx; -+ InitializeListHead(&interrupt->list); -+ interrupt->irql = irql; -+ interrupt->synch_irql = synch_irql; -+ interrupt->mode = mode; -+ if (request_irq(vector, io_irq_isr, shared ? IRQF_SHARED : 0, -+ DRIVER_NAME, interrupt)) { -+ WARNING("request for irq %d failed", vector); -+ kfree(interrupt); -+ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); -+ } -+ *kinterrupt = interrupt; -+#ifdef CONFIG_DEBUG_SHIRQ -+ interrupt->u.enabled = 1; -+#endif -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(IoDisconnectInterrupt,1) -+ (struct kinterrupt *interrupt) -+{ -+#ifdef CONFIG_DEBUG_SHIRQ -+ interrupt->u.enabled = 0; -+#endif -+ free_irq(interrupt->vector, interrupt); -+ kfree(interrupt); -+} -+ -+wstdcall struct mdl *WIN_FUNC(IoAllocateMdl,5) -+ (void *virt, ULONG length, BOOLEAN second_buf, BOOLEAN charge_quota, -+ struct irp *irp) -+{ -+ struct mdl *mdl; -+ mdl = allocate_init_mdl(virt, length); -+ if (!mdl) -+ return NULL; -+ if (irp) { -+ if (second_buf == TRUE) { -+ struct mdl *last; -+ -+ last = irp->mdl; -+ while (last->next) -+ last = last->next; -+ last->next = mdl; -+ } else -+ irp->mdl = mdl; -+ } -+ IOTRACE("%p", mdl); -+ return mdl; -+} -+ -+wstdcall void WIN_FUNC(IoFreeMdl,1) -+ (struct mdl *mdl) -+{ -+ IOTRACE("%p", mdl); -+ free_mdl(mdl); -+} -+ -+wstdcall struct io_workitem *WIN_FUNC(IoAllocateWorkItem,1) -+ (struct device_object *dev_obj) -+{ -+ struct io_workitem *io_workitem; -+ -+ IOENTER("%p", dev_obj); -+ io_workitem = kmalloc(sizeof(*io_workitem), irql_gfp()); -+ if (!io_workitem) -+ IOEXIT(return NULL); -+ io_workitem->dev_obj = dev_obj; -+ IOEXIT(return io_workitem); -+} -+ -+wstdcall void WIN_FUNC(IoFreeWorkItem,1) -+ (struct io_workitem *io_workitem) -+{ -+ kfree(io_workitem); -+ IOEXIT(return); -+} -+ -+wstdcall void WIN_FUNC(IoQueueWorkItem,4) -+ (struct io_workitem *io_workitem, void *func, -+ enum work_queue_type queue_type, void *context) -+{ -+ IOENTER("%p, %p", io_workitem, io_workitem->dev_obj); -+ io_workitem->worker_routine = func; -+ io_workitem->context = context; -+ schedule_ntos_work_item(func, io_workitem->dev_obj, context); -+ IOEXIT(return); -+} -+ -+wstdcall void WIN_FUNC(ExQueueWorkItem,2) -+ (struct io_workitem *io_workitem, enum work_queue_type queue_type) -+{ -+ IOENTER("%p", io_workitem); -+ schedule_ntos_work_item(io_workitem->worker_routine, -+ io_workitem->dev_obj, io_workitem->context); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoAllocateDriverObjectExtension,4) -+ (struct driver_object *drv_obj, void *client_id, ULONG extlen, -+ void **ext) -+{ -+ struct custom_ext *ce; -+ -+ IOENTER("%p, %p", drv_obj, client_id); -+ ce = kmalloc(sizeof(*ce) + extlen, irql_gfp()); -+ if (ce == NULL) -+ return STATUS_INSUFFICIENT_RESOURCES; -+ -+ IOTRACE("custom_ext: %p", ce); -+ ce->client_id = client_id; -+ spin_lock_bh(&ntoskernel_lock); -+ InsertTailList(&drv_obj->drv_ext->custom_ext, &ce->list); -+ spin_unlock_bh(&ntoskernel_lock); -+ -+ *ext = (void *)ce + sizeof(*ce); -+ IOTRACE("ext: %p", *ext); -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall void *WIN_FUNC(IoGetDriverObjectExtension,2) -+ (struct driver_object *drv_obj, void *client_id) -+{ -+ struct custom_ext *ce; -+ void *ret; -+ -+ IOENTER("drv_obj: %p, client_id: %p", drv_obj, client_id); -+ ret = NULL; -+ spin_lock_bh(&ntoskernel_lock); -+ nt_list_for_each_entry(ce, &drv_obj->drv_ext->custom_ext, list) { -+ if (ce->client_id == client_id) { -+ ret = (void *)ce + sizeof(*ce); -+ break; -+ } -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ IOTRACE("ret: %p", ret); -+ return ret; -+} -+ -+void free_custom_extensions(struct driver_extension *drv_ext) -+{ -+ struct nt_list *ent; -+ -+ IOENTER("%p", drv_ext); -+ spin_lock_bh(&ntoskernel_lock); -+ while ((ent = RemoveHeadList(&drv_ext->custom_ext))) -+ kfree(ent); -+ spin_unlock_bh(&ntoskernel_lock); -+ IOEXIT(return); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoCreateDevice,7) -+ (struct driver_object *drv_obj, ULONG dev_ext_length, -+ struct unicode_string *dev_name, DEVICE_TYPE dev_type, -+ ULONG dev_chars, BOOLEAN exclusive, struct device_object **newdev) -+{ -+ struct device_object *dev; -+ struct dev_obj_ext *dev_obj_ext; -+ int size; -+ -+ IOENTER("%p, %u, %p", drv_obj, dev_ext_length, dev_name); -+ -+ size = sizeof(*dev) + dev_ext_length + sizeof(*dev_obj_ext); -+ dev = allocate_object(size, OBJECT_TYPE_DEVICE, dev_name); -+ if (!dev) -+ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); -+ if (dev_ext_length) -+ dev->dev_ext = dev + 1; -+ else -+ dev->dev_ext = NULL; -+ -+ dev_obj_ext = ((void *)(dev + 1)) + dev_ext_length; -+ dev_obj_ext->dev_obj = dev; -+ dev_obj_ext->size = 0; -+ dev_obj_ext->type = IO_TYPE_DEVICE; -+ dev->dev_obj_ext = dev_obj_ext; -+ -+ dev->type = dev_type; -+ dev->flags = 0; -+ dev->size = sizeof(*dev) + dev_ext_length; -+ dev->ref_count = 1; -+ dev->attached = NULL; -+ dev->stack_count = 1; -+ -+ dev->drv_obj = drv_obj; -+ dev->next = drv_obj->dev_obj; -+ drv_obj->dev_obj = dev; -+ -+ dev->align_req = 1; -+ dev->characteristics = dev_chars; -+ dev->io_timer = NULL; -+ KeInitializeEvent(&dev->lock, SynchronizationEvent, TRUE); -+ dev->vpb = NULL; -+ -+ IOTRACE("dev: %p, ext: %p", dev, dev->dev_ext); -+ *newdev = dev; -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoCreateUnprotectedSymbolicLink,2) -+ (struct unicode_string *link, struct unicode_string *dev_name) -+{ -+ struct ansi_string ansi; -+ -+ IOENTER("%p, %p", dev_name, link); -+ if (dev_name && (RtlUnicodeStringToAnsiString(&ansi, dev_name, TRUE) == -+ STATUS_SUCCESS)) { -+ IOTRACE("dev_name: %s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) == -+ STATUS_SUCCESS)) { -+ IOTRACE("link: %s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+// TODO(); -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoCreateSymbolicLink,2) -+ (struct unicode_string *link, struct unicode_string *dev_name) -+{ -+ IOEXIT(return IoCreateUnprotectedSymbolicLink(link, dev_name)); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoDeleteSymbolicLink,1) -+ (struct unicode_string *link) -+{ -+ struct ansi_string ansi; -+ -+ IOENTER("%p", link); -+ if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) == -+ STATUS_SUCCESS)) { -+ IOTRACE("dev_name: %s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(IoDeleteDevice,1) -+ (struct device_object *dev) -+{ -+ IOENTER("%p", dev); -+ if (dev == NULL) -+ IOEXIT(return); -+ IOTRACE("drv_obj: %p", dev->drv_obj); -+ if (dev->drv_obj) { -+ struct device_object *prev; -+ -+ prev = dev->drv_obj->dev_obj; -+ IOTRACE("dev_obj: %p", prev); -+ if (prev == dev) -+ dev->drv_obj->dev_obj = dev->next; -+ else if (prev) { -+ while (prev->next != dev) -+ prev = prev->next; -+ prev->next = dev->next; -+ } -+ } -+ ObDereferenceObject(dev); -+ IOEXIT(return); -+} -+ -+wstdcall void WIN_FUNC(IoDetachDevice,1) -+ (struct device_object *tgt) -+{ -+ struct device_object *tail; -+ -+ IOENTER("%p", tgt); -+ if (!tgt) -+ IOEXIT(return); -+ tail = tgt->attached; -+ if (!tail) -+ IOEXIT(return); -+ IOTRACE("tail: %p", tail); -+ -+ spin_lock_bh(&ntoskernel_lock); -+ tgt->attached = tail->attached; -+ IOTRACE("attached:%p", tgt->attached); -+ for ( ; tail; tail = tail->attached) { -+ IOTRACE("tail:%p", tail); -+ tail->stack_count--; -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ IOEXIT(return); -+} -+ -+wstdcall struct device_object *WIN_FUNC(IoGetAttachedDevice,1) -+ (struct device_object *dev) -+{ -+ IOENTER("%p", dev); -+ if (!dev) -+ IOEXIT(return NULL); -+ spin_lock_bh(&ntoskernel_lock); -+ while (dev->attached) -+ dev = dev->attached; -+ spin_unlock_bh(&ntoskernel_lock); -+ IOEXIT(return dev); -+} -+ -+wstdcall struct device_object *WIN_FUNC(IoGetAttachedDeviceReference,1) -+ (struct device_object *dev) -+{ -+ IOENTER("%p", dev); -+ if (!dev) -+ IOEXIT(return NULL); -+ dev = IoGetAttachedDevice(dev); -+ ObReferenceObject(dev); -+ IOEXIT(return dev); -+} -+ -+wstdcall struct device_object *WIN_FUNC(IoAttachDeviceToDeviceStack,2) -+ (struct device_object *src, struct device_object *tgt) -+{ -+ struct device_object *attached; -+ struct dev_obj_ext *src_dev_ext; -+ -+ IOENTER("%p, %p", src, tgt); -+ attached = IoGetAttachedDevice(tgt); -+ IOTRACE("%p", attached); -+ src_dev_ext = src->dev_obj_ext; -+ spin_lock_bh(&ntoskernel_lock); -+ if (attached) -+ attached->attached = src; -+ src->attached = NULL; -+ src->stack_count = attached->stack_count + 1; -+ src_dev_ext->attached_to = attached; -+ spin_unlock_bh(&ntoskernel_lock); -+ IOTRACE("stack_count: %d -> %d", attached->stack_count, -+ src->stack_count); -+ IOEXIT(return attached); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoGetDeviceProperty,5) -+ (struct device_object *pdo, enum device_registry_property dev_property, -+ ULONG buffer_len, void *buffer, ULONG *result_len) -+{ -+ struct ansi_string ansi; -+ struct unicode_string unicode; -+ struct wrap_device *wd; -+ ULONG need; -+ -+ IOENTER("dev_obj = %p, dev_property = %d, buffer_len = %u, " -+ "buffer = %p, result_len = %p", pdo, dev_property, -+ buffer_len, buffer, result_len); -+ -+ wd = pdo->reserved; -+ switch (dev_property) { -+ case DevicePropertyDeviceDescription: -+ case DevicePropertyFriendlyName: -+ case DevicePropertyDriverKeyName: -+ if (wrap_is_pci_bus(wd->dev_bus)) -+ RtlInitAnsiString(&ansi, "PCI"); -+ else // if (wrap_is_usb_bus(wd->dev_bus)) -+ RtlInitAnsiString(&ansi, "USB"); -+ need = sizeof(wchar_t) * (ansi.max_length + 1); -+ if (buffer_len < need) { -+ *result_len = need; -+ IOEXIT(return STATUS_BUFFER_TOO_SMALL); -+ } -+ unicode.max_length = buffer_len; -+ unicode.buf = buffer; -+ if (RtlAnsiStringToUnicodeString(&unicode, &ansi, -+ FALSE) != STATUS_SUCCESS) { -+ *result_len = unicode.length; -+ IOEXIT(return STATUS_BUFFER_TOO_SMALL); -+ } -+ IOEXIT(return STATUS_SUCCESS); -+ default: -+ WARNING("%d not implemented", dev_property); -+ IOEXIT(return STATUS_INVALID_PARAMETER_2); -+ } -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoGetDeviceObjectPointer,4) -+ (struct unicode_string *name, ACCESS_MASK desired_access, -+ struct file_object *file_obj, struct device_object *dev_obj) -+{ -+ struct common_object_header *coh; -+ -+ dev_obj = NULL; -+ /* TODO: access is not checked and file_obj is filled with zeroes */ -+ spin_lock_bh(&ntoskernel_lock); -+ nt_list_for_each_entry(coh, &object_list, list) { -+ TRACE5("header: %p, type: %d", coh, coh->type); -+ if (coh->type != OBJECT_TYPE_DEVICE) -+ continue; -+ if (!RtlCompareUnicodeString(&coh->name, name, TRUE)) { -+ dev_obj = HEADER_TO_OBJECT(coh); -+ TRACE5("dev_obj: %p", dev_obj); -+ break; -+ } -+ } -+ spin_unlock_bh(&ntoskernel_lock); -+ if (dev_obj) { -+ memset(file_obj, 0, sizeof(*file_obj)); -+ WARNING("file_obj filled with zeroes"); -+ IOEXIT(return STATUS_SUCCESS); -+ } else -+ IOEXIT(return STATUS_OBJECT_NAME_INVALID); -+} -+ -+/* NOTE: Make sure to compile with -freg-struct-return, so gcc will -+ * return union in register, like Windows */ -+wstdcall union power_state WIN_FUNC(PoSetPowerState,3) -+ (struct device_object *dev_obj, enum power_state_type type, -+ union power_state state) -+{ -+ IOEXIT(return state); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(PoCallDriver,2) -+ (struct device_object *dev_obj, struct irp *irp) -+{ -+ return IoCallDriver(dev_obj, irp); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(PoRequestPowerIrp,6) -+ (struct device_object *dev_obj, UCHAR minor_fn, -+ union power_state power_state, void *completion_func, -+ void *context, struct irp **pirp) -+{ -+ struct irp *irp; -+ struct io_stack_location *irp_sl; -+ -+ TRACE1("%p, %d, %p", dev_obj, dev_obj->stack_count, dev_obj->drv_obj); -+ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); -+ if (!irp) -+ return STATUS_INSUFFICIENT_RESOURCES; -+ irp_sl = IoGetNextIrpStackLocation(irp); -+ irp_sl->major_fn = IRP_MJ_POWER; -+ irp_sl->minor_fn = minor_fn; -+ if (minor_fn == IRP_MN_WAIT_WAKE) -+ irp_sl->params.power.type = SystemPowerState; -+ else -+ irp_sl->params.power.type = DevicePowerState; -+ irp_sl->params.power.state = power_state; -+ irp_sl->completion_routine = completion_func; -+ irp->io_status.status = STATUS_NOT_SUPPORTED; -+ *pirp = irp; -+ return PoCallDriver(dev_obj, irp); -+} -+ -+wstdcall void WIN_FUNC(PoStartNextPowerIrp,1) -+ (struct irp *irp) -+{ -+ IOENTER("irp = %p", irp); -+ IOEXIT(return); -+} -+ -+wstdcall void WIN_FUNC(IoInitializeRemoveLockEx,5) -+ (struct io_remove_lock *lock, ULONG alloc_tag, ULONG max_locked_min, -+ ULONG high_mark, ULONG lock_size) -+{ -+ TODO(); -+} -+ -+wstdcall void *WIN_FUNC(IoAllocateErrorLogEntry,2) -+ (void *io_object, UCHAR entry_size) -+{ -+ /* not implemented fully */ -+ void *ret = kmalloc(sizeof(struct io_error_log_packet) + entry_size, -+ irql_gfp()); -+ TRACE2("%p", ret); -+ if (ret) -+ return ret + sizeof(struct io_error_log_packet); -+ else -+ return NULL; -+} -+ -+wstdcall void WIN_FUNC(IoWriteErrorLogEntry,1) -+ (void *entry) -+{ -+ /* TODO: log error with codes and message */ -+ ERROR(""); -+} -+ -+wstdcall void WIN_FUNC(IoFreeErrorLogEntry,1) -+ (void *entry) -+{ -+ TRACE2("%p", entry); -+ kfree(entry - sizeof(struct io_error_log_packet)); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoAcquireRemoveLockEx,5) -+ (struct io_remove_lock *lock, void *tag, char *file, ULONG line, -+ ULONG lock_size) -+{ -+ TODO(); -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoReleaseRemoveLockEx,3) -+ (struct io_remove_lock *lock, void *tag, ULONG lock_size) -+{ -+ TODO(); -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoRegisterDeviceInterface,4) -+ (struct device_object *pdo, struct guid *guid_class, -+ struct unicode_string *reference, struct unicode_string *link) -+{ -+ struct ansi_string ansi; -+ -+ /* TODO: check if pdo is valid */ -+ RtlInitAnsiString(&ansi, "ndis"); -+ ENTER1("pdo: %p, ref: %p, link: %p, %x, %x, %x", pdo, reference, link, -+ guid_class->data1, guid_class->data2, guid_class->data3); -+ return RtlAnsiStringToUnicodeString(link, &ansi, TRUE); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoSetDeviceInterfaceState,2) -+ (struct unicode_string *link, BOOLEAN enable) -+{ -+ ENTER1("link: %p, enable: %d", link, enable); -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoOpenDeviceRegistryKey,4) -+ (struct device_object *dev_obj, ULONG type, ACCESS_MASK mask, -+ void **handle) -+{ -+ ENTER1("dev_obj: %p", dev_obj); -+ *handle = dev_obj; -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoWMIRegistrationControl,2) -+ (struct device_object *dev_obj, ULONG action) -+{ -+ ENTER2("%p, %d", dev_obj, action); -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(IoInvalidateDeviceRelations,2) -+ (struct device_object *dev_obj, enum device_relation_type type) -+{ -+ INFO("%p, %d", dev_obj, type); -+ TODO(); -+} -+ -+wstdcall void WIN_FUNC(IoInvalidateDeviceState,1) -+ (struct device_object *pdo) -+{ -+ INFO("%p", pdo); -+ TODO(); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoRegisterPlugPlayNotification,7) -+ (UINT category, ULONG flags, void *data, struct driver_object *object, -+ void *callback, void *context, void **notification_entry) -+{ -+ TRACE2("category: %d, flags 0x%x, data: %p, object: %p, callback: %p, " -+ "context: %p, notification_entry: %p", category, flags, data, -+ object, callback, context, notification_entry); -+ TODO(); -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoUnregisterPlugPlayNotification,1) -+ (void *notification_entry) -+{ -+ TRACE2("%p", notification_entry); -+ TODO(); -+ IOEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoWMIOpenBlock,3) -+ (struct guid *guid, ULONG access, void *object) -+{ -+ TODO(); -+ IOEXIT(return STATUS_NOT_IMPLEMENTED); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(IoWMIQueryAllData,3) -+ (void *data_block_object, UINT *buffer_size, void *buffer) -+{ -+ TODO(); -+ IOEXIT(return STATUS_NOT_IMPLEMENTED); -+} -+ -+wstdcall void WIN_FUNC(IoGetStackLimits,2) -+ (ULONG_PTR *LowLimit, ULONG_PTR *HighLimit) -+{ -+ *LowLimit = (ULONG_PTR)&LowLimit & ~(THREAD_SIZE - 1); -+ *HighLimit = *LowLimit + THREAD_SIZE; -+ IOTRACE("LowLimit: 0x%lx, HighLimit: 0x%lx", *LowLimit, *HighLimit); -+ IOEXIT(return); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/pe_linker.c linux-5.6.11-ndis/3rdparty/ndiswrapper/pe_linker.c ---- linux-5.6.11/3rdparty/ndiswrapper/pe_linker.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/pe_linker.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,600 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifdef TEST_LOADER -+ -+#include "usr_linker.h" -+ -+#else -+ -+#include -+#include -+ -+//#define DEBUGLINKER 2 -+ -+#include "ntoskernel.h" -+ -+#endif -+ -+struct pe_exports { -+ char *dll; -+ char *name; -+ generic_func addr; -+}; -+ -+static struct pe_exports pe_exports[40]; -+static int num_pe_exports; -+ -+#define RVA2VA(image, rva, type) (type)(ULONG_PTR)((void *)image + rva) -+#define CHECK_SZ(a,b) { if (sizeof(a) != b) { \ -+ ERROR("%s is bad, got %zd, expected %d", \ -+ #a , sizeof(a), (b)); return -EINVAL; } } -+ -+#if defined(DEBUGLINKER) && DEBUGLINKER > 0 -+#define DBGLINKER(fmt, ...) printk(KERN_INFO "%s (%s:%d): " fmt "\n", \ -+ DRIVER_NAME, __func__, \ -+ __LINE__ , ## __VA_ARGS__); -+static const char *image_directory_name[] = { -+ "EXPORT", -+ "IMPORT", -+ "RESOURCE", -+ "EXCEPTION", -+ "SECURITY", -+ "BASERELOC", -+ "DEBUG", -+ "COPYRIGHT", -+ "GLOBALPTR", -+ "TLS", -+ "LOAD_CONFIG", -+ "BOUND_IMPORT", -+ "IAT", -+ "DELAY_IMPORT", -+ "COM_DESCRIPTOR" }; -+#else -+#define DBGLINKER(fmt, ...) do { } while (0) -+#endif -+ -+#ifndef TEST_LOADER -+extern struct wrap_export ntoskernel_exports[], ntoskernel_io_exports[], -+ ndis_exports[], crt_exports[], hal_exports[], rtl_exports[]; -+#ifdef ENABLE_USB -+extern struct wrap_export usb_exports[]; -+#endif -+ -+static int get_export(char *name, generic_func *func) -+{ -+ int i, j; -+ -+ struct wrap_export *exports[] = { -+ ntoskernel_exports, -+ ntoskernel_io_exports, -+ ndis_exports, -+ crt_exports, -+ hal_exports, -+ rtl_exports, -+#ifdef ENABLE_USB -+ usb_exports, -+#endif -+ }; -+ -+ for (j = 0; j < ARRAY_SIZE(exports); j++) -+ for (i = 0; exports[j][i].name != NULL; i++) -+ if (strcmp(exports[j][i].name, name) == 0) { -+ *func = exports[j][i].func; -+ return 0; -+ } -+ -+ for (i = 0; i < num_pe_exports; i++) -+ if (strcmp(pe_exports[i].name, name) == 0) { -+ *func = pe_exports[i].addr; -+ return 0; -+ } -+ -+ return -1; -+} -+#endif // TEST_LOADER -+ -+static void *get_dll_init(char *name) -+{ -+ int i; -+ for (i = 0; i < num_pe_exports; i++) -+ if ((strcmp(pe_exports[i].dll, name) == 0) && -+ (strcmp(pe_exports[i].name, "DllInitialize") == 0)) -+ return (void *)pe_exports[i].addr; -+ return NULL; -+} -+ -+/* -+ * Find and validate the coff header -+ * -+ */ -+static int check_nt_hdr(IMAGE_NT_HEADERS *nt_hdr) -+{ -+ int i; -+ WORD attr; -+ PIMAGE_OPTIONAL_HEADER opt_hdr; -+ -+ /* Validate the "PE\0\0" signature */ -+ if (nt_hdr->Signature != IMAGE_NT_SIGNATURE) { -+ ERROR("is this driver file? bad signature %08x", -+ nt_hdr->Signature); -+ return -EINVAL; -+ } -+ -+ opt_hdr = &nt_hdr->OptionalHeader; -+ /* Make sure Image is PE32 or PE32+ */ -+#ifdef CONFIG_X86_64 -+ if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { -+ ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" -+ "bad magic: %04X", opt_hdr->Magic); -+ return -EINVAL; -+ } -+#else -+ if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { -+ ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" -+ "bad magic: %04X", opt_hdr->Magic); -+ return -EINVAL; -+ } -+#endif -+ -+ /* Validate the image for the current architecture. */ -+#ifdef CONFIG_X86_64 -+ if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { -+ ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" -+ " (PE signature is %04X)", nt_hdr->FileHeader.Machine); -+ return -EINVAL; -+ } -+#else -+ if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { -+ ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" -+ " (PE signature is %04X)", nt_hdr->FileHeader.Machine); -+ return -EINVAL; -+ } -+#endif -+ -+ /* Must have attributes */ -+#ifdef CONFIG_X86_64 -+ attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE; -+#else -+ attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE; -+#endif -+ if ((nt_hdr->FileHeader.Characteristics & attr) != attr) -+ return -EINVAL; -+ -+ /* Must be relocatable */ -+ attr = IMAGE_FILE_RELOCS_STRIPPED; -+ if ((nt_hdr->FileHeader.Characteristics & attr)) -+ return -EINVAL; -+ -+ /* Make sure we have at least one section */ -+ if (nt_hdr->FileHeader.NumberOfSections == 0) -+ return -EINVAL; -+ -+ if (opt_hdr->SectionAlignment < opt_hdr->FileAlignment) { -+ ERROR("alignment mismatch: section: 0x%x, file: 0x%x", -+ opt_hdr->SectionAlignment, opt_hdr->FileAlignment); -+ return -EINVAL; -+ } -+ -+ DBGLINKER("number of datadictionary entries %d", -+ opt_hdr->NumberOfRvaAndSizes); -+ for (i = 0; i < opt_hdr->NumberOfRvaAndSizes; i++) { -+ DBGLINKER("datadirectory %s RVA:%X Size:%d", -+ (i <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) ? -+ image_directory_name[i] : "unknown", -+ opt_hdr->DataDirectory[i].VirtualAddress, -+ opt_hdr->DataDirectory[i].Size); -+ } -+ -+ if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) -+ return IMAGE_FILE_EXECUTABLE_IMAGE; -+ if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_DLL)) -+ return IMAGE_FILE_DLL; -+ return -EINVAL; -+} -+ -+static int import(void *image, IMAGE_IMPORT_DESCRIPTOR *dirent, char *dll) -+{ -+ ULONG_PTR *lookup_tbl, *address_tbl; -+ char *symname = NULL; -+ int i; -+ int ret = 0; -+ generic_func adr; -+ -+ lookup_tbl = RVA2VA(image, dirent->u.OriginalFirstThunk, ULONG_PTR *); -+ address_tbl = RVA2VA(image, dirent->FirstThunk, ULONG_PTR *); -+ -+ for (i = 0; lookup_tbl[i]; i++) { -+ if (IMAGE_SNAP_BY_ORDINAL(lookup_tbl[i])) { -+ ERROR("ordinal import not supported: %llu", -+ (uint64_t)lookup_tbl[i]); -+ return -1; -+ } -+ else { -+ symname = RVA2VA(image, -+ ((lookup_tbl[i] & -+ ~IMAGE_ORDINAL_FLAG) + 2), char *); -+ } -+ -+ if (get_export(symname, &adr) < 0) { -+ ERROR("unknown symbol: %s:'%s'", dll, symname); -+ ret = -1; -+ } else { -+ DBGLINKER("found symbol: %s:%s: addr: %p, rva = %llu", -+ dll, symname, adr, (uint64_t)address_tbl[i]); -+ address_tbl[i] = (ULONG_PTR)adr; -+ } -+ } -+ return ret; -+} -+ -+static int read_exports(struct pe_image *pe) -+{ -+ IMAGE_EXPORT_DIRECTORY *export_dir_table; -+ uint32_t *export_addr_table; -+ int i; -+ uint32_t *name_table; -+ PIMAGE_OPTIONAL_HEADER opt_hdr; -+ IMAGE_DATA_DIRECTORY *export_data_dir; -+ -+ opt_hdr = &pe->nt_hdr->OptionalHeader; -+ export_data_dir = -+ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; -+ -+ if (export_data_dir->Size == 0) { -+ DBGLINKER("no exports"); -+ return 0; -+ } -+ -+ export_dir_table = -+ RVA2VA(pe->image, export_data_dir->VirtualAddress, -+ IMAGE_EXPORT_DIRECTORY *); -+ -+ name_table = (unsigned int *)(pe->image + -+ export_dir_table->AddressOfNames); -+ export_addr_table = (uint32_t *) -+ (pe->image + export_dir_table->AddressOfFunctions); -+ -+ for (i = 0; i < export_dir_table->NumberOfNames; i++) { -+ -+ if (export_data_dir->VirtualAddress <= *export_addr_table || -+ *export_addr_table >= (export_data_dir->VirtualAddress + -+ export_data_dir->Size)) -+ DBGLINKER("forwarder rva"); -+ -+ DBGLINKER("export symbol: %s, at %p", -+ (char *)(pe->image + *name_table), -+ pe->image + *export_addr_table); -+ -+ pe_exports[num_pe_exports].dll = pe->name; -+ pe_exports[num_pe_exports].name = pe->image + *name_table; -+ pe_exports[num_pe_exports].addr = -+ pe->image + *export_addr_table; -+ -+ num_pe_exports++; -+ name_table++; -+ export_addr_table++; -+ } -+ return 0; -+} -+ -+static int fixup_imports(void *image, IMAGE_NT_HEADERS *nt_hdr) -+{ -+ int i; -+ char *name; -+ int ret = 0; -+ IMAGE_IMPORT_DESCRIPTOR *dirent; -+ IMAGE_DATA_DIRECTORY *import_data_dir; -+ PIMAGE_OPTIONAL_HEADER opt_hdr; -+ -+ opt_hdr = &nt_hdr->OptionalHeader; -+ import_data_dir = -+ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; -+ dirent = RVA2VA(image, import_data_dir->VirtualAddress, -+ IMAGE_IMPORT_DESCRIPTOR *); -+ -+ for (i = 0; dirent[i].Name; i++) { -+ name = RVA2VA(image, dirent[i].Name, char*); -+ -+ DBGLINKER("imports from dll: %s", name); -+ ret += import(image, &dirent[i], name); -+ } -+ return ret; -+} -+ -+static int fixup_reloc(void *image, IMAGE_NT_HEADERS *nt_hdr) -+{ -+ ULONG_PTR base; -+ ULONG_PTR size; -+ IMAGE_BASE_RELOCATION *fixup_block; -+ IMAGE_DATA_DIRECTORY *base_reloc_data_dir; -+ PIMAGE_OPTIONAL_HEADER opt_hdr; -+ -+ opt_hdr = &nt_hdr->OptionalHeader; -+ base = opt_hdr->ImageBase; -+ base_reloc_data_dir = -+ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; -+ if (base_reloc_data_dir->Size == 0) -+ return 0; -+ -+ fixup_block = RVA2VA(image, base_reloc_data_dir->VirtualAddress, -+ IMAGE_BASE_RELOCATION *); -+ DBGLINKER("fixup_block=%p, image=%p", fixup_block, image); -+ DBGLINKER("fixup_block info: %x %d", -+ fixup_block->VirtualAddress, fixup_block->SizeOfBlock); -+ -+ while (fixup_block->SizeOfBlock) { -+ int i; -+ WORD fixup, offset; -+ -+ size = (fixup_block->SizeOfBlock - -+ sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); -+ DBGLINKER("found %llu relocations in this block", -+ (uint64_t)size); -+ -+ for (i = 0; i < size; i++) { -+ fixup = fixup_block->TypeOffset[i]; -+ offset = fixup & 0xfff; -+ switch ((fixup >> 12) & 0x0f) { -+ case IMAGE_REL_BASED_ABSOLUTE: -+ break; -+ -+ case IMAGE_REL_BASED_HIGHLOW: { -+ uint32_t addr; -+ uint32_t *loc = -+ RVA2VA(image, -+ fixup_block->VirtualAddress + -+ offset, uint32_t *); -+ addr = RVA2VA(image, (*loc - base), uint32_t); -+ DBGLINKER("relocation: *%p (Val:%X)= %X", -+ loc, *loc, addr); -+ *loc = addr; -+ } -+ break; -+ -+ case IMAGE_REL_BASED_DIR64: { -+ uint64_t addr; -+ uint64_t *loc = -+ RVA2VA(image, -+ fixup_block->VirtualAddress + -+ offset, uint64_t *); -+ addr = RVA2VA(image, (*loc - base), uint64_t); -+ DBGLINKER("relocation: *%p (Val:%llX)= %llx", -+ loc, *loc, addr); -+ *loc = addr; -+ } -+ break; -+ -+ default: -+ ERROR("unknown fixup: %08X", -+ (fixup >> 12) & 0x0f); -+ return -EOPNOTSUPP; -+ break; -+ } -+ } -+ DBGLINKER("finished relocating block"); -+ -+ fixup_block = (IMAGE_BASE_RELOCATION *) -+ ((void *)fixup_block + fixup_block->SizeOfBlock); -+ }; -+ DBGLINKER("done relocating all"); -+ -+ return 0; -+} -+ -+/* Expand the image in memory if necessary. The image on disk does not -+ * necessarily maps the image of the driver in memory, so we have to -+ * re-write it in order to fulfill the sections alignments. The -+ * advantage to do that is that rva_to_va becomes a simple -+ * addition. */ -+static int fix_pe_image(struct pe_image *pe) -+{ -+ void *image; -+ IMAGE_SECTION_HEADER *sect_hdr; -+ int i, sections; -+ int image_size; -+ -+ if (pe->size == pe->opt_hdr->SizeOfImage) { -+ /* Nothing to do */ -+ return 0; -+ } -+ -+ image_size = pe->opt_hdr->SizeOfImage; -+#ifdef CONFIG_X86_64 -+#ifdef PAGE_KERNEL_EXECUTABLE -+ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM -+ ); -+#elif defined PAGE_KERNEL_EXEC -+ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM -+ ); -+#else -+#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC -+#endif -+#else -+#ifdef cpu_has_nx -+ /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is -+ * not available to modules! */ -+ if (cpu_has_nx) -+ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM -+ ); -+ else -+ image = vmalloc(image_size); -+#else -+ image = vmalloc(image_size); -+#endif -+#endif -+ if (image == NULL) { -+ ERROR("failed to allocate enough space for new image:" -+ " %d bytes", image_size); -+ return -ENOMEM; -+ } -+ memset(image, 0, image_size); -+ -+ /* Copy all the headers, ie everything before the first section. */ -+ -+ sections = pe->nt_hdr->FileHeader.NumberOfSections; -+ sect_hdr = IMAGE_FIRST_SECTION(pe->nt_hdr); -+ -+ DBGLINKER("copying headers: %u bytes", sect_hdr->PointerToRawData); -+ -+ memcpy(image, pe->image, sect_hdr->PointerToRawData); -+ -+ /* Copy all the sections */ -+ for (i = 0; i < sections; i++) { -+ DBGLINKER("Copy section %s from %x to %x", -+ sect_hdr->Name, sect_hdr->PointerToRawData, -+ sect_hdr->VirtualAddress); -+ if (sect_hdr->VirtualAddress+sect_hdr->SizeOfRawData > -+ image_size) { -+ ERROR("Invalid section %s in driver", sect_hdr->Name); -+ vfree(image); -+ return -EINVAL; -+ } -+ -+ memcpy(image+sect_hdr->VirtualAddress, -+ pe->image + sect_hdr->PointerToRawData, -+ sect_hdr->SizeOfRawData); -+ sect_hdr++; -+ } -+ -+ vfree(pe->image); -+ pe->image = image; -+ pe->size = image_size; -+ -+ /* Update our internal pointers */ -+ pe->nt_hdr = (IMAGE_NT_HEADERS *) -+ (pe->image + ((IMAGE_DOS_HEADER *)pe->image)->e_lfanew); -+ pe->opt_hdr = &pe->nt_hdr->OptionalHeader; -+ -+ DBGLINKER("set nt headers: nt_hdr=%p, opt_hdr=%p, image=%p", -+ pe->nt_hdr, pe->opt_hdr, pe->image); -+ -+ return 0; -+} -+ -+#if defined(CONFIG_X86_64) -+static void fix_user_shared_data_addr(char *driver, unsigned long length) -+{ -+ unsigned long i, n, max_addr, *addr; -+ -+ TRACE1("fixing KI_USER_SHARED_DATA address in the driver"); -+ n = length - sizeof(unsigned long); -+ max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data); -+ for (i = 0; i < n; i++) { -+ addr = (unsigned long *)(driver + i); -+ if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) { -+ *addr -= KI_USER_SHARED_DATA; -+ *addr += (unsigned long)&kuser_shared_data; -+ kuser_shared_data.reserved1 = 1; -+ } -+ } -+} -+#endif -+ -+int link_pe_images(struct pe_image *pe_image, unsigned short n) -+{ -+ int i; -+ struct pe_image *pe; -+ -+#if DEBUG >= 1 -+ /* Sanity checks */ -+ CHECK_SZ(IMAGE_SECTION_HEADER, IMAGE_SIZEOF_SECTION_HEADER); -+ CHECK_SZ(IMAGE_FILE_HEADER, IMAGE_SIZEOF_FILE_HEADER); -+ CHECK_SZ(IMAGE_OPTIONAL_HEADER, IMAGE_SIZEOF_NT_OPTIONAL_HEADER); -+ CHECK_SZ(IMAGE_NT_HEADERS, 4 + IMAGE_SIZEOF_FILE_HEADER + -+ IMAGE_SIZEOF_NT_OPTIONAL_HEADER); -+ CHECK_SZ(IMAGE_DOS_HEADER, 0x40); -+ CHECK_SZ(IMAGE_EXPORT_DIRECTORY, 40); -+ CHECK_SZ(IMAGE_BASE_RELOCATION, 8); -+ CHECK_SZ(IMAGE_IMPORT_DESCRIPTOR, 20); -+#endif -+ -+ for (i = 0; i < n; i++) { -+ IMAGE_DOS_HEADER *dos_hdr; -+ pe = &pe_image[i]; -+ dos_hdr = pe->image; -+ -+ if (pe->size < sizeof(IMAGE_DOS_HEADER)) { -+ TRACE1("image too small: %d", pe->size); -+ return -EINVAL; -+ } -+ -+ pe->nt_hdr = -+ (IMAGE_NT_HEADERS *)(pe->image + dos_hdr->e_lfanew); -+ pe->opt_hdr = &pe->nt_hdr->OptionalHeader; -+ -+ pe->type = check_nt_hdr(pe->nt_hdr); -+ if (pe->type <= 0) { -+ TRACE1("type <= 0"); -+ return -EINVAL; -+ } -+ -+ if (fix_pe_image(pe)) { -+ TRACE1("bad PE image"); -+ return -EINVAL; -+ } -+ -+ if (read_exports(pe)) { -+ TRACE1("read exports failed"); -+ return -EINVAL; -+ } -+ } -+ -+ for (i = 0; i < n; i++) { -+ pe = &pe_image[i]; -+ -+ if (fixup_reloc(pe->image, pe->nt_hdr)) { -+ TRACE1("fixup reloc failed"); -+ return -EINVAL; -+ } -+ if (fixup_imports(pe->image, pe->nt_hdr)) { -+ TRACE1("fixup imports failed"); -+ return -EINVAL; -+ } -+#if defined(CONFIG_X86_64) -+ fix_user_shared_data_addr(pe_image[i].image, pe_image[i].size); -+#endif -+ flush_icache_range((unsigned long)pe->image, pe->size); -+ -+ pe->entry = -+ RVA2VA(pe->image, -+ pe->opt_hdr->AddressOfEntryPoint, void *); -+ TRACE1("entry is at %p, rva at %08X", pe->entry, -+ pe->opt_hdr->AddressOfEntryPoint); -+ } -+ -+ for (i = 0; i < n; i++) { -+ pe = &pe_image[i]; -+ -+ if (pe->type == IMAGE_FILE_DLL) { -+ struct unicode_string ustring; -+ char *buf = "0/0t0m0p00"; -+ int (*dll_entry)(struct unicode_string *ustring) -+ wstdcall; -+ -+ memset(&ustring, 0, sizeof(ustring)); -+ ustring.buf = (wchar_t *)buf; -+ dll_entry = (void *)get_dll_init(pe->name); -+ -+ TRACE1("calling dll_init at %p", dll_entry); -+ if (!dll_entry || dll_entry(&ustring)) -+ ERROR("DLL initialize failed for %s", -+ pe->name); -+ } -+ else if (pe->type != IMAGE_FILE_EXECUTABLE_IMAGE) -+ ERROR("illegal image type: %d", pe->type); -+ } -+ return 0; -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/pe_linker.h linux-5.6.11-ndis/3rdparty/ndiswrapper/pe_linker.h ---- linux-5.6.11/3rdparty/ndiswrapper/pe_linker.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/pe_linker.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,992 @@ -+/* -+ * This file is an excerpt of winnt.h from WINE, which bears the -+ * following copyright: -+ * -+ * Win32 definitions for Windows NT -+ * -+ * Copyright 1996 Alexandre Julliard -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library 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 -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+/* -+ * File formats definitions -+ */ -+typedef struct _IMAGE_DOS_HEADER { -+ WORD e_magic; /* 00: MZ Header signature */ -+ WORD e_cblp; /* 02: Bytes on last page of file */ -+ WORD e_cp; /* 04: Pages in file */ -+ WORD e_crlc; /* 06: Relocations */ -+ WORD e_cparhdr; /* 08: Size of header in paragraphs */ -+ WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */ -+ WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */ -+ WORD e_ss; /* 0e: Initial (relative) SS value */ -+ WORD e_sp; /* 10: Initial SP value */ -+ WORD e_csum; /* 12: Checksum */ -+ WORD e_ip; /* 14: Initial IP value */ -+ WORD e_cs; /* 16: Initial (relative) CS value */ -+ WORD e_lfarlc; /* 18: File address of relocation table */ -+ WORD e_ovno; /* 1a: Overlay number */ -+ WORD e_res[4]; /* 1c: Reserved words */ -+ WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */ -+ WORD e_oeminfo; /* 26: OEM information; e_oemid specific */ -+ WORD e_res2[10]; /* 28: Reserved words */ -+ DWORD e_lfanew; /* 3c: Offset to extended header */ -+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; -+ -+#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ -+#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ -+#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ -+#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ -+#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ -+#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ -+ -+/* -+ * This is the Windows executable (NE) header. -+ * the name IMAGE_OS2_HEADER is misleading, but in the SDK this way. -+ */ -+typedef struct -+{ -+ WORD ne_magic; /* 00 NE signature 'NE' */ -+ BYTE ne_ver; /* 02 Linker version number */ -+ BYTE ne_rev; /* 03 Linker revision number */ -+ WORD ne_enttab; /* 04 Offset to entry table relative to NE */ -+ WORD ne_cbenttab; /* 06 Length of entry table in bytes */ -+ LONG ne_crc; /* 08 Checksum */ -+ WORD ne_flags; /* 0c Flags about segments in this file */ -+ WORD ne_autodata; /* 0e Automatic data segment number */ -+ WORD ne_heap; /* 10 Initial size of local heap */ -+ WORD ne_stack; /* 12 Initial size of stack */ -+ DWORD ne_csip; /* 14 Initial CS:IP */ -+ DWORD ne_sssp; /* 18 Initial SS:SP */ -+ WORD ne_cseg; /* 1c # of entries in segment table */ -+ WORD ne_cmod; /* 1e # of entries in module reference tab. */ -+ WORD ne_cbnrestab; /* 20 Length of nonresident-name table */ -+ WORD ne_segtab; /* 22 Offset to segment table */ -+ WORD ne_rsrctab; /* 24 Offset to resource table */ -+ WORD ne_restab; /* 26 Offset to resident-name table */ -+ WORD ne_modtab; /* 28 Offset to module reference table */ -+ WORD ne_imptab; /* 2a Offset to imported name table */ -+ DWORD ne_nrestab; /* 2c Offset to nonresident-name table */ -+ WORD ne_cmovent; /* 30 # of movable entry points */ -+ WORD ne_align; /* 32 Logical sector alignment shift count */ -+ WORD ne_cres; /* 34 # of resource segments */ -+ BYTE ne_exetyp; /* 36 Flags indicating target OS */ -+ BYTE ne_flagsothers; /* 37 Additional information flags */ -+ WORD ne_pretthunks; /* 38 Offset to return thunks */ -+ WORD ne_psegrefbytes; /* 3a Offset to segment ref. bytes */ -+ WORD ne_swaparea; /* 3c Reserved by Microsoft */ -+ WORD ne_expver; /* 3e Expected Windows version number */ -+} IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; -+ -+typedef struct _IMAGE_VXD_HEADER { -+ WORD e32_magic; -+ BYTE e32_border; -+ BYTE e32_worder; -+ DWORD e32_level; -+ WORD e32_cpu; -+ WORD e32_os; -+ DWORD e32_ver; -+ DWORD e32_mflags; -+ DWORD e32_mpages; -+ DWORD e32_startobj; -+ DWORD e32_eip; -+ DWORD e32_stackobj; -+ DWORD e32_esp; -+ DWORD e32_pagesize; -+ DWORD e32_lastpagesize; -+ DWORD e32_fixupsize; -+ DWORD e32_fixupsum; -+ DWORD e32_ldrsize; -+ DWORD e32_ldrsum; -+ DWORD e32_objtab; -+ DWORD e32_objcnt; -+ DWORD e32_objmap; -+ DWORD e32_itermap; -+ DWORD e32_rsrctab; -+ DWORD e32_rsrccnt; -+ DWORD e32_restab; -+ DWORD e32_enttab; -+ DWORD e32_dirtab; -+ DWORD e32_dircnt; -+ DWORD e32_fpagetab; -+ DWORD e32_frectab; -+ DWORD e32_impmod; -+ DWORD e32_impmodcnt; -+ DWORD e32_impproc; -+ DWORD e32_pagesum; -+ DWORD e32_datapage; -+ DWORD e32_preload; -+ DWORD e32_nrestab; -+ DWORD e32_cbnrestab; -+ DWORD e32_nressum; -+ DWORD e32_autodata; -+ DWORD e32_debuginfo; -+ DWORD e32_debuglen; -+ DWORD e32_instpreload; -+ DWORD e32_instdemand; -+ DWORD e32_heapsize; -+ BYTE e32_res3[12]; -+ DWORD e32_winresoff; -+ DWORD e32_winreslen; -+ WORD e32_devid; -+ WORD e32_ddkver; -+} IMAGE_VXD_HEADER, *PIMAGE_VXD_HEADER; -+ -+/* These defines describe the meanings of the bits in the -+ Characteristics field */ -+ -+#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ -+#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 -+#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 -+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 -+#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 -+#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 -+#define IMAGE_FILE_16BIT_MACHINE 0x0040 -+#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 -+#define IMAGE_FILE_32BIT_MACHINE 0x0100 -+#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 -+#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 -+#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 -+#define IMAGE_FILE_SYSTEM 0x1000 -+#define IMAGE_FILE_DLL 0x2000 -+#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 -+#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 -+ -+/* These are the settings of the Machine field. */ -+#define IMAGE_FILE_MACHINE_UNKNOWN 0 -+#define IMAGE_FILE_MACHINE_I860 0x014d -+#define IMAGE_FILE_MACHINE_I386 0x014c -+#define IMAGE_FILE_MACHINE_R3000 0x0162 -+#define IMAGE_FILE_MACHINE_R4000 0x0166 -+#define IMAGE_FILE_MACHINE_R10000 0x0168 -+#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 -+#define IMAGE_FILE_MACHINE_ALPHA 0x0184 -+#define IMAGE_FILE_MACHINE_SH3 0x01a2 -+#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 -+#define IMAGE_FILE_MACHINE_SH3E 0x01a4 -+#define IMAGE_FILE_MACHINE_SH4 0x01a6 -+#define IMAGE_FILE_MACHINE_SH5 0x01a8 -+#define IMAGE_FILE_MACHINE_ARM 0x01c0 -+#define IMAGE_FILE_MACHINE_THUMB 0x01c2 -+#define IMAGE_FILE_MACHINE_AM33 0x01d3 -+#define IMAGE_FILE_MACHINE_POWERPC 0x01f0 -+#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 -+#define IMAGE_FILE_MACHINE_IA64 0x0200 -+#define IMAGE_FILE_MACHINE_MIPS16 0x0266 -+#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 -+#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 -+#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 -+#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 -+#define IMAGE_FILE_MACHINE_TRICORE 0x0520 -+#define IMAGE_FILE_MACHINE_CEF 0x0cef -+#define IMAGE_FILE_MACHINE_EBC 0x0ebc -+#define IMAGE_FILE_MACHINE_AMD64 0x8664 -+#define IMAGE_FILE_MACHINE_M32R 0x9041 -+#define IMAGE_FILE_MACHINE_CEE 0xc0ee -+ -+#define IMAGE_SIZEOF_FILE_HEADER 20 -+#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 -+#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 -+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 224 -+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 240 -+#define IMAGE_SIZEOF_SHORT_NAME 8 -+#define IMAGE_SIZEOF_SECTION_HEADER 40 -+#define IMAGE_SIZEOF_SYMBOL 18 -+#define IMAGE_SIZEOF_AUX_SYMBOL 18 -+#define IMAGE_SIZEOF_RELOCATION 10 -+#define IMAGE_SIZEOF_BASE_RELOCATION 8 -+#define IMAGE_SIZEOF_LINENUMBER 6 -+#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 -+ -+/* Possible Magic values */ -+#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b -+#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b -+#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x0107 -+ -+#ifdef CONFIG_X86_64 -+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 -+#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC -+#else -+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 -+#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC -+#endif -+ -+/* These are indexes into the DataDirectory array */ -+#define IMAGE_FILE_EXPORT_DIRECTORY 0 -+#define IMAGE_FILE_IMPORT_DIRECTORY 1 -+#define IMAGE_FILE_RESOURCE_DIRECTORY 2 -+#define IMAGE_FILE_EXCEPTION_DIRECTORY 3 -+#define IMAGE_FILE_SECURITY_DIRECTORY 4 -+#define IMAGE_FILE_BASE_RELOCATION_TABLE 5 -+#define IMAGE_FILE_DEBUG_DIRECTORY 6 -+#define IMAGE_FILE_DESCRIPTION_STRING 7 -+#define IMAGE_FILE_MACHINE_VALUE 8 /* Mips */ -+#define IMAGE_FILE_THREAD_LOCAL_STORAGE 9 -+#define IMAGE_FILE_CALLBACK_DIRECTORY 10 -+ -+/* Directory Entries, indices into the DataDirectory array */ -+ -+#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 -+#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 -+#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 -+#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 -+#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 -+#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 -+#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 -+#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 -+#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ -+#define IMAGE_DIRECTORY_ENTRY_TLS 9 -+#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 -+#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 -+#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ -+#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 -+#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 -+ -+/* Subsystem Values */ -+ -+#define IMAGE_SUBSYSTEM_UNKNOWN 0 -+#define IMAGE_SUBSYSTEM_NATIVE 1 -+#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */ -+#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem */ -+#define IMAGE_SUBSYSTEM_OS2_CUI 5 -+#define IMAGE_SUBSYSTEM_POSIX_CUI 7 -+#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 /* native Win9x driver */ -+#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 /* Windows CE subsystem */ -+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 -+#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 -+#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 -+#define IMAGE_SUBSYSTEM_EFI_ROM 13 -+#define IMAGE_SUBSYSTEM_XBOX 14 -+ -+typedef struct _IMAGE_FILE_HEADER { -+ WORD Machine; -+ WORD NumberOfSections; -+ DWORD TimeDateStamp; -+ DWORD PointerToSymbolTable; -+ DWORD NumberOfSymbols; -+ WORD SizeOfOptionalHeader; -+ WORD Characteristics; -+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; -+ -+typedef struct _IMAGE_DATA_DIRECTORY { -+ DWORD VirtualAddress; -+ DWORD Size; -+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; -+ -+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 -+ -+typedef struct _IMAGE_OPTIONAL_HEADER32 { -+ -+ /* Standard fields */ -+ -+ WORD Magic; -+ BYTE MajorLinkerVersion; -+ BYTE MinorLinkerVersion; -+ DWORD SizeOfCode; -+ DWORD SizeOfInitializedData; -+ DWORD SizeOfUninitializedData; -+ DWORD AddressOfEntryPoint; -+ DWORD BaseOfCode; -+ DWORD BaseOfData; -+ -+ /* NT additional fields */ -+ DWORD ImageBase; -+ DWORD SectionAlignment; -+ DWORD FileAlignment; -+ WORD MajorOperatingSystemVersion; -+ WORD MinorOperatingSystemVersion; -+ WORD MajorImageVersion; -+ WORD MinorImageVersion; -+ WORD MajorSubsystemVersion; -+ WORD MinorSubsystemVersion; -+ DWORD Win32VersionValue; -+ DWORD SizeOfImage; -+ DWORD SizeOfHeaders; -+ DWORD CheckSum; -+ WORD Subsystem; -+ WORD DllCharacteristics; -+ DWORD SizeOfStackReserve; -+ DWORD SizeOfStackCommit; -+ DWORD SizeOfHeapReserve; -+ DWORD SizeOfHeapCommit; -+ DWORD LoaderFlags; -+ DWORD NumberOfRvaAndSizes; -+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; -+} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; -+ -+typedef struct _IMAGE_OPTIONAL_HEADER64 { -+ -+ /* Standard fields */ -+ -+ WORD Magic; -+ BYTE MajorLinkerVersion; -+ BYTE MinorLinkerVersion; -+ DWORD SizeOfCode; -+ DWORD SizeOfInitializedData; -+ DWORD SizeOfUninitializedData; -+ DWORD AddressOfEntryPoint; -+ DWORD BaseOfCode; -+ -+ /* NT additional fields */ -+ ULONGLONG ImageBase; -+ DWORD SectionAlignment; -+ DWORD FileAlignment; -+ WORD MajorOperatingSystemVersion; -+ WORD MinorOperatingSystemVersion; -+ WORD MajorImageVersion; -+ WORD MinorImageVersion; -+ WORD MajorSubsystemVersion; -+ WORD MinorSubsystemVersion; -+ DWORD Win32VersionValue; -+ DWORD SizeOfImage; -+ DWORD SizeOfHeaders; -+ DWORD CheckSum; -+ WORD Subsystem; -+ WORD DllCharacteristics; -+ ULONGLONG SizeOfStackReserve; -+ ULONGLONG SizeOfStackCommit; -+ ULONGLONG SizeOfHeapReserve; -+ ULONGLONG SizeOfHeapCommit; -+ DWORD LoaderFlags; -+ DWORD NumberOfRvaAndSizes; -+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; -+} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; -+ -+#ifdef CONFIG_X86_64 -+typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; -+typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; -+#else -+typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; -+typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; -+#endif -+ -+typedef struct _IMAGE_NT_HEADERS32 { -+ DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ -+ IMAGE_FILE_HEADER FileHeader; /* 0x04 */ -+ IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */ -+} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; -+ -+typedef struct _IMAGE_NT_HEADERS64 { -+ DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ -+ IMAGE_FILE_HEADER FileHeader; /* 0x04 */ -+ IMAGE_OPTIONAL_HEADER64 OptionalHeader; /* 0x18 */ -+} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; -+ -+#ifdef CONFIG_X86_64 -+typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; -+typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; -+#else -+typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; -+typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; -+#endif -+ -+#define IMAGE_SIZEOF_SHORT_NAME 8 -+ -+typedef struct _IMAGE_SECTION_HEADER { -+ BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; -+ union { -+ DWORD PhysicalAddress; -+ DWORD VirtualSize; -+ } Misc; -+ DWORD VirtualAddress; -+ DWORD SizeOfRawData; -+ DWORD PointerToRawData; -+ DWORD PointerToRelocations; -+ DWORD PointerToLinenumbers; -+ WORD NumberOfRelocations; -+ WORD NumberOfLinenumbers; -+ DWORD Characteristics; -+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; -+ -+#define IMAGE_SIZEOF_SECTION_HEADER 40 -+ -+#define IMAGE_FIRST_SECTION(ntheader) \ -+((PIMAGE_SECTION_HEADER)((LPBYTE)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \ -+((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) -+ -+/* These defines are for the Characteristics bitfield. */ -+/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */ -+/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */ -+/* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */ -+/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */ -+#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved */ -+/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */ -+ -+#define IMAGE_SCN_CNT_CODE 0x00000020 -+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 -+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 -+ -+#define IMAGE_SCN_LNK_OTHER 0x00000100 -+#define IMAGE_SCN_LNK_INFO 0x00000200 -+/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */ -+#define IMAGE_SCN_LNK_REMOVE 0x00000800 -+#define IMAGE_SCN_LNK_COMDAT 0x00001000 -+ -+/* 0x00002000 - Reserved */ -+/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */ -+#define IMAGE_SCN_MEM_FARDATA 0x00008000 -+ -+/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */ -+#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 -+#define IMAGE_SCN_MEM_16BIT 0x00020000 -+#define IMAGE_SCN_MEM_LOCKED 0x00040000 -+#define IMAGE_SCN_MEM_PRELOAD 0x00080000 -+ -+#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 -+#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 -+#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 -+#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 -+#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */ -+#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 -+#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 -+#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 -+#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 -+#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 -+#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 -+#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 -+#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 -+#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 -+/* 0x00F00000 - Unused */ -+#define IMAGE_SCN_ALIGN_MASK 0x00F00000 -+ -+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 -+ -+ -+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 -+#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 -+#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 -+#define IMAGE_SCN_MEM_SHARED 0x10000000 -+#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -+#define IMAGE_SCN_MEM_READ 0x40000000 -+#define IMAGE_SCN_MEM_WRITE 0x80000000 -+ -+typedef struct _IMAGE_SYMBOL { -+ union { -+ BYTE ShortName[8]; -+ struct { -+ DWORD Short; -+ DWORD Long; -+ } Name; -+ DWORD LongName[2]; -+ } N; -+ DWORD Value; -+ SHORT SectionNumber; -+ WORD Type; -+ BYTE StorageClass; -+ BYTE NumberOfAuxSymbols; -+} IMAGE_SYMBOL; -+typedef IMAGE_SYMBOL *PIMAGE_SYMBOL; -+ -+#define IMAGE_SIZEOF_SYMBOL 18 -+ -+typedef struct _IMAGE_LINENUMBER { -+ union { -+ DWORD SymbolTableIndex; -+ DWORD VirtualAddress; -+ } Type; -+ WORD Linenumber; -+} IMAGE_LINENUMBER; -+typedef IMAGE_LINENUMBER *PIMAGE_LINENUMBER; -+ -+#define IMAGE_SIZEOF_LINENUMBER 6 -+ -+typedef union _IMAGE_AUX_SYMBOL { -+ struct { -+ DWORD TagIndex; -+ union { -+ struct { -+ WORD Linenumber; -+ WORD Size; -+ } LnSz; -+ DWORD TotalSize; -+ } Misc; -+ union { -+ struct { -+ DWORD PointerToLinenumber; -+ DWORD PointerToNextFunction; -+ } Function; -+ struct { -+ WORD Dimension[4]; -+ } Array; -+ } FcnAry; -+ WORD TvIndex; -+ } Sym; -+ struct { -+ BYTE Name[IMAGE_SIZEOF_SYMBOL]; -+ } File; -+ struct { -+ DWORD Length; -+ WORD NumberOfRelocations; -+ WORD NumberOfLinenumbers; -+ DWORD CheckSum; -+ SHORT Number; -+ BYTE Selection; -+ } Section; -+} IMAGE_AUX_SYMBOL; -+typedef IMAGE_AUX_SYMBOL *PIMAGE_AUX_SYMBOL; -+ -+#define IMAGE_SIZEOF_AUX_SYMBOL 18 -+ -+#define IMAGE_SYM_UNDEFINED (SHORT)0 -+#define IMAGE_SYM_ABSOLUTE (SHORT)-1 -+#define IMAGE_SYM_DEBUG (SHORT)-2 -+ -+#define IMAGE_SYM_TYPE_NULL 0x0000 -+#define IMAGE_SYM_TYPE_VOID 0x0001 -+#define IMAGE_SYM_TYPE_CHAR 0x0002 -+#define IMAGE_SYM_TYPE_SHORT 0x0003 -+#define IMAGE_SYM_TYPE_INT 0x0004 -+#define IMAGE_SYM_TYPE_LONG 0x0005 -+#define IMAGE_SYM_TYPE_FLOAT 0x0006 -+#define IMAGE_SYM_TYPE_DOUBLE 0x0007 -+#define IMAGE_SYM_TYPE_STRUCT 0x0008 -+#define IMAGE_SYM_TYPE_UNION 0x0009 -+#define IMAGE_SYM_TYPE_ENUM 0x000A -+#define IMAGE_SYM_TYPE_MOE 0x000B -+#define IMAGE_SYM_TYPE_BYTE 0x000C -+#define IMAGE_SYM_TYPE_WORD 0x000D -+#define IMAGE_SYM_TYPE_UINT 0x000E -+#define IMAGE_SYM_TYPE_DWORD 0x000F -+#define IMAGE_SYM_TYPE_PCODE 0x8000 -+ -+#define IMAGE_SYM_DTYPE_NULL 0 -+#define IMAGE_SYM_DTYPE_POINTER 1 -+#define IMAGE_SYM_DTYPE_FUNCTION 2 -+#define IMAGE_SYM_DTYPE_ARRAY 3 -+ -+#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 -+#define IMAGE_SYM_CLASS_NULL 0x0000 -+#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 -+#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 -+#define IMAGE_SYM_CLASS_STATIC 0x0003 -+#define IMAGE_SYM_CLASS_REGISTER 0x0004 -+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 -+#define IMAGE_SYM_CLASS_LABEL 0x0006 -+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 -+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 -+#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 -+#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A -+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B -+#define IMAGE_SYM_CLASS_UNION_TAG 0x000C -+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D -+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E -+#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F -+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 -+#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 -+#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 -+ -+#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 -+#define IMAGE_SYM_CLASS_BLOCK 0x0064 -+#define IMAGE_SYM_CLASS_FUNCTION 0x0065 -+#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 -+#define IMAGE_SYM_CLASS_FILE 0x0067 -+#define IMAGE_SYM_CLASS_SECTION 0x0068 -+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 -+ -+#define N_BTMASK 0x000F -+#define N_TMASK 0x0030 -+#define N_TMASK1 0x00C0 -+#define N_TMASK2 0x00F0 -+#define N_BTSHFT 4 -+#define N_TSHIFT 2 -+ -+#define BTYPE(x) ((x) & N_BTMASK) -+ -+#ifndef ISPTR -+#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) -+#endif -+ -+#ifndef ISFCN -+#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) -+#endif -+ -+#ifndef ISARY -+#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) -+#endif -+ -+#ifndef ISTAG -+#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) -+#endif -+ -+#ifndef INCREF -+#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) -+#endif -+ -+#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 -+#define IMAGE_COMDAT_SELECT_ANY 2 -+#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 -+#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 -+#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 -+#define IMAGE_COMDAT_SELECT_LARGEST 6 -+#define IMAGE_COMDAT_SELECT_NEWEST 7 -+ -+#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 -+#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 -+#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 -+ -+/* Export module directory */ -+ -+typedef struct _IMAGE_EXPORT_DIRECTORY { -+ DWORD Characteristics; -+ DWORD TimeDateStamp; -+ WORD MajorVersion; -+ WORD MinorVersion; -+ DWORD Name; -+ DWORD Base; -+ DWORD NumberOfFunctions; -+ DWORD NumberOfNames; -+ DWORD AddressOfFunctions; -+ DWORD AddressOfNames; -+ DWORD AddressOfNameOrdinals; -+} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; -+ -+/* Import name entry */ -+typedef struct _IMAGE_IMPORT_BY_NAME { -+ WORD Hint; -+ BYTE Name[1]; -+} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; -+ -+/* Import thunk */ -+typedef struct _IMAGE_THUNK_DATA32 { -+ union { -+ DWORD ForwarderString; -+ DWORD Function; -+ DWORD Ordinal; -+ DWORD AddressOfData; -+ } u1; -+} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32; -+ -+typedef struct _IMAGE_THUNK_DATA64 { -+ union { -+ ULONGLONG ForwarderString; -+ ULONGLONG Function; -+ ULONGLONG Ordinal; -+ ULONGLONG AddressOfData; -+ } u1; -+} IMAGE_THUNK_DATA64,*PIMAGE_THUNK_DATA64; -+ -+#ifdef CONFIG_X86_64 -+typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; -+typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; -+#else -+typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; -+typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; -+#endif -+ -+/* Import module directory */ -+ -+typedef struct __packed _IMAGE_IMPORT_DESCRIPTOR { -+ union { -+ DWORD Characteristics; /* 0 for terminating null -+ * import descriptor */ -+ DWORD OriginalFirstThunk; /* RVA to original unbound -+ * IAT */ -+ } u; -+ DWORD TimeDateStamp; /* 0 if not bound, -+ * -1 if bound, and real date\time stamp -+ * in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT -+ * (new BIND) -+ * otherwise date/time stamp of DLL bound to -+ * (Old BIND) -+ */ -+ DWORD ForwarderChain; /* -1 if no forwarders */ -+ DWORD Name; -+ /* RVA to IAT (if bound this IAT has actual addresses) */ -+ DWORD FirstThunk; -+} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR; -+ -+#define IMAGE_ORDINAL_FLAG32 0x80000000 -+#define IMAGE_ORDINAL_FLAG64 0x8000000000000000UL -+#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0) -+#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0) -+#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) -+ -+#ifdef CONFIG_X86_64 -+#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 -+#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL64 -+#else -+#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 -+#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL32 -+#endif -+ -+typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR -+{ -+ DWORD TimeDateStamp; -+ WORD OffsetModuleName; -+ WORD NumberOfModuleForwarderRefs; -+/* Array of zero or more IMAGE_BOUND_FORWARDER_REF follows */ -+} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR; -+ -+typedef struct _IMAGE_BOUND_FORWARDER_REF -+{ -+ DWORD TimeDateStamp; -+ WORD OffsetModuleName; -+ WORD Reserved; -+} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF; -+ -+typedef struct _IMAGE_BASE_RELOCATION -+{ -+ DWORD VirtualAddress; -+ DWORD SizeOfBlock; -+ WORD TypeOffset[0]; -+} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION; -+ -+typedef struct _IMAGE_RELOCATION -+{ -+ union { -+ DWORD VirtualAddress; -+ DWORD RelocCount; -+ } DUMMYUNIONNAME; -+ DWORD SymbolTableIndex; -+ WORD Type; -+} IMAGE_RELOCATION, *PIMAGE_RELOCATION; -+ -+#define IMAGE_SIZEOF_RELOCATION 10 -+ -+/* generic relocation types */ -+#define IMAGE_REL_BASED_ABSOLUTE 0 -+#define IMAGE_REL_BASED_HIGH 1 -+#define IMAGE_REL_BASED_LOW 2 -+#define IMAGE_REL_BASED_HIGHLOW 3 -+#define IMAGE_REL_BASED_HIGHADJ 4 -+#define IMAGE_REL_BASED_MIPS_JMPADDR 5 -+#define IMAGE_REL_BASED_SECTION 6 -+#define IMAGE_REL_BASED_REL 7 -+#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 -+#define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ -+#define IMAGE_REL_BASED_DIR64 10 -+#define IMAGE_REL_BASED_HIGH3ADJ 11 -+ -+/* I386 relocation types */ -+#define IMAGE_REL_I386_ABSOLUTE 0 -+#define IMAGE_REL_I386_DIR16 1 -+#define IMAGE_REL_I386_REL16 2 -+#define IMAGE_REL_I386_DIR32 6 -+#define IMAGE_REL_I386_DIR32NB 7 -+#define IMAGE_REL_I386_SEG12 9 -+#define IMAGE_REL_I386_SECTION 10 -+#define IMAGE_REL_I386_SECREL 11 -+#define IMAGE_REL_I386_REL32 20 -+ -+/* MIPS relocation types */ -+#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 -+#define IMAGE_REL_MIPS_REFHALF 0x0001 -+#define IMAGE_REL_MIPS_REFWORD 0x0002 -+#define IMAGE_REL_MIPS_JMPADDR 0x0003 -+#define IMAGE_REL_MIPS_REFHI 0x0004 -+#define IMAGE_REL_MIPS_REFLO 0x0005 -+#define IMAGE_REL_MIPS_GPREL 0x0006 -+#define IMAGE_REL_MIPS_LITERAL 0x0007 -+#define IMAGE_REL_MIPS_SECTION 0x000A -+#define IMAGE_REL_MIPS_SECREL 0x000B -+#define IMAGE_REL_MIPS_SECRELLO 0x000C -+#define IMAGE_REL_MIPS_SECRELHI 0x000D -+#define IMAGE_REL_MIPS_JMPADDR16 0x0010 -+#define IMAGE_REL_MIPS_REFWORDNB 0x0022 -+#define IMAGE_REL_MIPS_PAIR 0x0025 -+ -+/* ALPHA relocation types */ -+#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 -+#define IMAGE_REL_ALPHA_REFLONG 0x0001 -+#define IMAGE_REL_ALPHA_REFQUAD 0x0002 -+#define IMAGE_REL_ALPHA_GPREL 0x0003 -+#define IMAGE_REL_ALPHA_LITERAL 0x0004 -+#define IMAGE_REL_ALPHA_LITUSE 0x0005 -+#define IMAGE_REL_ALPHA_GPDISP 0x0006 -+#define IMAGE_REL_ALPHA_BRADDR 0x0007 -+#define IMAGE_REL_ALPHA_HINT 0x0008 -+#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 -+#define IMAGE_REL_ALPHA_REFHI 0x000A -+#define IMAGE_REL_ALPHA_REFLO 0x000B -+#define IMAGE_REL_ALPHA_PAIR 0x000C -+#define IMAGE_REL_ALPHA_MATCH 0x000D -+#define IMAGE_REL_ALPHA_SECTION 0x000E -+#define IMAGE_REL_ALPHA_SECREL 0x000F -+#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 -+#define IMAGE_REL_ALPHA_SECRELLO 0x0011 -+#define IMAGE_REL_ALPHA_SECRELHI 0x0012 -+#define IMAGE_REL_ALPHA_REFQ3 0x0013 -+#define IMAGE_REL_ALPHA_REFQ2 0x0014 -+#define IMAGE_REL_ALPHA_REFQ1 0x0015 -+#define IMAGE_REL_ALPHA_GPRELLO 0x0016 -+#define IMAGE_REL_ALPHA_GPRELHI 0x0017 -+ -+/* PowerPC relocation types */ -+#define IMAGE_REL_PPC_ABSOLUTE 0x0000 -+#define IMAGE_REL_PPC_ADDR64 0x0001 -+#define IMAGE_REL_PPC_ADDR 0x0002 -+#define IMAGE_REL_PPC_ADDR24 0x0003 -+#define IMAGE_REL_PPC_ADDR16 0x0004 -+#define IMAGE_REL_PPC_ADDR14 0x0005 -+#define IMAGE_REL_PPC_REL24 0x0006 -+#define IMAGE_REL_PPC_REL14 0x0007 -+#define IMAGE_REL_PPC_TOCREL16 0x0008 -+#define IMAGE_REL_PPC_TOCREL14 0x0009 -+#define IMAGE_REL_PPC_ADDR32NB 0x000A -+#define IMAGE_REL_PPC_SECREL 0x000B -+#define IMAGE_REL_PPC_SECTION 0x000C -+#define IMAGE_REL_PPC_IFGLUE 0x000D -+#define IMAGE_REL_PPC_IMGLUE 0x000E -+#define IMAGE_REL_PPC_SECREL16 0x000F -+#define IMAGE_REL_PPC_REFHI 0x0010 -+#define IMAGE_REL_PPC_REFLO 0x0011 -+#define IMAGE_REL_PPC_PAIR 0x0012 -+#define IMAGE_REL_PPC_SECRELLO 0x0013 -+#define IMAGE_REL_PPC_SECRELHI 0x0014 -+#define IMAGE_REL_PPC_GPREL 0x0015 -+#define IMAGE_REL_PPC_TYPEMASK 0x00FF -+/* modifier bits */ -+#define IMAGE_REL_PPC_NEG 0x0100 -+#define IMAGE_REL_PPC_BRTAKEN 0x0200 -+#define IMAGE_REL_PPC_BRNTAKEN 0x0400 -+#define IMAGE_REL_PPC_TOCDEFN 0x0800 -+ -+/* SH3 ? relocation type */ -+#define IMAGE_REL_SH3_ABSOLUTE 0x0000 -+#define IMAGE_REL_SH3_DIRECT16 0x0001 -+#define IMAGE_REL_SH3_DIRECT 0x0002 -+#define IMAGE_REL_SH3_DIRECT8 0x0003 -+#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 -+#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 -+#define IMAGE_REL_SH3_DIRECT4 0x0006 -+#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 -+#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 -+#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 -+#define IMAGE_REL_SH3_PCREL8_LONG 0x000A -+#define IMAGE_REL_SH3_PCREL12_WORD 0x000B -+#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C -+#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D -+#define IMAGE_REL_SH3_SECTION 0x000E -+#define IMAGE_REL_SH3_SECREL 0x000F -+#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 -+ -+/* ARM (Archimedes?) relocation types */ -+#define IMAGE_REL_ARM_ABSOLUTE 0x0000 -+#define IMAGE_REL_ARM_ADDR 0x0001 -+#define IMAGE_REL_ARM_ADDR32NB 0x0002 -+#define IMAGE_REL_ARM_BRANCH24 0x0003 -+#define IMAGE_REL_ARM_BRANCH11 0x0004 -+#define IMAGE_REL_ARM_SECTION 0x000E -+#define IMAGE_REL_ARM_SECREL 0x000F -+ -+/* IA64 relocation types */ -+#define IMAGE_REL_IA64_ABSOLUTE 0x0000 -+#define IMAGE_REL_IA64_IMM14 0x0001 -+#define IMAGE_REL_IA64_IMM22 0x0002 -+#define IMAGE_REL_IA64_IMM64 0x0003 -+#define IMAGE_REL_IA64_DIR 0x0004 -+#define IMAGE_REL_IA64_DIR64 0x0005 -+#define IMAGE_REL_IA64_PCREL21B 0x0006 -+#define IMAGE_REL_IA64_PCREL21M 0x0007 -+#define IMAGE_REL_IA64_PCREL21F 0x0008 -+#define IMAGE_REL_IA64_GPREL22 0x0009 -+#define IMAGE_REL_IA64_LTOFF22 0x000A -+#define IMAGE_REL_IA64_SECTION 0x000B -+#define IMAGE_REL_IA64_SECREL22 0x000C -+#define IMAGE_REL_IA64_SECREL64I 0x000D -+#define IMAGE_REL_IA64_SECREL 0x000E -+#define IMAGE_REL_IA64_LTOFF64 0x000F -+#define IMAGE_REL_IA64_DIR32NB 0x0010 -+#define IMAGE_REL_IA64_RESERVED_11 0x0011 -+#define IMAGE_REL_IA64_RESERVED_12 0x0012 -+#define IMAGE_REL_IA64_RESERVED_13 0x0013 -+#define IMAGE_REL_IA64_RESERVED_14 0x0014 -+#define IMAGE_REL_IA64_RESERVED_15 0x0015 -+#define IMAGE_REL_IA64_RESERVED_16 0x0016 -+#define IMAGE_REL_IA64_ADDEND 0x001F -+ -+/* archive format */ -+ -+#define IMAGE_ARCHIVE_START_SIZE 8 -+#define IMAGE_ARCHIVE_START "!\n" -+#define IMAGE_ARCHIVE_END "`\n" -+#define IMAGE_ARCHIVE_PAD "\n" -+#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " -+#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " -+ -+typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER -+{ -+ BYTE Name[16]; -+ BYTE Date[12]; -+ BYTE UserID[6]; -+ BYTE GroupID[6]; -+ BYTE Mode[8]; -+ BYTE Size[10]; -+ BYTE EndHeader[2]; -+} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; -+ -+#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 -+ -+/* -+ * Resource directory stuff -+ */ -+typedef struct _IMAGE_RESOURCE_DIRECTORY { -+ DWORD Characteristics; -+ DWORD TimeDateStamp; -+ WORD MajorVersion; -+ WORD MinorVersion; -+ WORD NumberOfNamedEntries; -+ WORD NumberOfIdEntries; -+ /* IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; */ -+} IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; -+ -+#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 -+#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 -+ -+typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { -+ union { -+ struct { -+#ifdef BITFIELDS_BIGENDIAN -+ unsigned NameIsString:1; -+ unsigned NameOffset:31; -+#else -+ unsigned NameOffset:31; -+ unsigned NameIsString:1; -+#endif -+ } DUMMYSTRUCTNAME1; -+ DWORD Name; -+ struct { -+#ifdef WORDS_BIGENDIAN -+ WORD __pad; -+ WORD Id; -+#else -+ WORD Id; -+ WORD __pad; -+#endif -+ } DUMMYSTRUCTNAME2; -+ } DUMMYUNIONNAME1; -+ union { -+ DWORD OffsetToData; -+ struct { -+#ifdef BITFIELDS_BIGENDIAN -+ unsigned DataIsDirectory:1; -+ unsigned OffsetToDirectory:31; -+#else -+ unsigned OffsetToDirectory:31; -+ unsigned DataIsDirectory:1; -+#endif -+ } DUMMYSTRUCTNAME3; -+ } DUMMYUNIONNAME2; -+} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; -+ -+ -+typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { -+ WORD Length; -+ CHAR NameString[ 1 ]; -+} IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/pnp.c linux-5.6.11-ndis/3rdparty/ndiswrapper/pnp.c ---- linux-5.6.11/3rdparty/ndiswrapper/pnp.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/pnp.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,697 @@ -+/* -+ * Copyright (C) 2005 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "usb.h" -+#include "pnp.h" -+#include "wrapndis.h" -+#include "loader.h" -+ -+/* Functions callable from the NDIS driver */ -+wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, -+ struct irp *irp); -+wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp); -+wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp); -+ -+static NTSTATUS start_pdo(struct device_object *pdo) -+{ -+ int i, ret, count, resources_size; -+ struct wrap_device *wd; -+ struct pci_dev *pdev; -+ struct cm_partial_resource_descriptor *entry; -+ struct cm_partial_resource_list *partial_resource_list; -+ -+ ENTER1("%p, %p", pdo, pdo->reserved); -+ wd = pdo->reserved; -+ if (ntoskernel_init_device(wd)) -+ EXIT1(return STATUS_FAILURE); -+ if (wrap_is_usb_bus(wd->dev_bus)) { -+ if (usb_init_device(wd)) { -+ ntoskernel_exit_device(wd); -+ EXIT1(return STATUS_FAILURE); -+ } -+ EXIT1(return STATUS_SUCCESS); -+ } -+ if (!wrap_is_pci_bus(wd->dev_bus)) -+ EXIT1(return STATUS_SUCCESS); -+ pdev = wd->pci.pdev; -+ ret = pci_enable_device(pdev); -+ if (ret) { -+ ERROR("couldn't enable PCI device: %x", ret); -+ return STATUS_FAILURE; -+ } -+ ret = pci_request_regions(pdev, DRIVER_NAME); -+ if (ret) { -+ ERROR("couldn't request PCI regions: %x", ret); -+ goto err_enable; -+ } -+ pci_set_power_state(pdev, PCI_D0); -+#ifdef CONFIG_X86_64 -+ /* 64-bit broadcom driver doesn't work if DMA is allocated -+ * from over 1GB */ -+ if (wd->vendor == 0x14e4) { -+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(30)) || -+ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(30))) -+ WARNING("couldn't set DMA mask; this driver " -+ "may not work with more than 1GB RAM"); -+ } -+#endif -+ /* IRQ resource entry is filled in from pdev, instead of -+ * pci_resource macros */ -+ for (i = count = 0; pci_resource_start(pdev, i); i++) -+ if ((pci_resource_flags(pdev, i) & IORESOURCE_MEM) || -+ (pci_resource_flags(pdev, i) & IORESOURCE_IO)) -+ count++; -+ /* space for entry for IRQ is already in -+ * cm_partial_resource_list */ -+ resources_size = sizeof(struct cm_resource_list) + -+ sizeof(struct cm_partial_resource_descriptor) * count; -+ TRACE2("resources: %d, %d", count, resources_size); -+ wd->resource_list = kzalloc(resources_size, GFP_KERNEL); -+ if (!wd->resource_list) { -+ WARNING("couldn't allocate memory"); -+ goto err_regions; -+ } -+ wd->resource_list->count = 1; -+ wd->resource_list->list[0].interface_type = PCIBus; -+ /* bus_number is not used by WDM drivers */ -+ wd->resource_list->list[0].bus_number = pdev->bus->number; -+ -+ partial_resource_list = -+ &wd->resource_list->list->partial_resource_list; -+ partial_resource_list->version = 1; -+ partial_resource_list->revision = 1; -+ partial_resource_list->count = count + 1; -+ -+ for (i = count = 0; pci_resource_start(pdev, i); i++) { -+ entry = &partial_resource_list->partial_descriptors[count]; -+ TRACE2("%d", count); -+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { -+ entry->type = CmResourceTypeMemory; -+ entry->flags = CM_RESOURCE_MEMORY_READ_WRITE; -+ entry->share = CmResourceShareDeviceExclusive; -+ } else if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { -+ entry->type = CmResourceTypePort; -+ entry->flags = CM_RESOURCE_PORT_IO; -+ entry->share = CmResourceShareDeviceExclusive; -+#if 0 -+ } else if (pci_resource_flags(pdev, i) & IORESOURCE_DMA) { -+ /* it looks like no driver uses this resource */ -+ typeof(pci_resource_flags(pdev, 0)) flags; -+ entry->type = CmResourceTypeDma; -+ flags = pci_resource_flags(pdev, i); -+ if (flags & IORESOURCE_DMA_TYPEA) -+ entry->flags |= CM_RESOURCE_DMA_TYPE_A; -+ else if (flags & IORESOURCE_DMA_TYPEB) -+ entry->flags |= CM_RESOURCE_DMA_TYPE_B; -+ else if (flags & IORESOURCE_DMA_TYPEF) -+ entry->flags |= CM_RESOURCE_DMA_TYPE_F; -+ if (flags & IORESOURCE_DMA_8BIT) -+ entry->flags |= CM_RESOURCE_DMA_8; -+ else if (flags & IORESOURCE_DMA_16BIT) -+ entry->flags |= CM_RESOURCE_DMA_16; -+ /* what about 32bit DMA? */ -+ else if (flags & IORESOURCE_DMA_8AND16BIT) -+ entry->flags |= CM_RESOURCE_DMA_8_AND_16; -+ if (flags & IORESOURCE_DMA_MASTER) -+ entry->flags |= CM_RESOURCE_DMA_BUS_MASTER; -+ entry->u.dma.channel = pci_resource_start(pdev, i); -+ /* what should this be? */ -+ entry->u.dma.port = 1; -+#endif -+ } else -+ continue; -+ /* TODO: Add other resource types? */ -+ entry->u.generic.start = -+ (ULONG_PTR)pci_resource_start(pdev, i); -+ entry->u.generic.length = pci_resource_len(pdev, i); -+ count++; -+ } -+ -+ /* put IRQ resource at the end */ -+ entry = &partial_resource_list->partial_descriptors[count++]; -+ entry->type = CmResourceTypeInterrupt; -+ entry->flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; -+ /* we assume all devices use shared IRQ */ -+ entry->share = CmResourceShareShared; -+ /* as per documentation, interrupt level should be DIRQL, but -+ * examples from DDK as well some drivers, such as AR5211, -+ * RT8180L use interrupt level as interrupt vector also in -+ * NdisMRegisterInterrupt */ -+ entry->u.interrupt.level = pdev->irq; -+ entry->u.interrupt.vector = pdev->irq; -+ entry->u.interrupt.affinity = -1; -+ -+ TRACE2("resource list count %d, irq: %d", -+ partial_resource_list->count, pdev->irq); -+ pci_set_drvdata(pdev, wd); -+ EXIT1(return STATUS_SUCCESS); -+err_regions: -+ pci_release_regions(pdev); -+err_enable: -+ pci_disable_device(pdev); -+ wd->pci.pdev = NULL; -+ wd->pdo = NULL; -+ EXIT1(return STATUS_FAILURE); -+} -+ -+static void remove_pdo(struct device_object *pdo) -+{ -+ struct wrap_device *wd = pdo->reserved; -+ -+ ntoskernel_exit_device(wd); -+ if (wrap_is_pci_bus(wd->dev_bus)) { -+ struct pci_dev *pdev = wd->pci.pdev; -+ pci_release_regions(pdev); -+ pci_disable_device(pdev); -+ wd->pci.pdev = NULL; -+ pci_set_drvdata(pdev, NULL); -+ } else if (wrap_is_usb_bus(wd->dev_bus)) { -+ usb_exit_device(wd); -+ } -+ kfree(wd->resource_list); -+ wd->resource_list = NULL; -+ return; -+} -+ -+static NTSTATUS IoSendIrpTopDev(struct device_object *dev_obj, ULONG major_fn, -+ ULONG minor_fn, struct io_stack_location *sl) -+{ -+ NTSTATUS status; -+ struct nt_event event; -+ struct irp *irp; -+ struct io_stack_location *irp_sl; -+ struct device_object *top_dev = IoGetAttachedDeviceReference(dev_obj); -+ -+ KeInitializeEvent(&event, NotificationEvent, FALSE); -+ irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, top_dev, NULL, 0, NULL, -+ &event, NULL); -+ irp->io_status.status = STATUS_NOT_IMPLEMENTED; -+ irp->io_status.info = 0; -+ irp_sl = IoGetNextIrpStackLocation(irp); -+ if (sl) -+ memcpy(irp_sl, sl, sizeof(*irp_sl)); -+ irp_sl->major_fn = major_fn; -+ irp_sl->minor_fn = minor_fn; -+ status = IoCallDriver(top_dev, irp); -+ if (status == STATUS_PENDING) { -+ KeWaitForSingleObject(&event, Executive, KernelMode, -+ FALSE, NULL); -+ status = irp->io_status.status; -+ } -+ ObDereferenceObject(top_dev); -+ return status; -+} -+ -+wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, -+ struct irp *irp) -+{ -+ NTSTATUS status; -+ struct wrap_device *wd = pdo->reserved; -+ -+ DUMP_IRP(irp); -+ (void)wd; -+ if (wrap_is_usb_bus(wd->dev_bus)) { -+ status = wrap_submit_irp(pdo, irp); -+ IOTRACE("status: %08X", status); -+ if (status != STATUS_PENDING) -+ IoCompleteRequest(irp, IO_NO_INCREMENT); -+ } else { -+ status = irp->io_status.status = STATUS_NOT_IMPLEMENTED; -+ IoCompleteRequest(irp, IO_NO_INCREMENT); -+ } -+ IOEXIT(return status); -+} -+WIN_FUNC_DECL(pdoDispatchDeviceControl,2) -+ -+wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp) -+{ -+ struct io_stack_location *irp_sl; -+ NTSTATUS status; -+ struct wrap_device *wd = pdo->reserved; -+ -+ irp_sl = IoGetCurrentIrpStackLocation(irp); -+ TRACE2("%p %d:%d", pdo, irp_sl->major_fn, irp_sl->minor_fn); -+ switch (irp_sl->minor_fn) { -+ case IRP_MN_START_DEVICE: -+ status = start_pdo(pdo); -+ break; -+ case IRP_MN_QUERY_STOP_DEVICE: -+ case IRP_MN_STOP_DEVICE: -+ case IRP_MN_QUERY_REMOVE_DEVICE: -+ status = STATUS_SUCCESS; -+ break; -+ case IRP_MN_REMOVE_DEVICE: -+ remove_pdo(pdo); -+ status = STATUS_SUCCESS; -+ break; -+ case IRP_MN_QUERY_INTERFACE: -+ if (wrap_is_usb_bus(wd->dev_bus)) -+ status = usb_query_interface(wd, irp_sl); -+ else -+ status = STATUS_NOT_IMPLEMENTED; -+ break; -+ default: -+ TRACE2("fn %d not implemented", irp_sl->minor_fn); -+ status = STATUS_SUCCESS; -+ break; -+ } -+ irp->io_status.status = status; -+ TRACE2("status: %08X", status); -+ IoCompleteRequest(irp, IO_NO_INCREMENT); -+ IOEXIT(return status); -+} -+WIN_FUNC_DECL(pdoDispatchPnp,2) -+ -+wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp) -+{ -+ struct io_stack_location *irp_sl; -+ struct wrap_device *wd; -+ union power_state power_state; -+ struct pci_dev *pdev; -+ NTSTATUS status; -+ -+ irp_sl = IoGetCurrentIrpStackLocation(irp); -+ wd = pdo->reserved; -+ TRACE2("pdo: %p, fn: %d:%d, wd: %p", -+ pdo, irp_sl->major_fn, irp_sl->minor_fn, wd); -+ switch (irp_sl->minor_fn) { -+ case IRP_MN_WAIT_WAKE: -+ /* TODO: this is not complete/correct */ -+ TRACE2("state: %d, completion: %p", -+ irp_sl->params.power.state.system_state, -+ irp_sl->completion_routine); -+ IoMarkIrpPending(irp); -+ status = STATUS_PENDING; -+ break; -+ case IRP_MN_SET_POWER: -+ power_state = irp_sl->params.power.state; -+ if (power_state.device_state == PowerDeviceD0) { -+ TRACE2("resuming %p", wd); -+ if (wrap_is_pci_bus(wd->dev_bus)) { -+ pdev = wd->pci.pdev; -+ pci_restore_state(pdev); -+ if (wd->pci.wake_state == PowerDeviceD3) { -+ pci_enable_wake(wd->pci.pdev, -+ PCI_D3hot, 0); -+ pci_enable_wake(wd->pci.pdev, -+ PCI_D3cold, 0); -+ } -+ pci_set_power_state(pdev, PCI_D0); -+ } else if (wrap_is_usb_bus(wd->dev_bus)) { -+ wrap_resume_urbs(wd); -+ } -+ } else { -+ TRACE2("suspending device %p", wd); -+ if (wrap_is_pci_bus(wd->dev_bus)) { -+ pdev = wd->pci.pdev; -+ pci_save_state(pdev); -+ TRACE2("%d", wd->pci.wake_state); -+ if (wd->pci.wake_state == PowerDeviceD3) { -+ pci_enable_wake(wd->pci.pdev, -+ PCI_D3hot, 1); -+ pci_enable_wake(wd->pci.pdev, -+ PCI_D3cold, 1); -+ } -+ pci_set_power_state(pdev, PCI_D3hot); -+ } else if (wrap_is_usb_bus(wd->dev_bus)) { -+ wrap_suspend_urbs(wd); -+ } -+ } -+ status = STATUS_SUCCESS; -+ break; -+ case IRP_MN_QUERY_POWER: -+ status = STATUS_SUCCESS; -+ break; -+ default: -+ TRACE2("fn %d not implemented", irp_sl->minor_fn); -+ status = STATUS_SUCCESS; -+ break; -+ } -+ irp->io_status.status = status; -+ IoCompleteRequest(irp, IO_NO_INCREMENT); -+ return status; -+} -+WIN_FUNC_DECL(pdoDispatchPower,2) -+ -+static NTSTATUS pnp_set_device_power_state(struct wrap_device *wd, -+ enum device_power_state state) -+{ -+ NTSTATUS status; -+ struct device_object *pdo; -+ struct io_stack_location irp_sl; -+ -+ pdo = wd->pdo; -+ IOTRACE("%p, %p", pdo, IoGetAttachedDevice(pdo)); -+ memset(&irp_sl, 0, sizeof(irp_sl)); -+ irp_sl.params.power.state.device_state = state; -+ irp_sl.params.power.type = DevicePowerState; -+ if (state > PowerDeviceD0) { -+ status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_QUERY_POWER, -+ &irp_sl); -+ if (status != STATUS_SUCCESS) { -+ TRACE1("query of power to %d returns %08X", -+ state, status); -+ EXIT1(return status); -+ } -+ } -+ status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_SET_POWER, &irp_sl); -+ if (status != STATUS_SUCCESS) -+ WARNING("setting power to %d failed: %08X", state, status); -+ EXIT1(return status); -+} -+ -+static NTSTATUS pnp_start_device(struct wrap_device *wd) -+{ -+ struct device_object *fdo; -+ struct device_object *pdo; -+ struct io_stack_location irp_sl; -+ NTSTATUS status; -+ -+ pdo = wd->pdo; -+ /* TODO: for now we use same resources for both translated -+ * resources and raw resources */ -+ memset(&irp_sl, 0, sizeof(irp_sl)); -+ irp_sl.params.start_device.allocated_resources = -+ wd->resource_list; -+ irp_sl.params.start_device.allocated_resources_translated = -+ wd->resource_list; -+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_START_DEVICE, &irp_sl); -+ fdo = IoGetAttachedDevice(pdo); -+ fdo->drv_obj->drv_ext->count++; -+ if (status != STATUS_SUCCESS) -+ WARNING("Windows driver couldn't initialize the device (%08X)", -+ status); -+ EXIT1(return status); -+} -+ -+#if 0 -+static NTSTATUS pnp_stop_device(struct wrap_device *wd) -+{ -+ struct device_object *pdo; -+ NTSTATUS status; -+ -+ pdo = wd->pdo; -+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_STOP_DEVICE, -+ NULL); -+ if (status != STATUS_SUCCESS) -+ WARNING("status: %08X", status); -+ /* for now we ignore query status */ -+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_STOP_DEVICE, NULL); -+ if (status != STATUS_SUCCESS) -+ WARNING("status: %08X", status); -+ if (status != STATUS_SUCCESS) -+ WARNING("status: %08X", status); -+ EXIT2(return status); -+} -+#endif -+ -+static NTSTATUS pnp_remove_device(struct wrap_device *wd) -+{ -+ struct device_object *pdo, *fdo; -+ struct driver_object *fdo_drv_obj; -+ NTSTATUS status; -+ -+ pdo = wd->pdo; -+ fdo = IoGetAttachedDevice(pdo); -+ fdo_drv_obj = fdo->drv_obj; -+ TRACE2("%p, %p, %p", pdo, fdo, fdo_drv_obj); -+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_REMOVE_DEVICE, -+ NULL); -+ if (status != STATUS_SUCCESS) -+ WARNING("status: %08X", status); -+ -+ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE, NULL); -+ if (status != STATUS_SUCCESS) -+ WARNING("status: %08X", status); -+ /* TODO: should we use count in drv_ext or driver's Object -+ * header reference count to keep count of devices associated -+ * with a driver? */ -+ if (status == STATUS_SUCCESS) -+ fdo_drv_obj->drv_ext->count--; -+ TRACE1("count: %d", fdo_drv_obj->drv_ext->count); -+ if ((LONG)fdo_drv_obj->drv_ext->count < 0) -+ WARNING("wrong count: %d", fdo_drv_obj->drv_ext->count); -+ if (fdo_drv_obj->drv_ext->count == 0) { -+ struct wrap_driver *wrap_driver; -+ TRACE1("unloading driver: %p", fdo_drv_obj); -+ wrap_driver = -+ IoGetDriverObjectExtension(fdo_drv_obj, -+ (void *)WRAP_DRIVER_CLIENT_ID); -+ if (fdo_drv_obj->unload) -+ LIN2WIN1(fdo_drv_obj->unload, fdo_drv_obj); -+ if (wrap_driver) { -+ mutex_lock(&loader_mutex); -+ unload_wrap_driver(wrap_driver); -+ mutex_unlock(&loader_mutex); -+ } else -+ ERROR("couldn't get wrap_driver"); -+ ObDereferenceObject(fdo_drv_obj); -+ } -+ IoDeleteDevice(pdo); -+ unload_wrap_device(wd); -+ EXIT1(return status); -+} -+ -+WIN_FUNC_DECL(IoInvalidDeviceRequest,2) -+ -+static struct device_object *alloc_pdo(struct driver_object *drv_obj) -+{ -+ struct device_object *pdo; -+ NTSTATUS status; -+ int i; -+ struct ansi_string ansi_name; -+ struct unicode_string unicode_name; -+ -+ RtlInitAnsiString(&ansi_name, "NDISpdo"); -+ if (RtlAnsiStringToUnicodeString(&unicode_name, &ansi_name, TRUE) == -+ STATUS_SUCCESS) { -+ status = IoCreateDevice(drv_obj, 0, &unicode_name, -+ FILE_DEVICE_UNKNOWN, -+ FILE_AUTOGENERATED_DEVICE_NAME, -+ FALSE, &pdo); -+ RtlFreeUnicodeString(&unicode_name); -+ } else { -+ status = IoCreateDevice(drv_obj, 0, NULL, -+ FILE_DEVICE_UNKNOWN, -+ FILE_AUTOGENERATED_DEVICE_NAME, -+ FALSE, &pdo); -+ } -+ TRACE1("%p, %d, %p", drv_obj, status, pdo); -+ if (status != STATUS_SUCCESS) -+ return NULL; -+ /* dispatch routines are called as Windows functions */ -+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) -+ drv_obj->major_func[i] = WIN_FUNC_PTR(IoInvalidDeviceRequest,2); -+ drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] = -+ WIN_FUNC_PTR(pdoDispatchDeviceControl,2); -+ drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = -+ WIN_FUNC_PTR(pdoDispatchDeviceControl,2); -+ drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(pdoDispatchPower,2); -+ drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(pdoDispatchPnp,2); -+ return pdo; -+} -+ -+static int wrap_pnp_start_device(struct wrap_device *wd) -+{ -+ struct wrap_driver *driver; -+ struct device_object *pdo; -+ struct driver_object *pdo_drv_obj; -+ -+ ENTER1("wd: %p", wd); -+ -+ if (!((wrap_is_pci_bus(wd->dev_bus)) || -+ (wrap_is_usb_bus(wd->dev_bus)))) { -+ ERROR("bus type %d (%d) not supported", -+ WRAP_BUS(wd->dev_bus), wd->dev_bus); -+ EXIT1(return -EINVAL); -+ } -+ driver = load_wrap_driver(wd); -+ if (!driver) -+ return -ENODEV; -+ -+ wd->driver = driver; -+ wd->dev_bus = WRAP_DEVICE_BUS(driver->dev_type, WRAP_BUS(wd->dev_bus)); -+ TRACE1("dev type: %d, bus type: %d, %d", WRAP_DEVICE(wd->dev_bus), -+ WRAP_BUS(wd->dev_bus), wd->dev_bus); -+ TRACE1("%d, %d", driver->dev_type, wrap_is_usb_bus(wd->dev_bus)); -+ /* first create pdo */ -+ if (wrap_is_pci_bus(wd->dev_bus)) -+ pdo_drv_obj = find_bus_driver("PCI"); -+ else // if (wrap_is_usb_bus(wd->dev_bus)) -+ pdo_drv_obj = find_bus_driver("USB"); -+ if (!pdo_drv_obj) -+ return -EINVAL; -+ pdo = alloc_pdo(pdo_drv_obj); -+ if (!pdo) -+ return -ENOMEM; -+ wd->pdo = pdo; -+ pdo->reserved = wd; -+ if (WRAP_DEVICE(wd->dev_bus) == WRAP_NDIS_DEVICE) { -+ if (init_ndis_driver(driver->drv_obj)) { -+ IoDeleteDevice(pdo); -+ return -EINVAL; -+ } -+ } -+ TRACE1("%p", driver->drv_obj->drv_ext->add_device); -+ if (driver->drv_obj->drv_ext->add_device(driver->drv_obj, pdo) != -+ STATUS_SUCCESS) { -+ IoDeleteDevice(pdo); -+ return -ENOMEM; -+ } -+ if (pnp_start_device(wd) != STATUS_SUCCESS) { -+ /* TODO: we need proper cleanup, to deallocate memory, -+ * for example */ -+ pnp_remove_device(wd); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+int wrap_pnp_start_pci_device(struct pci_dev *pdev, -+ const struct pci_device_id *ent) -+{ -+ struct load_device load_device; -+ struct wrap_device *wd; -+ -+ ENTER1("called for %04x:%04x:%04x:%04x", pdev->vendor, pdev->device, -+ pdev->subsystem_vendor, pdev->subsystem_device); -+ -+ load_device.bus = WRAP_PCI_BUS; -+ load_device.vendor = pdev->vendor; -+ load_device.device = pdev->device; -+ load_device.subvendor = pdev->subsystem_vendor; -+ load_device.subdevice = pdev->subsystem_device; -+ wd = load_wrap_device(&load_device); -+ if (!wd) -+ EXIT1(return -ENODEV); -+ wd->pci.pdev = pdev; -+ return wrap_pnp_start_device(wd); -+} -+ -+void wrap_pnp_remove_pci_device(struct pci_dev *pdev) -+{ -+ struct wrap_device *wd; -+ -+ wd = (struct wrap_device *)pci_get_drvdata(pdev); -+ ENTER1("%p, %p", pdev, wd); -+ if (!wd) -+ EXIT1(return); -+ pnp_remove_device(wd); -+} -+ -+int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state) -+{ -+ struct wrap_device *wd; -+ -+ wd = (struct wrap_device *)pci_get_drvdata(pdev); -+ return pnp_set_device_power_state(wd, PowerDeviceD3); -+} -+ -+int wrap_pnp_resume_pci_device(struct pci_dev *pdev) -+{ -+ struct wrap_device *wd; -+ -+ wd = (struct wrap_device *)pci_get_drvdata(pdev); -+ return pnp_set_device_power_state(wd, PowerDeviceD0); -+} -+ -+#ifdef ENABLE_USB -+int wrap_pnp_start_usb_device(struct usb_interface *intf, -+ const struct usb_device_id *usb_id) -+{ -+ struct wrap_device *wd; -+ int ret; -+ struct usb_device *udev = interface_to_usbdev(intf); -+ ENTER1("%04x, %04x, %04x", udev->descriptor.idVendor, -+ udev->descriptor.idProduct, udev->descriptor.bDeviceClass); -+ -+ /* USB device (e.g., RNDIS) may have multiple interfaces; -+ initialize one interface only (is there a way to know which -+ of these interfaces is for network?) */ -+ -+ if ((wd = get_wrap_device(udev, WRAP_USB_BUS))) { -+ TRACE1("device already initialized: %p", wd); -+ usb_set_intfdata(intf, NULL); -+ ret = 0; -+ } else { -+ struct load_device load_device; -+ -+ load_device.bus = WRAP_USB_BUS; -+ load_device.vendor = le16_to_cpu(udev->descriptor.idVendor); -+ load_device.device = le16_to_cpu(udev->descriptor.idProduct); -+ load_device.subvendor = 0; -+ load_device.subdevice = 0; -+ wd = load_wrap_device(&load_device); -+ TRACE2("%p", wd); -+ if (wd) { -+ /* some devices (e.g., TI 4150, RNDIS) need -+ * full reset */ -+ ret = usb_reset_device(udev); -+ if (ret) -+ WARNING("reset failed: %d", ret); -+ usb_set_intfdata(intf, wd); -+ wd->usb.intf = intf; -+ wd->usb.udev = udev; -+ ret = wrap_pnp_start_device(wd); -+ } else -+ ret = -ENODEV; -+ } -+ -+ TRACE2("ret: %d", ret); -+ if (ret) -+ EXIT1(return ret); -+ else -+ return 0; -+} -+ -+void wrap_pnp_remove_usb_device(struct usb_interface *intf) -+{ -+ struct wrap_device *wd; -+ -+ wd = (struct wrap_device *)usb_get_intfdata(intf); -+ TRACE1("%p, %p", intf, wd); -+ if (wd == NULL) -+ EXIT1(return); -+ usb_set_intfdata(intf, NULL); -+ wd->usb.intf = NULL; -+ pnp_remove_device(wd); -+} -+ -+int wrap_pnp_suspend_usb_device(struct usb_interface *intf, pm_message_t state) -+{ -+ struct wrap_device *wd; -+ -+ wd = usb_get_intfdata(intf); -+ ENTER1("%p, %p", intf, wd); -+ if (!wd) -+ EXIT1(return 0); -+ if (pnp_set_device_power_state(wd, PowerDeviceD3)) -+ return -1; -+ return 0; -+} -+ -+int wrap_pnp_resume_usb_device(struct usb_interface *intf) -+{ -+ struct wrap_device *wd; -+ wd = usb_get_intfdata(intf); -+ ENTER1("%p, %p", intf, wd); -+ if (!wd) -+ EXIT1(return 0); -+ if (pnp_set_device_power_state(wd, PowerDeviceD0)) -+ return -1; -+ return 0; -+} -+ -+#endif // USB -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/pnp.h linux-5.6.11-ndis/3rdparty/ndiswrapper/pnp.h ---- linux-5.6.11/3rdparty/ndiswrapper/pnp.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/pnp.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,36 @@ -+/* -+ * Copyright (C) 2005 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _PNP_H_ -+#define _PNP_H_ -+ -+#include "ntoskernel.h" -+#include "ndis.h" -+#include "wrapndis.h" -+ -+int wrap_pnp_start_pci_device(struct pci_dev *pdev, -+ const struct pci_device_id *ent); -+void wrap_pnp_remove_pci_device(struct pci_dev *pdev); -+int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state); -+int wrap_pnp_resume_pci_device(struct pci_dev *pdev); -+ -+int wrap_pnp_start_usb_device(struct usb_interface *intf, -+ const struct usb_device_id *usb_id); -+void wrap_pnp_remove_usb_device(struct usb_interface *intf); -+int wrap_pnp_suspend_usb_device(struct usb_interface *intf, -+ pm_message_t state); -+int wrap_pnp_resume_usb_device(struct usb_interface *intf); -+ -+#endif -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/proc.c linux-5.6.11-ndis/3rdparty/ndiswrapper/proc.c ---- linux-5.6.11/3rdparty/ndiswrapper/proc.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/proc.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,619 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+#include -+#include -+#include -+#include -+ -+#include "ndis.h" -+#include "iw_ndis.h" -+#include "wrapndis.h" -+#include "pnp.h" -+#include "wrapper.h" -+ -+#define MAX_PROC_STR_LEN 32 -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) -+static kuid_t proc_kuid; -+static kgid_t proc_kgid; -+#else -+#define proc_kuid proc_uid -+#define proc_kgid proc_gid -+#define kuid_t uid_t -+#define kgid_t gid_t -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -+static inline struct inode *file_inode(struct file *f) -+{ -+ return f->f_dentry->d_inode; -+} -+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) -+static inline struct inode *file_inode(struct file *f) -+{ -+ return f->f_path.dentry->d_inode; -+} -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -+static inline void proc_set_user(struct proc_dir_entry *de, kuid_t uid, -+ kgid_t gid) -+{ -+ de->uid = uid; -+ de->gid = gid; -+} -+ -+static inline void proc_remove(struct proc_dir_entry *de) -+{ -+ if (de) -+ remove_proc_entry(de->name, de->parent); -+} -+ -+static inline void *PDE_DATA(const struct inode *inode) -+{ -+ return PDE(inode)->data; -+} -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) -+static inline struct proc_dir_entry *proc_create_data(const char *name, -+ umode_t mode, struct proc_dir_entry *parent, -+ struct file_operations *fops, void *data) -+{ -+ struct proc_dir_entry *de; -+ -+ de = create_proc_entry(name, mode, parent); -+ if (de) { -+ de->data = data; -+ de->proc_fops = fops; -+ } -+ -+ return de; -+} -+#endif -+ -+static int do_proc_make_entry(const char *name, umode_t mode, -+ struct proc_dir_entry *parent, -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) -+ const struct proc_ops *fops, -+#else -+ struct file_operations *fops, -+#endif -+ kuid_t uid, kgid_t gid, struct ndis_device *wnd) -+{ -+ struct proc_dir_entry *de; -+ -+ de = proc_create_data(name, mode, parent, fops, wnd); -+ if (de == NULL) { -+ ERROR("couldn't create proc entry for '%s'", name); -+ return -ENOMEM; -+ } -+ proc_set_user(de, uid, gid); -+ return 0; -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) -+#define PROC_DECLARE_RO(name) \ -+ static int proc_##name##_open(struct inode *inode, struct file *file) \ -+ { \ -+ return single_open(file, proc_##name##_read, PDE_DATA(inode)); \ -+ } \ -+ static const struct proc_ops name##_fops = { \ -+ .proc_open = proc_##name##_open, \ -+ .proc_read = seq_read, \ -+ .proc_lseek = seq_lseek, \ -+ .proc_release = single_release, \ -+ }; -+ -+#define PROC_DECLARE_RW(name) \ -+ static int proc_##name##_open(struct inode *inode, struct file *file) \ -+ { \ -+ return single_open(file, proc_##name##_read, PDE_DATA(inode)); \ -+ } \ -+ static const struct proc_ops name##_fops = { \ -+ .proc_open = proc_##name##_open, \ -+ .proc_read = seq_read, \ -+ .proc_lseek = seq_lseek, \ -+ .proc_release = single_release, \ -+ .proc_write = proc_##name##_write, \ -+ }; -+#else -+#define PROC_DECLARE_RO(name) \ -+ static int proc_##name##_open(struct inode *inode, struct file *file) \ -+ { \ -+ return single_open(file, proc_##name##_read, PDE_DATA(inode)); \ -+ } \ -+ static struct file_operations name##_fops = { \ -+ .owner = THIS_MODULE, \ -+ .open = proc_##name##_open, \ -+ .read = seq_read, \ -+ .llseek = seq_lseek, \ -+ .release = single_release, \ -+ }; -+ -+#define PROC_DECLARE_RW(name) \ -+ static int proc_##name##_open(struct inode *inode, struct file *file) \ -+ { \ -+ return single_open(file, proc_##name##_read, PDE_DATA(inode)); \ -+ } \ -+ static struct file_operations name##_fops = { \ -+ .owner = THIS_MODULE, \ -+ .open = proc_##name##_open, \ -+ .read = seq_read, \ -+ .llseek = seq_lseek, \ -+ .release = single_release, \ -+ .write = proc_##name##_write, \ -+ }; -+#endif -+ -+#define proc_make_entry_ro(name, parent, wnd) \ -+ do_proc_make_entry(#name, S_IFREG | S_IRUSR | S_IRGRP, parent, \ -+ &name##_fops, proc_kuid, proc_kgid, wnd) -+#define proc_make_entry_rw(name, parent, wnd) \ -+ do_proc_make_entry(#name, \ -+ S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP, \ -+ parent, &name##_fops, proc_kuid, proc_kgid, wnd) -+ -+#define add_text(fmt, ...) seq_printf(sf, fmt, ##__VA_ARGS__) -+ -+static struct proc_dir_entry *wrap_procfs_entry; -+ -+static int proc_stats_read(struct seq_file *sf, void *v) -+{ -+ struct ndis_device *wnd = (struct ndis_device *)sf->private; -+ struct ndis_wireless_stats stats; -+ NDIS_STATUS res; -+ ndis_rssi rssi; -+ -+ res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi)); -+ if (!res) -+ add_text("signal_level=%d dBm\n", (s32)rssi); -+ -+ res = mp_query(wnd, OID_802_11_STATISTICS, &stats, sizeof(stats)); -+ if (!res) { -+ add_text("tx_frames=%llu\n", stats.tx_frag); -+ add_text("tx_multicast_frames=%llu\n", stats.tx_multi_frag); -+ add_text("tx_failed=%llu\n", stats.failed); -+ add_text("tx_retry=%llu\n", stats.retry); -+ add_text("tx_multi_retry=%llu\n", stats.multi_retry); -+ add_text("tx_rtss_success=%llu\n", stats.rtss_succ); -+ add_text("tx_rtss_fail=%llu\n", stats.rtss_fail); -+ add_text("ack_fail=%llu\n", stats.ack_fail); -+ add_text("frame_duplicates=%llu\n", stats.frame_dup); -+ add_text("rx_frames=%llu\n", stats.rx_frag); -+ add_text("rx_multicast_frames=%llu\n", stats.rx_multi_frag); -+ add_text("fcs_errors=%llu\n", stats.fcs_err); -+ } -+ -+ return 0; -+} -+ -+PROC_DECLARE_RO(stats) -+ -+static int proc_encr_read(struct seq_file *sf, void *v) -+{ -+ struct ndis_device *wnd = (struct ndis_device *)sf->private; -+ int i, encr_status, auth_mode, infra_mode; -+ NDIS_STATUS res; -+ struct ndis_essid essid; -+ mac_address ap_address; -+ -+ res = mp_query(wnd, OID_802_11_BSSID, -+ &ap_address, sizeof(ap_address)); -+ if (res) -+ memset(ap_address, 0, ETH_ALEN); -+ add_text("ap_address=" MACSTRSEP "\n", MAC2STR(ap_address)); -+ -+ res = mp_query(wnd, OID_802_11_SSID, &essid, sizeof(essid)); -+ if (!res) -+ add_text("essid=%.*s\n", essid.length, essid.essid); -+ -+ res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &encr_status); -+ if (!res) { -+ typeof(&wnd->encr_info.keys[0]) tx_key; -+ add_text("tx_key=%u\n", wnd->encr_info.tx_key_index); -+ add_text("key="); -+ tx_key = &wnd->encr_info.keys[wnd->encr_info.tx_key_index]; -+ if (tx_key->length > 0) -+ for (i = 0; i < tx_key->length; i++) -+ add_text("%2.2X", tx_key->key[i]); -+ else -+ add_text("off"); -+ add_text("\n"); -+ add_text("encr_mode=%d\n", encr_status); -+ } -+ res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &auth_mode); -+ if (!res) -+ add_text("auth_mode=%d\n", auth_mode); -+ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &infra_mode); -+ add_text("mode=%s\n", (infra_mode == Ndis802_11IBSS) ? "adhoc" : -+ (infra_mode == Ndis802_11Infrastructure) ? "managed" : "auto"); -+ -+ return 0; -+} -+ -+PROC_DECLARE_RO(encr) -+ -+static int proc_hw_read(struct seq_file *sf, void *v) -+{ -+ struct ndis_device *wnd = (struct ndis_device *)sf->private; -+ struct ndis_configuration config; -+ enum ndis_power power_mode; -+ NDIS_STATUS res; -+ ndis_tx_power_level tx_power; -+ ULONG bit_rate; -+ ndis_rts_threshold rts_threshold; -+ ndis_fragmentation_threshold frag_threshold; -+ ndis_antenna antenna; -+ ULONG packet_filter; -+ int n; -+ mac_address mac; -+ char *hw_status[] = {"ready", "initializing", "resetting", "closing", -+ "not ready"}; -+ -+ res = mp_query_int(wnd, OID_GEN_HARDWARE_STATUS, &n); -+ if (res == NDIS_STATUS_SUCCESS && n >= 0 && n < ARRAY_SIZE(hw_status)) -+ add_text("status=%s\n", hw_status[n]); -+ -+ res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac)); -+ if (!res) -+ add_text("mac: " MACSTRSEP "\n", MAC2STR(mac)); -+ res = mp_query(wnd, OID_802_11_CONFIGURATION, &config, sizeof(config)); -+ if (!res) { -+ add_text("beacon_period=%u msec\n", config.beacon_period); -+ add_text("atim_window=%u msec\n", config.atim_window); -+ add_text("frequency=%u kHz\n", config.ds_config); -+ add_text("hop_pattern=%u\n", config.fh_config.hop_pattern); -+ add_text("hop_set=%u\n", config.fh_config.hop_set); -+ add_text("dwell_time=%u msec\n", config.fh_config.dwell_time); -+ } -+ -+ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, -+ &tx_power, sizeof(tx_power)); -+ if (!res) -+ add_text("tx_power=%u mW\n", tx_power); -+ -+ res = mp_query(wnd, OID_GEN_LINK_SPEED, &bit_rate, sizeof(bit_rate)); -+ if (!res) -+ add_text("bit_rate=%u kBps\n", (u32)bit_rate / 10); -+ -+ res = mp_query(wnd, OID_802_11_RTS_THRESHOLD, -+ &rts_threshold, sizeof(rts_threshold)); -+ if (!res) -+ add_text("rts_threshold=%u bytes\n", rts_threshold); -+ -+ res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, -+ &frag_threshold, sizeof(frag_threshold)); -+ if (!res) -+ add_text("frag_threshold=%u bytes\n", frag_threshold); -+ -+ res = mp_query_int(wnd, OID_802_11_POWER_MODE, &power_mode); -+ if (!res) -+ add_text("power_mode=%s\n", -+ (power_mode == NDIS_POWER_OFF) ? "always_on" : -+ (power_mode == NDIS_POWER_MAX) ? "max_savings" : -+ "min_savings"); -+ -+ res = mp_query(wnd, OID_802_11_NUMBER_OF_ANTENNAS, -+ &antenna, sizeof(antenna)); -+ if (!res) -+ add_text("num_antennas=%u\n", antenna); -+ -+ res = mp_query(wnd, OID_802_11_TX_ANTENNA_SELECTED, -+ &antenna, sizeof(antenna)); -+ if (!res) -+ add_text("tx_antenna=%u\n", antenna); -+ -+ res = mp_query(wnd, OID_802_11_RX_ANTENNA_SELECTED, -+ &antenna, sizeof(antenna)); -+ if (!res) -+ add_text("rx_antenna=%u\n", antenna); -+ -+ add_text("encryption_modes=%s%s%s%s%s%s%s\n", -+ test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ? -+ "WEP" : "none", -+ test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ? -+ "; TKIP with WPA" : "", -+ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? -+ ", WPA2" : "", -+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? -+ ", WPA2PSK" : "", -+ test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ? -+ "; AES/CCMP with WPA" : "", -+ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? -+ ", WPA2" : "", -+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? -+ ", WPA2PSK" : ""); -+ -+ res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter); -+ if (!res) { -+ if (packet_filter != wnd->packet_filter) -+ WARNING("wrong packet_filter? 0x%08x, 0x%08x\n", -+ packet_filter, wnd->packet_filter); -+ add_text("packet_filter: 0x%08x\n", packet_filter); -+ } -+ -+ return 0; -+} -+ -+PROC_DECLARE_RO(hw) -+ -+static int proc_settings_read(struct seq_file *sf, void *v) -+{ -+ struct ndis_device *wnd = (struct ndis_device *)sf->private; -+ struct wrap_device_setting *setting; -+ -+ add_text("hangcheck_interval=%d\n", (hangcheck_interval == 0) ? -+ (wnd->hangcheck_interval / HZ) : -1); -+ -+ list_for_each_entry(setting, &wnd->wd->settings, list) { -+ add_text("%s=%s\n", setting->name, setting->value); -+ } -+ -+ list_for_each_entry(setting, &wnd->wd->driver->settings, list) { -+ add_text("%s=%s\n", setting->name, setting->value); -+ } -+ -+ return 0; -+} -+ -+static ssize_t proc_settings_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ struct ndis_device *wnd = PDE_DATA(file_inode(file)); -+ char setting[MAX_PROC_STR_LEN], *p; -+ unsigned int i; -+ NDIS_STATUS res; -+ -+ if (count > MAX_PROC_STR_LEN) -+ return -EINVAL; -+ -+ memset(setting, 0, sizeof(setting)); -+ if (copy_from_user(setting, buf, count)) -+ return -EFAULT; -+ -+ if ((p = strchr(setting, '\n'))) -+ *p = 0; -+ -+ if ((p = strchr(setting, '='))) -+ *p = 0; -+ -+ if (!strcmp(setting, "hangcheck_interval")) { -+ if (!p) -+ return -EINVAL; -+ p++; -+ i = simple_strtol(p, NULL, 10); -+ hangcheck_del(wnd); -+ if (i > 0) { -+ wnd->hangcheck_interval = i * HZ; -+ hangcheck_add(wnd); -+ } -+ } else if (!strcmp(setting, "suspend")) { -+ if (!p) -+ return -EINVAL; -+ p++; -+ i = simple_strtol(p, NULL, 10); -+ if (i <= 0 || i > 3) -+ return -EINVAL; -+ i = -1; -+ if (wrap_is_pci_bus(wnd->wd->dev_bus)) -+ i = wrap_pnp_suspend_pci_device(wnd->wd->pci.pdev, -+ PMSG_SUSPEND); -+ else if (wrap_is_usb_bus(wnd->wd->dev_bus)) -+ i = wrap_pnp_suspend_usb_device(wnd->wd->usb.intf, -+ PMSG_SUSPEND); -+ if (i) -+ return -EINVAL; -+ } else if (!strcmp(setting, "resume")) { -+ i = -1; -+ if (wrap_is_pci_bus(wnd->wd->dev_bus)) -+ i = wrap_pnp_resume_pci_device(wnd->wd->pci.pdev); -+ else if (wrap_is_usb_bus(wnd->wd->dev_bus)) -+ i = wrap_pnp_resume_usb_device(wnd->wd->usb.intf); -+ if (i) -+ return -EINVAL; -+ } else if (!strcmp(setting, "stats_enabled")) { -+ if (!p) -+ return -EINVAL; -+ p++; -+ i = simple_strtol(p, NULL, 10); -+ if (i > 0) -+ wnd->iw_stats_enabled = TRUE; -+ else -+ wnd->iw_stats_enabled = FALSE; -+ } else if (!strcmp(setting, "packet_filter")) { -+ if (!p) -+ return -EINVAL; -+ p++; -+ i = simple_strtol(p, NULL, 10); -+ res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, i); -+ if (res) -+ WARNING("setting packet_filter failed: %08X", res); -+ } else if (!strcmp(setting, "reinit")) { -+ if (ndis_reinit(wnd) != NDIS_STATUS_SUCCESS) -+ return -EFAULT; -+ } else { -+ struct ndis_configuration_parameter param; -+ struct unicode_string key; -+ struct ansi_string ansi; -+ -+ if (!p) -+ return -EINVAL; -+ p++; -+ RtlInitAnsiString(&ansi, p); -+ if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi, -+ TRUE) != STATUS_SUCCESS) -+ EXIT1(return -EFAULT); -+ param.type = NdisParameterString; -+ RtlInitAnsiString(&ansi, setting); -+ if (RtlAnsiStringToUnicodeString(&key, &ansi, -+ TRUE) != STATUS_SUCCESS) { -+ RtlFreeUnicodeString(¶m.data.string); -+ EXIT1(return -EINVAL); -+ } -+ NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m); -+ RtlFreeUnicodeString(&key); -+ RtlFreeUnicodeString(¶m.data.string); -+ if (res != NDIS_STATUS_SUCCESS) -+ return -EFAULT; -+ } -+ return count; -+} -+ -+PROC_DECLARE_RW(settings) -+ -+int wrap_procfs_add_ndis_device(struct ndis_device *wnd) -+{ -+ int ret; -+ -+ if (wrap_procfs_entry == NULL) -+ return -ENOMEM; -+ -+ if (wnd->procfs_iface) { -+ ERROR("%s already registered?", wnd->net_dev->name); -+ return -EINVAL; -+ } -+ wnd->procfs_iface = proc_mkdir(wnd->net_dev->name, wrap_procfs_entry); -+ if (wnd->procfs_iface == NULL) { -+ ERROR("couldn't create proc directory"); -+ return -ENOMEM; -+ } -+ proc_set_user(wnd->procfs_iface, proc_kuid, proc_kgid); -+ -+ ret = proc_make_entry_ro(hw, wnd->procfs_iface, wnd); -+ if (ret) -+ goto err_hw; -+ -+ ret = proc_make_entry_ro(stats, wnd->procfs_iface, wnd); -+ if (ret) -+ goto err_stats; -+ -+ ret = proc_make_entry_ro(encr, wnd->procfs_iface, wnd); -+ if (ret) -+ goto err_encr; -+ -+ ret = proc_make_entry_rw(settings, wnd->procfs_iface, wnd); -+ if (ret) -+ goto err_settings; -+ -+ return 0; -+ -+err_settings: -+ remove_proc_entry("encr", wnd->procfs_iface); -+err_encr: -+ remove_proc_entry("stats", wnd->procfs_iface); -+err_stats: -+ remove_proc_entry("hw", wnd->procfs_iface); -+err_hw: -+ proc_remove(wnd->procfs_iface); -+ wnd->procfs_iface = NULL; -+ return -ENOMEM; -+} -+ -+void wrap_procfs_remove_ndis_device(struct ndis_device *wnd) -+{ -+ struct proc_dir_entry *procfs_iface = xchg(&wnd->procfs_iface, NULL); -+ -+ if (procfs_iface == NULL) -+ return; -+ remove_proc_entry("hw", procfs_iface); -+ remove_proc_entry("stats", procfs_iface); -+ remove_proc_entry("encr", procfs_iface); -+ remove_proc_entry("settings", procfs_iface); -+ if (wrap_procfs_entry) -+ proc_remove(procfs_iface); -+} -+ -+static int proc_debug_read(struct seq_file *sf, void *v) -+{ -+#if ALLOC_DEBUG -+ enum alloc_type type; -+#endif -+ -+ add_text("%d\n", debug); -+#if ALLOC_DEBUG -+ for (type = 0; type < ALLOC_TYPE_MAX; type++) -+ add_text("total size of allocations in %s: %d\n", -+ alloc_type_name[type], alloc_size(type)); -+#endif -+ return 0; -+} -+ -+static ssize_t proc_debug_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ int i; -+ char setting[MAX_PROC_STR_LEN], *p; -+ -+ if (count > MAX_PROC_STR_LEN) -+ return -EINVAL; -+ -+ memset(setting, 0, sizeof(setting)); -+ if (copy_from_user(setting, buf, count)) -+ return -EFAULT; -+ -+ if ((p = strchr(setting, '\n'))) -+ *p = 0; -+ -+ if ((p = strchr(setting, '='))) -+ *p = 0; -+ -+ i = simple_strtol(setting, NULL, 10); -+ if (i >= 0 && i < 10) -+ debug = i; -+ else -+ return -EINVAL; -+ return count; -+} -+ -+PROC_DECLARE_RW(debug) -+ -+int wrap_procfs_init(void) -+{ -+ int ret; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) -+ struct user_namespace *ns = current_user_ns(); -+ proc_kuid = make_kuid(ns, proc_uid); -+ if (!uid_valid(proc_kuid)) { -+ ERROR("invalid UID\n"); -+ return -EINVAL; -+ } -+ proc_kgid = make_kgid(ns, proc_gid); -+ if (!gid_valid(proc_kgid)) { -+ ERROR("invalid GID\n"); -+ return -EINVAL; -+ } -+#endif -+ -+ wrap_procfs_entry = proc_mkdir(DRIVER_NAME, proc_net_root); -+ if (wrap_procfs_entry == NULL) { -+ ERROR("couldn't create procfs directory"); -+ return -ENOMEM; -+ } -+ proc_set_user(wrap_procfs_entry, proc_kuid, proc_kgid); -+ -+ ret = proc_make_entry_rw(debug, wrap_procfs_entry, NULL); -+ -+ return ret; -+} -+ -+void wrap_procfs_remove(void) -+{ -+ if (wrap_procfs_entry == NULL) -+ return; -+ remove_proc_entry("debug", wrap_procfs_entry); -+ proc_remove(wrap_procfs_entry); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/rtl.c linux-5.6.11-ndis/3rdparty/ndiswrapper/rtl.c ---- linux-5.6.11/3rdparty/ndiswrapper/rtl.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/rtl.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,715 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * Copyright (C) 2006-2007 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ntoskernel.h" -+#include "rtl_exports.h" -+ -+wstdcall SIZE_T WIN_FUNC(RtlCompareMemory,3) -+ (const void *a, const void *b, SIZE_T len) -+{ -+ size_t i; -+ char *x, *y; -+ -+ ENTER1("%p %p %zd", a, b, len); -+ x = (char *)a; -+ y = (char *)b; -+ /* MSDN says this should return number of bytes that compare as -+ * equal. This can be interpreted as either all bytes that are -+ * equal in 'len' bytes or that only until the bytes compare as -+ * not equal. Initially we had it the former way, but Realtek driver -+ * doesn't like it that way - it takes many attempts to associate -+ * with WPA. ReactOS returns the number of bytes that are equal -+ * before the first differing byte. -+ * According to lords at #reactos, that is the way it should be -+ * and that msdn is wrong about it! -+ */ -+ for (i = 0; i < len && x[i] == y[i]; i++) -+ ; -+ return i; -+} -+ -+wstdcall void WIN_FUNC(RtlCopyMemory,3) -+ (void *dst, const void *src, SIZE_T length) -+{ -+ memcpy(dst, src, length); -+} -+ -+wstdcall void WIN_FUNC(RtlZeroMemory,2) -+ (void *dst, SIZE_T length) -+{ -+ memset(dst, 0, length); -+} -+ -+wstdcall void WIN_FUNC(RtlSecureZeroMemory,2) -+ (void *dst, SIZE_T length) -+{ -+ memset(dst, 0, length); -+} -+ -+wstdcall void WIN_FUNC(RtlFillMemory,3) -+ (void *dest, SIZE_T length, UCHAR fill) -+{ -+ memset(dest, fill, length); -+} -+ -+wstdcall void WIN_FUNC(RtlMoveMemory,3) -+ (void *dest, const void *src, SIZE_T length) -+{ -+ memmove(dest, src, length); -+} -+ -+wstdcall LONG WIN_FUNC(RtlCompareString,3) -+ (const struct ansi_string *s1, const struct ansi_string *s2, -+ BOOLEAN case_insensitive) -+{ -+ unsigned int len; -+ LONG ret = 0; -+ const char *p1, *p2; -+ -+ ENTER2(""); -+ len = min(s1->length, s2->length); -+ p1 = s1->buf; -+ p2 = s2->buf; -+ if (case_insensitive) -+ while (!ret && len--) -+ ret = toupper(*p1++) - toupper(*p2++); -+ else -+ while (!ret && len--) -+ ret = *p1++ - *p2++; -+ if (!ret) -+ ret = s1->length - s2->length; -+ EXIT2(return ret); -+} -+ -+wstdcall LONG WIN_FUNC(RtlCompareUnicodeString,3) -+ (const struct unicode_string *s1, const struct unicode_string *s2, -+ BOOLEAN case_insensitive) -+{ -+ unsigned int len; -+ LONG ret = 0; -+ const wchar_t *p1, *p2; -+ -+ ENTER2(""); -+ -+ len = min(s1->length, s2->length) / sizeof(wchar_t); -+ p1 = s1->buf; -+ p2 = s2->buf; -+ if (case_insensitive) -+ while (!ret && len--) -+ ret = toupper((u8)*p1++) - toupper((u8)*p2++); -+ else -+ while (!ret && len--) -+ ret = (u8)*p1++ - (u8)*p2++; -+ if (!ret) -+ ret = s1->length - s2->length; -+ TRACE2("len: %d, ret: %d", len, ret); -+ EXIT2(return ret); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(RtlEqualString,3) -+ (const struct ansi_string *s1, const struct ansi_string *s2, -+ BOOLEAN case_insensitive) -+{ -+ ENTER1(""); -+ if (s1->length != s2->length) -+ return FALSE; -+ return !RtlCompareString(s1, s2, case_insensitive); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(RtlEqualUnicodeString,3) -+ (const struct unicode_string *s1, const struct unicode_string *s2, -+ BOOLEAN case_insensitive) -+{ -+ if (s1->length != s2->length) -+ return FALSE; -+ return !RtlCompareUnicodeString(s1, s2, case_insensitive); -+} -+ -+wstdcall void WIN_FUNC(RtlCopyUnicodeString,2) -+ (struct unicode_string *dst, struct unicode_string *src) -+{ -+ ENTER1("%p, %p", dst, src); -+ if (src && src->buf && dst->buf) { -+ dst->length = min(src->length, dst->max_length); -+ memcpy(dst->buf, src->buf, dst->length); -+ if (dst->length < dst->max_length) -+ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; -+ } else -+ dst->length = 0; -+ EXIT1(return); -+} -+ -+wstdcall void WIN_FUNC(RtlCopyString,2) -+ (struct ansi_string *dst, struct ansi_string *src) -+{ -+ ENTER1("%p, %p", dst, src); -+ if (src && src->buf && dst->buf) { -+ dst->length = min(src->length, dst->max_length); -+ memcpy(dst->buf, src->buf, dst->length); -+ if (dst->length < dst->max_length) -+ dst->buf[dst->length] = 0; -+ } else -+ dst->length = 0; -+ EXIT1(return); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeToString,2) -+ (struct unicode_string *dst, wchar_t *src) -+{ -+ if (src) { -+ int len; -+ for (len = 0; src[len]; len++) -+ ; -+ if (dst->length + (len * sizeof(dst->buf[0])) > dst->max_length) -+ return STATUS_BUFFER_TOO_SMALL; -+ memcpy(&dst->buf[dst->length], src, len * sizeof(dst->buf[0])); -+ dst->length += len * sizeof(dst->buf[0]); -+ if (dst->max_length > dst->length) -+ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; -+ } -+ return STATUS_SUCCESS; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeStringToString,2) -+ (struct unicode_string *dst, struct unicode_string *src) -+{ -+ if (dst->max_length < src->length + dst->length) -+ return STATUS_BUFFER_TOO_SMALL; -+ if (src->length) { -+ memcpy(&dst->buf[dst->length], src->buf, src->length); -+ dst->length += src->length; -+ if (dst->max_length > dst->length) -+ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; -+ } -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall ULONG WIN_FUNC(RtlxAnsiStringToUnicodeSize,1) -+ (const struct ansi_string *string) -+{ -+ int i; -+ -+ for (i = 0; i < string->max_length && string->buf[i]; i++) -+ ; -+ return i * sizeof(wchar_t); -+} -+ -+wstdcall ULONG WIN_FUNC(RtlxUnicodeStringToAnsiSize,1) -+ (const struct unicode_string *string) -+{ -+ int i; -+ -+ for (i = 0; i < string->max_length && string->buf[i]; i++) -+ ; -+ return i; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlAnsiStringToUnicodeString,3) -+ (struct unicode_string *dst, const struct ansi_string *src, -+ BOOLEAN alloc) -+{ -+ int i, n; -+ -+ n = RtlxAnsiStringToUnicodeSize(src); -+ TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length, -+ src->max_length, src->buf); -+ if (alloc == TRUE) { -+#if 0 -+ if (n == 0) { -+ dst->length = dst->max_length = 0; -+ dst->buf = NULL; -+ EXIT2(return STATUS_SUCCESS); -+ } -+#endif -+ dst->max_length = n + sizeof(dst->buf[0]); -+ dst->buf = ExAllocatePoolWithTag(NonPagedPool, -+ dst->max_length, 0); -+ if (!dst->buf) { -+ dst->max_length = dst->length = 0; -+ EXIT2(return STATUS_NO_MEMORY); -+ } -+ } else if (dst->max_length < n) -+ EXIT2(return STATUS_BUFFER_TOO_SMALL); -+ -+ dst->length = n; -+ n /= sizeof(dst->buf[0]); -+ for (i = 0; i < n; i++) -+ dst->buf[i] = src->buf[i]; -+ if (i * sizeof(dst->buf[0]) < dst->max_length) -+ dst->buf[i] = 0; -+ TRACE2("dst: length: %d, max_length: %d, string: %p", -+ dst->length, dst->max_length, src->buf); -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToAnsiString,3) -+ (struct ansi_string *dst, const struct unicode_string *src, -+ BOOLEAN alloc) -+{ -+ int i, n; -+ -+ n = RtlxUnicodeStringToAnsiSize(src); -+ TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length, -+ src->max_length, src->buf); -+ if (alloc == TRUE) { -+#if 0 -+ if (n == 0) { -+ dst->length = dst->max_length = 0; -+ dst->buf = NULL; -+ EXIT2(return STATUS_SUCCESS); -+ } -+#endif -+ dst->max_length = n + sizeof(dst->buf[0]); -+ dst->buf = ExAllocatePoolWithTag(NonPagedPool, -+ dst->max_length, 0); -+ if (!dst->buf) { -+ dst->max_length = dst->length = 0; -+ EXIT1(return STATUS_NO_MEMORY); -+ } -+ } else if (dst->max_length < n) -+ EXIT2(return STATUS_BUFFER_TOO_SMALL); -+ -+ dst->length = n; -+ for (i = 0; i < n; i++) -+ dst->buf[i] = src->buf[i]; -+ if (i < dst->max_length) -+ dst->buf[i] = 0; -+ TRACE2("string: %p, len: %d(%d)", dst->buf, dst->length, -+ dst->max_length); -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToInteger,3) -+ (struct unicode_string *ustring, ULONG base, ULONG *value) -+{ -+ int i, sign = 1; -+ ULONG res; -+ typeof(ustring->buf) string; -+ -+ if (ustring->length == 0) { -+ *value = 0; -+ return STATUS_SUCCESS; -+ } -+ -+ string = ustring->buf; -+ i = 0; -+ while (i < (ustring->length / sizeof(*string)) && string[i] == ' ') -+ i++; -+ if (string[i] == '+') -+ i++; -+ else if (string[i] == '-') { -+ i++; -+ sign = -1; -+ } -+ if (base == 0) { -+ base = 10; -+ if (i <= ((ustring->length / sizeof(*string)) - 2) && -+ string[i] == '0') { -+ i++; -+ if (string[i] == 'b') { -+ base = 2; -+ i++; -+ } else if (string[i] == 'o') { -+ base = 8; -+ i++; -+ } else if (string[i] == 'x') { -+ base = 16; -+ i++; -+ } -+ } -+ } -+ if (!(base == 2 || base == 8 || base == 10 || base == 16)) -+ EXIT2(return STATUS_INVALID_PARAMETER); -+ -+ for (res = 0; i < (ustring->length / sizeof(*string)); i++) { -+ int v; -+ if (isdigit((char)string[i])) -+ v = string[i] - '0'; -+ else if (isxdigit((char)string[i])) -+ v = tolower((char)string[i]) - 'a' + 10; -+ else -+ v = base; -+ if (v >= base) -+ EXIT2(return STATUS_INVALID_PARAMETER); -+ res = res * base + v; -+ } -+ *value = sign * res; -+ EXIT3(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlCharToInteger,3) -+ (const char *string, ULONG base, ULONG *value) -+{ -+ int sign = 1; -+ ULONG res; -+ -+ if (!string || !value) -+ EXIT2(return STATUS_INVALID_PARAMETER); -+ while (*string == ' ') -+ string++; -+ if (*string == '+') -+ string++; -+ else if (*string == '-') { -+ string++; -+ sign = -1; -+ } -+ if (base == 0) { -+ base = 10; -+ if (*string == '0') { -+ string++; -+ if (*string == 'b') { -+ base = 2; -+ string++; -+ } else if (*string == 'o') { -+ base = 8; -+ string++; -+ } else if (*string == 'x') { -+ base = 16; -+ string++; -+ } -+ } -+ } -+ if (!(base == 2 || base == 8 || base == 10 || base == 16)) -+ EXIT2(return STATUS_INVALID_PARAMETER); -+ -+ for (res = 0; *string; string++) { -+ int v; -+ if (isdigit(*string)) -+ v = *string - '0'; -+ else if (isxdigit(*string)) -+ v = tolower(*string) - 'a' + 10; -+ else -+ v = base; -+ if (v >= base) -+ EXIT2(return STATUS_INVALID_PARAMETER); -+ res = res * base + v; -+ } -+ *value = sign * res; -+ EXIT3(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlIntegerToUnicodeString,3) -+ (ULONG value, ULONG base, struct unicode_string *ustring) -+{ -+ typeof(ustring->buf) buf = ustring->buf; -+ int i; -+ -+ if (base == 0) -+ base = 10; -+ if (!(base == 2 || base == 8 || base == 10 || base == 16)) -+ return STATUS_INVALID_PARAMETER; -+ for (i = 0; value && i < ustring->max_length / sizeof(*buf); i++) { -+ int r; -+ r = value % base; -+ value /= base; -+ if (r < 10) -+ buf[i] = r + '0'; -+ else -+ buf[i] = r + 'a' - 10; -+ } -+ if (value) -+ return STATUS_BUFFER_OVERFLOW; -+ ustring->length = i * sizeof(*buf); -+ return STATUS_SUCCESS; -+} -+ -+wstdcall LARGE_INTEGER WIN_FUNC(RtlConvertUlongToLargeInteger,1) -+ (ULONG ul) -+{ -+ LARGE_INTEGER li = ul; -+ return li; -+} -+ -+wfastcall USHORT WIN_FUNC(RtlUshortByteSwap,1) -+ (USHORT src) -+{ -+ return __swab16(src); -+} -+ -+wfastcall ULONG WIN_FUNC(RtlUlongByteSwap,1) -+ (ULONG src) -+{ -+ /* ULONG is 32 bits for both 32-bit and 64-bit architectures */ -+ return __swab32(src); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlUpcaseUnicodeString,3) -+ (struct unicode_string *dst, struct unicode_string *src, BOOLEAN alloc) -+{ -+ USHORT i, n; -+ -+ if (alloc) { -+ dst->buf = ExAllocatePoolWithTag(NonPagedPool, src->length, 0); -+ if (dst->buf) -+ dst->max_length = src->length; -+ else -+ EXIT2(return STATUS_NO_MEMORY); -+ } else { -+ if (dst->max_length < src->length) -+ EXIT2(return STATUS_BUFFER_OVERFLOW); -+ } -+ -+ n = src->length / sizeof(src->buf[0]); -+ for (i = 0; i < n; i++) -+ dst->buf[i] = toupper(src->buf[i]); -+ -+ dst->length = src->length; -+ EXIT3(return STATUS_SUCCESS); -+} -+ -+wstdcall void WIN_FUNC(RtlInitUnicodeString,2) -+ (struct unicode_string *dst, const wchar_t *src) -+{ -+ ENTER2("%p", dst); -+ if (dst == NULL) -+ EXIT1(return); -+ if (src == NULL) { -+ dst->max_length = dst->length = 0; -+ dst->buf = NULL; -+ } else { -+ int i; -+ for (i = 0; (char)src[i]; i++) -+ ; -+ dst->buf = (typeof(dst->buf))src; -+ dst->length = i * sizeof(dst->buf[0]); -+ dst->max_length = (i + 1) * sizeof(dst->buf[0]); -+ } -+ EXIT1(return); -+} -+ -+wstdcall void WIN_FUNC(RtlInitAnsiString,2) -+ (struct ansi_string *dst, const char *src) -+{ -+ ENTER2("%p", dst); -+ if (dst == NULL) -+ EXIT2(return); -+ if (src == NULL) { -+ dst->max_length = dst->length = 0; -+ dst->buf = NULL; -+ } else { -+ int i; -+ for (i = 0; src[i]; i++) -+ ; -+ dst->buf = (typeof(dst->buf))src; -+ dst->length = i; -+ dst->max_length = i + 1; -+ } -+ TRACE2("%p", dst->buf); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(RtlInitString,2) -+ (struct ansi_string *dst, const char *src) -+{ -+ ENTER2("%p", dst); -+ RtlInitAnsiString(dst, src); -+ EXIT2(return); -+} -+ -+wstdcall void WIN_FUNC(RtlFreeUnicodeString,1) -+ (struct unicode_string *string) -+{ -+ ENTER2("%p", string); -+ if (string == NULL) -+ return; -+ if (string->buf) -+ ExFreePool(string->buf); -+ string->length = string->max_length = 0; -+ string->buf = NULL; -+ return; -+} -+ -+wstdcall void WIN_FUNC(RtlFreeAnsiString,1) -+ (struct ansi_string *string) -+{ -+ ENTER2("%p", string); -+ if (string == NULL) -+ return; -+ if (string->buf) -+ ExFreePool(string->buf); -+ string->length = string->max_length = 0; -+ string->buf = NULL; -+ return; -+} -+ -+/* guid string is of the form: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ -+wstdcall NTSTATUS WIN_FUNC(RtlGUIDFromString,2) -+ (struct unicode_string *guid_string, struct guid *guid) -+{ -+ struct ansi_string ansi; -+ NTSTATUS ret; -+ int i, j, k, l, m; -+ -+ ret = RtlUnicodeStringToAnsiString(&ansi, guid_string, TRUE); -+ if (ret != STATUS_SUCCESS) -+ return ret; -+ if (ansi.length != 37 || ansi.buf[0] != '{' || -+ ansi.buf[36] != '}' || ansi.buf[9] != '-' || -+ ansi.buf[14] != '-' || ansi.buf[19] != '-' || -+ ansi.buf[24] != '-') { -+ RtlFreeAnsiString(&ansi); -+ EXIT2(return STATUS_INVALID_PARAMETER); -+ } -+ memcpy(&guid->data4, &ansi.buf[29], sizeof(guid->data3)); -+ /* set end of data3 for scanf */ -+ ansi.buf[29] = 0; -+ if (sscanf(&ansi.buf[1], "%x", &i) == 1 && -+ sscanf(&ansi.buf[10], "%x", &j) == 1 && -+ sscanf(&ansi.buf[15], "%x", &k) == 1 && -+ sscanf(&ansi.buf[20], "%x", &l) == 1 && -+ sscanf(&ansi.buf[25], "%x", &m) == 1) { -+ guid->data1 = (i << 16) | (j < 8) | k; -+ guid->data2 = l; -+ guid->data3 = m; -+ ret = STATUS_SUCCESS; -+ } else -+ ret = STATUS_INVALID_PARAMETER; -+ RtlFreeAnsiString(&ansi); -+ return ret; -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlQueryRegistryValues,5) -+ (ULONG relative, wchar_t *path, struct rtl_query_registry_table *tbl, -+ void *context, void *env) -+{ -+ struct ansi_string ansi; -+ struct unicode_string unicode; -+ NTSTATUS status, ret; -+ static int i = 0; -+ -+ ENTER3("%x, %p", relative, tbl); -+// TODO(); -+ -+ RtlInitUnicodeString(&unicode, path); -+ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == -+ STATUS_SUCCESS) { -+ TRACE2("%s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ ret = STATUS_SUCCESS; -+ for (; tbl->name; tbl++) { -+ RtlInitUnicodeString(&unicode, tbl->name); -+ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == -+ STATUS_SUCCESS) { -+ TRACE2("name: %s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ TRACE2("flags: %08X", tbl->flags); -+ if (tbl->flags == RTL_QUERY_REGISTRY_DIRECT) { -+ TRACE2("type: %08X", tbl->def_type); -+ if (tbl->def_type == REG_DWORD) { -+ /* Atheros USB driver needs this, but -+ * don't know where and how to get its -+ * value */ -+ if (tbl->def_data) { -+ TRACE2("def_data: %x", -+ *(int *)tbl->def_data); -+ *(DWORD *)tbl->context = 0x5f292a + i++; -+// *(DWORD *)tbl->def_data; -+ } else -+ *(DWORD *)tbl->context = 0x2345dbe; -+ } -+ } else { -+ void *data; -+ ULONG type, length; -+ -+ if (!tbl->query_func) { -+ ERROR("oops: no query_func"); -+ ret = STATUS_INVALID_PARAMETER; -+ break; -+ } -+ if (tbl->flags & RTL_QUERY_REGISTRY_NOVALUE) { -+ data = NULL; -+ type = REG_NONE; -+ length = 0; -+ } else { -+ data = tbl->def_data; -+ type = tbl->def_type; -+ length = tbl->def_length;; -+ } -+ TRACE2("calling query_func: %p", tbl->query_func); -+ status = LIN2WIN6(tbl->query_func, tbl->name, type, -+ data, length, context, env); -+ TRACE2("status: %08X", status); -+ if (status) { -+ if (status == STATUS_BUFFER_TOO_SMALL) -+ ret = STATUS_BUFFER_TOO_SMALL; -+ else -+ EXIT2(return STATUS_INVALID_PARAMETER); -+ } -+ } -+ } -+ EXIT3(return ret); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlWriteRegistryValue,6) -+ (ULONG relative, wchar_t *path, wchar_t *name, ULONG type, -+ void *data, ULONG length) -+{ -+ struct ansi_string ansi; -+ struct unicode_string unicode; -+ -+ ENTER3("%d", relative); -+ TODO(); -+ -+ RtlInitUnicodeString(&unicode, path); -+ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == -+ STATUS_SUCCESS) { -+ TRACE2("%s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ RtlInitUnicodeString(&unicode, name); -+ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == -+ STATUS_SUCCESS) { -+ TRACE2("%s", ansi.buf); -+ RtlFreeAnsiString(&ansi); -+ } -+ EXIT5(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS WIN_FUNC(RtlDeleteRegistryValue,3) -+ (ULONG relative, wchar_t *path, wchar_t *name) -+{ -+ return STATUS_SUCCESS; -+} -+ -+wstdcall void WIN_FUNC(RtlAssert,4) -+ (char *failed_assertion, char *file_name, ULONG line_num, char *message) -+{ -+ ERROR("assertion '%s' failed at %s line %d%s", -+ failed_assertion, file_name, line_num, message ? message : ""); -+ return; -+} -+ -+wstdcall void WIN_FUNC(RtlUnwind,0) -+ (void) -+{ -+ TODO(); -+} -+ -+wstdcall void WIN_FUNC(RtlRaiseException,1) -+ (void *exception_record) -+{ -+ TODO(); -+} -+ -+wstdcall BOOLEAN WIN_FUNC(RtlIsServicePackVersionInstalled,1) -+ (ULONG version) -+{ -+ /* Assume we have all service packs */ -+ TRACE1("version: %d", version); -+ return TRUE; -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/usb.c linux-5.6.11-ndis/3rdparty/ndiswrapper/usb.c ---- linux-5.6.11/3rdparty/ndiswrapper/usb.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/usb.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,1501 @@ -+/* -+ * Copyright (C) 2004 Jan Kiszka -+ * Copyright (C) 2005 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ndis.h" -+#include "usb.h" -+#include "usb_exports.h" -+ -+#ifdef USB_DEBUG -+static unsigned int urb_id = 0; -+ -+#define DUMP_WRAP_URB(wrap_urb, dir) \ -+ USBTRACE("urb %p (%d) %s: buf: %p, len: %d, pipe: 0x%x, %d", \ -+ (wrap_urb)->urb, (wrap_urb)->id, \ -+ (dir == USB_DIR_OUT) ? "going down" : "coming back", \ -+ (wrap_urb)->urb->transfer_buffer, \ -+ (wrap_urb)->urb->transfer_buffer_length, \ -+ (wrap_urb)->urb->pipe, (wrap_urb)->urb->status) -+ -+#define DUMP_URB_BUFFER(urb, dir) \ -+ while (debug >= 2) { \ -+ int i; \ -+ char msg[20], *t; \ -+ if (!urb->transfer_buffer) \ -+ break; \ -+ if (!((usb_pipein(urb->pipe) && dir == USB_DIR_IN) || \ -+ (usb_pipeout(urb->pipe) && dir == USB_DIR_OUT))) \ -+ break; \ -+ t = msg; \ -+ t += sprintf(t, "%d: ", (urb)->actual_length); \ -+ for (i = 0; i < urb->actual_length && \ -+ t < &msg[sizeof(msg) - 4]; i++) \ -+ t += sprintf(t, "%02X ", \ -+ ((char *)urb->transfer_buffer)[i]); \ -+ *t = 0; \ -+ USBTRACE("%s", msg); \ -+ break; \ -+ } -+ -+#else -+ -+#define DUMP_WRAP_URB(wrap_urb, dir) (void)0 -+#define DUMP_URB_BUFFER(urb, dir) (void)0 -+ -+#endif -+ -+#define CUR_ALT_SETTING(intf) (intf)->cur_altsetting -+ -+#ifndef USB_CTRL_SET_TIMEOUT -+#define USB_CTRL_SET_TIMEOUT 5000 -+#endif -+ -+#ifndef USB_CTRL_GET_TIMEOUT -+#define USB_CTRL_GET_TIMEOUT 5000 -+#endif -+ -+#ifndef URB_NO_TRANSFER_DMA_MAP -+#define URB_NO_TRANSFER_DMA_MAP 0 -+#endif -+ -+/* wrap_urb->flags */ -+/* transfer_buffer for urb is allocated; free it in wrap_free_urb */ -+#define WRAP_URB_COPY_BUFFER 0x01 -+ -+static inline int wrap_cancel_urb(struct wrap_urb *wrap_urb) -+{ -+ int ret; -+ USBTRACE("%p, %p, %d", wrap_urb, wrap_urb->urb, wrap_urb->state); -+ if (wrap_urb->state != URB_SUBMITTED) -+ USBEXIT(return -1); -+ ret = usb_unlink_urb(wrap_urb->urb); -+ USBTRACE("ret: %d", ret); -+ if (ret == -EINPROGRESS) -+ return 0; -+ else { -+ WARNING("unlink failed: %d", ret); -+ return ret; -+ } -+} -+ -+#define URB_STATUS(wrap_urb) (wrap_urb->urb->status) -+ -+static struct nt_list wrap_urb_complete_list; -+static spinlock_t wrap_urb_complete_list_lock; -+ -+static struct work_struct wrap_urb_complete_work; -+static void wrap_urb_complete_worker(struct work_struct *dummy); -+ -+static void kill_all_urbs(struct wrap_device *wd, int complete) -+{ -+ struct nt_list *ent; -+ struct wrap_urb *wrap_urb; -+ KIRQL irql; -+ -+ USBTRACE("%d", wd->usb.num_alloc_urbs); -+ while (1) { -+ IoAcquireCancelSpinLock(&irql); -+ ent = RemoveHeadList(&wd->usb.wrap_urb_list); -+ IoReleaseCancelSpinLock(irql); -+ if (!ent) -+ break; -+ wrap_urb = container_of(ent, struct wrap_urb, list); -+ if (wrap_urb->state == URB_SUBMITTED) { -+ WARNING("Windows driver %s didn't free urb: %p", -+ wd->driver->name, wrap_urb->urb); -+ if (!complete) -+ wrap_urb->urb->complete = NULL; -+ usb_kill_urb(wrap_urb->urb); -+ } -+ USBTRACE("%p, %p", wrap_urb, wrap_urb->urb); -+ usb_free_urb(wrap_urb->urb); -+ kfree(wrap_urb); -+ } -+ wd->usb.num_alloc_urbs = 0; -+} -+ -+/* for a given Linux urb status code, return corresponding NT urb status */ -+static USBD_STATUS wrap_urb_status(int urb_status) -+{ -+ switch (urb_status) { -+ case 0: -+ return USBD_STATUS_SUCCESS; -+ case -EPROTO: -+ return USBD_STATUS_TIMEOUT; -+ case -EILSEQ: -+ return USBD_STATUS_CRC; -+ case -EPIPE: -+ return USBD_STATUS_INVALID_PIPE_HANDLE; -+ case -ECOMM: -+ return USBD_STATUS_DATA_OVERRUN; -+ case -ENOSR: -+ return USBD_STATUS_DATA_UNDERRUN; -+ case -EOVERFLOW: -+ return USBD_STATUS_BABBLE_DETECTED; -+ case -EREMOTEIO: -+ return USBD_STATUS_ERROR_SHORT_TRANSFER;; -+ case -ENODEV: -+ case -ESHUTDOWN: -+ case -ENOENT: -+ return USBD_STATUS_DEVICE_GONE; -+ case -ENOMEM: -+ return USBD_STATUS_NO_MEMORY; -+ case -EINVAL: -+ return USBD_STATUS_REQUEST_FAILED; -+ default: -+ return USBD_STATUS_NOT_SUPPORTED; -+ } -+} -+ -+/* for a given USBD_STATUS, return its corresponding NTSTATUS (for irp) */ -+static NTSTATUS nt_urb_irp_status(USBD_STATUS nt_urb_status) -+{ -+ switch (nt_urb_status) { -+ case USBD_STATUS_SUCCESS: -+ return STATUS_SUCCESS; -+ case USBD_STATUS_DEVICE_GONE: -+ return STATUS_DEVICE_REMOVED; -+ case USBD_STATUS_PENDING: -+ return STATUS_PENDING; -+ case USBD_STATUS_NOT_SUPPORTED: -+ return STATUS_NOT_IMPLEMENTED; -+ case USBD_STATUS_NO_MEMORY: -+ return STATUS_NO_MEMORY; -+ case USBD_STATUS_REQUEST_FAILED: -+ return STATUS_NOT_SUPPORTED; -+ default: -+ return STATUS_FAILURE; -+ } -+} -+ -+static void wrap_free_urb(struct urb *urb) -+{ -+ struct wrap_urb *wrap_urb = urb->context; -+ struct irp *irp = wrap_urb->irp; -+ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); -+ -+ USBTRACE("freeing urb: %p", urb); -+ irp->cancel_routine = NULL; -+ IRP_WRAP_URB(irp) = NULL; -+ if (wrap_urb->flags & WRAP_URB_COPY_BUFFER) { -+ USBTRACE("freeing DMA buffer for URB: %p %p", -+ urb, urb->transfer_buffer); -+ usb_free_coherent(wd->usb.udev, urb->transfer_buffer_length, -+ urb->transfer_buffer, urb->transfer_dma); -+ } -+ kfree(urb->setup_packet); -+ if (wd->usb.num_alloc_urbs > MAX_ALLOCATED_URBS) { -+ IoAcquireCancelSpinLock(&irp->cancel_irql); -+ RemoveEntryList(&wrap_urb->list); -+ wd->usb.num_alloc_urbs--; -+ IoReleaseCancelSpinLock(irp->cancel_irql); -+ usb_free_urb(urb); -+ kfree(wrap_urb); -+ } else { -+ wrap_urb->state = URB_FREE; -+ wrap_urb->flags = 0; -+ wrap_urb->irp = NULL; -+ } -+ return; -+} -+ -+void wrap_suspend_urbs(struct wrap_device *wd) -+{ -+ /* TODO: do we need to cancel urbs? */ -+ USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs); -+} -+ -+void wrap_resume_urbs(struct wrap_device *wd) -+{ -+ /* TODO: do we need to resubmit urbs? */ -+ USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs); -+} -+ -+wstdcall void wrap_cancel_irp(struct device_object *dev_obj, struct irp *irp) -+{ -+ struct urb *urb; -+ struct wrap_urb *wrap_urb = IRP_WRAP_URB(irp); -+ -+ /* NB: this function is called holding Cancel spinlock */ -+ USBENTER("irp: %p", irp); -+ urb = wrap_urb->urb; -+ USBTRACE("canceling urb %p", urb); -+ if (wrap_cancel_urb(IRP_WRAP_URB(irp))) { -+ irp->cancel = FALSE; -+ ERROR("urb %p can't be canceled: %d", urb, wrap_urb->state); -+ } else -+ USBTRACE("urb %p canceled", urb); -+ IoReleaseCancelSpinLock(irp->cancel_irql); -+ return; -+} -+WIN_FUNC_DECL(wrap_cancel_irp,2) -+ -+static struct urb *wrap_alloc_urb(struct irp *irp, unsigned int pipe, -+ void *buf, unsigned int buf_len) -+{ -+ struct urb *urb; -+ gfp_t alloc_flags; -+ struct wrap_urb *wrap_urb; -+ struct wrap_device *wd; -+ -+ USBENTER("irp: %p", irp); -+ wd = IRP_WRAP_DEVICE(irp); -+ -+ /* Don't interfere with URB cleanup by the kernel */ -+ if (test_bit(HW_DISABLED, &wd->hw_status)) -+ return NULL; -+ -+ alloc_flags = irql_gfp(); -+ IoAcquireCancelSpinLock(&irp->cancel_irql); -+ urb = NULL; -+ nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { -+ if (cmpxchg(&wrap_urb->state, URB_FREE, -+ URB_ALLOCATED) == URB_FREE) { -+ urb = wrap_urb->urb; -+ /* Clean URB but keep the refcount */ -+ memset((char *)urb + sizeof(urb->kref), 0, -+ sizeof(*urb) - sizeof(urb->kref)); -+ break; -+ } -+ } -+ if (!urb) { -+ IoReleaseCancelSpinLock(irp->cancel_irql); -+ wrap_urb = kzalloc(sizeof(*wrap_urb), alloc_flags); -+ if (!wrap_urb) { -+ WARNING("couldn't allocate memory"); -+ return NULL; -+ } -+ urb = usb_alloc_urb(0, alloc_flags); -+ if (!urb) { -+ WARNING("couldn't allocate urb"); -+ kfree(wrap_urb); -+ return NULL; -+ } -+ IoAcquireCancelSpinLock(&irp->cancel_irql); -+ wrap_urb->urb = urb; -+ wrap_urb->state = URB_ALLOCATED; -+ InsertTailList(&wd->usb.wrap_urb_list, &wrap_urb->list); -+ wd->usb.num_alloc_urbs++; -+ } -+ -+#ifdef URB_ASYNC_UNLINK -+ urb->transfer_flags |= URB_ASYNC_UNLINK; -+#elif defined(USB_ASYNC_UNLINK) -+ urb->transfer_flags |= USB_ASYNC_UNLINK; -+#endif -+ urb->context = wrap_urb; -+ wrap_urb->irp = irp; -+ IRP_WRAP_URB(irp) = wrap_urb; -+ /* called as Windows function */ -+ irp->cancel_routine = WIN_FUNC_PTR(wrap_cancel_irp,2); -+ IoReleaseCancelSpinLock(irp->cancel_irql); -+ USBTRACE("urb: %p", urb); -+ -+ urb->transfer_buffer_length = buf_len; -+ if (buf_len && buf && (!virt_addr_valid(buf) -+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_HIGHMEM4G) -+ || PageHighMem(virt_to_page(buf)) -+#endif -+ )) { -+ urb->transfer_buffer = -+ usb_alloc_coherent(wd->usb.udev, buf_len, alloc_flags, -+ &urb->transfer_dma); -+ if (!urb->transfer_buffer) { -+ WARNING("couldn't allocate dma buf"); -+ IoAcquireCancelSpinLock(&irp->cancel_irql); -+ irp->cancel_routine = NULL; -+ wrap_urb->state = URB_FREE; -+ wrap_urb->irp = NULL; -+ IRP_WRAP_URB(irp) = NULL; -+ IoReleaseCancelSpinLock(irp->cancel_irql); -+ return NULL; -+ } -+ if (urb->transfer_dma) -+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -+ wrap_urb->flags |= WRAP_URB_COPY_BUFFER; -+ if (usb_pipeout(pipe)) -+ memcpy(urb->transfer_buffer, buf, buf_len); -+ USBTRACE("DMA buf for urb %p: %p", urb, urb->transfer_buffer); -+ } else -+ urb->transfer_buffer = buf; -+ return urb; -+} -+ -+static USBD_STATUS wrap_submit_urb(struct irp *irp) -+{ -+ int ret; -+ struct wrap_urb *wrap_urb = IRP_WRAP_URB(irp); -+ struct urb *urb = wrap_urb->urb; -+ union nt_urb *nt_urb = IRP_URB(irp); -+ -+#ifdef USB_DEBUG -+ if (wrap_urb->state != URB_ALLOCATED) { -+ ERROR("urb %p is in wrong state: %d", -+ urb, wrap_urb->state); -+ NT_URB_STATUS(nt_urb) = USBD_STATUS_REQUEST_FAILED; -+ return NT_URB_STATUS(nt_urb); -+ } -+ wrap_urb->id = pre_atomic_add(urb_id, 1); -+#endif -+ DUMP_WRAP_URB(IRP_WRAP_URB(irp), USB_DIR_OUT); -+ irp->io_status.status = STATUS_PENDING; -+ irp->io_status.info = 0; -+ NT_URB_STATUS(nt_urb) = USBD_STATUS_PENDING; -+ IoMarkIrpPending(irp); -+ DUMP_URB_BUFFER(urb, USB_DIR_OUT); -+ USBTRACE("%p", urb); -+ wrap_urb->state = URB_SUBMITTED; -+ ret = usb_submit_urb(urb, irql_gfp()); -+ if (ret) { -+ USBTRACE("ret: %d", ret); -+ wrap_free_urb(urb); -+ /* we assume that IRP was not in pending state before */ -+ IoUnmarkIrpPending(irp); -+ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); -+ USBEXIT(return NT_URB_STATUS(nt_urb)); -+ } else -+ USBEXIT(return USBD_STATUS_PENDING); -+} -+ -+static void wrap_urb_complete(struct urb *urb ISR_PT_REGS_PARAM_DECL) -+{ -+ struct irp *irp; -+ struct wrap_urb *wrap_urb; -+ -+ wrap_urb = urb->context; -+ USBTRACE("%p (%p) completed", wrap_urb, urb); -+ irp = wrap_urb->irp; -+ DUMP_WRAP_URB(wrap_urb, USB_DIR_IN); -+ irp->cancel_routine = NULL; -+#ifdef USB_DEBUG -+ if (wrap_urb->state != URB_SUBMITTED) { -+ WARNING("urb %p in wrong state: %d (%d)", urb, wrap_urb->state, -+ urb->status); -+ return; -+ } -+#endif -+ wrap_urb->state = URB_COMPLETED; -+ spin_lock(&wrap_urb_complete_list_lock); -+ InsertTailList(&wrap_urb_complete_list, &wrap_urb->complete_list); -+ spin_unlock(&wrap_urb_complete_list_lock); -+ queue_work(ntos_wq, &wrap_urb_complete_work); -+} -+ -+/* one worker for all devices */ -+static void wrap_urb_complete_worker(struct work_struct *dummy) -+{ -+ struct irp *irp; -+ struct urb *urb; -+ struct usbd_bulk_or_intr_transfer *bulk_int_tx; -+ struct usbd_vendor_or_class_request *vc_req; -+ union nt_urb *nt_urb; -+ struct wrap_urb *wrap_urb; -+ struct nt_list *ent; -+ unsigned long flags; -+ -+ USBENTER(""); -+ while (1) { -+ spin_lock_irqsave(&wrap_urb_complete_list_lock, flags); -+ ent = RemoveHeadList(&wrap_urb_complete_list); -+ spin_unlock_irqrestore(&wrap_urb_complete_list_lock, flags); -+ if (!ent) -+ break; -+ wrap_urb = container_of(ent, struct wrap_urb, complete_list); -+ urb = wrap_urb->urb; -+#ifdef USB_DEBUG -+ if (wrap_urb->state != URB_COMPLETED && -+ wrap_urb->state != URB_INT_UNLINKED) -+ WARNING("urb %p in wrong state: %d", -+ urb, wrap_urb->state); -+#endif -+ irp = wrap_urb->irp; -+ DUMP_IRP(irp); -+ nt_urb = IRP_URB(irp); -+ USBTRACE("urb: %p, nt_urb: %p, status: %d", -+ urb, nt_urb, urb->status); -+ switch (urb->status) { -+ case 0: -+ /* successfully transferred */ -+ irp->io_status.info = urb->actual_length; -+ if (nt_urb->header.function == -+ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) { -+ bulk_int_tx = &nt_urb->bulk_int_transfer; -+ bulk_int_tx->transfer_buffer_length = -+ urb->actual_length; -+ DUMP_URB_BUFFER(urb, USB_DIR_IN); -+ if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && -+ usb_pipein(urb->pipe)) -+ memcpy(bulk_int_tx->transfer_buffer, -+ urb->transfer_buffer, -+ urb->actual_length); -+ } else { // vendor or class request -+ vc_req = &nt_urb->vendor_class_request; -+ vc_req->transfer_buffer_length = -+ urb->actual_length; -+ DUMP_URB_BUFFER(urb, USB_DIR_IN); -+ if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && -+ usb_pipein(urb->pipe)) -+ memcpy(vc_req->transfer_buffer, -+ urb->transfer_buffer, -+ urb->actual_length); -+ } -+ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; -+ irp->io_status.status = STATUS_SUCCESS; -+ break; -+ case -ENOENT: -+ case -ECONNRESET: -+ /* urb canceled */ -+ irp->io_status.info = 0; -+ TRACE2("urb %p canceled", urb); -+ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; -+ irp->io_status.status = STATUS_CANCELLED; -+ break; -+ default: -+ TRACE2("irp: %p, urb: %p, status: %d/%d", -+ irp, urb, urb->status, wrap_urb->state); -+ irp->io_status.info = 0; -+ NT_URB_STATUS(nt_urb) = wrap_urb_status(urb->status); -+ irp->io_status.status = -+ nt_urb_irp_status(NT_URB_STATUS(nt_urb)); -+ break; -+ } -+ wrap_free_urb(urb); -+ IoCompleteRequest(irp, IO_NO_INCREMENT); -+ } -+ USBEXIT(return); -+} -+ -+static USBD_STATUS wrap_bulk_or_intr_trans(struct irp *irp) -+{ -+ struct usb_endpoint_descriptor *pipe_handle; -+ struct urb *urb; -+ unsigned int pipe; -+ struct usbd_bulk_or_intr_transfer *bulk_int_tx; -+ USBD_STATUS status; -+ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); -+ struct usb_device *udev = wd->usb.udev; -+ union nt_urb *nt_urb = IRP_URB(irp); -+ -+ bulk_int_tx = &nt_urb->bulk_int_transfer; -+ pipe_handle = bulk_int_tx->pipe_handle; -+ USBTRACE("flags: 0x%x, length: %u, buffer: %p, handle: %p", -+ bulk_int_tx->transfer_flags, -+ bulk_int_tx->transfer_buffer_length, -+ bulk_int_tx->transfer_buffer, pipe_handle); -+ -+ if (USBD_IS_BULK_PIPE(pipe_handle)) { -+ if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) -+ pipe = usb_rcvbulkpipe(udev, -+ pipe_handle->bEndpointAddress); -+ else -+ pipe = usb_sndbulkpipe(udev, -+ pipe_handle->bEndpointAddress); -+ } else { -+ if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) -+ pipe = usb_rcvintpipe(udev, -+ pipe_handle->bEndpointAddress); -+ else -+ pipe = usb_sndintpipe(udev, -+ pipe_handle->bEndpointAddress); -+ } -+ -+ DUMP_IRP(irp); -+ urb = wrap_alloc_urb(irp, pipe, bulk_int_tx->transfer_buffer, -+ bulk_int_tx->transfer_buffer_length); -+ if (!urb) { -+ ERROR("couldn't allocate urb"); -+ return USBD_STATUS_NO_MEMORY; -+ } -+ if (usb_pipein(pipe) && -+ (!(bulk_int_tx->transfer_flags & USBD_SHORT_TRANSFER_OK))) { -+ USBTRACE("short not ok"); -+ urb->transfer_flags |= URB_SHORT_NOT_OK; -+ } -+ if (usb_pipebulk(pipe)) { -+ usb_fill_bulk_urb(urb, udev, pipe, urb->transfer_buffer, -+ bulk_int_tx->transfer_buffer_length, -+ wrap_urb_complete, urb->context); -+ USBTRACE("submitting bulk urb %p on pipe 0x%x (ep 0x%x)", -+ urb, urb->pipe, pipe_handle->bEndpointAddress); -+ } else { -+ usb_fill_int_urb(urb, udev, pipe, urb->transfer_buffer, -+ bulk_int_tx->transfer_buffer_length, -+ wrap_urb_complete, urb->context, -+ pipe_handle->bInterval); -+ USBTRACE("submitting interrupt urb %p on pipe 0x%x (ep 0x%x), " -+ "intvl: %d", urb, urb->pipe, -+ pipe_handle->bEndpointAddress, pipe_handle->bInterval); -+ } -+ status = wrap_submit_urb(irp); -+ USBTRACE("status: %08X", status); -+ USBEXIT(return status); -+} -+ -+static USBD_STATUS wrap_vendor_or_class_req(struct irp *irp) -+{ -+ u8 req_type; -+ unsigned int pipe; -+ struct usbd_vendor_or_class_request *vc_req; -+ USBD_STATUS status; -+ struct urb *urb; -+ struct usb_ctrlrequest *dr; -+ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); -+ struct usb_device *udev = wd->usb.udev; -+ union nt_urb *nt_urb = IRP_URB(irp); -+ -+ vc_req = &nt_urb->vendor_class_request; -+ USBTRACE("bits: %x, req: %x, val: %08x, index: %08x, flags: %x," -+ "buf: %p, len: %d", vc_req->reserved_bits, vc_req->request, -+ vc_req->value, vc_req->index, vc_req->transfer_flags, -+ vc_req->transfer_buffer, vc_req->transfer_buffer_length); -+ -+ USBTRACE("%x", nt_urb->header.function); -+ switch (nt_urb->header.function) { -+ case URB_FUNCTION_VENDOR_DEVICE: -+ req_type = USB_TYPE_VENDOR | USB_RECIP_DEVICE; -+ break; -+ case URB_FUNCTION_VENDOR_INTERFACE: -+ req_type = USB_TYPE_VENDOR | USB_RECIP_INTERFACE; -+ break; -+ case URB_FUNCTION_VENDOR_ENDPOINT: -+ req_type = USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; -+ break; -+ case URB_FUNCTION_VENDOR_OTHER: -+ req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; -+ break; -+ case URB_FUNCTION_CLASS_DEVICE: -+ req_type = USB_TYPE_CLASS | USB_RECIP_DEVICE; -+ break; -+ case URB_FUNCTION_CLASS_INTERFACE: -+ req_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; -+ break; -+ case URB_FUNCTION_CLASS_ENDPOINT: -+ req_type = USB_TYPE_CLASS | USB_RECIP_ENDPOINT; -+ break; -+ case URB_FUNCTION_CLASS_OTHER: -+ req_type = USB_TYPE_CLASS | USB_RECIP_OTHER; -+ break; -+ default: -+ ERROR("unknown request type: %x", nt_urb->header.function); -+ req_type = 0; -+ break; -+ } -+ -+ req_type |= vc_req->reserved_bits; -+ USBTRACE("req type: %08x", req_type); -+ -+ if (vc_req->transfer_flags & USBD_TRANSFER_DIRECTION_IN) { -+ pipe = usb_rcvctrlpipe(udev, 0); -+ req_type |= USB_DIR_IN; -+ USBTRACE("pipe: %x, dir in", pipe); -+ } else { -+ pipe = usb_sndctrlpipe(udev, 0); -+ req_type |= USB_DIR_OUT; -+ USBTRACE("pipe: %x, dir out", pipe); -+ } -+ urb = wrap_alloc_urb(irp, pipe, vc_req->transfer_buffer, -+ vc_req->transfer_buffer_length); -+ if (!urb) { -+ ERROR("couldn't allocate urb"); -+ return USBD_STATUS_NO_MEMORY; -+ } -+ -+ if (usb_pipein(pipe) && -+ (!(vc_req->transfer_flags & USBD_SHORT_TRANSFER_OK))) { -+ USBTRACE("short not ok"); -+ urb->transfer_flags |= URB_SHORT_NOT_OK; -+ } -+ -+ dr = kzalloc(sizeof(*dr), irql_gfp()); -+ if (!dr) { -+ ERROR("couldn't allocate memory"); -+ wrap_free_urb(urb); -+ return USBD_STATUS_NO_MEMORY; -+ } -+ dr->bRequestType = req_type; -+ dr->bRequest = vc_req->request; -+ dr->wValue = cpu_to_le16(vc_req->value); -+ dr->wIndex = cpu_to_le16((u16)vc_req->index); -+ dr->wLength = cpu_to_le16((u16)urb->transfer_buffer_length); -+ -+ usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, -+ urb->transfer_buffer, urb->transfer_buffer_length, -+ wrap_urb_complete, urb->context); -+ status = wrap_submit_urb(irp); -+ USBTRACE("status: %08X", status); -+ USBEXIT(return status); -+} -+ -+static USBD_STATUS wrap_reset_pipe(struct usb_device *udev, struct irp *irp) -+{ -+ int ret; -+ union nt_urb *nt_urb; -+ struct usb_endpoint_descriptor *pipe_handle; -+ unsigned int pipe1, pipe2; -+ -+ nt_urb = IRP_URB(irp); -+ pipe_handle = nt_urb->pipe_req.pipe_handle; -+ /* TODO: not clear if both directions should be cleared? */ -+ if (USBD_IS_BULK_PIPE(pipe_handle)) { -+ pipe1 = usb_rcvbulkpipe(udev, pipe_handle->bEndpointAddress); -+ pipe2 = usb_sndbulkpipe(udev, pipe_handle->bEndpointAddress); -+ } else if (USBD_IS_INT_PIPE(pipe_handle)) { -+ pipe1 = usb_rcvintpipe(udev, pipe_handle->bEndpointAddress); -+ pipe2 = pipe1; -+ } else { -+ WARNING("invalid pipe %d", pipe_handle->bEndpointAddress); -+ return USBD_STATUS_INVALID_PIPE_HANDLE; -+ } -+ USBTRACE("ep: %d, pipe: 0x%x", pipe_handle->bEndpointAddress, pipe1); -+ ret = usb_clear_halt(udev, pipe1); -+ if (ret) -+ USBTRACE("resetting pipe %d failed: %d", pipe1, ret); -+ if (pipe2 != pipe1) { -+ ret = usb_clear_halt(udev, pipe2); -+ if (ret) -+ USBTRACE("resetting pipe %d failed: %d", pipe2, ret); -+ } -+// return wrap_urb_status(ret); -+ return USBD_STATUS_SUCCESS; -+} -+ -+static USBD_STATUS wrap_abort_pipe(struct usb_device *udev, struct irp *irp) -+{ -+ union nt_urb *nt_urb; -+ struct usb_endpoint_descriptor *pipe_handle; -+ struct wrap_urb *wrap_urb; -+ struct wrap_device *wd; -+ KIRQL irql; -+ -+ wd = IRP_WRAP_DEVICE(irp); -+ nt_urb = IRP_URB(irp); -+ pipe_handle = nt_urb->pipe_req.pipe_handle; -+ USBENTER("%p, %x", irp, pipe_handle->bEndpointAddress); -+ IoAcquireCancelSpinLock(&irql); -+ nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { -+ USBTRACE("%p, %p, %d, %x, %x", wrap_urb, wrap_urb->urb, -+ wrap_urb->state, wrap_urb->urb->pipe, -+ usb_pipeendpoint(wrap_urb->urb->pipe)); -+ /* for WG111T driver, urbs for endpoint 0 should also -+ * be canceled */ -+ if ((usb_pipeendpoint(wrap_urb->urb->pipe) == -+ pipe_handle->bEndpointAddress) || -+ (usb_pipeendpoint(wrap_urb->urb->pipe) == 0)) { -+ if (wrap_cancel_urb(wrap_urb) == 0) -+ USBTRACE("canceled wrap_urb: %p", wrap_urb); -+ } -+ } -+ IoReleaseCancelSpinLock(irql); -+ NT_URB_STATUS(nt_urb) = USBD_STATUS_CANCELED; -+ USBEXIT(return USBD_STATUS_SUCCESS); -+} -+ -+static USBD_STATUS wrap_set_clear_feature(struct usb_device *udev, -+ struct irp *irp) -+{ -+ union nt_urb *nt_urb; -+ struct urb_control_feature_request *feat_req; -+ int ret = 0; -+ __u8 request, type; -+ __u16 feature; -+ -+ nt_urb = IRP_URB(irp); -+ feat_req = &nt_urb->feat_req; -+ feature = feat_req->feature_selector; -+ switch (nt_urb->header.function) { -+ case URB_FUNCTION_SET_FEATURE_TO_DEVICE: -+ request = USB_REQ_SET_FEATURE; -+ type = USB_DT_DEVICE; -+ break; -+ case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: -+ request = USB_REQ_SET_FEATURE; -+ type = USB_DT_INTERFACE; -+ break; -+ case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: -+ request = USB_REQ_SET_FEATURE; -+ type = USB_DT_ENDPOINT; -+ break; -+ case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: -+ request = USB_REQ_CLEAR_FEATURE; -+ type = USB_DT_DEVICE; -+ break; -+ case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: -+ request = USB_REQ_CLEAR_FEATURE; -+ type = USB_DT_INTERFACE; -+ break; -+ case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: -+ request = USB_REQ_CLEAR_FEATURE; -+ type = USB_DT_ENDPOINT; -+ break; -+ default: -+ WARNING("invalid function: %x", nt_urb->header.function); -+ NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; -+ return NT_URB_STATUS(nt_urb); -+ } -+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, type, -+ feature, feat_req->index, NULL, 0, 1000); -+ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); -+ USBEXIT(return NT_URB_STATUS(nt_urb)); -+} -+ -+static USBD_STATUS wrap_get_status_request(struct usb_device *udev, -+ struct irp *irp) -+{ -+ union nt_urb *nt_urb; -+ struct urb_control_get_status_request *status_req; -+ int ret = 0; -+ __u8 type; -+ -+ nt_urb = IRP_URB(irp); -+ status_req = &nt_urb->status_req; -+ switch (nt_urb->header.function) { -+ case URB_FUNCTION_GET_STATUS_FROM_DEVICE: -+ type = USB_RECIP_DEVICE; -+ break; -+ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: -+ type = USB_RECIP_INTERFACE; -+ break; -+ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: -+ type = USB_RECIP_ENDPOINT; -+ break; -+ default: -+ WARNING("invalid function: %x", nt_urb->header.function); -+ NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; -+ return NT_URB_STATUS(nt_urb); -+ } -+ assert(status_req->transfer_buffer_length == sizeof(u16)); -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+ ret = usb_get_std_status(udev, type, status_req->index, -+ status_req->transfer_buffer); -+#else -+ ret = usb_get_status(udev, type, status_req->index, -+ status_req->transfer_buffer); -+#endif -+ if (ret >= 0) { -+ assert(ret <= status_req->transfer_buffer_length); -+ status_req->transfer_buffer_length = ret; -+ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; -+ } else -+ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); -+ USBEXIT(return NT_URB_STATUS(nt_urb)); -+} -+ -+static void set_intf_pipe_info(struct wrap_device *wd, -+ struct usb_interface *usb_intf, -+ struct usbd_interface_information *intf) -+{ -+ int i; -+ struct usb_endpoint_descriptor *ep; -+ struct usbd_pipe_information *pipe; -+ -+ for (i = 0; i < CUR_ALT_SETTING(usb_intf)->desc.bNumEndpoints; i++) { -+ ep = &(CUR_ALT_SETTING(usb_intf)->endpoint[i]).desc; -+ if (i >= intf->bNumEndpoints) { -+ ERROR("intf %p has only %d endpoints, " -+ "ignoring endpoints above %d", -+ intf, intf->bNumEndpoints, i); -+ break; -+ } -+ pipe = &intf->pipes[i]; -+ -+ if (pipe->flags & USBD_PF_CHANGE_MAX_PACKET) -+ USBTRACE("pkt_sz: %d: %d", pipe->wMaxPacketSize, -+ pipe->max_tx_size); -+ USBTRACE("driver wants max_tx_size to %d", -+ pipe->max_tx_size); -+ -+ pipe->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); -+ pipe->bEndpointAddress = ep->bEndpointAddress; -+ pipe->type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -+ if (pipe->type == UsbdPipeTypeInterrupt) { -+ /* Windows and Linux differ in how the -+ * bInterval is interpreted */ -+ /* for low speed: -+ interval (Windows) -> frames per ms (Linux) -+ 0 to 15 -> 8 -+ 16 to 35 -> 16 -+ 36 to 255 -> 32 -+ -+ for full speed: interval -> frames per ms -+ 1 -> 1 -+ 2 to 3 -> 2 -+ 4 to 7 -> 4 -+ 8 to 15 -> 8 -+ 16 to 31 -> 16 -+ 32 to 255 -> 32 -+ -+ for high speed: interval -> microframes -+ 1 -> 1 -+ 2 -> 2 -+ 3 -> 4 -+ 4 -> 8 -+ 5 -> 16 -+ 6 -> 32 -+ 7 to 255 -> 32 -+ */ -+ if (wd->usb.udev->speed == USB_SPEED_LOW) -+ pipe->bInterval = ep->bInterval + 5; -+ else if (wd->usb.udev->speed == USB_SPEED_FULL) -+ pipe->bInterval = ep->bInterval; -+ else { -+ int j, k; -+ for (j = k = 1; j < ep->bInterval; k++) -+ j *= 2; -+ pipe->bInterval = k; -+ } -+ } -+ pipe->handle = ep; -+ USBTRACE("%d: ep 0x%x, type %d, pkt_sz %d, intv %d (%d)," -+ "type: %d, handle %p", i, ep->bEndpointAddress, -+ ep->bmAttributes, pipe->wMaxPacketSize, ep->bInterval, -+ pipe->bInterval, pipe->type, pipe->handle); -+ } -+} -+ -+static USBD_STATUS wrap_select_configuration(struct wrap_device *wd, -+ union nt_urb *nt_urb, -+ struct irp *irp) -+{ -+ int i, ret; -+ struct usbd_select_configuration *sel_conf; -+ struct usb_device *udev; -+ struct usbd_interface_information *intf; -+ struct usb_config_descriptor *config; -+ struct usb_interface *usb_intf; -+ -+ udev = wd->usb.udev; -+ sel_conf = &nt_urb->select_conf; -+ config = sel_conf->config; -+ USBTRACE("%p", config); -+ if (config == NULL) { -+ kill_all_urbs(wd, 1); -+ ret = usb_reset_configuration(udev); -+ return wrap_urb_status(ret); -+ } -+ -+ USBTRACE("conf: %d, type: %d, length: %d, numif: %d, attr: %08x", -+ config->bConfigurationValue, config->bDescriptorType, -+ config->wTotalLength, config->bNumInterfaces, -+ config->bmAttributes); -+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), -+ USB_REQ_SET_CONFIGURATION, 0, -+ config->bConfigurationValue, 0, -+ NULL, 0, USB_CTRL_SET_TIMEOUT); -+ if (ret < 0) { -+ ERROR("ret: %d", ret); -+ return wrap_urb_status(ret); -+ } -+ sel_conf->handle = udev->actconfig; -+ intf = &sel_conf->intf; -+ for (i = 0; i < config->bNumInterfaces && intf->bLength > 0; -+ i++, intf = (((void *)intf) + intf->bLength)) { -+ -+ USBTRACE("intf: %d, alt setting: %d", -+ intf->bInterfaceNumber, intf->bAlternateSetting); -+ ret = usb_set_interface(udev, intf->bInterfaceNumber, -+ intf->bAlternateSetting); -+ if (ret < 0) { -+ ERROR("failed with %d", ret); -+ return wrap_urb_status(ret); -+ } -+ usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); -+ if (!usb_intf) { -+ ERROR("couldn't obtain ifnum"); -+ return USBD_STATUS_REQUEST_FAILED; -+ } -+ USBTRACE("intf: %p, num ep: %d", intf, intf->bNumEndpoints); -+ set_intf_pipe_info(wd, usb_intf, intf); -+ } -+ return USBD_STATUS_SUCCESS; -+} -+ -+static USBD_STATUS wrap_select_interface(struct wrap_device *wd, -+ union nt_urb *nt_urb, -+ struct irp *irp) -+{ -+ int ret; -+ struct usbd_select_interface *sel_intf; -+ struct usb_device *udev; -+ struct usbd_interface_information *intf; -+ struct usb_interface *usb_intf; -+ -+ udev = wd->usb.udev; -+ sel_intf = &nt_urb->select_intf; -+ intf = &sel_intf->intf; -+ -+ ret = usb_set_interface(udev, intf->bInterfaceNumber, -+ intf->bAlternateSetting); -+ if (ret < 0) { -+ ERROR("failed with %d", ret); -+ return wrap_urb_status(ret); -+ } -+ usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); -+ if (!usb_intf) { -+ ERROR("couldn't get interface information"); -+ return USBD_STATUS_REQUEST_FAILED; -+ } -+ USBTRACE("intf: %p, num ep: %d", usb_intf, intf->bNumEndpoints); -+ set_intf_pipe_info(wd, usb_intf, intf); -+ return USBD_STATUS_SUCCESS; -+} -+ -+static int wrap_usb_get_string(struct usb_device *udev, unsigned short langid, -+ unsigned char index, void *buf, int size) -+{ -+ int i, ret; -+ /* if langid is 0, return array of languages supported in -+ * buf */ -+ for (i = 0; i < 3; i++) { -+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), -+ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, -+ (USB_DT_STRING << 8) + index, langid, -+ buf, size, USB_CTRL_GET_TIMEOUT); -+ if (ret > 0 || ret == -EPIPE) -+ break; -+ } -+ return ret; -+} -+ -+static USBD_STATUS wrap_get_descriptor(struct wrap_device *wd, -+ union nt_urb *nt_urb, struct irp *irp) -+{ -+ struct usbd_control_descriptor_request *control_desc; -+ int ret = 0; -+ struct usb_device *udev; -+ -+ udev = wd->usb.udev; -+ control_desc = &nt_urb->control_desc; -+ USBTRACE("desctype = %d, descindex = %d, transfer_buffer = %p," -+ "transfer_buffer_length = %d", control_desc->desc_type, -+ control_desc->index, control_desc->transfer_buffer, -+ control_desc->transfer_buffer_length); -+ -+ if (control_desc->desc_type == USB_DT_STRING) { -+ USBTRACE("langid: %x", control_desc->language_id); -+ ret = wrap_usb_get_string(udev, control_desc->language_id, -+ control_desc->index, -+ control_desc->transfer_buffer, -+ control_desc->transfer_buffer_length); -+ } else { -+ ret = usb_get_descriptor(udev, control_desc->desc_type, -+ control_desc->index, -+ control_desc->transfer_buffer, -+ control_desc->transfer_buffer_length); -+ } -+ if (ret < 0) { -+ USBTRACE("request %d failed: %d", control_desc->desc_type, ret); -+ control_desc->transfer_buffer_length = 0; -+ return wrap_urb_status(ret); -+ } else { -+ USBTRACE("ret: %08x", ret); -+ control_desc->transfer_buffer_length = ret; -+ irp->io_status.info = ret; -+ return USBD_STATUS_SUCCESS; -+ } -+} -+ -+static USBD_STATUS wrap_process_nt_urb(struct irp *irp) -+{ -+ USBD_STATUS status; -+ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); -+ struct usb_device *udev = wd->usb.udev; -+ union nt_urb *nt_urb = IRP_URB(irp); -+ -+ USBENTER("nt_urb = %p, irp = %p, length = %d, function = %x", -+ nt_urb, irp, nt_urb->header.length, nt_urb->header.function); -+ -+ if (test_bit(HW_DISABLED, &wd->hw_status)) { -+ status = USBD_STATUS_DEVICE_GONE; -+ NT_URB_STATUS(nt_urb) = status; -+ return status; -+ } -+ -+ DUMP_IRP(irp); -+ switch (nt_urb->header.function) { -+ /* bulk/int and vendor/class urbs are submitted to -+ * Linux USB core; if the call is successful, urb's -+ * completion worker will return IRP later */ -+ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: -+ USBTRACE("submitting bulk/int irp: %p", irp); -+ status = wrap_bulk_or_intr_trans(irp); -+ break; -+ -+ case URB_FUNCTION_VENDOR_DEVICE: -+ case URB_FUNCTION_VENDOR_INTERFACE: -+ case URB_FUNCTION_VENDOR_ENDPOINT: -+ case URB_FUNCTION_VENDOR_OTHER: -+ case URB_FUNCTION_CLASS_DEVICE: -+ case URB_FUNCTION_CLASS_INTERFACE: -+ case URB_FUNCTION_CLASS_ENDPOINT: -+ case URB_FUNCTION_CLASS_OTHER: -+ USBTRACE("submitting vendor/class irp: %p", irp); -+ status = wrap_vendor_or_class_req(irp); -+ break; -+ -+ /* rest are synchronous */ -+ case URB_FUNCTION_SELECT_CONFIGURATION: -+ status = wrap_select_configuration(wd, nt_urb, irp); -+ NT_URB_STATUS(nt_urb) = status; -+ break; -+ -+ case URB_FUNCTION_SELECT_INTERFACE: -+ status = wrap_select_interface(wd, nt_urb, irp); -+ NT_URB_STATUS(nt_urb) = status; -+ break; -+ -+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: -+ status = wrap_get_descriptor(wd, nt_urb, irp); -+ NT_URB_STATUS(nt_urb) = status; -+ break; -+ -+ case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: -+ status = wrap_reset_pipe(udev, irp); -+ NT_URB_STATUS(nt_urb) = status; -+ break; -+ -+ case URB_FUNCTION_ABORT_PIPE: -+ status = wrap_abort_pipe(udev, irp); -+ break; -+ -+ case URB_FUNCTION_SET_FEATURE_TO_DEVICE: -+ case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: -+ case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: -+ case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: -+ case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: -+ case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: -+ status = wrap_set_clear_feature(udev, irp); -+ break; -+ -+ case URB_FUNCTION_GET_STATUS_FROM_DEVICE: -+ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: -+ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: -+ status = wrap_get_status_request(udev, irp); -+ break; -+ -+ default: -+ ERROR("function %x not implemented", nt_urb->header.function); -+ status = NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; -+ break; -+ } -+ USBTRACE("status: %08X", status); -+ return status; -+} -+ -+static USBD_STATUS wrap_reset_port(struct irp *irp) -+{ -+ int ret, lock = 0; -+ struct wrap_device *wd; -+ -+ wd = IRP_WRAP_DEVICE(irp); -+ USBENTER("%p, %p", wd, wd->usb.udev); -+ lock = usb_lock_device_for_reset(wd->usb.udev, wd->usb.intf); -+ if (lock < 0) { -+ WARNING("locking failed: %d", lock); -+// return wrap_urb_status(lock); -+ return USBD_STATUS_SUCCESS; -+ } -+ ret = usb_reset_device(wd->usb.udev); -+ if (ret < 0) -+ USBTRACE("reset failed: %d", ret); -+ /* TODO: should reconfigure? */ -+ if (lock) -+ usb_unlock_device(wd->usb.udev); -+// return wrap_urb_status(ret); -+ return USBD_STATUS_SUCCESS; -+} -+ -+static USBD_STATUS wrap_get_port_status(struct irp *irp) -+{ -+ struct wrap_device *wd; -+ ULONG *status; -+ enum usb_device_state state; -+ -+ wd = IRP_WRAP_DEVICE(irp); -+ USBENTER("%p, %p", wd, wd->usb.udev); -+ status = IoGetCurrentIrpStackLocation(irp)->params.others.arg1; -+ state = wd->usb.udev->state; -+ if (state != USB_STATE_NOTATTACHED && -+ state != USB_STATE_SUSPENDED) { -+ *status |= USBD_PORT_CONNECTED; -+ if (state == USB_STATE_CONFIGURED) -+ *status |= USBD_PORT_ENABLED; -+ } -+ USBTRACE("state: %d, *status: %08X", state, *status); -+ return USBD_STATUS_SUCCESS; -+} -+ -+NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp) -+{ -+ struct io_stack_location *irp_sl; -+ struct wrap_device *wd; -+ USBD_STATUS status; -+ struct usbd_idle_callback *idle_callback; -+ -+ USBENTER("%p, %p", pdo, irp); -+ wd = pdo->reserved; -+ if (wd->usb.intf == NULL) { -+ USBTRACE("%p", irp); -+ irp->io_status.status = STATUS_DEVICE_REMOVED; -+ irp->io_status.info = 0; -+ USBEXIT(return STATUS_DEVICE_REMOVED); -+ } -+ IRP_WRAP_DEVICE(irp) = wd; -+ irp_sl = IoGetCurrentIrpStackLocation(irp); -+ switch (irp_sl->params.dev_ioctl.code) { -+ case IOCTL_INTERNAL_USB_SUBMIT_URB: -+ status = wrap_process_nt_urb(irp); -+ break; -+ case IOCTL_INTERNAL_USB_RESET_PORT: -+ status = wrap_reset_port(irp); -+ break; -+ case IOCTL_INTERNAL_USB_GET_PORT_STATUS: -+ status = wrap_get_port_status(irp); -+ break; -+ case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: -+ idle_callback = irp_sl->params.dev_ioctl.type3_input_buf; -+ (void)idle_callback; -+ USBTRACE("suspend function: %p", idle_callback->callback); -+ status = USBD_STATUS_NOT_SUPPORTED; -+ break; -+ default: -+ ERROR("ioctl %08X NOT IMPLEMENTED", -+ irp_sl->params.dev_ioctl.code); -+ status = USBD_STATUS_NOT_SUPPORTED; -+ break; -+ } -+ -+ USBTRACE("status: %08X", status); -+ if (status == USBD_STATUS_PENDING) { -+ /* don't touch this IRP - it may have been already -+ * completed/returned */ -+ return STATUS_PENDING; -+ } else { -+ irp->io_status.status = nt_urb_irp_status(status); -+ if (status != USBD_STATUS_SUCCESS) -+ irp->io_status.info = 0; -+ USBEXIT(return irp->io_status.status); -+ } -+} -+ -+/* TODO: The example on msdn in reference section suggests that second -+ * argument should be an array of usbd_interface_information, but -+ * description and examples elsewhere suggest that it should be -+ * usbd_interface_list_entry structre. Which is correct? */ -+ -+wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequestEx,2) -+ (struct usb_config_descriptor *config, -+ struct usbd_interface_list_entry *intf_list) -+{ -+ int size, i, n; -+ struct usbd_interface_information *intf; -+ struct usbd_pipe_information *pipe; -+ struct usb_interface_descriptor *intf_desc; -+ struct usbd_select_configuration *select_conf; -+ -+ USBENTER("config = %p, intf_list = %p", config, intf_list); -+ -+ /* calculate size required; select_conf already has space for -+ * one intf structure */ -+ size = sizeof(*select_conf) - sizeof(*intf); -+ for (n = 0; n < config->bNumInterfaces; n++) { -+ i = intf_list[n].intf_desc->bNumEndpoints; -+ /* intf already has space for one pipe */ -+ size += sizeof(*intf) + (i - 1) * sizeof(*pipe); -+ } -+ /* don't use kmalloc - driver frees it with ExFreePool */ -+ select_conf = ExAllocatePoolWithTag(NonPagedPool, size, -+ POOL_TAG('L', 'U', 'S', 'B')); -+ if (!select_conf) { -+ WARNING("couldn't allocate memory"); -+ return NULL; -+ } -+ memset(select_conf, 0, size); -+ intf = &select_conf->intf; -+ select_conf->handle = config; -+ for (n = 0; n < config->bNumInterfaces && intf_list[n].intf_desc; n++) { -+ /* initialize 'intf' fields in intf_list so they point -+ * to appropriate entry; these may be read/written by -+ * driver after this function returns */ -+ intf_list[n].intf = intf; -+ intf_desc = intf_list[n].intf_desc; -+ -+ i = intf_desc->bNumEndpoints; -+ intf->bLength = sizeof(*intf) + (i - 1) * sizeof(*pipe); -+ -+ intf->bInterfaceNumber = intf_desc->bInterfaceNumber; -+ intf->bAlternateSetting = intf_desc->bAlternateSetting; -+ intf->bInterfaceClass = intf_desc->bInterfaceClass; -+ intf->bInterfaceSubClass = intf_desc->bInterfaceSubClass; -+ intf->bInterfaceProtocol = intf_desc->bInterfaceProtocol; -+ intf->bNumEndpoints = intf_desc->bNumEndpoints; -+ -+ pipe = &intf->pipes[0]; -+ for (i = 0; i < intf->bNumEndpoints; i++) { -+ memset(&pipe[i], 0, sizeof(*pipe)); -+ pipe[i].max_tx_size = -+ USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; -+ } -+ intf->handle = intf_desc; -+ intf = (((void *)intf) + intf->bLength); -+ } -+ select_conf->header.function = URB_FUNCTION_SELECT_CONFIGURATION; -+ select_conf->header.length = size; -+ select_conf->config = config; -+ USBEXIT(return (union nt_urb *)select_conf); -+} -+ -+WIN_SYMBOL_MAP("_USBD_CreateConfigurationRequestEx@8", USBD_CreateConfigurationRequestEx) -+ -+wstdcall struct usb_interface_descriptor * -+WIN_FUNC(USBD_ParseConfigurationDescriptorEx,7) -+ (struct usb_config_descriptor *config, void *start, -+ LONG bInterfaceNumber, LONG bAlternateSetting, LONG bInterfaceClass, -+ LONG bInterfaceSubClass, LONG bInterfaceProtocol) -+{ -+ void *pos; -+ struct usb_interface_descriptor *intf; -+ -+ USBENTER("config = %p, start = %p, ifnum = %d, alt_setting = %d," -+ " class = %d, subclass = %d, proto = %d", config, start, -+ bInterfaceNumber, bAlternateSetting, bInterfaceClass, -+ bInterfaceSubClass, bInterfaceProtocol); -+ -+ for (pos = start; -+ pos < ((void *)config + le16_to_cpu(config->wTotalLength)); -+ pos += intf->bLength) { -+ -+ intf = pos; -+ -+ if ((intf->bDescriptorType == USB_DT_INTERFACE) && -+ ((bInterfaceNumber == -1) || -+ (intf->bInterfaceNumber == bInterfaceNumber)) && -+ ((bAlternateSetting == -1) || -+ (intf->bAlternateSetting == bAlternateSetting)) && -+ ((bInterfaceClass == -1) || -+ (intf->bInterfaceClass == bInterfaceClass)) && -+ ((bInterfaceSubClass == -1) || -+ (intf->bInterfaceSubClass == bInterfaceSubClass)) && -+ ((bInterfaceProtocol == -1) || -+ (intf->bInterfaceProtocol == bInterfaceProtocol))) { -+ USBTRACE("selected interface = %p", intf); -+ USBEXIT(return intf); -+ } -+ } -+ USBEXIT(return NULL); -+} -+ -+WIN_SYMBOL_MAP("_USBD_ParseConfigurationDescriptorEx@28", USBD_ParseConfigurationDescriptorEx) -+ -+wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequest,2) -+ (struct usb_config_descriptor *config, USHORT *size) -+{ -+ union nt_urb *nt_urb; -+ struct usbd_interface_list_entry intf_list[2]; -+ struct usb_interface_descriptor *intf_desc; -+ -+ USBENTER("config = %p, urb_size = %p", config, size); -+ -+ intf_desc = USBD_ParseConfigurationDescriptorEx(config, config, -1, -1, -+ -1, -1, -1); -+ intf_list[0].intf_desc = intf_desc; -+ intf_list[0].intf = NULL; -+ intf_list[1].intf_desc = NULL; -+ intf_list[1].intf = NULL; -+ nt_urb = USBD_CreateConfigurationRequestEx(config, intf_list); -+ if (!nt_urb) -+ return NULL; -+ -+ *size = nt_urb->select_conf.header.length; -+ USBEXIT(return nt_urb); -+} -+ -+wstdcall struct usb_interface_descriptor * -+WIN_FUNC(USBD_ParseConfigurationDescriptor,3) -+ (struct usb_config_descriptor *config, UCHAR bInterfaceNumber, -+ UCHAR bAlternateSetting) -+{ -+ return USBD_ParseConfigurationDescriptorEx(config, config, -+ bInterfaceNumber, -+ bAlternateSetting, -+ -1, -1, -1); -+} -+ -+wstdcall struct usb_descriptor_header *WIN_FUNC(USBD_ParseDescriptors,4) -+ (void *buf, ULONG length, struct usb_descriptor_header *descr, -+ LONG type) -+{ -+ while ((void *)descr < buf + length) { -+ if (descr->bDescriptorType == type) -+ return descr; -+ if (descr->bLength == 0) -+ break; -+ descr = (void *)descr + descr->bLength; -+ } -+ USBEXIT(return NULL); -+} -+ -+WIN_SYMBOL_MAP("_USBD_ParseDescriptors@16", USBD_ParseDescriptors) -+ -+wstdcall void WIN_FUNC(USBD_GetUSBDIVersion,1) -+ (struct usbd_version_info *version_info) -+{ -+ /* this function is obsolete in Windows XP */ -+ if (version_info) { -+ version_info->usbdi_version = USBDI_VERSION_XP; -+ /* TODO: how do we get this correctly? */ -+ version_info->supported_usb_version = 0x110; -+ } -+ USBEXIT(return); -+} -+ -+wstdcall void -+USBD_InterfaceGetUSBDIVersion(void *context, -+ struct usbd_version_info *version_info, -+ ULONG *hcd_capa) -+{ -+ struct wrap_device *wd = context; -+ -+ if (version_info) { -+ version_info->usbdi_version = USBDI_VERSION_XP; -+ if (wd->usb.udev->speed == USB_SPEED_HIGH) -+ version_info->supported_usb_version = 0x200; -+ else -+ version_info->supported_usb_version = 0x110; -+ } -+ *hcd_capa = USB_HCD_CAPS_SUPPORTS_RT_THREADS; -+ USBEXIT(return); -+} -+ -+wstdcall BOOLEAN USBD_InterfaceIsDeviceHighSpeed(void *context) -+{ -+ struct wrap_device *wd = context; -+ -+ USBTRACE("wd: %p", wd); -+ if (wd->usb.udev->speed == USB_SPEED_HIGH) -+ USBEXIT(return TRUE); -+ else -+ USBEXIT(return FALSE); -+} -+ -+wstdcall void USBD_InterfaceReference(void *context) -+{ -+ USBTRACE("%p", context); -+ TODO(); -+} -+ -+wstdcall void USBD_InterfaceDereference(void *context) -+{ -+ USBTRACE("%p", context); -+ TODO(); -+} -+ -+wstdcall NTSTATUS USBD_InterfaceQueryBusTime(void *context, ULONG *frame) -+{ -+ struct wrap_device *wd = context; -+ -+ *frame = usb_get_current_frame_number(wd->usb.udev); -+ USBEXIT(return STATUS_SUCCESS); -+} -+ -+wstdcall NTSTATUS USBD_InterfaceSubmitIsoOutUrb(void *context, -+ union nt_urb *nt_urb) -+{ -+ /* TODO: implement this */ -+ TODO(); -+ USBEXIT(return STATUS_NOT_IMPLEMENTED); -+} -+ -+wstdcall NTSTATUS -+USBD_InterfaceQueryBusInformation(void *context, ULONG level, void *buf, -+ ULONG *buf_length, ULONG *buf_actual_length) -+{ -+#if 0 -+ struct wrap_device *wd = context; -+ struct usb_bus *bus = wd->usb.udev->bus; -+ struct usb_bus_information_level *bus_info = buf; -+#endif -+ -+ TODO(); -+ USBEXIT(return STATUS_NOT_IMPLEMENTED); -+} -+ -+wstdcall NTSTATUS -+USBD_InterfaceLogEntry(void *context, ULONG driver_tag, ULONG enum_tag, -+ ULONG p1, ULONG p2) -+{ -+ ERROR("%p, %x, %x, %x, %x", context, driver_tag, enum_tag, p1, p2); -+ USBEXIT(return STATUS_SUCCESS); -+} -+ -+NTSTATUS -+usb_query_interface(struct wrap_device *wd, struct io_stack_location *irp_sl) -+{ -+ struct usbd_bus_interface_usbdi *intf = -+ (struct usbd_bus_interface_usbdi *) -+ irp_sl->params.query_intf.intf; -+ -+ TRACE2("type: %x, size: %d, version: %d", -+ irp_sl->params.query_intf.type->data1, -+ irp_sl->params.query_intf.size, -+ irp_sl->params.query_intf.version); -+ intf->Context = wd; -+ intf->InterfaceReference = -+ WIN_FUNC_PTR(USBD_InterfaceReference, 1); -+ intf->InterfaceDereference = -+ WIN_FUNC_PTR(USBD_InterfaceDereference, 1); -+ intf->GetUSBDIVersion = -+ WIN_FUNC_PTR(USBD_InterfaceGetUSBDIVersion, 3); -+ intf->QueryBusTime = -+ WIN_FUNC_PTR(USBD_InterfaceQueryBusTime, 2); -+ intf->SubmitIsoOutUrb = -+ WIN_FUNC_PTR(USBD_InterfaceSubmitIsoOutUrb, 2); -+ intf->QueryBusInformation = -+ WIN_FUNC_PTR(USBD_InterfaceQueryBusInformation, 5); -+ if (irp_sl->params.query_intf.version >= USB_BUSIF_USBDI_VERSION_1) -+ intf->IsDeviceHighSpeed = -+ WIN_FUNC_PTR(USBD_InterfaceIsDeviceHighSpeed, 1); -+ if (irp_sl->params.query_intf.version >= USB_BUSIF_USBDI_VERSION_2) -+ intf->LogEntry = WIN_FUNC_PTR(USBD_InterfaceLogEntry, 5); -+ return STATUS_SUCCESS; -+} -+ -+int usb_init(void) -+{ -+ InitializeListHead(&wrap_urb_complete_list); -+ spin_lock_init(&wrap_urb_complete_list_lock); -+ INIT_WORK(&wrap_urb_complete_work, wrap_urb_complete_worker); -+#ifdef USB_DEBUG -+ urb_id = 0; -+#endif -+ return 0; -+} -+ -+void usb_exit(void) -+{ -+ USBEXIT(return); -+} -+ -+int usb_init_device(struct wrap_device *wd) -+{ -+ InitializeListHead(&wd->usb.wrap_urb_list); -+ wd->usb.num_alloc_urbs = 0; -+ USBEXIT(return 0); -+} -+ -+void usb_exit_device(struct wrap_device *wd) -+{ -+ kill_all_urbs(wd, 0); -+ USBEXIT(return); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/usb.h linux-5.6.11-ndis/3rdparty/ndiswrapper/usb.h ---- linux-5.6.11/3rdparty/ndiswrapper/usb.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/usb.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,360 @@ -+/* -+ * Copyright (C) 2004 Jan Kiszka -+ * Copyright (C) 2005 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _USB_H_ -+#define _USB_H_ -+ -+#include "ntoskernel.h" -+ -+#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003 -+#define IOCTL_INTERNAL_USB_RESET_PORT 0x00220007 -+#define IOCTL_INTERNAL_USB_GET_PORT_STATUS 0x00220013 -+#define IOCTL_INTERNAL_USB_CYCLE_PORT 0x0022001F -+#define IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION 0x00220027 -+ -+#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000 -+#define URB_FUNCTION_SELECT_INTERFACE 0x0001 -+#define URB_FUNCTION_ABORT_PIPE 0x0002 -+#define URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003 -+#define URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004 -+#define URB_FUNCTION_GET_FRAME_LENGTH 0x0005 -+#define URB_FUNCTION_SET_FRAME_LENGTH 0x0006 -+#define URB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007 -+#define URB_FUNCTION_CONTROL_TRANSFER 0x0008 -+#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 -+#define URB_FUNCTION_ISOCH_TRANSFER 0x000A -+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B -+#define URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C -+#define URB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D -+#define URB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E -+#define URB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F -+#define URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010 -+#define URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011 -+#define URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012 -+#define URB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013 -+#define URB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014 -+#define URB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015 -+#define URB_FUNCTION_RESERVED_0X0016 0x0016 -+#define URB_FUNCTION_VENDOR_DEVICE 0x0017 -+#define URB_FUNCTION_VENDOR_INTERFACE 0x0018 -+#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019 -+#define URB_FUNCTION_CLASS_DEVICE 0x001A -+#define URB_FUNCTION_CLASS_INTERFACE 0x001B -+#define URB_FUNCTION_CLASS_ENDPOINT 0x001C -+#define URB_FUNCTION_RESERVE_0X001D 0x001D -+#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E -+#define URB_FUNCTION_CLASS_OTHER 0x001F -+#define URB_FUNCTION_VENDOR_OTHER 0x0020 -+#define URB_FUNCTION_GET_STATUS_FROM_OTHER 0x0021 -+#define URB_FUNCTION_CLEAR_FEATURE_TO_OTHER 0x0022 -+#define URB_FUNCTION_SET_FEATURE_TO_OTHER 0x0023 -+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024 -+#define URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT 0x0025 -+#define URB_FUNCTION_GET_CONFIGURATION 0x0026 -+#define URB_FUNCTION_GET_INTERFACE 0x0027 -+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 -+#define URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE 0x0029 -+#define URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR 0x002A -+#define URB_FUNCTION_RESERVE_0X002B 0x002B -+#define URB_FUNCTION_RESERVE_0X002C 0x002C -+#define URB_FUNCTION_RESERVE_0X002D 0x002D -+#define URB_FUNCTION_RESERVE_0X002E 0x002E -+#define URB_FUNCTION_RESERVE_0X002F 0x002F -+// USB 2.0 calls start at 0x0030 -+#define URB_FUNCTION_SYNC_RESET_PIPE 0x0030 -+#define URB_FUNCTION_SYNC_CLEAR_STALL 0x0031 -+#define URB_FUNCTION_CONTROL_TRANSFER_EX 0x0032 -+ -+#define USBD_PF_CHANGE_MAX_PACKET 0x00000001 -+ -+#define USBD_TRANSFER_DIRECTION_OUT 0 -+#define USBD_TRANSFER_DIRECTION_IN 1 -+ -+#define USBD_SHORT_TRANSFER_OK 0x00000002 -+#define USBD_START_ISO_TRANSFER_ASAP 0x00000004 -+#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008 -+ -+#define USBD_TRANSFER_DIRECTION(flags) \ -+ ((flags) & USBD_TRANSFER_DIRECTION_IN) -+ -+enum pipe_type {UsbdPipeTypeControl = USB_ENDPOINT_XFER_CONTROL, -+ UsbdPipeTypeIsochronous = USB_ENDPOINT_XFER_ISOC, -+ UsbdPipeTypeBulk = USB_ENDPOINT_XFER_BULK, -+ UsbdPipeTypeInterrupt = USB_ENDPOINT_XFER_INT}; -+ -+#define USBD_IS_BULK_PIPE(pipe_handle) \ -+ (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ -+ == USB_ENDPOINT_XFER_BULK) -+ -+#define USBD_IS_INT_PIPE(pipe_handle) \ -+ (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ -+ == USB_ENDPOINT_XFER_INT) -+ -+#define USBD_PORT_ENABLED 0x00000001 -+#define USBD_PORT_CONNECTED 0x00000002 -+ -+typedef LONG USBD_STATUS; -+ -+#define USBD_STATUS_SUCCESS 0x0 -+#define USBD_STATUS_PENDING 0x40000000 -+#define USBD_STATUS_CANCELED 0x00010000 -+ -+#define USBD_STATUS_CRC 0xC0000001 -+#define USBD_STATUS_BTSTUFF 0xC0000002 -+#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 -+#define USBD_STATUS_STALL_PID 0xC0000004 -+#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005 -+#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006 -+#define USBD_STATUS_UNEXPECTED_PID 0xC0000007 -+#define USBD_STATUS_DATA_OVERRUN 0xC0000008 -+#define USBD_STATUS_DATA_UNDERRUN 0xC0000009 -+#define USBD_STATUS_RESERVED1 0xC000000A -+#define USBD_STATUS_RESERVED2 0xC000000B -+#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C -+#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D -+#define USBD_STATUS_NOT_ACCESSED 0xC000000F -+#define USBD_STATUS_FIFO 0xC0000010 -+#define USBD_STATUS_XACT_ERROR 0xC0000011 -+#define USBD_STATUS_BABBLE_DETECTED 0xC0000012 -+#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013 -+ -+#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00 -+#define USBD_STATUS_BUFFER_TOO_SMALL 0xC0003000 -+#define USBD_STATUS_TIMEOUT 0xC0006000 -+#define USBD_STATUS_DEVICE_GONE 0xC0007000 -+ -+#define USBD_STATUS_NO_MEMORY 0x80000100 -+#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200 -+#define USBD_STATUS_INVALID_PARAMETER 0x80000300 -+#define USBD_STATUS_REQUEST_FAILED 0x80000500 -+#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600 -+#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900 -+ -+#define USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE PAGE_SIZE -+ -+struct urb_hcd_area { -+ void *reserved8[8]; -+}; -+ -+struct usbd_pipe_information { -+ USHORT wMaxPacketSize; -+ UCHAR bEndpointAddress; -+ UCHAR bInterval; -+ enum pipe_type type; -+ struct usb_endpoint_descriptor *handle; -+ ULONG max_tx_size; -+ ULONG flags; -+}; -+ -+struct usbd_interface_information { -+ USHORT bLength; -+ UCHAR bInterfaceNumber; -+ UCHAR bAlternateSetting; -+ UCHAR bInterfaceClass; -+ UCHAR bInterfaceSubClass; -+ UCHAR bInterfaceProtocol; -+ UCHAR reserved; -+ void *handle; -+ ULONG bNumEndpoints; -+ struct usbd_pipe_information pipes[1]; -+}; -+ -+struct usbd_interface_list_entry { -+ struct usb_interface_descriptor *intf_desc; -+ struct usbd_interface_information *intf; -+}; -+ -+struct nt_urb_header { -+ USHORT length; -+ USHORT function; -+ USBD_STATUS status; -+ void *usbd_dev_handle; -+ ULONG usbd_flags; -+}; -+ -+struct usbd_select_interface { -+ struct nt_urb_header header; -+ void *handle; -+ struct usbd_interface_information intf; -+}; -+ -+struct usbd_select_configuration { -+ struct nt_urb_header header; -+ struct usb_config_descriptor *config; -+ void *handle; -+ struct usbd_interface_information intf; -+}; -+ -+struct usbd_control_descriptor_request { -+ struct nt_urb_header header; -+ void *reserved; -+ ULONG reserved0; -+ ULONG transfer_buffer_length; -+ void *transfer_buffer; -+ struct mdl *mdl; -+ union nt_urb *urb_link; -+ struct urb_hcd_area hca; -+ USHORT reserved1; -+ UCHAR index; -+ UCHAR desc_type; -+ USHORT language_id; -+ USHORT reserved2; -+}; -+ -+struct usbd_bulk_or_intr_transfer { -+ struct nt_urb_header header; -+ struct usb_endpoint_descriptor *pipe_handle; -+ ULONG transfer_flags; -+ ULONG transfer_buffer_length; -+ void *transfer_buffer; -+ struct mdl *mdl; -+ union nt_urb *urb_link; -+ struct urb_hcd_area hca; -+}; -+ -+struct usbd_pipe_request { -+ struct nt_urb_header header; -+ struct usb_endpoint_descriptor *pipe_handle; -+}; -+ -+struct usbd_vendor_or_class_request { -+ struct nt_urb_header header; -+ void *reserved; -+ ULONG transfer_flags; -+ ULONG transfer_buffer_length; -+ void *transfer_buffer; -+ struct mdl *mdl; -+ union nt_urb *link; -+ struct urb_hcd_area hca; -+ UCHAR reserved_bits; -+ UCHAR request; -+ USHORT value; -+ USHORT index; -+ USHORT reserved1; -+}; -+ -+struct urb_control_feature_request { -+ struct nt_urb_header header; -+ void *reserved; -+ ULONG reserved2; -+ ULONG reserved3; -+ void *reserved4; -+ struct mdl *reserved5; -+ union nt_urb *link; -+ struct urb_hcd_area hca; -+ USHORT reserved0; -+ USHORT feature_selector; -+ USHORT index; -+ USHORT reserved1; -+}; -+ -+struct urb_control_get_status_request { -+ struct nt_urb_header header; -+ void *reserved; -+ ULONG reserved0; -+ ULONG transfer_buffer_length; -+ void *transfer_buffer; -+ struct mdl *mdl; -+ union nt_urb *link; -+ struct urb_hcd_area hca; -+ UCHAR reserved1[4]; -+ USHORT index; -+ USHORT reserved2; -+}; -+ -+struct usbd_iso_packet_desc { -+ ULONG offset; -+ ULONG length; -+ USBD_STATUS status; -+}; -+ -+struct usbd_isochronous_transfer { -+ struct nt_urb_header header; -+ struct usb_endpoint_descriptor *pipe_handle; -+ ULONG transfer_flags; -+ ULONG transfer_buffer_length; -+ void *transfer_buffer; -+ struct mdl *mdl; -+ union nt_urb *urb_link; -+ struct urb_hcd_area hca; -+ ULONG start_frame; -+ ULONG number_of_packets; -+ ULONG error_count; -+ struct usbd_iso_packet_desc iso_packet[1]; -+}; -+ -+union nt_urb { -+ struct nt_urb_header header; -+ struct usbd_select_interface select_intf; -+ struct usbd_select_configuration select_conf; -+ struct usbd_bulk_or_intr_transfer bulk_int_transfer; -+ struct usbd_control_descriptor_request control_desc; -+ struct usbd_vendor_or_class_request vendor_class_request; -+ struct usbd_isochronous_transfer isochronous; -+ struct usbd_pipe_request pipe_req; -+ struct urb_control_feature_request feat_req; -+ struct urb_control_get_status_request status_req; -+}; -+ -+struct usbd_bus_interface_usbdi { -+ USHORT Size; -+ USHORT Version; -+ void *Context; -+ void *InterfaceReference; -+ void *InterfaceDereference; -+ void *GetUSBDIVersion; -+ void *QueryBusTime; -+ void *SubmitIsoOutUrb; -+ void *QueryBusInformation; -+ /* version 1 and above have following field */ -+ void *IsDeviceHighSpeed; -+ /* version 2 (and above) have following field */ -+ void *LogEntry; -+}; -+ -+struct usbd_bus_information_level { -+ ULONG TotalBandwidth; -+ ULONG ConsumedBandwidth; -+ /* level 1 and above have following fields */ -+ ULONG ControllerNameLength; -+ wchar_t ControllerName[1]; -+}; -+ -+#define USBDI_VERSION_XP 0x00000500 // Windows XP -+#define USB_HCD_CAPS_SUPPORTS_RT_THREADS 0x00000001 -+#define USB_BUSIF_USBDI_VERSION_0 0x0000 -+#define USB_BUSIF_USBDI_VERSION_1 0x0001 -+#define USB_BUSIF_USBDI_VERSION_2 0x0002 -+ -+struct usbd_version_info { -+ ULONG usbdi_version; -+ ULONG supported_usb_version; -+}; -+ -+struct usbd_idle_callback { -+ void *callback; -+ void *context; -+}; -+ -+#define NT_URB_STATUS(nt_urb) ((nt_urb)->header.status) -+ -+NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp); -+void wrap_suspend_urbs(struct wrap_device *wd); -+void wrap_resume_urbs(struct wrap_device *wd); -+NTSTATUS usb_query_interface(struct wrap_device *wd, -+ struct io_stack_location *irp_sl); -+ -+#endif /* USB_H */ -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/win2lin_stubs.S linux-5.6.11-ndis/3rdparty/ndiswrapper/win2lin_stubs.S ---- linux-5.6.11/3rdparty/ndiswrapper/win2lin_stubs.S 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/win2lin_stubs.S 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,262 @@ -+/* -+ * Copyright (C) 2005 Karl Vogel, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include -+#include -+ -+#ifdef CONFIG_X86_64 -+ -+/* -+# Windows <---> Linux register usage conversion when calling functions -+# V = Volatile -+# NV = Non Volatile (needs to be saved) -+# -+# Win Lin -+# --------------------------------------- -+# Rax Return V Return V -+# Rbx NV NV -+# Rcx Arg1 V Arg4 V -+# Rdx Arg2 V Arg3 V -+# Rsi NV Arg2 V -+# Rdi NV Arg1 V -+# Rsp NV NV -+# Rbp NV NV -+# R8 Arg3 V Arg5 V -+# R9 Arg4 V Arg6 V -+# R10 V V -+# R11 V V -+# R12 NV NV -+# R13 NV NV -+# R14 NV NV -+# R15 NV NV -+# -+# In addition, Linux uses %rax to indicate number of SSE registers used -+# when variadic functions are called. Since there is no way to obtain this -+# from Windows, for now, we just assume this is 0 (hence %rax is cleared). -+# -+# Windows pushes arguments 5 and higher onto stack in case of integer -+# variables and 4 and higher in case of floating point variables (passed -+# in SSE registers). -+ -+In a windows function, the stackframe/registers look like this: -+ -+# 0x0048 .... -+# 0x0040 arg8 -+# 0x0038 arg7 -+# 0x0030 arg6 -+# 0x0028 arg5 -+# 0x0020 shadow/spill space for arg4 -+# 0x0018 shadow/spill space for arg3 -+# 0x0010 shadow/spill space for arg2 -+# 0x0008 shadow/spill space for arg1 -+# 0x0000 ret -+ -+# register spill space is same irrespective of number of arguments - even -+# if Windows function takes less than 4 arguments, 32 bytes above return -+# address is reserved for the function -+ -+In Linux it should look like: -+ -+# 0x0018 .... -+# 0x0010 arg8 -+# 0x0008 arg7 -+# 0x0000 ret -+ -+*/ -+ -+ .text -+ -+#define LINUX_REG_ARGS 6 -+#define LOOP_THRESHOLD 9 -+#define WORD_BYTES 8 -+ -+/* -+ * %rsi and %rdi must be saved because they are not saved by Linux calls, but -+ * Windows callers expect them to be saved. %rbp is saved to create a stack -+ * frame, which can help with debugging. We need to reserve space for an odd -+ * number of registers anyway to keep 16-bit alignment of the stack (one more -+ * position is used by the return address). -+ */ -+#define SAVED_REGS 3 -+ -+/* -+ * When calling the Linux function, several registers are saved on the stack. -+ * When passing more than 6 arguments, arguments starting with argument 7 are -+ * pushed to the stack as well. -+ * -+ * We also need to allocate an additional word on the stack to keep it aligned -+ * to the 16-bit boundary if the number of saved arguments plus one (for the -+ * return address) is odd. -+ */ -+ -+/* -+ * Number of arguments we pass on stack to the Linux function. -+ * The value of true is -1 in assembler, so we multiply it by another true -+ * value. -+ */ -+#define stack_args(argc) \ -+ ((0 < 1) * (argc > LINUX_REG_ARGS) * (argc - LINUX_REG_ARGS)) -+ -+/* Full required change of stack pointer, in words */ -+#define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1) -+ -+/* Full actual change of stack pointer, in words (must be even) */ -+#define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1) -+ -+/* Space allocated for Linux arguments on stack */ -+#define stack_space(argc) \ -+ ((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES) -+ -+/* -+ * win2lin_win_arg(N, ARGC) gives the address of the Windows argument N out of -+ * total ARGC after the stack has been prepared for the Linux function call. -+ * -+ * When called from Windows, the Nth argument is at (N * 8)(%rsp). We add the -+ * stack space allocated by the Linux function to compensate for %rsp change. -+ * -+ * Don't call with N less than 5! -+ */ -+#define win2lin_win_arg(n, argc) \ -+ ((n + SAVED_REGS) * WORD_BYTES + stack_space(argc))(%rsp) -+ -+/* -+ * win2lin_lin_arg(N) gives the address of the Nth Linux argument on the extra -+ * Linux stack frame. When more than 6 arguments are used, %rsp points to the -+ * 7th argument. The Nth argument is therefore at ((N - 7) * 8)(%rsp). -+ * -+ * Don't call with N less than 7! -+ */ -+#define win2lin_lin_arg(n) ((n - 1 - LINUX_REG_ARGS) * WORD_BYTES)(%rsp) -+ -+/* Declare function LONGNAME, call function SHORTNAME with ARGC arguments */ -+.macro win2linm longname, shortname, argc -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) -+ SYM_FUNC_START(\longname) -+#else -+ .type \longname, @function -+ ENTRY(\longname) -+#endif -+ -+ /* Create a call frame - it's optional, but good for debugging */ -+ .cfi_startproc -+ push %rbp -+ .cfi_def_cfa %rsp, 2 * WORD_BYTES -+ .cfi_offset %rbp, -2 * WORD_BYTES -+ mov %rsp, %rbp -+ .cfi_def_cfa %rbp, 2 * WORD_BYTES -+ -+ /* -+ * Registers %rdi and %rsi are volatile on Linux, but not on Windows, -+ * so save them on the stack. -+ */ -+ push %rsi -+ push %rdi -+ -+ /* Allocate extra stack space for arguments 7 and up */ -+ sub $stack_space(\argc), %rsp -+ -+ /* -+ * Copy arguments 7 and up. We do it early, before %rdi and %rsi -+ * are used for arguments 1 and 2, so we don't have to save them. -+ * We still need to save %rcx if using a string copy. -+ */ -+ .if (\argc < LOOP_THRESHOLD) -+ /* If a few arguments, copy them individually through %r11 */ -+ .if (\argc >= 7) -+ mov win2lin_win_arg(7, \argc), %r11 -+ mov %r11, win2lin_lin_arg(7) -+ .endif -+ .if (\argc >= 8) -+ mov win2lin_win_arg(8, \argc), %r11 -+ mov %r11, win2lin_lin_arg(8) -+ .endif -+ .else -+ /* If there are many arguments, copy them in a loop */ -+ /* Save arg1 to %r11 */ -+ mov %rcx, %r11 -+ /* Source and destination */ -+ lea win2lin_win_arg(LINUX_REG_ARGS + 1, \argc), %rsi -+ lea win2lin_lin_arg(LINUX_REG_ARGS + 1), %rdi -+ /* Number of arguments to copy (%ecx zero-extends to %rcx) */ -+ mov $(\argc - LINUX_REG_ARGS), %ecx -+ rep movsq -+ /* Restore arg1 directly to %rdi */ -+ mov %r11, %rdi -+ .endif -+ -+ /* -+ * Argument 1 - %rcx on Windows, %rdi on Linux -+ * Micro-optimization - if we used loop, arg1 is already in %rdi -+ */ -+ .if (\argc >= 1) && (\argc < LOOP_THRESHOLD) -+ mov %rcx, %rdi -+ .endif -+ -+ /* Argument 2 - %rdx on Windows, %rsi on Linux */ -+ .if (\argc >= 2) -+ mov %rdx, %rsi -+ .endif -+ -+ /* Argument 3 - %r8 on Windows, %rdx on Linux */ -+ .if (\argc >= 3) -+ mov %r8, %rdx -+ .endif -+ -+ /* Argument 4 - %r9 on Windows, %rcx on Linux */ -+ .if (\argc >= 4) -+ mov %r9, %rcx -+ .endif -+ -+ /* Argument 5 - first argument on stack on Windows, %r8 Linux */ -+ .if (\argc >= 5) -+ mov win2lin_win_arg(5, \argc), %r8 -+ .endif -+ -+ /* Argument 6 - second argument on stack on Windows, %r9 Linux */ -+ .if (\argc >= 6) -+ mov win2lin_win_arg(6, \argc), %r9 -+ .endif -+ -+ /* %rax on Linux is the number of arguments in SSE registers (zero) */ -+ xor %rax, %rax -+ -+ /* Call the function */ -+ call \shortname -+ -+ /* Free stack space for arguments 7 and up */ -+ add $stack_space(\argc), %rsp -+ -+ /* Restore saved registers */ -+ pop %rdi -+ pop %rsi -+ -+ /* Return to Windows code */ -+ leave -+ .cfi_def_cfa %rsp, WORD_BYTES -+ .cfi_restore %rbp -+ ret -+ .cfi_endproc -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0) -+ SYM_FUNC_END(\longname) -+#else -+ .size \longname, (. - \longname) -+#endif -+.endm -+ -+#define win2lin(name, argc) win2linm win2lin_ ## name ## _ ## argc, name, argc -+ -+#include "win2lin_stubs.h" -+ -+#endif /* CONFIG_X86_64 */ -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/winnt_types.h linux-5.6.11-ndis/3rdparty/ndiswrapper/winnt_types.h ---- linux-5.6.11/3rdparty/ndiswrapper/winnt_types.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/winnt_types.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,1701 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _WINNT_TYPES_H_ -+#define _WINNT_TYPES_H_ -+ -+#define TRUE 1 -+#define FALSE 0 -+ -+#define PASSIVE_LEVEL 0 -+#define APC_LEVEL 1 -+#define DISPATCH_LEVEL 2 -+#define DEVICE_LEVEL_BASE 4 -+ -+/* soft interrupts / bottom-half's are disabled at SOFT_IRQL */ -+#define SOFT_IRQL (DEVICE_LEVEL_BASE + 1) -+#define DIRQL (DEVICE_LEVEL_BASE + 2) -+ -+#define STATUS_WAIT_0 0 -+#define STATUS_SUCCESS 0 -+#define STATUS_ALERTED 0x00000101 -+#define STATUS_TIMEOUT 0x00000102 -+#define STATUS_PENDING 0x00000103 -+#define STATUS_FAILURE 0xC0000001 -+#define STATUS_NOT_IMPLEMENTED 0xC0000002 -+#define STATUS_INVALID_PARAMETER 0xC000000D -+#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010 -+#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 -+#define STATUS_ACCESS_DENIED 0xC0000022 -+#define STATUS_BUFFER_TOO_SMALL 0xC0000023 -+#define STATUS_OBJECT_NAME_INVALID 0xC0000023 -+#define STATUS_MUTANT_NOT_OWNED 0xC0000046 -+#define STATUS_RESOURCES 0xC000009A -+#define STATUS_DELETE_PENDING 0xC0000056 -+#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A -+#define STATUS_NOT_SUPPORTED 0xC00000BB -+#define STATUS_INVALID_PARAMETER_2 0xC00000F0 -+#define STATUS_NO_MEMORY 0xC0000017 -+#define STATUS_CANCELLED 0xC0000120 -+#define STATUS_DEVICE_REMOVED 0xC00002B6 -+#define STATUS_DEVICE_NOT_CONNECTED 0xC000009D -+ -+#define STATUS_BUFFER_OVERFLOW 0x80000005 -+ -+#define SL_PENDING_RETURNED 0x01 -+#define SL_INVOKE_ON_CANCEL 0x20 -+#define SL_INVOKE_ON_SUCCESS 0x40 -+#define SL_INVOKE_ON_ERROR 0x80 -+ -+#define IRP_MJ_CREATE 0x00 -+#define IRP_MJ_CREATE_NAMED_PIPE 0x01 -+#define IRP_MJ_CLOSE 0x02 -+#define IRP_MJ_READ 0x03 -+#define IRP_MJ_WRITE 0x04 -+ -+#define IRP_MJ_DEVICE_CONTROL 0x0E -+#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0F -+#define IRP_MJ_POWER 0x16 -+#define IRP_MJ_SYSTEM_CONTROL 0x0E -+#define IRP_MJ_PNP 0x1b -+#define IRP_MJ_MAXIMUM_FUNCTION 0x1b -+ -+#define IRP_MN_WAIT_WAKE 0x00 -+#define IRP_MN_POWER_SEQUENCE 0x01 -+#define IRP_MN_SET_POWER 0x02 -+#define IRP_MN_QUERY_POWER 0x03 -+ -+#define IRP_MN_REGINFO 0x08 -+#define IRP_MN_REGINFO_EX 0x0b -+ -+#define IRP_MN_START_DEVICE 0x00 -+#define IRP_MN_QUERY_REMOVE_DEVICE 0x01 -+#define IRP_MN_REMOVE_DEVICE 0x02 -+#define IRP_MN_CANCEL_REMOVE_DEVICE 0x03 -+#define IRP_MN_STOP_DEVICE 0x04 -+#define IRP_MN_QUERY_STOP_DEVICE 0x05 -+#define IRP_MN_CANCEL_STOP_DEVICE 0x06 -+#define IRP_MN_QUERY_DEVICE_RELATIONS 0x07 -+#define IRP_MN_QUERY_INTERFACE 0x08 -+ -+#define IRP_BUFFERED_IO 0x00000010 -+#define IRP_DEALLOCATE_BUFFER 0x00000020 -+#define IRP_INPUT_OPERATION 0x00000040 -+ -+#define IRP_DEFFER_IO_COMPLETION 0x00000800 -+ -+#define THREAD_WAIT_OBJECTS 3 -+#define MAX_WAIT_OBJECTS 64 -+ -+#define LOW_PRIORITY 0 -+#define LOW_REALTIME_PRIORITY 16 -+#define HIGH_PRIORITY 31 -+#define MAXIMUM_PRIORITY 32 -+ -+#define PROCESSOR_FEATURE_MAX 64 -+ -+#define IO_NO_INCREMENT 0 -+ -+#define WMIREG_ACTION_REGISTER 1 -+#define WMIREG_ACTION_DEREGISTER 2 -+#define WMIREG_ACTION_REREGISTER 3 -+#define WMIREG_ACTION_UPDATE_GUIDS 4 -+ -+#define WMIREGISTER 0 -+#define WMIUPDATE 1 -+ -+#ifdef CONFIG_X86_64 -+#define wstdcall -+#define wfastcall -+#define noregparm -+#define regparm3 -+ -+#define KI_USER_SHARED_DATA 0xfffff78000000000UL -+ -+#else -+ -+#define noregparm __attribute__((regparm(0))) -+#define regparm3 __attribute__((regparm(3))) -+#define wstdcall __attribute__((__stdcall__, regparm(0))) -+#if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ > 3) || __GNUC__ > 3) -+#undef fastcall -+#define wfastcall __attribute__((fastcall)) -+#else -+#error "gcc 3.4 or newer should be used for compiling this module" -+#endif -+ -+#define KI_USER_SHARED_DATA 0xffdf0000 -+ -+#endif -+ -+typedef u8 BOOLEAN; -+typedef u8 BYTE; -+typedef u8 *LPBYTE; -+typedef s8 CHAR; -+typedef u8 UCHAR; -+typedef s16 SHORT; -+typedef u16 USHORT; -+typedef u16 WORD; -+typedef s32 INT; -+typedef u32 UINT; -+typedef u32 DWORD; -+typedef s32 LONG; -+typedef u32 ULONG; -+typedef s64 LONGLONG; -+typedef u64 ULONGLONG; -+typedef u64 ULONGULONG; -+typedef u64 ULONG64; -+ -+typedef CHAR CCHAR; -+typedef USHORT wchar_t; -+typedef SHORT CSHORT; -+typedef LONGLONG LARGE_INTEGER; -+ -+typedef LONG NTSTATUS; -+ -+typedef LONG KPRIORITY; -+typedef LARGE_INTEGER PHYSICAL_ADDRESS; -+typedef UCHAR KIRQL; -+typedef CHAR KPROCESSOR_MODE; -+ -+/* ULONG_PTR is 32 bits on 32-bit platforms and 64 bits on 64-bit -+ * platform, which is same as 'unsigned long' in Linux */ -+typedef unsigned long ULONG_PTR; -+ -+typedef size_t SIZE_T; -+typedef ULONG_PTR KAFFINITY; -+typedef ULONG ACCESS_MASK; -+ -+typedef ULONG_PTR PFN_NUMBER; -+typedef ULONG SECURITY_INFORMATION; -+ -+/* non-negative numbers indicate success */ -+#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0) -+ -+struct ansi_string { -+ USHORT length; -+ USHORT max_length; -+ char *buf; -+}; -+ -+struct unicode_string { -+ USHORT length; -+ USHORT max_length; -+ wchar_t *buf; -+}; -+ -+struct nt_slist { -+ struct nt_slist *next; -+}; -+ -+#ifdef CONFIG_X86_64 -+/* it is not clear how nt_slist_head is used to store pointer to -+ * slists and depth; here we assume 'align' field is used to store -+ * depth and 'region' field is used to store slist pointers */ -+struct nt_slist_head { -+ union { -+ USHORT depth; -+ ULONGLONG align; -+ }; -+ union { -+ ULONGLONG region; -+ struct nt_slist *next; -+ }; -+} __attribute__((aligned(16))); -+typedef struct nt_slist_head nt_slist_header; -+#else -+union nt_slist_head { -+ ULONGLONG align; -+ struct { -+ struct nt_slist *next; -+ USHORT depth; -+ USHORT sequence; -+ }; -+}; -+typedef union nt_slist_head nt_slist_header; -+#endif -+ -+struct nt_list { -+ struct nt_list *next; -+ struct nt_list *prev; -+}; -+ -+typedef ULONG_PTR NT_SPIN_LOCK; -+ -+enum kdpc_importance {LowImportance, MediumImportance, HighImportance}; -+ -+struct kdpc; -+typedef void (*DPC)(struct kdpc *kdpc, void *ctx, void *arg1, -+ void *arg2) wstdcall; -+struct kdpc { -+ SHORT type; -+ UCHAR nr_cpu; -+ UCHAR importance; -+ struct nt_list list; -+ DPC func; -+ void *ctx; -+ void *arg1; -+ void *arg2; -+ union { -+ NT_SPIN_LOCK *lock; -+ /* 'lock' is not used; 'queued' represents whether -+ * kdpc is queued or not */ -+ int queued; -+ }; -+}; -+ -+enum pool_type { -+ NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType, -+ NonPagedPoolCacheAligned, PagedPoolCacheAligned, -+ NonPagedPoolCacheAlignedMustS, MaxPoolType, -+ NonPagedPoolSession = 32, -+ PagedPoolSession = NonPagedPoolSession + 1, -+ NonPagedPoolMustSucceedSession = PagedPoolSession + 1, -+ DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1, -+ NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1, -+ PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1, -+ NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1 -+}; -+ -+enum memory_caching_type_orig { -+ MmFrameBufferCached = 2 -+}; -+ -+enum memory_caching_type { -+ MmNonCached = FALSE, MmCached = TRUE, -+ MmWriteCombined = MmFrameBufferCached, MmHardwareCoherentCached, -+ MmNonCachedUnordered, MmUSWCCached, MmMaximumCacheType -+}; -+ -+enum lock_operation { -+ IoReadAccess, IoWriteAccess, IoModifyAccess -+}; -+ -+enum mode { -+ KernelMode, UserMode, MaximumMode -+}; -+ -+struct mdl { -+ struct mdl *next; -+ CSHORT size; -+ CSHORT flags; -+ /* NdisFreeBuffer doesn't pass pool, so we store pool in -+ * unused field 'process' */ -+ union { -+ void *process; -+ void *pool; -+ }; -+ void *mappedsystemva; -+ void *startva; -+ ULONG bytecount; -+ ULONG byteoffset; -+}; -+ -+#define MDL_MAPPED_TO_SYSTEM_VA 0x0001 -+#define MDL_PAGES_LOCKED 0x0002 -+#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004 -+#define MDL_ALLOCATED_FIXED_SIZE 0x0008 -+#define MDL_PARTIAL 0x0010 -+#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020 -+#define MDL_IO_PAGE_READ 0x0040 -+#define MDL_WRITE_OPERATION 0x0080 -+#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100 -+#define MDL_FREE_EXTRA_PTES 0x0200 -+#define MDL_IO_SPACE 0x0800 -+#define MDL_NETWORK_HEADER 0x1000 -+#define MDL_MAPPING_CAN_FAIL 0x2000 -+#define MDL_ALLOCATED_MUST_SUCCEED 0x4000 -+ -+#define MDL_POOL_ALLOCATED 0x0400 -+#define MDL_CACHE_ALLOCATED 0x8000 -+ -+#define PAGE_START(ptr) ((void *)((ULONG_PTR)(ptr) & ~(PAGE_SIZE - 1))) -+#define BYTE_OFFSET(ptr) ((ULONG)((ULONG_PTR)(ptr) & (PAGE_SIZE - 1))) -+ -+#define MmGetMdlByteCount(mdl) ((mdl)->bytecount) -+#define MmGetMdlVirtualAddress(mdl) ((mdl)->startva + (mdl)->byteoffset) -+#define MmGetMdlByteOffset(mdl) ((mdl)->byteoffset) -+#define MmGetSystemAddressForMdl(mdl) ((mdl)->mappedsystemva) -+#define MmGetSystemAddressForMdlSafe(mdl, priority) ((mdl)->mappedsystemva) -+#define MmGetMdlPfnArray(mdl) ((PFN_NUMBER *)(mdl + 1)) -+#define MmInitializeMdl(mdl, baseva, length) \ -+do { \ -+ (mdl)->next = NULL; \ -+ (mdl)->size = MmSizeOfMdl(baseva, length); \ -+ (mdl)->flags = 0; \ -+ (mdl)->startva = PAGE_START(baseva); \ -+ (mdl)->byteoffset = BYTE_OFFSET(baseva); \ -+ (mdl)->bytecount = length; \ -+ (mdl)->mappedsystemva = baseva; \ -+ TRACE4("%p %p %p %d %d", (mdl), baseva, (mdl)->startva, \ -+ (mdl)->byteoffset, length); \ -+} while (0) -+ -+struct kdevice_queue_entry { -+ struct nt_list list; -+ ULONG sort_key; -+ BOOLEAN inserted; -+}; -+ -+struct kdevice_queue { -+ USHORT type; -+ USHORT size; -+ struct nt_list list; -+ NT_SPIN_LOCK lock; -+ BOOLEAN busy; -+}; -+ -+struct wait_context_block { -+ struct kdevice_queue_entry wait_queue_entry; -+ void *device_routine; -+ void *device_context; -+ ULONG num_regs; -+ void *device_object; -+ void *current_irp; -+ void *buffer_chaining_dpc; -+}; -+ -+struct wait_block { -+ struct nt_list list; -+ struct task_struct *thread; -+ void *object; -+ int *wait_done; -+ USHORT wait_key; -+ USHORT wait_type; -+}; -+ -+struct dispatcher_header { -+ UCHAR type; -+ UCHAR absolute; -+ UCHAR size; -+ UCHAR inserted; -+ LONG signal_state; -+ struct nt_list wait_blocks; -+}; -+ -+enum event_type { -+ NotificationEvent, -+ SynchronizationEvent, -+}; -+ -+enum timer_type { -+ NotificationTimer = NotificationEvent, -+ SynchronizationTimer = SynchronizationEvent, -+}; -+ -+enum dh_type { -+ NotificationObject = NotificationEvent, -+ SynchronizationObject = SynchronizationEvent, -+ MutexObject, -+ SemaphoreObject, -+ ThreadObject, -+}; -+ -+enum wait_type { -+ WaitAll, WaitAny -+}; -+ -+/* objects that use dispatcher_header have it as the first field, so -+ * whenever we need to initialize dispatcher_header, we can convert -+ * that object into a nt_event and access dispatcher_header */ -+struct nt_event { -+ struct dispatcher_header dh; -+}; -+ -+struct wrap_timer; -+ -+#define WRAP_TIMER_MAGIC 47697249 -+ -+struct nt_timer { -+ struct dispatcher_header dh; -+ /* We can't fit Linux timer in this structure. Instead of -+ * padding the nt_timer structure, we replace due_time field -+ * with *wrap_timer and allocate memory for it when nt_timer is -+ * initialized */ -+ union { -+ ULONGLONG due_time; -+ struct wrap_timer *wrap_timer; -+ }; -+ struct nt_list nt_timer_list; -+ struct kdpc *kdpc; -+ union { -+ LONG period; -+ LONG wrap_timer_magic; -+ }; -+}; -+ -+struct nt_mutex { -+ struct dispatcher_header dh; -+ struct nt_list list; -+ struct task_struct *owner_thread; -+ BOOLEAN abandoned; -+ BOOLEAN apc_disable; -+}; -+ -+struct nt_semaphore { -+ struct dispatcher_header dh; -+ LONG limit; -+}; -+ -+struct nt_thread { -+ struct dispatcher_header dh; -+ /* the rest in Windows is a long structure; since this -+ * structure is opaque to drivers, we just define what we -+ * need */ -+ int pid; -+ NTSTATUS status; -+ struct task_struct *task; -+ struct nt_list irps; -+ NT_SPIN_LOCK lock; -+ KPRIORITY prio; -+}; -+ -+#define set_object_type(dh, type) ((dh)->type = (type)) -+#define is_notify_object(dh) ((dh)->type == NotificationObject) -+#define is_synch_object(dh) ((dh)->type == SynchronizationObject) -+#define is_mutex_object(dh) ((dh)->type == MutexObject) -+#define is_semaphore_object(dh) ((dh)->type == SemaphoreObject) -+#define is_nt_thread_object(dh) ((dh)->type == ThreadObject) -+ -+#define IO_TYPE_ADAPTER 1 -+#define IO_TYPE_CONTROLLER 2 -+#define IO_TYPE_DEVICE 3 -+#define IO_TYPE_DRIVER 4 -+#define IO_TYPE_FILE 5 -+#define IO_TYPE_IRP 6 -+#define IO_TYPE_DEVICE_OBJECT_EXTENSION 13 -+ -+struct irp; -+struct dev_obj_ext; -+struct driver_object; -+ -+struct device_object { -+ CSHORT type; -+ USHORT size; -+ LONG ref_count; -+ struct driver_object *drv_obj; -+ struct device_object *next; -+ struct device_object *attached; -+ struct irp *current_irp; -+ void *io_timer; -+ ULONG flags; -+ ULONG characteristics; -+ void *vpb; -+ void *dev_ext; -+ CCHAR stack_count; -+ union { -+ struct nt_list queue_list; -+ struct wait_context_block wcb; -+ } queue; -+ ULONG align_req; -+ struct kdevice_queue dev_queue; -+ struct kdpc dpc; -+ ULONG active_threads; -+ void *security_desc; -+ struct nt_event lock; -+ USHORT sector_size; -+ USHORT spare1; -+ struct dev_obj_ext *dev_obj_ext; -+ void *reserved; -+}; -+ -+struct dev_obj_ext { -+ CSHORT type; -+ CSHORT size; -+ struct device_object *dev_obj; -+ struct device_object *attached_to; -+}; -+ -+struct io_status_block { -+ union { -+ NTSTATUS status; -+ void *pointer; -+ }; -+ ULONG_PTR info; -+}; -+ -+#ifdef CONFIG_X86_64 -+struct io_status_block32 { -+ NTSTATUS status; -+ ULONG info; -+}; -+#endif -+ -+#define DEVICE_TYPE ULONG -+ -+struct driver_extension; -+ -+typedef NTSTATUS driver_dispatch_t(struct device_object *dev_obj, -+ struct irp *irp) wstdcall; -+ -+struct driver_object { -+ CSHORT type; -+ CSHORT size; -+ struct device_object *dev_obj; -+ ULONG flags; -+ void *start; -+ ULONG driver_size; -+ void *section; -+ struct driver_extension *drv_ext; -+ struct unicode_string name; -+ struct unicode_string *hardware_database; -+ void *fast_io_dispatch; -+ void *init; -+ void *start_io; -+ void (*unload)(struct driver_object *driver) wstdcall; -+ driver_dispatch_t *major_func[IRP_MJ_MAXIMUM_FUNCTION + 1]; -+}; -+ -+struct driver_extension { -+ struct driver_object *drv_obj; -+ NTSTATUS (*add_device)(struct driver_object *drv_obj, -+ struct device_object *dev_obj); -+ ULONG count; -+ struct unicode_string service_key_name; -+ struct nt_list custom_ext; -+}; -+ -+struct custom_ext { -+ struct nt_list list; -+ void *client_id; -+}; -+ -+struct wrap_bin_file; -+ -+struct file_object { -+ CSHORT type; -+ CSHORT size; -+ struct device_object *dev_obj; -+ void *volume_parameter_block; -+ void *fs_context; -+ void *fs_context2; -+ void *section_object_pointer; -+ void *private_cache_map; -+ NTSTATUS final_status; -+ union { -+ struct file_object *related_file_object; -+ struct wrap_bin_file *wrap_bin_file; -+ }; -+ BOOLEAN lock_operation; -+ BOOLEAN delete_pending; -+ BOOLEAN read_access; -+ BOOLEAN write_access; -+ BOOLEAN delete_access; -+ BOOLEAN shared_read; -+ BOOLEAN shared_write; -+ BOOLEAN shared_delete; -+ ULONG flags; -+ struct unicode_string _name_; -+ LARGE_INTEGER current_byte_offset; -+ ULONG waiters; -+ ULONG busy; -+ void *last_lock; -+ struct nt_event lock; -+ struct nt_event event; -+ void *completion_context; -+}; -+ -+#ifdef CONFIG_X86_64 -+#define POINTER_ALIGN __attribute__((aligned(8))) -+#else -+#define POINTER_ALIGN -+#endif -+ -+#define CACHE_ALIGN __attribute__((aligned(128))) -+ -+enum system_power_state { -+ PowerSystemUnspecified = 0, -+ PowerSystemWorking, PowerSystemSleeping1, PowerSystemSleeping2, -+ PowerSystemSleeping3, PowerSystemHibernate, PowerSystemShutdown, -+ PowerSystemMaximum, -+}; -+ -+enum device_power_state { -+ PowerDeviceUnspecified = 0, -+ PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, PowerDeviceD3, -+ PowerDeviceMaximum, -+}; -+ -+union power_state { -+ enum system_power_state system_state; -+ enum device_power_state device_state; -+}; -+ -+enum power_state_type { -+ SystemPowerState = 0, DevicePowerState, -+}; -+ -+enum power_action { -+ PowerActionNone = 0, -+ PowerActionReserved, PowerActionSleep, PowerActionHibernate, -+ PowerActionShutdown, PowerActionShutdownReset, PowerActionShutdownOff, -+ PowerActionWarmEject, -+}; -+ -+struct guid { -+ ULONG data1; -+ USHORT data2; -+ USHORT data3; -+ UCHAR data4[8]; -+}; -+ -+struct nt_interface { -+ USHORT size; -+ USHORT version; -+ void *context; -+ void (*reference)(void *context) wstdcall; -+ void (*dereference)(void *context) wstdcall; -+}; -+ -+enum interface_type { -+ InterfaceTypeUndefined = -1, Internal, Isa, Eisa, MicroChannel, -+ TurboChannel, PCIBus, VMEBus, NuBus, PCMCIABus, CBus, MPIBus, -+ MPSABus, ProcessorInternal, InternalPowerBus, PNPISABus, -+ PNPBus, MaximumInterfaceType, -+}; -+ -+#define CmResourceTypeNull 0 -+#define CmResourceTypePort 1 -+#define CmResourceTypeInterrupt 2 -+#define CmResourceTypeMemory 3 -+#define CmResourceTypeDma 4 -+#define CmResourceTypeDeviceSpecific 5 -+#define CmResourceTypeBusNumber 6 -+#define CmResourceTypeMaximum 7 -+ -+#define CmResourceTypeNonArbitrated 128 -+#define CmResourceTypeConfigData 128 -+#define CmResourceTypeDevicePrivate 129 -+#define CmResourceTypePcCardConfig 130 -+#define CmResourceTypeMfCardConfig 131 -+ -+enum cm_share_disposition { -+ CmResourceShareUndetermined = 0, CmResourceShareDeviceExclusive, -+ CmResourceShareDriverExclusive, CmResourceShareShared -+}; -+ -+#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0 -+#define CM_RESOURCE_INTERRUPT_LATCHED 1 -+#define CM_RESOURCE_MEMORY_READ_WRITE 0x0000 -+#define CM_RESOURCE_MEMORY_READ_ONLY 0x0001 -+#define CM_RESOURCE_MEMORY_WRITE_ONLY 0x0002 -+#define CM_RESOURCE_MEMORY_PREFETCHABLE 0x0004 -+ -+#define CM_RESOURCE_MEMORY_COMBINEDWRITE 0x0008 -+#define CM_RESOURCE_MEMORY_24 0x0010 -+#define CM_RESOURCE_MEMORY_CACHEABLE 0x0020 -+ -+#define CM_RESOURCE_PORT_MEMORY 0x0000 -+#define CM_RESOURCE_PORT_IO 0x0001 -+#define CM_RESOURCE_PORT_10_BIT_DECODE 0x0004 -+#define CM_RESOURCE_PORT_12_BIT_DECODE 0x0008 -+#define CM_RESOURCE_PORT_16_BIT_DECODE 0x0010 -+#define CM_RESOURCE_PORT_POSITIVE_DECODE 0x0020 -+#define CM_RESOURCE_PORT_PASSIVE_DECODE 0x0040 -+#define CM_RESOURCE_PORT_WINDOW_DECODE 0x0080 -+ -+#define CM_RESOURCE_DMA_8 0x0000 -+#define CM_RESOURCE_DMA_16 0x0001 -+#define CM_RESOURCE_DMA_32 0x0002 -+#define CM_RESOURCE_DMA_8_AND_16 0x0004 -+#define CM_RESOURCE_DMA_BUS_MASTER 0x0008 -+#define CM_RESOURCE_DMA_TYPE_A 0x0010 -+#define CM_RESOURCE_DMA_TYPE_B 0x0020 -+#define CM_RESOURCE_DMA_TYPE_F 0x0040 -+ -+#define MAX_RESOURCES 20 -+ -+#pragma pack(push,4) -+struct cm_partial_resource_descriptor { -+ UCHAR type; -+ UCHAR share; -+ USHORT flags; -+ union { -+ struct { -+ PHYSICAL_ADDRESS start; -+ ULONG length; -+ } generic; -+ struct { -+ PHYSICAL_ADDRESS start; -+ ULONG length; -+ } port; -+ struct { -+ ULONG level; -+ ULONG vector; -+ KAFFINITY affinity; -+ } interrupt; -+ struct { -+ PHYSICAL_ADDRESS start; -+ ULONG length; -+ } memory; -+ struct { -+ ULONG channel; -+ ULONG port; -+ ULONG reserved1; -+ } dma; -+ struct { -+ ULONG data[3]; -+ } device_private; -+ struct { -+ ULONG start; -+ ULONG length; -+ ULONG reserved; -+ } bus_number; -+ struct { -+ ULONG data_size; -+ ULONG reserved1; -+ ULONG reserved2; -+ } device_specific_data; -+ } u; -+}; -+#pragma pack(pop) -+ -+struct cm_partial_resource_list { -+ USHORT version; -+ USHORT revision; -+ ULONG count; -+ struct cm_partial_resource_descriptor partial_descriptors[1]; -+}; -+ -+struct cm_full_resource_descriptor { -+ enum interface_type interface_type; -+ ULONG bus_number; -+ struct cm_partial_resource_list partial_resource_list; -+}; -+ -+struct cm_resource_list { -+ ULONG count; -+ struct cm_full_resource_descriptor list[1]; -+}; -+ -+enum file_info_class { -+ FileDirectoryInformation = 1, -+ FileBasicInformation = 4, -+ FileStandardInformation = 5, -+ FileNameInformation = 9, -+ FilePositionInformation = 14, -+ FileAlignmentInformation = 17, -+ FileNetworkOpenInformation = 34, -+ FileAttributeTagInformation = 35, -+ FileMaximumInformation = 41, -+}; -+ -+enum fs_info_class { -+ FileFsVolumeInformation = 1, -+ /* ... */ -+ FileFsMaximumInformation = 9, -+}; -+ -+enum device_relation_type { -+ BusRelations, EjectionRelations, PowerRelations, RemovalRelations, -+ TargetDeviceRelation, SingleBusRelations, -+}; -+ -+enum bus_query_id_type { -+ BusQueryDeviceID = 0, BusQueryHardwareIDs = 1, -+ BusQueryCompatibleIDs = 2, BusQueryInstanceID = 3, -+ BusQueryDeviceSerialNumber = 4, -+}; -+ -+enum device_text_type { -+ DeviceTextDescription = 0, DeviceTextLocationInformation = 1, -+}; -+ -+enum device_usage_notification_type { -+ DeviceUsageTypeUndefined, DeviceUsageTypePaging, -+ DeviceUsageTypeHibernation, DevbiceUsageTypeDumpFile, -+}; -+ -+#define METHOD_BUFFERED 0 -+#define METHOD_IN_DIRECT 1 -+#define METHOD_OUT_DIRECT 2 -+#define METHOD_NEITHER 3 -+ -+#define CTL_CODE(dev_type, func, method, access) \ -+ (((dev_type) << 16) | ((access) << 14) | ((func) << 2) | (method)) -+ -+#define IO_METHOD_FROM_CTL_CODE(code) (code & 0x3) -+ -+#ifndef CONFIG_X86_64 -+#pragma pack(push,4) -+#endif -+struct io_stack_location { -+ UCHAR major_fn; -+ UCHAR minor_fn; -+ UCHAR flags; -+ UCHAR control; -+ union { -+ struct { -+ void *security_context; -+ ULONG options; -+ USHORT POINTER_ALIGN file_attributes; -+ USHORT share_access; -+ ULONG POINTER_ALIGN ea_length; -+ } create; -+ struct { -+ ULONG length; -+ ULONG POINTER_ALIGN key; -+ LARGE_INTEGER byte_offset; -+ } read; -+ struct { -+ ULONG length; -+ ULONG POINTER_ALIGN key; -+ LARGE_INTEGER byte_offset; -+ } write; -+ struct { -+ ULONG length; -+ enum file_info_class POINTER_ALIGN file_info_class; -+ } query_file; -+ struct { -+ ULONG length; -+ enum file_info_class POINTER_ALIGN file_info_class; -+ struct file_object *file_object; -+ union { -+ struct { -+ BOOLEAN replace_if_exists; -+ BOOLEAN advance_only; -+ }; -+ ULONG cluster_count; -+ void *delete_handle; -+ }; -+ } set_file; -+ struct { -+ ULONG length; -+ enum fs_info_class POINTER_ALIGN fs_info_class; -+ } query_volume; -+ struct { -+ ULONG output_buf_len; -+ ULONG POINTER_ALIGN input_buf_len; -+ ULONG POINTER_ALIGN code; -+ void *type3_input_buf; -+ } dev_ioctl; -+ struct { -+ SECURITY_INFORMATION security_info; -+ ULONG POINTER_ALIGN length; -+ } query_security; -+ struct { -+ SECURITY_INFORMATION security_info; -+ void *security_descriptor; -+ } set_security; -+ struct { -+ void *vpb; -+ struct device_object *device_object; -+ } mount_volume; -+ struct { -+ void *vpb; -+ struct device_object *device_object; -+ } verify_volume; -+ struct { -+ void *srb; -+ } scsi; -+ struct { -+ enum device_relation_type type; -+ } query_device_relations; -+ struct { -+ const struct guid *type; -+ USHORT size; -+ USHORT version; -+ struct nt_interface *intf; -+ void *intf_data; -+ } query_intf; -+ struct { -+ void *capabilities; -+ } device_capabilities; -+ struct { -+ void *io_resource_requirement_list; -+ } filter_resource_requirements; -+ struct { -+ ULONG which_space; -+ void *buffer; -+ ULONG offset; -+ ULONG POINTER_ALIGN length; -+ } read_write_config; -+ struct { -+ BOOLEAN lock; -+ } set_lock; -+ struct { -+ enum bus_query_id_type id_type; -+ } query_id; -+ struct { -+ enum device_text_type device_text_type; -+ ULONG POINTER_ALIGN locale_id; -+ } query_device_text; -+ struct { -+ BOOLEAN in_path; -+ BOOLEAN reserved[3]; -+ enum device_usage_notification_type POINTER_ALIGN type; -+ } usage_notification; -+ struct { -+ enum system_power_state power_state; -+ } wait_wake; -+ struct { -+ void *power_sequence; -+ } power_sequence; -+ struct { -+ ULONG sys_context; -+ enum power_state_type POINTER_ALIGN type; -+ union power_state POINTER_ALIGN state; -+ enum power_action POINTER_ALIGN shutdown_type; -+ } power; -+ struct { -+ struct cm_resource_list *allocated_resources; -+ struct cm_resource_list *allocated_resources_translated; -+ } start_device; -+ struct { -+ ULONG_PTR provider_id; -+ void *data_path; -+ ULONG buf_len; -+ void *buf; -+ } wmi; -+ struct { -+ void *arg1; -+ void *arg2; -+ void *arg3; -+ void *arg4; -+ } others; -+ } params; -+ struct device_object *dev_obj; -+ struct file_object *file_obj; -+ NTSTATUS (*completion_routine)(struct device_object *, -+ struct irp *, void *) wstdcall; -+ void *context; -+}; -+#ifndef CONFIG_X86_64 -+#pragma pack(pop) -+#endif -+ -+struct kapc { -+ CSHORT type; -+ CSHORT size; -+ ULONG spare0; -+ struct nt_thread *thread; -+ struct nt_list list; -+ void *kernele_routine; -+ void *rundown_routine; -+ void *normal_routine; -+ void *normal_context; -+ void *sys_arg1; -+ void *sys_arg2; -+ CCHAR apc_state_index; -+ KPROCESSOR_MODE apc_mode; -+ BOOLEAN inserted; -+}; -+ -+#define IRP_NOCACHE 0x00000001 -+#define IRP_SYNCHRONOUS_API 0x00000004 -+#define IRP_ASSOCIATED_IRP 0x00000008 -+ -+enum urb_state { -+ URB_INVALID = 1, URB_ALLOCATED, URB_SUBMITTED, -+ URB_COMPLETED, URB_FREE, URB_SUSPEND, URB_INT_UNLINKED }; -+ -+struct wrap_urb { -+ struct nt_list list; -+ enum urb_state state; -+ struct nt_list complete_list; -+ unsigned int flags; -+ struct urb *urb; -+ struct irp *irp; -+#ifdef USB_DEBUG -+ unsigned int id; -+#endif -+}; -+ -+struct irp { -+ SHORT type; -+ USHORT size; -+ struct mdl *mdl; -+ ULONG flags; -+ union { -+ struct irp *master_irp; -+ LONG irp_count; -+ void *system_buffer; -+ } associated_irp; -+ struct nt_list thread_list; -+ struct io_status_block io_status; -+ KPROCESSOR_MODE requestor_mode; -+ BOOLEAN pending_returned; -+ CHAR stack_count; -+ CHAR current_location; -+ BOOLEAN cancel; -+ KIRQL cancel_irql; -+ CCHAR apc_env; -+ UCHAR alloc_flags; -+ struct io_status_block *user_status; -+ struct nt_event *user_event; -+ union { -+ struct { -+ void *user_apc_routine; -+ void *user_apc_context; -+ } async_params; -+ LARGE_INTEGER alloc_size; -+ } overlay; -+ void (*cancel_routine)(struct device_object *, struct irp *) wstdcall; -+ void *user_buf; -+ union { -+ struct { -+ union { -+ struct kdevice_queue_entry dev_q_entry; -+ struct { -+ void *driver_context[4]; -+ }; -+ }; -+ void *thread; -+ char *aux_buf; -+ struct { -+ struct nt_list list; -+ union { -+ struct io_stack_location *csl; -+ ULONG packet_type; -+ }; -+ }; -+ struct file_object *file_object; -+ } overlay; -+ union { -+ struct kapc apc; -+ /* space for apc is used for ndiswrapper -+ * specific fields */ -+ struct { -+ struct wrap_urb *wrap_urb; -+ struct wrap_device *wrap_device; -+ }; -+ }; -+ void *completion_key; -+ } tail; -+}; -+ -+#define IoSizeOfIrp(stack_count) \ -+ ((USHORT)(sizeof(struct irp) + \ -+ ((stack_count) * sizeof(struct io_stack_location)))) -+#define IoGetCurrentIrpStackLocation(irp) \ -+ (irp)->tail.overlay.csl -+#define IoGetNextIrpStackLocation(irp) \ -+ (IoGetCurrentIrpStackLocation(irp) - 1) -+#define IoGetPreviousIrpStackLocation(irp) \ -+ (IoGetCurrentIrpStackLocation(irp) + 1) -+ -+#define IoSetNextIrpStackLocation(irp) \ -+do { \ -+ KIRQL _irql_; \ -+ IoAcquireCancelSpinLock(&_irql_); \ -+ (irp)->current_location--; \ -+ IoGetCurrentIrpStackLocation(irp)--; \ -+ IoReleaseCancelSpinLock(_irql_); \ -+} while (0) -+ -+#define IoSkipCurrentIrpStackLocation(irp) \ -+do { \ -+ KIRQL _irql_; \ -+ IoAcquireCancelSpinLock(&_irql_); \ -+ (irp)->current_location++; \ -+ IoGetCurrentIrpStackLocation(irp)++; \ -+ IoReleaseCancelSpinLock(_irql_); \ -+} while (0) -+ -+static inline void -+IoCopyCurrentIrpStackLocationToNext(struct irp *irp) -+{ -+ struct io_stack_location *next; -+ next = IoGetNextIrpStackLocation(irp); -+ memcpy(next, IoGetCurrentIrpStackLocation(irp), -+ offsetof(struct io_stack_location, completion_routine)); -+ next->control = 0; -+} -+ -+static inline void -+IoSetCompletionRoutine(struct irp *irp, void *routine, void *context, -+ BOOLEAN success, BOOLEAN error, BOOLEAN cancel) -+{ -+ struct io_stack_location *irp_sl = IoGetNextIrpStackLocation(irp); -+ irp_sl->completion_routine = routine; -+ irp_sl->context = context; -+ irp_sl->control = 0; -+ if (success) -+ irp_sl->control |= SL_INVOKE_ON_SUCCESS; -+ if (error) -+ irp_sl->control |= SL_INVOKE_ON_ERROR; -+ if (cancel) -+ irp_sl->control |= SL_INVOKE_ON_CANCEL; -+} -+ -+#define IoMarkIrpPending(irp) \ -+ (IoGetCurrentIrpStackLocation((irp))->control |= SL_PENDING_RETURNED) -+#define IoUnmarkIrpPending(irp) \ -+ (IoGetCurrentIrpStackLocation((irp))->control &= ~SL_PENDING_RETURNED) -+ -+#define IRP_SL(irp, n) (((struct io_stack_location *)((irp) + 1)) + (n)) -+#define IRP_DRIVER_CONTEXT(irp) (irp)->tail.overlay.driver_context -+#define IoIrpThread(irp) ((irp)->tail.overlay.thread) -+ -+#define IRP_URB(irp) \ -+ (union nt_urb *)(IoGetCurrentIrpStackLocation(irp)->params.others.arg1) -+ -+#define IRP_WRAP_DEVICE(irp) (irp)->tail.wrap_device -+#define IRP_WRAP_URB(irp) (irp)->tail.wrap_urb -+ -+struct wmi_guid_reg_info { -+ struct guid *guid; -+ ULONG instance_count; -+ ULONG flags; -+}; -+ -+struct wmilib_context { -+ ULONG guid_count; -+ struct wmi_guid_reg_info *guid_list; -+ void *query_wmi_reg_info; -+ void *query_wmi_data_block; -+ void *set_wmi_data_block; -+ void *set_wmi_data_item; -+ void *execute_wmi_method; -+ void *wmi_function_control; -+}; -+ -+enum key_value_information_class { -+ KeyValueBasicInformation, KeyValueFullInformation, -+ KeyValuePartialInformation, KeyValueFullInformationAlign64, -+ KeyValuePartialInformationAlign64 -+}; -+ -+struct file_name_info { -+ ULONG length; -+ wchar_t *name; -+}; -+ -+struct file_std_info { -+ LARGE_INTEGER alloc_size; -+ LARGE_INTEGER eof; -+ ULONG num_links; -+ BOOLEAN delete_pending; -+ BOOLEAN dir; -+}; -+ -+enum nt_obj_type { -+ NT_OBJ_EVENT = 10, NT_OBJ_MUTEX, NT_OBJ_THREAD, NT_OBJ_TIMER, -+ NT_OBJ_SEMAPHORE, -+}; -+ -+enum common_object_type { -+ OBJECT_TYPE_NONE, OBJECT_TYPE_DEVICE, OBJECT_TYPE_DRIVER, -+ OBJECT_TYPE_NT_THREAD, OBJECT_TYPE_FILE, OBJECT_TYPE_CALLBACK, -+}; -+ -+struct common_object_header { -+ struct nt_list list; -+ enum common_object_type type; -+ UINT size; -+ UINT ref_count; -+ BOOLEAN close_in_process; -+ BOOLEAN permanent; -+ struct unicode_string name; -+}; -+ -+#define OBJECT_TO_HEADER(object) \ -+ (struct common_object_header *)((void *)(object) - \ -+ sizeof(struct common_object_header)) -+#define OBJECT_SIZE(size) \ -+ ((size) + sizeof(struct common_object_header)) -+#define HEADER_TO_OBJECT(hdr) \ -+ ((void *)(hdr) + sizeof(struct common_object_header)) -+#define HANDLE_TO_OBJECT(handle) HEADER_TO_OBJECT(handle) -+#define HANDLE_TO_HEADER(handle) (handle) -+ -+enum work_queue_type { -+ CriticalWorkQueue, DelayedWorkQueue, HyperCriticalWorkQueue, -+ MaximumWorkQueue -+}; -+ -+typedef void (*NTOS_WORK_FUNC)(void *arg1, void *arg2) wstdcall; -+ -+struct io_workitem { -+ enum work_queue_type type; -+ struct device_object *dev_obj; -+ NTOS_WORK_FUNC worker_routine; -+ void *context; -+}; -+ -+struct io_workitem_entry { -+ struct nt_list list; -+ struct io_workitem *io_workitem; -+}; -+ -+enum mm_page_priority { -+ LowPagePriority, NormalPagePriority = 16, HighPagePriority = 32 -+}; -+ -+enum kinterrupt_mode { -+ LevelSensitive, Latched -+}; -+ -+enum ntos_wait_reason { -+ Executive, FreePage, PageIn, PoolAllocation, DelayExecution, -+ Suspended, UserRequest, WrExecutive, WrFreePage, WrPageIn, -+ WrPoolAllocation, WrDelayExecution, WrSuspended, WrUserRequest, -+ WrEventPair, WrQueue, WrLpcReceive, WrLpcReply, WrVirtualMemory, -+ WrPageOut, WrRendezvous, Spare2, Spare3, Spare4, Spare5, Spare6, -+ WrKernel, MaximumWaitReason -+}; -+ -+typedef enum ntos_wait_reason KWAIT_REASON; -+ -+typedef void *LOOKASIDE_ALLOC_FUNC(enum pool_type pool_type, -+ SIZE_T size, ULONG tag) wstdcall; -+typedef void LOOKASIDE_FREE_FUNC(void *) wstdcall; -+ -+struct npaged_lookaside_list { -+ nt_slist_header head; -+ USHORT depth; -+ USHORT maxdepth; -+ ULONG totalallocs; -+ union { -+ ULONG allocmisses; -+ ULONG allochits; -+ } u1; -+ ULONG totalfrees; -+ union { -+ ULONG freemisses; -+ ULONG freehits; -+ } u2; -+ enum pool_type pool_type; -+ ULONG tag; -+ ULONG size; -+ LOOKASIDE_ALLOC_FUNC *alloc_func; -+ LOOKASIDE_FREE_FUNC *free_func; -+ struct nt_list list; -+ ULONG lasttotallocs; -+ union { -+ ULONG lastallocmisses; -+ ULONG lastallochits; -+ } u3; -+ ULONG pad[2]; -+#ifndef CONFIG_X86_64 -+ NT_SPIN_LOCK obsolete; -+#endif -+} -+#ifdef CONFIG_X86_64 -+CACHE_ALIGN -+#endif -+; -+ -+enum device_registry_property { -+ DevicePropertyDeviceDescription, DevicePropertyHardwareID, -+ DevicePropertyCompatibleIDs, DevicePropertyBootConfiguration, -+ DevicePropertyBootConfigurationTranslated, -+ DevicePropertyClassName, DevicePropertyClassGuid, -+ DevicePropertyDriverKeyName, DevicePropertyManufacturer, -+ DevicePropertyFriendlyName, DevicePropertyLocationInformation, -+ DevicePropertyPhysicalDeviceObjectName, DevicePropertyBusTypeGuid, -+ DevicePropertyLegacyBusType, DevicePropertyBusNumber, -+ DevicePropertyEnumeratorName, DevicePropertyAddress, -+ DevicePropertyUINumber, DevicePropertyInstallState, -+ DevicePropertyRemovalPolicy -+}; -+ -+enum trace_information_class { -+ TraceIdClass, TraceHandleClass, TraceEnableFlagsClass, -+ TraceEnableLevelClass, GlobalLoggerHandleClass, EventLoggerHandleClass, -+ AllLoggerHandlesClass, TraceHandleByNameClass -+}; -+ -+struct kinterrupt; -+typedef BOOLEAN (*PKSERVICE_ROUTINE)(struct kinterrupt *interrupt, -+ void *context) wstdcall; -+typedef BOOLEAN (*PKSYNCHRONIZE_ROUTINE)(void *context) wstdcall; -+ -+struct kinterrupt { -+ ULONG vector; -+ KAFFINITY cpu_mask; -+ NT_SPIN_LOCK lock; -+ NT_SPIN_LOCK *actual_lock; -+ BOOLEAN shared; -+ BOOLEAN save_fp; -+ union { -+ CHAR processor_number; -+#ifdef CONFIG_DEBUG_SHIRQ -+ CHAR enabled; -+#endif -+ } u; -+ PKSERVICE_ROUTINE isr; -+ void *isr_ctx; -+ struct nt_list list; -+ KIRQL irql; -+ KIRQL synch_irql; -+ enum kinterrupt_mode mode; -+}; -+ -+struct time_fields { -+ CSHORT year; -+ CSHORT month; -+ CSHORT day; -+ CSHORT hour; -+ CSHORT minute; -+ CSHORT second; -+ CSHORT milliseconds; -+ CSHORT weekday; -+}; -+ -+struct object_attributes { -+ ULONG length; -+ void *root_dir; -+ struct unicode_string *name; -+ ULONG attributes; -+ void *security_descr; -+ void *security_qos; -+}; -+ -+typedef void (*PCALLBACK_FUNCTION)(void *context, void *arg1, -+ void *arg2) wstdcall; -+ -+struct callback_object; -+struct callback_func { -+ PCALLBACK_FUNCTION func; -+ void *context; -+ struct nt_list list; -+ struct callback_object *object; -+}; -+ -+struct callback_object { -+ NT_SPIN_LOCK lock; -+ struct nt_list list; -+ struct nt_list callback_funcs; -+ BOOLEAN allow_multiple_callbacks; -+ struct object_attributes *attributes; -+}; -+ -+enum section_inherit { -+ ViewShare = 1, ViewUnmap = 2 -+}; -+ -+struct ksystem_time { -+ ULONG low_part; -+ LONG high1_time; -+ LONG high2_time; -+}; -+ -+enum nt_product_type { -+ nt_product_win_nt = 1, nt_product_lan_man_nt, nt_product_server -+}; -+ -+enum alt_arch_type { -+ arch_type_standard, arch_type_nex98x86, end_alternatives -+}; -+ -+struct kuser_shared_data { -+ ULONG tick_count; -+ ULONG tick_count_multiplier; -+ volatile struct ksystem_time interrupt_time; -+ volatile struct ksystem_time system_time; -+ volatile struct ksystem_time time_zone_bias; -+ USHORT image_number_low; -+ USHORT image_number_high; -+ wchar_t nt_system_root[260]; -+ ULONG max_stack_trace_depth; -+ ULONG crypto_exponent; -+ ULONG time_zone_id; -+ ULONG large_page_min; -+ ULONG reserved2[7]; -+ enum nt_product_type nt_product_type; -+ BOOLEAN product_type_is_valid; -+ ULONG nt_major_version; -+ ULONG nt_minor_version; -+ BOOLEAN processor_features[PROCESSOR_FEATURE_MAX]; -+ ULONG reserved1; -+ ULONG reserved3; -+ volatile LONG time_slip; -+ enum alt_arch_type alt_arch_type; -+ LARGE_INTEGER system_expiration_date; -+ ULONG suite_mask; -+ BOOLEAN kdbg_enabled; -+ volatile ULONG active_console; -+ volatile ULONG dismount_count; -+ ULONG com_plus_package; -+ ULONG last_system_rite_event_tick_count; -+ ULONG num_phys_pages; -+ BOOLEAN safe_boot_mode; -+ ULONG trace_log; -+ ULONGLONG fill0; -+ ULONGLONG sys_call[4]; -+ union { -+ volatile struct ksystem_time tick_count; -+ volatile ULONG64 tick_count_quad; -+ } tick; -+}; -+ -+#define REG_NONE (0) -+#define REG_SZ (1) -+#define REG_EXPAND_SZ (2) -+#define REG_BINARY (3) -+#define REG_DWORD (4) -+ -+#define RTL_REGISTRY_ABSOLUTE 0 -+#define RTL_REGISTRY_SERVICES 1 -+#define RTL_REGISTRY_CONTROL 2 -+#define RTL_REGISTRY_WINDOWS_NT 3 -+#define RTL_REGISTRY_DEVICEMAP 4 -+#define RTL_REGISTRY_USER 5 -+#define RTL_REGISTRY_MAXIMUM 6 -+#define RTL_REGISTRY_HANDLE 0x40000000 -+#define RTL_REGISTRY_OPTIONAL 0x80000000 -+ -+#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 -+#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 -+#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 -+#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 -+#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 -+#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 -+#define RTL_QUERY_REGISTRY_DELETE 0x00000040 -+ -+typedef NTSTATUS (*PRTL_QUERY_REGISTRY_ROUTINE)(wchar_t *name, ULONG type, -+ void *data, ULONG length, -+ void *context, -+ void *entry) wstdcall; -+ -+struct rtl_query_registry_table { -+ PRTL_QUERY_REGISTRY_ROUTINE query_func; -+ ULONG flags; -+ wchar_t *name; -+ void *context; -+ ULONG def_type; -+ void *def_data; -+ ULONG def_length; -+}; -+ -+struct io_remove_lock { -+ BOOLEAN removed; -+ BOOLEAN reserved[3]; -+ LONG io_count; -+ struct nt_event remove_event; -+}; -+ -+struct io_error_log_packet { -+ UCHAR major_fn_code; -+ UCHAR retry_count; -+ USHORT dump_data_size; -+ USHORT nr_of_strings; -+ USHORT string_offset; -+ USHORT event_category; -+ NTSTATUS error_code; -+ ULONG unique_error_value; -+ NTSTATUS final_status; -+ ULONG sequence_number; -+ ULONG io_control_code; -+ LARGE_INTEGER device_offset; -+ ULONG dump_data[1]; -+}; -+ -+/* some of the functions below are slightly different from DDK's -+ * implementation; e.g., Insert functions return appropriate -+ * pointer */ -+ -+/* instead of using Linux's lists, we implement list manipulation -+ * functions because nt_list is used by drivers and we don't want to -+ * worry about Linux's list being different from nt_list (right now -+ * they are same, but in future they could be different) */ -+ -+static inline void InitializeListHead(struct nt_list *head) -+{ -+ head->next = head->prev = head; -+} -+ -+static inline BOOLEAN IsListEmpty(struct nt_list *head) -+{ -+ if (head == head->next) -+ return TRUE; -+ else -+ return FALSE; -+} -+ -+static inline void RemoveEntryList(struct nt_list *entry) -+{ -+ entry->prev->next = entry->next; -+ entry->next->prev = entry->prev; -+} -+ -+static inline struct nt_list *RemoveHeadList(struct nt_list *head) -+{ -+ struct nt_list *entry; -+ -+ entry = head->next; -+ if (entry == head) -+ return NULL; -+ else { -+ RemoveEntryList(entry); -+ return entry; -+ } -+} -+ -+static inline struct nt_list *RemoveTailList(struct nt_list *head) -+{ -+ struct nt_list *entry; -+ -+ entry = head->prev; -+ if (entry == head) -+ return NULL; -+ else { -+ RemoveEntryList(entry); -+ return entry; -+ } -+} -+ -+static inline void InsertListEntry(struct nt_list *entry, struct nt_list *prev, -+ struct nt_list *next) -+{ -+ next->prev = entry; -+ entry->next = next; -+ entry->prev = prev; -+ prev->next = entry; -+} -+ -+static inline struct nt_list *InsertHeadList(struct nt_list *head, -+ struct nt_list *entry) -+{ -+ struct nt_list *ret; -+ -+ if (IsListEmpty(head)) -+ ret = NULL; -+ else -+ ret = head->next; -+ -+ InsertListEntry(entry, head, head->next); -+ return ret; -+} -+ -+static inline struct nt_list *InsertTailList(struct nt_list *head, -+ struct nt_list *entry) -+{ -+ struct nt_list *ret; -+ -+ if (IsListEmpty(head)) -+ ret = NULL; -+ else -+ ret = head->prev; -+ -+ InsertListEntry(entry, head->prev, head); -+ return ret; -+} -+ -+#define nt_list_for_each(pos, head) \ -+ for (pos = (head)->next; pos != (head); pos = pos->next) -+ -+#define nt_list_for_each_entry(pos, head, member) \ -+ for (pos = container_of((head)->next, typeof(*pos), member); \ -+ &pos->member != (head); \ -+ pos = container_of(pos->member.next, typeof(*pos), member)) -+ -+#define nt_list_for_each_safe(pos, n, head) \ -+ for (pos = (head)->next, n = pos->next; pos != (head); \ -+ pos = n, n = pos->next) -+ -+/* device object flags */ -+#define DO_VERIFY_VOLUME 0x00000002 -+#define DO_BUFFERED_IO 0x00000004 -+#define DO_EXCLUSIVE 0x00000008 -+#define DO_DIRECT_IO 0x00000010 -+#define DO_MAP_IO_BUFFER 0x00000020 -+#define DO_DEVICE_HAS_NAME 0x00000040 -+#define DO_DEVICE_INITIALIZING 0x00000080 -+#define DO_SYSTEM_BOOT_PARTITION 0x00000100 -+#define DO_LONG_TERM_REQUESTS 0x00000200 -+#define DO_NEVER_LAST_DEVICE 0x00000400 -+#define DO_SHUTDOWN_REGISTERED 0x00000800 -+#define DO_BUS_ENUMERATED_DEVICE 0x00001000 -+#define DO_POWER_PAGABLE 0x00002000 -+#define DO_POWER_INRUSH 0x00004000 -+#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000 -+ -+/* Various supported device types (used with IoCreateDevice()) */ -+ -+#define FILE_DEVICE_BEEP 0x00000001 -+#define FILE_DEVICE_CD_ROM 0x00000002 -+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 -+#define FILE_DEVICE_CONTROLLER 0x00000004 -+#define FILE_DEVICE_DATALINK 0x00000005 -+#define FILE_DEVICE_DFS 0x00000006 -+#define FILE_DEVICE_DISK 0x00000007 -+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 -+#define FILE_DEVICE_FILE_SYSTEM 0x00000009 -+#define FILE_DEVICE_INPORT_PORT 0x0000000A -+#define FILE_DEVICE_KEYBOARD 0x0000000B -+#define FILE_DEVICE_MAILSLOT 0x0000000C -+#define FILE_DEVICE_MIDI_IN 0x0000000D -+#define FILE_DEVICE_MIDI_OUT 0x0000000E -+#define FILE_DEVICE_MOUSE 0x0000000F -+#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 -+#define FILE_DEVICE_NAMED_PIPE 0x00000011 -+#define FILE_DEVICE_NETWORK 0x00000012 -+#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 -+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 -+#define FILE_DEVICE_NULL 0x00000015 -+#define FILE_DEVICE_PARALLEL_PORT 0x00000016 -+#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 -+#define FILE_DEVICE_PRINTER 0x00000018 -+#define FILE_DEVICE_SCANNER 0x00000019 -+#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001A -+#define FILE_DEVICE_SERIAL_PORT 0x0000001B -+#define FILE_DEVICE_SCREEN 0x0000001C -+#define FILE_DEVICE_SOUND 0x0000001D -+#define FILE_DEVICE_STREAMS 0x0000001E -+#define FILE_DEVICE_TAPE 0x0000001F -+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 -+#define FILE_DEVICE_TRANSPORT 0x00000021 -+#define FILE_DEVICE_UNKNOWN 0x00000022 -+#define FILE_DEVICE_VIDEO 0x00000023 -+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 -+#define FILE_DEVICE_WAVE_IN 0x00000025 -+#define FILE_DEVICE_WAVE_OUT 0x00000026 -+#define FILE_DEVICE_8042_PORT 0x00000027 -+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 -+#define FILE_DEVICE_BATTERY 0x00000029 -+#define FILE_DEVICE_BUS_EXTENDER 0x0000002A -+#define FILE_DEVICE_MODEM 0x0000002B -+#define FILE_DEVICE_VDM 0x0000002C -+#define FILE_DEVICE_MASS_STORAGE 0x0000002D -+#define FILE_DEVICE_SMB 0x0000002E -+#define FILE_DEVICE_KS 0x0000002F -+#define FILE_DEVICE_CHANGER 0x00000030 -+#define FILE_DEVICE_SMARTCARD 0x00000031 -+#define FILE_DEVICE_ACPI 0x00000032 -+#define FILE_DEVICE_DVD 0x00000033 -+#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 -+#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 -+#define FILE_DEVICE_DFS_VOLUME 0x00000036 -+#define FILE_DEVICE_SERENUM 0x00000037 -+#define FILE_DEVICE_TERMSRV 0x00000038 -+#define FILE_DEVICE_KSEC 0x00000039 -+#define FILE_DEVICE_FIPS 0x0000003A -+ -+/* Device characteristics */ -+ -+#define FILE_REMOVABLE_MEDIA 0x00000001 -+#define FILE_READ_ONLY_DEVICE 0x00000002 -+#define FILE_FLOPPY_DISKETTE 0x00000004 -+#define FILE_WRITE_ONCE_MEDIA 0x00000008 -+#define FILE_REMOTE_DEVICE 0x00000010 -+#define FILE_DEVICE_IS_MOUNTED 0x00000020 -+#define FILE_VIRTUAL_VOLUME 0x00000040 -+#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 -+#define FILE_DEVICE_SECURE_OPEN 0x00000100 -+ -+#define FILE_READ_DATA 0x0001 -+#define FILE_WRITE_DATA 0x0002 -+ -+#define FILE_SUPERSEDED 0x00000000 -+#define FILE_OPENED 0x00000001 -+#define FILE_CREATED 0x00000002 -+#define FILE_OVERWRITTEN 0x00000003 -+#define FILE_EXISTS 0x00000004 -+#define FILE_DOES_NOT_EXIST 0x00000005 -+ -+ -+#endif /* WINNT_TYPES_H */ -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/workqueue.c linux-5.6.11-ndis/3rdparty/ndiswrapper/workqueue.c ---- linux-5.6.11/3rdparty/ndiswrapper/workqueue.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/workqueue.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,279 @@ -+/* -+ * Copyright (C) 2006 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ntoskernel.h" -+ -+struct workqueue_thread { -+ spinlock_t lock; -+ struct task_struct *task; -+ struct completion *completion; -+ char name[16]; -+ int pid; -+ /* whether any work_structs pending? <0 implies quit */ -+ s8 pending; -+ /* list of work_structs pending */ -+ struct list_head work_list; -+}; -+ -+struct workq_thread_data { -+ struct workqueue_struct *workq; -+ int index; -+}; -+ -+struct wrap_workqueue_struct { -+ u8 singlethread; -+ u8 qon; -+ int num_cpus; -+ struct workqueue_thread threads[0]; -+}; -+ -+static void wrap_destroy_wq_on(struct workqueue_struct *workq, int cpu); -+ -+static int workq_thread(void *data) -+{ -+ struct workq_thread_data *thread_data = data; -+ struct workqueue_thread *thread; -+ struct workqueue_struct *workq; -+ struct work_struct *work; -+ -+ workq = thread_data->workq; -+ thread = &workq->threads[thread_data->index]; -+ WORKTRACE("%p, %d, %p", workq, thread_data->index, thread); -+ strncpy(thread->name, current->comm, sizeof(thread->name)); -+ -+ daemonize(thread->name); -+ set_user_nice(current, -5); -+ -+ if (thread->task != current) { -+ WARNING("invalid task: %p, %p", thread->task, current); -+ thread->task = current; -+ } -+ thread->pid = current->pid; -+ complete(xchg(&thread->completion, NULL)); -+ WORKTRACE("%s (%d) started", thread->name, thread->pid); -+ while (1) { -+ if (wait_condition(thread->pending, 0, TASK_INTERRUPTIBLE) < 0) { -+ /* TODO: deal with signal */ -+ WARNING("signal not blocked?"); -+ flush_signals(current); -+ continue; -+ } -+ while (1) { -+ struct list_head *entry; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&thread->lock, flags); -+ if (list_empty(&thread->work_list)) { -+ struct completion *completion; -+ if (thread->pending < 0) { -+ spin_unlock_irqrestore(&thread->lock, -+ flags); -+ goto out; -+ } -+ thread->pending = 0; -+ completion = thread->completion; -+ thread->completion = NULL; -+ spin_unlock_irqrestore(&thread->lock, flags); -+ if (completion) -+ complete(completion); -+ break; -+ } -+ entry = thread->work_list.next; -+ work = list_entry(entry, struct work_struct, list); -+ if (xchg(&work->thread, NULL)) -+ list_del(entry); -+ else -+ work = NULL; -+ spin_unlock_irqrestore(&thread->lock, flags); -+ DBG_BLOCK(4) { -+ WORKTRACE("%p, %p", work, thread); -+ } -+ if (work) -+ work->func(work->data); -+ } -+ } -+ -+out: -+ WORKTRACE("%s exiting", thread->name); -+ thread->pid = 0; -+ return 0; -+} -+ -+static int wrap_queue_work_on(struct workqueue_struct *workq, -+ struct work_struct *work, int cpu) -+{ -+ struct workqueue_thread *thread = &workq->threads[cpu]; -+ unsigned long flags; -+ int ret; -+ -+ assert(thread->pid > 0); -+ DBG_BLOCK(4) { -+ WORKTRACE("%p, %d", workq, cpu); -+ } -+ spin_lock_irqsave(&thread->lock, flags); -+ if (work->thread) -+ ret = 0; -+ else { -+ work->thread = thread; -+ list_add_tail(&work->list, &thread->work_list); -+ thread->pending = 1; -+ wake_up_process(thread->task); -+ ret = 1; -+ } -+ spin_unlock_irqrestore(&thread->lock, flags); -+ return ret; -+} -+ -+int wrap_queue_work(struct workqueue_struct *workq, struct work_struct *work) -+{ -+ if (num_online_cpus() == 1 || workq->singlethread) -+ return wrap_queue_work_on(workq, work, 0); -+ else { -+ typeof(workq->qon) qon; -+ /* work is queued on threads in a round-robin fashion */ -+ do { -+ qon = workq->qon % workq->num_cpus; -+ atomic_inc_var(workq->qon); -+ } while (!workq->threads[qon].pid); -+ return wrap_queue_work_on(workq, work, qon); -+ } -+} -+ -+void wrap_cancel_work(struct work_struct *work) -+{ -+ struct workqueue_thread *thread; -+ unsigned long flags; -+ -+ WORKTRACE("%p", work); -+ if ((thread = xchg(&work->thread, NULL))) { -+ WORKTRACE("%p", thread); -+ spin_lock_irqsave(&thread->lock, flags); -+ list_del(&work->list); -+ spin_unlock_irqrestore(&thread->lock, flags); -+ } -+} -+ -+struct workqueue_struct *wrap_create_wq(const char *name, u8 singlethread, -+ u8 freeze) -+{ -+ struct completion started; -+ struct workqueue_struct *workq; -+ int i, n; -+ -+ if (singlethread) -+ n = 1; -+ else -+ n = num_online_cpus(); -+ workq = kzalloc(sizeof(*workq) + n * sizeof(workq->threads[0]), -+ GFP_KERNEL); -+ if (!workq) { -+ WARNING("couldn't allocate memory"); -+ return NULL; -+ } -+ WORKTRACE("%p", workq); -+ workq->singlethread = singlethread; -+ init_completion(&started); -+ for_each_online_cpu(i) { -+ struct workq_thread_data thread_data; -+ spin_lock_init(&workq->threads[i].lock); -+ INIT_LIST_HEAD(&workq->threads[i].work_list); -+ reinit_completion(&started); -+ workq->threads[i].completion = &started; -+ thread_data.workq = workq; -+ thread_data.index = i; -+ WORKTRACE("%p, %d, %p", workq, i, &workq->threads[i]); -+ workq->threads[i].task = -+ kthread_create(workq_thread, &thread_data, -+ "%s/%d", name, i); -+ if (IS_ERR(workq->threads[i].task)) { -+ int j; -+ for (j = 0; j < i; j++) -+ wrap_destroy_wq_on(workq, j); -+ kfree(workq); -+ WARNING("couldn't start thread %s", name); -+ return NULL; -+ } -+#ifdef PF_NOFREEZE -+ if (!freeze) -+ workq->threads[i].task->flags |= PF_NOFREEZE; -+#endif -+ kthread_bind(workq->threads[i].task, i); -+ workq->num_cpus = max(workq->num_cpus, i); -+ wake_up_process(workq->threads[i].task); -+ wait_for_completion(&started); -+ WORKTRACE("%s, %d: %p, %d", name, i, -+ workq, workq->threads[i].pid); -+ if (singlethread) -+ break; -+ } -+ workq->num_cpus++; -+ return workq; -+} -+ -+static void wrap_flush_wq_on(struct workqueue_struct *workq, int cpu) -+{ -+ struct workqueue_thread *thread = &workq->threads[cpu]; -+ struct completion done; -+ -+ WORKTRACE("%p: %d, %s", workq, cpu, thread->name); -+ init_completion(&done); -+ thread->completion = &done; -+ thread->pending = 1; -+ wake_up_process(thread->task); -+ wait_for_completion(&done); -+ return; -+} -+ -+void wrap_flush_wq(struct workqueue_struct *workq) -+{ -+ int i, n; -+ -+ WORKTRACE("%p", workq); -+ if (workq->singlethread) -+ n = 1; -+ else -+ n = num_online_cpus(); -+ for (i = 0; i < n; i++) -+ wrap_flush_wq_on(workq, i); -+} -+ -+static void wrap_destroy_wq_on(struct workqueue_struct *workq, int cpu) -+{ -+ struct workqueue_thread *thread = &workq->threads[cpu]; -+ -+ WORKTRACE("%p: %d, %s", workq, cpu, thread->name); -+ if (!thread->pid) -+ return; -+ thread->pending = -1; -+ wake_up_process(thread->task); -+ while (thread->pid) { -+ WORKTRACE("%d", thread->pid); -+ schedule(); -+ } -+} -+ -+void wrap_destroy_wq(struct workqueue_struct *workq) -+{ -+ int i, n; -+ -+ WORKTRACE("%p", workq); -+ if (workq->singlethread) -+ n = 1; -+ else -+ n = num_online_cpus(); -+ for (i = 0; i < n; i++) -+ wrap_destroy_wq_on(workq, i); -+ kfree(workq); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/wrapmem.c linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapmem.c ---- linux-5.6.11/3rdparty/ndiswrapper/wrapmem.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapmem.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,366 @@ -+/* -+ * Copyright (C) 2006 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#define _WRAPMEM_C_ -+ -+#include "ntoskernel.h" -+#include "wrapmem.h" -+ -+struct slack_alloc_info { -+ struct nt_list list; -+ size_t size; -+}; -+ -+#if ALLOC_DEBUG > 1 -+static struct nt_list allocs; -+#endif -+ -+static struct nt_list slack_allocs; -+static spinlock_t alloc_lock; -+ -+#if ALLOC_DEBUG -+const char *alloc_type_name[ALLOC_TYPE_MAX] = { -+ "kmalloc_atomic", -+ "kmalloc_nonatomic", -+ "vmalloc_atomic", -+ "vmalloc_nonatomic", -+ "kmalloc_slack", -+ "pages" -+}; -+ -+struct alloc_info { -+ enum alloc_type type; -+ size_t size; -+#if ALLOC_DEBUG > 1 -+ struct nt_list list; -+ const char *file; -+ int line; -+ ULONG tag; -+#endif -+}; -+ -+static atomic_t alloc_sizes[ALLOC_TYPE_MAX]; -+#endif -+ -+/* allocate memory and add it to list of allocated pointers; if a -+ * driver doesn't free this memory for any reason (buggy driver or we -+ * allocate space behind driver's back since we need more space than -+ * corresponding Windows structure provides etc.), this gets freed -+ * automatically when module is unloaded -+ */ -+void *slack_kmalloc(size_t size) -+{ -+ struct slack_alloc_info *info; -+ -+ ENTER4("size = %zu", size); -+ info = kmalloc(size + sizeof(*info), irql_gfp()); -+ if (!info) -+ return NULL; -+ info->size = size; -+ spin_lock_bh(&alloc_lock); -+ InsertTailList(&slack_allocs, &info->list); -+ spin_unlock_bh(&alloc_lock); -+#if ALLOC_DEBUG -+ atomic_add(size, &alloc_sizes[ALLOC_TYPE_SLACK]); -+#endif -+ TRACE4("%p, %p", info, info + 1); -+ EXIT4(return info + 1); -+} -+ -+/* free pointer and remove from list of allocated pointers */ -+void slack_kfree(void *ptr) -+{ -+ struct slack_alloc_info *info; -+ -+ ENTER4("%p", ptr); -+ info = ptr - sizeof(*info); -+ spin_lock_bh(&alloc_lock); -+ RemoveEntryList(&info->list); -+ spin_unlock_bh(&alloc_lock); -+#if ALLOC_DEBUG -+ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); -+#endif -+ kfree(info); -+ EXIT4(return); -+} -+ -+void *slack_kzalloc(size_t size) -+{ -+ void *ptr = slack_kmalloc(size); -+ if (ptr) -+ memset(ptr, 0, size); -+ return ptr; -+} -+ -+#if ALLOC_DEBUG -+void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line) -+{ -+ struct alloc_info *info; -+ -+ info = kmalloc(size + sizeof(*info), flags); -+ if (!info) -+ return NULL; -+ if (flags & GFP_ATOMIC) -+ info->type = ALLOC_TYPE_KMALLOC_ATOMIC; -+ else -+ info->type = ALLOC_TYPE_KMALLOC_NON_ATOMIC; -+ info->size = size; -+ atomic_add(size, &alloc_sizes[info->type]); -+#if ALLOC_DEBUG > 1 -+ info->file = file; -+ info->line = line; -+ info->tag = 0; -+ spin_lock_bh(&alloc_lock); -+ InsertTailList(&allocs, &info->list); -+ spin_unlock_bh(&alloc_lock); -+#endif -+ TRACE4("%p", info + 1); -+ return info + 1; -+} -+ -+void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line) -+{ -+ void *ptr = wrap_kmalloc(size, flags, file, line); -+ if (ptr) -+ memset(ptr, 0, size); -+ return ptr; -+} -+ -+void wrap_kfree(void *ptr) -+{ -+ struct alloc_info *info; -+ -+ TRACE4("%p", ptr); -+ if (!ptr) -+ return; -+ info = ptr - sizeof(*info); -+ atomic_sub(info->size, &alloc_sizes[info->type]); -+#if ALLOC_DEBUG > 1 -+ spin_lock_bh(&alloc_lock); -+ RemoveEntryList(&info->list); -+ spin_unlock_bh(&alloc_lock); -+ if (!(info->type == ALLOC_TYPE_KMALLOC_ATOMIC || -+ info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC)) { -+ WARNING("invalid type: %d", info->type); -+ return; -+ } -+#endif -+ kfree(info); -+} -+ -+void *wrap_vmalloc(unsigned long size, const char *file, int line) -+{ -+ struct alloc_info *info; -+ -+ info = vmalloc(size + sizeof(*info)); -+ if (!info) -+ return NULL; -+ info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC; -+ info->size = size; -+ atomic_add(size, &alloc_sizes[info->type]); -+#if ALLOC_DEBUG > 1 -+ info->file = file; -+ info->line = line; -+ info->tag = 0; -+ spin_lock_bh(&alloc_lock); -+ InsertTailList(&allocs, &info->list); -+ spin_unlock_bh(&alloc_lock); -+#endif -+ return info + 1; -+} -+ -+void *wrap__vmalloc(unsigned long size, gfp_t gfp_mask, -+ const char *file, int line) -+{ -+ struct alloc_info *info; -+ -+ info = __vmalloc(size + sizeof(*info), gfp_mask); -+ if (!info) -+ return NULL; -+ if (gfp_mask & GFP_ATOMIC) -+ info->type = ALLOC_TYPE_VMALLOC_ATOMIC; -+ else -+ info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC; -+ info->size = size; -+ atomic_add(size, &alloc_sizes[info->type]); -+#if ALLOC_DEBUG > 1 -+ info->file = file; -+ info->line = line; -+ info->tag = 0; -+ spin_lock_bh(&alloc_lock); -+ InsertTailList(&allocs, &info->list); -+ spin_unlock_bh(&alloc_lock); -+#endif -+ return info + 1; -+} -+ -+void wrap_vfree(void *ptr) -+{ -+ struct alloc_info *info; -+ -+ info = ptr - sizeof(*info); -+ atomic_sub(info->size, &alloc_sizes[info->type]); -+#if ALLOC_DEBUG > 1 -+ spin_lock_bh(&alloc_lock); -+ RemoveEntryList(&info->list); -+ spin_unlock_bh(&alloc_lock); -+ if (!(info->type == ALLOC_TYPE_VMALLOC_ATOMIC || -+ info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC)) { -+ WARNING("invalid type: %d", info->type); -+ return; -+ } -+#endif -+ vfree(info); -+} -+ -+void *wrap_alloc_pages(gfp_t flags, unsigned int size, -+ const char *file, int line) -+{ -+ struct alloc_info *info; -+ -+ size += sizeof(*info); -+ info = (struct alloc_info *)__get_free_pages(flags, get_order(size)); -+ if (!info) -+ return NULL; -+ info->type = ALLOC_TYPE_PAGES; -+ info->size = size; -+ atomic_add(size, &alloc_sizes[info->type]); -+#if ALLOC_DEBUG > 1 -+ info->file = file; -+ info->line = line; -+ info->tag = 0; -+ spin_lock_bh(&alloc_lock); -+ InsertTailList(&allocs, &info->list); -+ spin_unlock_bh(&alloc_lock); -+#endif -+ return info + 1; -+} -+ -+void wrap_free_pages(unsigned long ptr, int order) -+{ -+ struct alloc_info *info; -+ -+ info = (void *)ptr - sizeof(*info); -+ atomic_sub(info->size, &alloc_sizes[info->type]); -+#if ALLOC_DEBUG > 1 -+ spin_lock_bh(&alloc_lock); -+ RemoveEntryList(&info->list); -+ spin_unlock_bh(&alloc_lock); -+ if (info->type != ALLOC_TYPE_PAGES) { -+ WARNING("invalid type: %d", info->type); -+ return; -+ } -+#endif -+ free_pages((unsigned long)info, get_order(info->size)); -+} -+ -+#if ALLOC_DEBUG > 1 -+void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, -+ ULONG tag, const char *file, int line) -+{ -+ void *addr; -+ struct alloc_info *info; -+ -+ ENTER4("pool_type: %d, size: %zu, tag: %u", pool_type, size, tag); -+ addr = (ExAllocatePoolWithTag)(pool_type, size, tag); -+ if (!addr) -+ return NULL; -+ info = addr - sizeof(*info); -+ info->file = file; -+ info->line = line; -+ info->tag = tag; -+ EXIT4(return addr); -+} -+#endif -+ -+int alloc_size(enum alloc_type type) -+{ -+ if ((int)type >= 0 && type < ALLOC_TYPE_MAX) -+ return atomic_read(&alloc_sizes[type]); -+ else -+ return -EINVAL; -+} -+ -+#endif // ALLOC_DEBUG -+ -+int wrapmem_init(void) -+{ -+#if ALLOC_DEBUG > 1 -+ InitializeListHead(&allocs); -+#endif -+ InitializeListHead(&slack_allocs); -+ spin_lock_init(&alloc_lock); -+ return 0; -+} -+ -+void wrapmem_exit(void) -+{ -+#if ALLOC_DEBUG -+ enum alloc_type type; -+#endif -+ struct nt_list *ent; -+ -+ /* free all pointers on the slack list */ -+ while (1) { -+ struct slack_alloc_info *info; -+ spin_lock_bh(&alloc_lock); -+ ent = RemoveHeadList(&slack_allocs); -+ spin_unlock_bh(&alloc_lock); -+ if (!ent) -+ break; -+ info = container_of(ent, struct slack_alloc_info, list); -+#if ALLOC_DEBUG -+ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); -+#endif -+ kfree(info); -+ } -+#if ALLOC_DEBUG -+ for (type = 0; type < ALLOC_TYPE_MAX; type++) { -+ int n = atomic_read(&alloc_sizes[type]); -+ if (n) -+ WARNING("%d bytes of memory in %s leaking", n, -+ alloc_type_name[type]); -+ } -+ -+#if ALLOC_DEBUG > 1 -+ while (1) { -+ struct alloc_info *info; -+ -+ spin_lock_bh(&alloc_lock); -+ ent = RemoveHeadList(&allocs); -+ spin_unlock_bh(&alloc_lock); -+ if (!ent) -+ break; -+ info = container_of(ent, struct alloc_info, list); -+ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); -+ printk(KERN_DEBUG DRIVER_NAME -+ ": %s:%d leaked %zd bytes at %p (%s, tag 0x%08X)\n", -+ info->file, info->line, info->size, info + 1, -+ alloc_type_name[info->type], info->tag); -+ if (info->type == ALLOC_TYPE_KMALLOC_ATOMIC || -+ info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC) -+ kfree(info); -+ else if (info->type == ALLOC_TYPE_VMALLOC_ATOMIC || -+ info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC) -+ vfree(info); -+ else if (info->type == ALLOC_TYPE_PAGES) -+ free_pages((unsigned long)info, get_order(info->size)); -+ else -+ WARNING("invalid type: %d; not freed", info->type); -+ } -+#endif -+#endif -+ return; -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/wrapmem.h linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapmem.h ---- linux-5.6.11/3rdparty/ndiswrapper/wrapmem.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapmem.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,97 @@ -+/* -+ * Copyright (C) 2006 Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _WRAPMEM_H_ -+#define _WRAPMEM_H_ -+ -+/* -+ * Set ALLOC_DEBUG to 1 to show information about memory used by both -+ * ndiswrapper and Windows driver in /proc/net/ndiswrapper/debug -+ * This will also show memory leaks (memory allocated but not freed) when -+ * ndiswrapper module is unloaded. -+ * -+ * Set ALLOC_DEBUG to 2 to see details about every leaking allocation. -+*/ -+ -+#ifndef ALLOC_DEBUG -+#define ALLOC_DEBUG 0 -+#endif -+ -+int wrapmem_init(void); -+void wrapmem_exit(void); -+void *slack_kmalloc(size_t size); -+void *slack_kzalloc(size_t size); -+void slack_kfree(void *ptr); -+ -+#if ALLOC_DEBUG -+enum alloc_type { ALLOC_TYPE_KMALLOC_ATOMIC, -+ ALLOC_TYPE_KMALLOC_NON_ATOMIC, -+ ALLOC_TYPE_VMALLOC_ATOMIC, ALLOC_TYPE_VMALLOC_NON_ATOMIC, -+ ALLOC_TYPE_SLACK, ALLOC_TYPE_PAGES, ALLOC_TYPE_MAX }; -+ -+extern const char *alloc_type_name[ALLOC_TYPE_MAX]; -+ -+void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line); -+void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line); -+void wrap_kfree(void *ptr); -+void *wrap_vmalloc(unsigned long size, const char *file, int line); -+void *wrap__vmalloc(unsigned long size, gfp_t flags, -+ const char *file, int line); -+void wrap_vfree(void *ptr); -+void *wrap_alloc_pages(gfp_t flags, unsigned int size, -+ const char *file, int line); -+void wrap_free_pages(unsigned long ptr, int order); -+int alloc_size(enum alloc_type type); -+ -+#if ALLOC_DEBUG > 1 -+void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, -+ ULONG tag, const char *file, int line); -+#define ExAllocatePoolWithTag(pool_type, size, tag) \ -+ wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__) -+#endif -+ -+#ifndef _WRAPMEM_C_ -+#undef kmalloc -+#undef kzalloc -+#undef kfree -+#undef vmalloc -+#undef __vmalloc -+#undef vfree -+#define kmalloc(size, flags) \ -+ wrap_kmalloc(size, flags, __FILE__, __LINE__) -+#define kzalloc(size, flags) \ -+ wrap_kzalloc(size, flags, __FILE__, __LINE__) -+#define vmalloc(size) \ -+ wrap_vmalloc(size, __FILE__, __LINE__) -+#define __vmalloc(size, flags) \ -+ wrap__vmalloc(size, flags, __FILE__, __LINE__) -+#define kfree(ptr) wrap_kfree(ptr) -+#define vfree(ptr) wrap_vfree(ptr) -+ -+#define wrap_get_free_pages(flags, size) \ -+ wrap_alloc_pages(flags, size, __FILE__, __LINE__) -+#undef free_pages -+#define free_pages(ptr, order) wrap_free_pages(ptr, order) -+ -+#endif // _WRAPMEM_C_ -+ -+#else -+ -+#define wrap_get_free_pages(flags, size) \ -+ (void *)__get_free_pages(flags, get_order(size)) -+ -+#endif // ALLOC_DEBUG -+ -+#endif -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/wrapndis.c linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapndis.c ---- linux-5.6.11/3rdparty/ndiswrapper/wrapndis.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapndis.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,2223 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include "ndis.h" -+#include "iw_ndis.h" -+#include "pnp.h" -+#include "loader.h" -+#include "wrapndis.h" -+#include "wrapper.h" -+ -+/* Functions callable from the NDIS driver */ -+wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, -+ struct irp *irp); -+wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp); -+wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp); -+ -+struct workqueue_struct *wrapndis_wq; -+ -+static int set_packet_filter(struct ndis_device *wnd, -+ ULONG packet_filter); -+static void add_iw_stats_timer(struct ndis_device *wnd); -+static void del_iw_stats_timer(struct ndis_device *wnd); -+static NDIS_STATUS ndis_start_device(struct ndis_device *wnd); -+static int ndis_remove_device(struct ndis_device *wnd); -+static void set_multicast_list(struct ndis_device *wnd); -+static int ndis_net_dev_open(struct net_device *net_dev); -+static int ndis_net_dev_close(struct net_device *net_dev); -+ -+/* MiniportReset */ -+NDIS_STATUS mp_reset(struct ndis_device *wnd) -+{ -+ NDIS_STATUS res; -+ struct miniport *mp; -+ BOOLEAN reset_address; -+ KIRQL irql; -+ -+ ENTER2("wnd: %p", wnd); -+ mutex_lock(&wnd->tx_ring_mutex); -+ mutex_lock(&wnd->ndis_req_mutex); -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0); -+ WARNING("%s is being reset", wnd->net_dev->name); -+ irql = serialize_lock_irql(wnd); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ res = LIN2WIN2(mp->reset, &reset_address, wnd->nmb->mp_ctx); -+ serialize_unlock_irql(wnd, irql); -+ -+ TRACE2("%08X, %08X", res, reset_address); -+ if (res == NDIS_STATUS_PENDING) { -+ /* wait for NdisMResetComplete */ -+ if (wait_condition((wnd->ndis_req_done > 0), 0, -+ TASK_INTERRUPTIBLE) < 0) -+ res = NDIS_STATUS_FAILURE; -+ else { -+ res = wnd->ndis_req_status; -+ reset_address = wnd->ndis_req_done - 1; -+ } -+ TRACE2("%08X, %08X", res, reset_address); -+ } -+ mutex_unlock(&wnd->ndis_req_mutex); -+ if (res == NDIS_STATUS_SUCCESS && reset_address) { -+ set_packet_filter(wnd, wnd->packet_filter); -+ set_multicast_list(wnd); -+ } -+ mutex_unlock(&wnd->tx_ring_mutex); -+ EXIT3(return res); -+} -+ -+/* MiniportRequest(Query/Set)Information */ -+NDIS_STATUS mp_request(enum ndis_request_type request, -+ struct ndis_device *wnd, ndis_oid oid, -+ void *buf, ULONG buflen, ULONG *written, ULONG *needed) -+{ -+ NDIS_STATUS res; -+ ULONG w, n; -+ struct miniport *mp; -+ KIRQL irql; -+ -+ mutex_lock(&wnd->ndis_req_mutex); -+ if (!written) -+ written = &w; -+ if (!needed) -+ needed = &n; -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0); -+ irql = serialize_lock_irql(wnd); -+ assert_irql(_irql_ == DISPATCH_LEVEL); -+ switch (request) { -+ case NdisRequestQueryInformation: -+ TRACE2("%p, %08X, %p", mp->queryinfo, oid, wnd->nmb->mp_ctx); -+ res = LIN2WIN6(mp->queryinfo, wnd->nmb->mp_ctx, oid, buf, -+ buflen, written, needed); -+ break; -+ case NdisRequestSetInformation: -+ TRACE2("%p, %08X, %p", mp->setinfo, oid, wnd->nmb->mp_ctx); -+ res = LIN2WIN6(mp->setinfo, wnd->nmb->mp_ctx, oid, buf, -+ buflen, written, needed); -+ break; -+ default: -+ WARNING("invalid request %d, %08X", request, oid); -+ res = NDIS_STATUS_NOT_SUPPORTED; -+ break; -+ } -+ serialize_unlock_irql(wnd, irql); -+ TRACE2("%08X, %08X", res, oid); -+ if (res == NDIS_STATUS_PENDING) { -+ /* wait for NdisMQueryInformationComplete */ -+ if (wait_condition((wnd->ndis_req_done > 0), 0, -+ TASK_INTERRUPTIBLE) < 0) -+ res = NDIS_STATUS_FAILURE; -+ else -+ res = wnd->ndis_req_status; -+ TRACE2("%08X, %08X", res, oid); -+ } -+ mutex_unlock(&wnd->ndis_req_mutex); -+ DBG_BLOCK(2) { -+ if (res || needed) -+ TRACE2("%08X, %d, %d, %d", res, buflen, *written, -+ *needed); -+ } -+ EXIT3(return res); -+} -+ -+/* MiniportPnPEventNotify */ -+static NDIS_STATUS mp_pnp_event(struct ndis_device *wnd, -+ enum ndis_device_pnp_event event, -+ ULONG power_profile) -+{ -+ struct miniport *mp; -+ -+ ENTER1("%p, %d", wnd, event); -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ if (!mp->pnp_event_notify) { -+ TRACE1("Windows driver %s doesn't support " -+ "MiniportPnpEventNotify", wnd->wd->driver->name); -+ return NDIS_STATUS_FAILURE; -+ } -+ /* RNDIS driver doesn't like to be notified if device is -+ * already halted */ -+ if (!test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) -+ EXIT1(return NDIS_STATUS_SUCCESS); -+ switch (event) { -+ case NdisDevicePnPEventSurpriseRemoved: -+ TRACE1("%u, %p", -+ (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK), -+ mp->pnp_event_notify); -+ if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) && -+ !test_bit(HW_DISABLED, &wnd->wd->hw_status) && -+ mp->pnp_event_notify) { -+ TRACE1("calling surprise_removed"); -+ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, -+ NdisDevicePnPEventSurpriseRemoved, NULL, 0); -+ } else -+ TRACE1("Windows driver %s doesn't support " -+ "MiniportPnpEventNotify for safe unplugging", -+ wnd->wd->driver->name); -+ return NDIS_STATUS_SUCCESS; -+ case NdisDevicePnPEventPowerProfileChanged: -+ if (power_profile) -+ power_profile = NdisPowerProfileAcOnLine; -+ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, -+ NdisDevicePnPEventPowerProfileChanged, -+ &power_profile, sizeof(power_profile)); -+ return NDIS_STATUS_SUCCESS; -+ default: -+ WARNING("event %d not yet implemented", event); -+ return NDIS_STATUS_SUCCESS; -+ } -+} -+ -+/* MiniportInitialize */ -+static NDIS_STATUS mp_init(struct ndis_device *wnd) -+{ -+ NDIS_STATUS error_status, status; -+ UINT medium_index; -+ enum ndis_medium medium_array[] = {NdisMedium802_3}; -+ struct miniport *mp; -+ -+ ENTER1("irql: %d", current_irql()); -+ if (test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) { -+ WARNING("device %p already initialized!", wnd); -+ return NDIS_STATUS_FAILURE; -+ } -+ -+ if (!wnd->wd->driver->ndis_driver || -+ !wnd->wd->driver->ndis_driver->mp.init) { -+ WARNING("assuming WDM (non-NDIS) driver"); -+ EXIT1(return NDIS_STATUS_NOT_RECOGNIZED); -+ } -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ status = LIN2WIN6(mp->init, &error_status, &medium_index, medium_array, -+ ARRAY_SIZE(medium_array), wnd->nmb, wnd->nmb); -+ TRACE1("init returns: %08X, irql: %d", status, current_irql()); -+ if (status != NDIS_STATUS_SUCCESS) { -+ WARNING("couldn't initialize device: %08X", status); -+ EXIT1(return NDIS_STATUS_FAILURE); -+ } -+ -+ /* Wait a little to let card power up otherwise ifup might -+ * fail after boot */ -+ sleep_hz(HZ / 5); -+ status = mp_pnp_event(wnd, NdisDevicePnPEventPowerProfileChanged, -+ NdisPowerProfileAcOnLine); -+ if (status != NDIS_STATUS_SUCCESS) -+ TRACE1("setting power failed: %08X", status); -+ set_bit(HW_INITIALIZED, &wnd->wd->hw_status); -+ /* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is -+ * misleading/confusing */ -+ status = mp_query(wnd, OID_PNP_CAPABILITIES, -+ &wnd->pnp_capa, sizeof(wnd->pnp_capa)); -+ if (status == NDIS_STATUS_SUCCESS) { -+ TRACE1("%d, %d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup, -+ wnd->pnp_capa.wakeup.min_pattern_wakeup); -+ wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; -+ status = mp_query_int(wnd, OID_PNP_ENABLE_WAKE_UP, -+ &wnd->ndis_wolopts); -+ TRACE1("%08X, %x", status, wnd->ndis_wolopts); -+ } else if (status == NDIS_STATUS_NOT_SUPPORTED) -+ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; -+ TRACE1("%d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup); -+ /* although some NDIS drivers support suspend, Linux kernel -+ * has issues with suspending USB devices */ -+ if (wrap_is_usb_bus(wnd->wd->dev_bus)) { -+ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; -+ wnd->ndis_wolopts = 0; -+ } -+ mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF); -+ EXIT1(return NDIS_STATUS_SUCCESS); -+} -+ -+/* MiniportHalt */ -+static void mp_halt(struct ndis_device *wnd) -+{ -+ struct miniport *mp; -+ -+ ENTER1("%p", wnd); -+ if (!test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) { -+ WARNING("device %p is not initialized - not halting", wnd); -+ return; -+ } -+ hangcheck_del(wnd); -+ del_iw_stats_timer(wnd); -+#ifdef CONFIG_WIRELESS_EXT -+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan && -+ wrap_is_pci_bus(wnd->wd->dev_bus)) { -+ mutex_unlock(&wnd->ndis_req_mutex); -+ disassociate(wnd, 0); -+ mutex_lock(&wnd->ndis_req_mutex); -+ } -+#endif -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ TRACE1("halt: %p", mp->mp_halt); -+ LIN2WIN1(mp->mp_halt, wnd->nmb->mp_ctx); -+ /* if a driver doesn't call NdisMDeregisterInterrupt during -+ * halt, deregister it now */ -+ if (wnd->mp_interrupt) -+ NdisMDeregisterInterrupt(wnd->mp_interrupt); -+ /* cancel any timers left by buggy windows driver; also free -+ * the memory for timers */ -+ while (1) { -+ struct nt_slist *slist; -+ struct wrap_timer *wrap_timer; -+ -+ spin_lock_bh(&ntoskernel_lock); -+ if ((slist = wnd->wrap_timer_slist.next)) -+ wnd->wrap_timer_slist.next = slist->next; -+ spin_unlock_bh(&ntoskernel_lock); -+ TIMERTRACE("%p", slist); -+ if (!slist) -+ break; -+ wrap_timer = container_of(slist, struct wrap_timer, slist); -+ wrap_timer->repeat = 0; -+ /* ktimer that this wrap_timer is associated to can't -+ * be touched, as it may have been freed by the driver -+ * already */ -+ if (del_timer_sync(&wrap_timer->timer)) -+ WARNING("Buggy Windows driver left timer %p " -+ "running", wrap_timer->nt_timer); -+ memset(wrap_timer, 0, sizeof(*wrap_timer)); -+ kfree(wrap_timer); -+ } -+ EXIT1(return); -+} -+ -+static NDIS_STATUS mp_set_power_state(struct ndis_device *wnd, -+ enum ndis_power_state state) -+{ -+ NDIS_STATUS status; -+ -+ TRACE1("%d", state); -+ if (state == NdisDeviceStateD0) { -+ status = NDIS_STATUS_SUCCESS; -+ mutex_unlock(&wnd->ndis_req_mutex); -+ if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) { -+ status = mp_init(wnd); -+ if (status == NDIS_STATUS_SUCCESS) { -+ set_packet_filter(wnd, wnd->packet_filter); -+ set_multicast_list(wnd); -+ } -+ } else if (test_and_clear_bit(HW_SUSPENDED, -+ &wnd->wd->hw_status)) { -+ status = mp_set_int(wnd, OID_PNP_SET_POWER, state); -+ if (status != NDIS_STATUS_SUCCESS) -+ WARNING("%s: setting power to state %d failed? " -+ "%08X", wnd->net_dev->name, state, -+ status); -+ } else -+ return NDIS_STATUS_FAILURE; -+ -+ if (wrap_is_pci_bus(wnd->wd->dev_bus)) { -+ pci_enable_wake(wnd->wd->pci.pdev, PCI_D3hot, 0); -+ pci_enable_wake(wnd->wd->pci.pdev, PCI_D3cold, 0); -+ } -+ if (status == NDIS_STATUS_SUCCESS) { -+ mutex_unlock(&wnd->tx_ring_mutex); -+ netif_device_attach(wnd->net_dev); -+ hangcheck_add(wnd); -+ add_iw_stats_timer(wnd); -+ } else -+ WARNING("%s: couldn't set power to state %d; device not" -+ " resumed", wnd->net_dev->name, state); -+ EXIT1(return status); -+ } else { -+ mutex_lock(&wnd->tx_ring_mutex); -+ netif_device_detach(wnd->net_dev); -+ hangcheck_del(wnd); -+ del_iw_stats_timer(wnd); -+ status = NDIS_STATUS_NOT_SUPPORTED; -+ if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { -+ status = mp_set_int(wnd, OID_PNP_ENABLE_WAKE_UP, -+ wnd->ndis_wolopts); -+ TRACE2("0x%x, 0x%x", status, wnd->ndis_wolopts); -+ if (status == NDIS_STATUS_SUCCESS && -+ wrap_is_pci_bus(wnd->wd->dev_bus)) { -+ if (wnd->ndis_wolopts) -+ wnd->wd->pci.wake_state = -+ PowerDeviceD3; -+ else -+ wnd->wd->pci.wake_state = -+ PowerDeviceUnspecified; -+ } else -+ WARNING("couldn't set wake-on-lan options: " -+ "0x%x, %08X", wnd->ndis_wolopts, status); -+ status = mp_set_int(wnd, OID_PNP_SET_POWER, state); -+ if (status == NDIS_STATUS_SUCCESS) -+ set_bit(HW_SUSPENDED, &wnd->wd->hw_status); -+ else -+ WARNING("suspend failed: %08X", status); -+ } -+ if (status != NDIS_STATUS_SUCCESS) { -+ WARNING("%s does not support power management; " -+ "halting the device", wnd->net_dev->name); -+ mp_halt(wnd); -+ set_bit(HW_HALTED, &wnd->wd->hw_status); -+ status = STATUS_SUCCESS; -+ } -+ mutex_lock(&wnd->ndis_req_mutex); -+ EXIT1(return status); -+ } -+} -+ -+static int ndis_set_mac_address(struct net_device *dev, void *p) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ struct sockaddr *addr = p; -+ struct ndis_configuration_parameter param; -+ struct unicode_string key; -+ struct ansi_string ansi; -+ NDIS_STATUS res; -+ unsigned char mac_string[2 * ETH_ALEN + 1]; -+ mac_address mac; -+ -+ memcpy(mac, addr->sa_data, sizeof(mac)); -+ memset(mac_string, 0, sizeof(mac_string)); -+ res = snprintf(mac_string, sizeof(mac_string), MACSTR, MAC2STR(mac)); -+ if (res != (sizeof(mac_string) - 1)) -+ EXIT1(return -EINVAL); -+ TRACE1("new mac: %s", mac_string); -+ -+ RtlInitAnsiString(&ansi, mac_string); -+ if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi, -+ TRUE) != STATUS_SUCCESS) -+ EXIT1(return -EINVAL); -+ -+ param.type = NdisParameterString; -+ RtlInitAnsiString(&ansi, "NetworkAddress"); -+ if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) { -+ RtlFreeUnicodeString(¶m.data.string); -+ EXIT1(return -EINVAL); -+ } -+ NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m); -+ RtlFreeUnicodeString(&key); -+ RtlFreeUnicodeString(¶m.data.string); -+ -+ if (res != NDIS_STATUS_SUCCESS) -+ EXIT1(return -EFAULT); -+ if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) { -+ res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, -+ mac, sizeof(mac)); -+ if (res == NDIS_STATUS_SUCCESS) { -+ TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); -+ memcpy(dev->dev_addr, mac, sizeof(mac)); -+ } else -+ ERROR("couldn't get mac address: %08X", res); -+ } -+ EXIT1(return 0); -+} -+ -+static int setup_tx_sg_list(struct ndis_device *wnd, struct sk_buff *skb, -+ struct ndis_packet_oob_data *oob_data) -+{ -+ struct ndis_sg_element *sg_element; -+ struct ndis_sg_list *sg_list; -+ int i; -+ -+ ENTER3("%p, %d", skb, skb_shinfo(skb)->nr_frags); -+ if (skb_shinfo(skb)->nr_frags <= 1) { -+ sg_element = &oob_data->wrap_tx_sg_list.elements[0]; -+ sg_element->address = -+ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data, -+ skb->len, PCI_DMA_TODEVICE); -+ sg_element->length = skb->len; -+ oob_data->wrap_tx_sg_list.nent = 1; -+ oob_data->ext.info[ScatterGatherListPacketInfo] = -+ &oob_data->wrap_tx_sg_list; -+ TRACE3("%llx, %u", sg_element->address, sg_element->length); -+ return 0; -+ } -+ sg_list = kmalloc(sizeof(*sg_list) + -+ (skb_shinfo(skb)->nr_frags + 1) * sizeof(*sg_element), -+ GFP_ATOMIC); -+ if (!sg_list) -+ return -ENOMEM; -+ sg_list->nent = skb_shinfo(skb)->nr_frags + 1; -+ TRACE3("%p, %d", sg_list, sg_list->nent); -+ sg_element = sg_list->elements; -+ sg_element->length = skb_headlen(skb); -+ sg_element->address = -+ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data, -+ skb_headlen(skb), PCI_DMA_TODEVICE); -+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { -+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; -+ sg_element++; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) -+ sg_element->length = skb_frag_size(frag); -+#else -+ sg_element->length = frag->size; -+#endif -+ sg_element->address = -+ pci_map_page(wnd->wd->pci.pdev, skb_frag_page(frag), -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) -+ skb_frag_off(frag), skb_frag_size(frag), -+#else -+ frag->page_offset, frag->size, -+#endif -+ PCI_DMA_TODEVICE); -+ TRACE3("%llx, %u", sg_element->address, sg_element->length); -+ } -+ oob_data->ext.info[ScatterGatherListPacketInfo] = sg_list; -+ return 0; -+} -+ -+static void free_tx_sg_list(struct ndis_device *wnd, -+ struct ndis_packet_oob_data *oob_data) -+{ -+ int i; -+ struct ndis_sg_element *sg_element; -+ struct ndis_sg_list *sg_list = -+ oob_data->ext.info[ScatterGatherListPacketInfo]; -+ sg_element = sg_list->elements; -+ TRACE3("%p, %d", sg_list, sg_list->nent); -+ PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, sg_element->address, -+ sg_element->length, PCI_DMA_TODEVICE); -+ if (sg_list->nent == 1) -+ EXIT3(return); -+ for (i = 1; i < sg_list->nent; i++, sg_element++) { -+ TRACE3("%llx, %u", sg_element->address, sg_element->length); -+ pci_unmap_page(wnd->wd->pci.pdev, sg_element->address, -+ sg_element->length, PCI_DMA_TODEVICE); -+ } -+ TRACE3("%p", sg_list); -+ kfree(sg_list); -+} -+ -+static struct ndis_packet *alloc_tx_packet(struct ndis_device *wnd, -+ struct sk_buff *skb) -+{ -+ struct ndis_packet *packet; -+ ndis_buffer *buffer; -+ struct ndis_packet_oob_data *oob_data; -+ NDIS_STATUS status; -+ -+ NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool); -+ if (status != NDIS_STATUS_SUCCESS) -+ return NULL; -+ NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool, -+ skb->data, skb->len); -+ if (status != NDIS_STATUS_SUCCESS) { -+ NdisFreePacket(packet); -+ return NULL; -+ } -+ packet->private.buffer_head = buffer; -+ packet->private.buffer_tail = buffer; -+ -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ oob_data->tx_skb = skb; -+ if (wnd->sg_dma_size) { -+ if (setup_tx_sg_list(wnd, skb, oob_data)) { -+ NdisFreeBuffer(buffer); -+ NdisFreePacket(packet); -+ return NULL; -+ } -+ } -+ if (skb->ip_summed == CHECKSUM_PARTIAL) { -+ struct ndis_tcp_ip_checksum_packet_info csum; -+ int protocol; -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) -+ protocol = ntohs(skb->protocol); -+#else -+ protocol = skb->nh.iph->protocol; -+#endif -+ csum.value = 0; -+ csum.tx.v4 = 1; -+ if (protocol == IPPROTO_TCP) -+ csum.tx.tcp = 1; -+ else if (protocol == IPPROTO_UDP) -+ csum.tx.udp = 1; -+// csum->tx.ip = 1; -+ packet->private.flags |= NDIS_PROTOCOL_ID_TCP_IP; -+ oob_data->ext.info[TcpIpChecksumPacketInfo] = -+ (void *)(ULONG_PTR)csum.value; -+ } -+ DBG_BLOCK(4) { -+ dump_bytes(__func__, skb->data, skb->len); -+ } -+ TRACE4("%p, %p, %p", packet, buffer, skb); -+ return packet; -+} -+ -+void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet, -+ NDIS_STATUS status) -+{ -+ ndis_buffer *buffer; -+ struct ndis_packet_oob_data *oob_data; -+ struct sk_buff *skb; -+ struct ndis_packet_pool *pool; -+ -+ assert_irql(_irql_ <= DISPATCH_LEVEL); -+ assert(packet->private.packet_flags); -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ skb = oob_data->tx_skb; -+ buffer = packet->private.buffer_head; -+ TRACE4("%p, %p, %p, %08X", packet, buffer, skb, status); -+ if (status == NDIS_STATUS_SUCCESS) { -+ pre_atomic_add(wnd->net_stats.tx_bytes, packet->private.len); -+ atomic_inc_var(wnd->net_stats.tx_packets); -+ } else { -+ TRACE1("packet dropped: %08X", status); -+ atomic_inc_var(wnd->net_stats.tx_dropped); -+ } -+ if (wnd->sg_dma_size) -+ free_tx_sg_list(wnd, oob_data); -+ NdisFreeBuffer(buffer); -+ dev_kfree_skb_any(skb); -+ pool = packet->private.pool; -+ NdisFreePacket(packet); -+ if (netif_queue_stopped(wnd->net_dev) && -+ ((pool->max_descr - pool->num_used_descr) >= -+ (wnd->max_tx_packets / 4))) { -+ set_bit(NETIF_WAKEQ, &wnd->ndis_pending_work); -+ queue_work(wrapndis_wq, &wnd->ndis_work); -+ } -+ EXIT4(return); -+} -+ -+/* MiniportSend and MiniportSendPackets */ -+/* this function is called holding tx_ring_mutex. start and n are such -+ * that start + n < TX_RING_SIZE; i.e., packets don't wrap around -+ * ring */ -+static u8 mp_tx_packets(struct ndis_device *wnd, u8 start, u8 n) -+{ -+ NDIS_STATUS res; -+ struct miniport *mp; -+ struct ndis_packet *packet; -+ u8 sent; -+ KIRQL irql; -+ -+ ENTER3("%d, %d", start, n); -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ if (mp->send_packets) { -+ if (deserialized_driver(wnd)) { -+ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, -+ &wnd->tx_ring[start], n); -+ sent = n; -+ } else { -+ irql = serialize_lock_irql(wnd); -+ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, -+ &wnd->tx_ring[start], n); -+ serialize_unlock_irql(wnd, irql); -+ for (sent = 0; sent < n && wnd->tx_ok; sent++) { -+ struct ndis_packet_oob_data *oob_data; -+ packet = wnd->tx_ring[start + sent]; -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ switch ((res = -+ xchg(&oob_data->status, -+ NDIS_STATUS_NOT_RECOGNIZED))) { -+ case NDIS_STATUS_SUCCESS: -+ free_tx_packet(wnd, packet, -+ NDIS_STATUS_SUCCESS); -+ break; -+ case NDIS_STATUS_PENDING: -+ break; -+ case NDIS_STATUS_RESOURCES: -+ wnd->tx_ok = 0; -+ /* resubmit this packet and -+ * the rest when resources -+ * become available */ -+ sent--; -+ break; -+ case NDIS_STATUS_FAILURE: -+ free_tx_packet(wnd, packet, -+ NDIS_STATUS_FAILURE); -+ break; -+ default: -+ ERROR("%p: invalid status: %08X", -+ packet, res); -+ free_tx_packet(wnd, packet, -+ oob_data->status); -+ break; -+ } -+ TRACE3("%p, %d", packet, res); -+ } -+ } -+ TRACE3("sent: %d(%d)", sent, n); -+ } else { -+ for (sent = 0; sent < n && wnd->tx_ok; sent++) { -+ struct ndis_packet_oob_data *oob_data; -+ packet = wnd->tx_ring[start + sent]; -+ oob_data = NDIS_PACKET_OOB_DATA(packet); -+ oob_data->status = NDIS_STATUS_NOT_RECOGNIZED; -+ irql = serialize_lock_irql(wnd); -+ res = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, -+ packet, packet->private.flags); -+ serialize_unlock_irql(wnd, irql); -+ switch (res) { -+ case NDIS_STATUS_SUCCESS: -+ free_tx_packet(wnd, packet, res); -+ break; -+ case NDIS_STATUS_PENDING: -+ break; -+ case NDIS_STATUS_RESOURCES: -+ wnd->tx_ok = 0; -+ /* resend this packet when resources -+ * become available */ -+ sent--; -+ break; -+ case NDIS_STATUS_FAILURE: -+ free_tx_packet(wnd, packet, res); -+ break; -+ default: -+ ERROR("packet %p: invalid status: %08X", -+ packet, res); -+ break; -+ } -+ } -+ } -+ EXIT3(return sent); -+} -+ -+static void tx_worker(struct work_struct *work) -+{ -+ struct ndis_device *wnd; -+ s8 n; -+ -+ wnd = container_of(work, struct ndis_device, tx_work); -+ ENTER3("tx_ok %d", wnd->tx_ok); -+ while (wnd->tx_ok) { -+ mutex_lock(&wnd->tx_ring_mutex); -+ spin_lock_bh(&wnd->tx_ring_lock); -+ n = wnd->tx_ring_end - wnd->tx_ring_start; -+ TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n); -+ /* end == start if either ring is empty or full; in -+ * the latter case is_tx_ring_full is set */ -+ if (n == 0) { -+ if (wnd->is_tx_ring_full) -+ n = TX_RING_SIZE - wnd->tx_ring_start; -+ else { -+ spin_unlock_bh(&wnd->tx_ring_lock); -+ mutex_unlock(&wnd->tx_ring_mutex); -+ break; -+ } -+ } else if (n < 0) -+ n = TX_RING_SIZE - wnd->tx_ring_start; -+ spin_unlock_bh(&wnd->tx_ring_lock); -+ if (unlikely(n > wnd->max_tx_packets)) -+ n = wnd->max_tx_packets; -+ n = mp_tx_packets(wnd, wnd->tx_ring_start, n); -+ if (n) { -+ netif_trans_update(wnd->net_dev); -+ wnd->tx_ring_start = -+ (wnd->tx_ring_start + n) % TX_RING_SIZE; -+ wnd->is_tx_ring_full = 0; -+ } -+ mutex_unlock(&wnd->tx_ring_mutex); -+ TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n); -+ } -+ EXIT3(return); -+} -+ -+static int tx_skbuff(struct sk_buff *skb, struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ struct ndis_packet *packet; -+ -+ packet = alloc_tx_packet(wnd, skb); -+ if (!packet) { -+ TRACE2("couldn't allocate packet"); -+ netif_tx_lock(dev); -+ netif_stop_queue(dev); -+ netif_tx_unlock(dev); -+ return NETDEV_TX_BUSY; -+ } -+ spin_lock(&wnd->tx_ring_lock); -+ wnd->tx_ring[wnd->tx_ring_end++] = packet; -+ if (wnd->tx_ring_end == TX_RING_SIZE) -+ wnd->tx_ring_end = 0; -+ if (wnd->tx_ring_end == wnd->tx_ring_start) { -+ netif_tx_lock(dev); -+ wnd->is_tx_ring_full = 1; -+ netif_stop_queue(dev); -+ netif_tx_unlock(dev); -+ } -+ spin_unlock(&wnd->tx_ring_lock); -+ TRACE4("ring: %d, %d", wnd->tx_ring_start, wnd->tx_ring_end); -+ queue_work(wrapndis_wq, &wnd->tx_work); -+ return NETDEV_TX_OK; -+} -+ -+static int set_packet_filter(struct ndis_device *wnd, ULONG packet_filter) -+{ -+ NDIS_STATUS res; -+ -+ while (1) { -+ res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, -+ packet_filter); -+ if (res == NDIS_STATUS_SUCCESS) -+ break; -+ TRACE2("couldn't set filter 0x%08x", packet_filter); -+ /* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */ -+ if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) { -+ packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS; -+ continue; -+ } -+ if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) { -+ packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL; -+ continue; -+ } -+ if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) { -+ packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL; -+ continue; -+ } -+ if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) { -+ packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST; -+ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; -+ continue; -+ } -+ if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) { -+ packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST; -+ continue; -+ } -+ break; -+ } -+ -+ wnd->packet_filter = packet_filter; -+ res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter); -+ if (packet_filter != wnd->packet_filter) { -+ WARNING("filter not set: 0x%08x, 0x%08x", -+ packet_filter, wnd->packet_filter); -+ wnd->packet_filter = packet_filter; -+ } -+ if (wnd->packet_filter) -+ EXIT3(return 0); -+ else -+ EXIT3(return -1); -+} -+ -+void set_media_state(struct ndis_device *wnd, enum ndis_media_state state) -+{ -+ struct net_device *net_dev = wnd->net_dev; -+ -+ ENTER2("state: 0x%x, carrier %d", state, netif_carrier_ok(net_dev)); -+ switch (state) { -+ case NdisMediaStateConnected: -+ if (netif_carrier_ok(net_dev)) -+ return; -+ netif_carrier_on(net_dev); -+ wnd->tx_ok = 1; -+ if (netif_queue_stopped(net_dev)) -+ netif_wake_queue(net_dev); -+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { -+ set_bit(LINK_STATUS_ON, &wnd->ndis_pending_work); -+ queue_work(wrapndis_wq, &wnd->ndis_work); -+ } -+ break; -+ case NdisMediaStateDisconnected: -+ if (!netif_carrier_ok(net_dev)) -+ return; -+ netif_carrier_off(net_dev); -+ netif_stop_queue(net_dev); -+ wnd->tx_ok = 0; -+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { -+ memset(&wnd->essid, 0, sizeof(wnd->essid)); -+ set_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work); -+ queue_work(wrapndis_wq, &wnd->ndis_work); -+ } -+ break; -+ default: -+ WARNING("invalid media state: 0x%x", state); -+ break; -+ } -+} -+ -+static int ndis_net_dev_init(struct net_device *net_dev) -+{ -+ struct ndis_device *wnd = netdev_priv(net_dev); -+ -+ ENTER1("%p", wnd); -+ wrap_procfs_add_ndis_device(wnd); -+ EXIT1(return 0); -+} -+ -+static void ndis_net_dev_uninit(struct net_device *net_dev) -+{ -+ struct ndis_device *wnd = netdev_priv(net_dev); -+ -+ ENTER1("%p", wnd); -+ wrap_procfs_remove_ndis_device(wnd); -+ EXIT1(return); -+} -+ -+static int ndis_net_dev_open(struct net_device *net_dev) -+{ -+ int status, res; -+ struct ndis_device *wnd = netdev_priv(net_dev); -+ -+ ENTER1("%p", wnd); -+ res = mp_query_int(wnd, OID_GEN_MEDIA_CONNECT_STATUS, &status); -+ if (res == NDIS_STATUS_SUCCESS && status >= NdisMediaStateConnected && -+ status <= NdisMediaStateDisconnected) -+ set_media_state(wnd, status); -+ netif_start_queue(net_dev); -+ netif_poll_enable(net_dev); -+ EXIT1(return 0); -+} -+ -+static int ndis_net_dev_close(struct net_device *net_dev) -+{ -+ ENTER1("%p", netdev_priv(net_dev)); -+ netif_poll_disable(net_dev); -+ netif_tx_disable(net_dev); -+ EXIT1(return 0); -+} -+ -+static int ndis_change_mtu(struct net_device *net_dev, int mtu) -+{ -+ struct ndis_device *wnd = netdev_priv(net_dev); -+ int max; -+ -+ if (mtu < ETH_ZLEN) -+ return -EINVAL; -+ if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &max) != -+ NDIS_STATUS_SUCCESS) -+ return -EOPNOTSUPP; -+ TRACE1("%d", max); -+ max -= ETH_HLEN; -+ if (max <= ETH_ZLEN) -+ return -EINVAL; -+ if (mtu + ETH_HLEN > max) -+ return -EINVAL; -+ net_dev->mtu = mtu; -+ return 0; -+} -+ -+#ifdef CONFIG_NET_POLL_CONTROLLER -+static void ndis_poll_controller(struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ disable_irq(dev->irq); -+ ndis_isr(wnd->mp_interrupt->kinterrupt, wnd->mp_interrupt); -+ enable_irq(dev->irq); -+} -+#endif -+ -+/* called from BH context */ -+static struct net_device_stats *ndis_get_stats(struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ return &wnd->net_stats; -+} -+ -+/* called from BH context */ -+static void ndis_set_multicast_list(struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ set_bit(SET_MULTICAST_LIST, &wnd->ndis_pending_work); -+ queue_work(wrapndis_wq, &wnd->ndis_work); -+} -+ -+/* called from BH context */ -+struct iw_statistics *get_iw_stats(struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ return &wnd->iw_stats; -+} -+ -+static void update_iw_stats(struct ndis_device *wnd) -+{ -+ struct iw_statistics *iw_stats = &wnd->iw_stats; -+ struct ndis_wireless_stats ndis_stats; -+ NDIS_STATUS res; -+ ndis_rssi rssi; -+ int qual; -+ -+ ENTER2("%p", wnd); -+ if (wnd->iw_stats_enabled == FALSE || !netif_carrier_ok(wnd->net_dev)) { -+ memset(iw_stats, 0, sizeof(*iw_stats)); -+ EXIT2(return); -+ } -+ res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi)); -+ if (res == NDIS_STATUS_SUCCESS) -+ iw_stats->qual.level = rssi; -+ -+ qual = 100 * (rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE); -+ if (qual < 0) -+ qual = 0; -+ else if (qual > 100) -+ qual = 100; -+ -+ iw_stats->qual.noise = WL_NOISE; -+ iw_stats->qual.qual = qual; -+ -+ res = mp_query(wnd, OID_802_11_STATISTICS, -+ &ndis_stats, sizeof(ndis_stats)); -+ if (res != NDIS_STATUS_SUCCESS) -+ EXIT2(return); -+ iw_stats->discard.retries = (unsigned long)ndis_stats.retry + -+ (unsigned long)ndis_stats.multi_retry; -+ iw_stats->discard.misc = (unsigned long)ndis_stats.fcs_err + -+ (unsigned long)ndis_stats.rtss_fail + -+ (unsigned long)ndis_stats.ack_fail + -+ (unsigned long)ndis_stats.frame_dup; -+ -+ EXIT2(return); -+} -+ -+static void set_multicast_list(struct ndis_device *wnd) -+{ -+ struct net_device *net_dev; -+ ULONG packet_filter; -+ NDIS_STATUS res; -+ -+ net_dev = wnd->net_dev; -+ packet_filter = wnd->packet_filter; -+ -+ TRACE2("0x%08x", packet_filter); -+ if (net_dev->flags & IFF_PROMISC) { -+ packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS | -+ NDIS_PACKET_TYPE_ALL_LOCAL; -+ } else if (net_dev->flags & IFF_ALLMULTI || -+ netdev_mc_count(net_dev) > wnd->multicast_size) { -+ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; -+ TRACE2("0x%08x", packet_filter); -+ } else if (netdev_mc_count(net_dev) > 0) { -+ int i, size; -+ char *buf; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) -+ struct netdev_hw_addr *ha; -+#else -+ struct dev_mc_list *mclist; -+#endif -+ size = min(wnd->multicast_size, netdev_mc_count(net_dev)); -+ TRACE2("%d, %d", wnd->multicast_size, netdev_mc_count(net_dev)); -+ buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); -+ if (!buf) { -+ WARNING("couldn't allocate memory"); -+ EXIT2(return); -+ } -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) -+ i = 0; -+ netdev_for_each_mc_addr(ha, net_dev) { -+ if (i >= size) -+ break; -+ memcpy(buf + i * ETH_ALEN, ha->addr, ETH_ALEN); -+ TRACE2(MACSTRSEP, MAC2STR(ha->addr)); -+ i++; -+ } -+#else -+ mclist = net_dev->mc_list; -+ for (i = 0; i < size && mclist; mclist = mclist->next) { -+ if (mclist->dmi_addrlen != ETH_ALEN) -+ continue; -+ memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN); -+ TRACE2(MACSTRSEP, MAC2STR(mclist->dmi_addr)); -+ i++; -+ } -+#endif -+ res = mp_set(wnd, OID_802_3_MULTICAST_LIST, buf, i * ETH_ALEN); -+ if (res == NDIS_STATUS_SUCCESS && i > 0) -+ packet_filter |= NDIS_PACKET_TYPE_MULTICAST; -+ else -+ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; -+ kfree(buf); -+ } -+ TRACE2("0x%08x", packet_filter); -+ res = set_packet_filter(wnd, packet_filter); -+ if (res) -+ TRACE1("couldn't set packet filter (%08X)", res); -+ EXIT2(return); -+} -+ -+static void link_status_off(struct ndis_device *wnd) -+{ -+#ifdef CONFIG_WIRELESS_EXT -+ union iwreq_data wrqu; -+ -+ memset(&wrqu, 0, sizeof(wrqu)); -+ wrqu.ap_addr.sa_family = ARPHRD_ETHER; -+ wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL); -+#endif -+ EXIT2(return); -+} -+ -+static void link_status_on(struct ndis_device *wnd) -+{ -+#ifdef CONFIG_WIRELESS_EXT -+ struct ndis_assoc_info *ndis_assoc_info; -+ union iwreq_data wrqu; -+ NDIS_STATUS res; -+ const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX + 32; -+#endif -+ -+ ENTER2(""); -+#ifdef CONFIG_WIRELESS_EXT -+ memset(&wrqu, 0, sizeof(wrqu)); -+ ndis_assoc_info = kzalloc(assoc_size, GFP_KERNEL); -+ if (!ndis_assoc_info) { -+ ERROR("couldn't allocate memory"); -+ goto send_assoc_event; -+ } -+ res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION, -+ ndis_assoc_info, assoc_size); -+ if (res) { -+ TRACE2("query assoc_info failed (%08X)", res); -+ kfree(ndis_assoc_info); -+ goto send_assoc_event; -+ } -+ TRACE2("%u, 0x%x, %u, 0x%x, %u", ndis_assoc_info->length, -+ ndis_assoc_info->req_ies, ndis_assoc_info->req_ie_length, -+ ndis_assoc_info->resp_ies, ndis_assoc_info->resp_ie_length); -+ if (ndis_assoc_info->req_ie_length > 0) { -+ wrqu.data.length = ndis_assoc_info->req_ie_length; -+ wireless_send_event(wnd->net_dev, IWEVASSOCREQIE, &wrqu, -+ ((char *)ndis_assoc_info) + -+ ndis_assoc_info->offset_req_ies); -+ } -+ if (ndis_assoc_info->resp_ie_length > 0) { -+ wrqu.data.length = ndis_assoc_info->resp_ie_length; -+ wireless_send_event(wnd->net_dev, IWEVASSOCRESPIE, &wrqu, -+ ((char *)ndis_assoc_info) + -+ ndis_assoc_info->offset_resp_ies); -+ } -+ kfree(ndis_assoc_info); -+ -+send_assoc_event: -+ get_ap_address(wnd, wrqu.ap_addr.sa_data); -+ wrqu.ap_addr.sa_family = ARPHRD_ETHER; -+ TRACE2(MACSTRSEP, MAC2STR(wrqu.ap_addr.sa_data)); -+ wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL); -+#endif -+ EXIT2(return); -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+static void iw_stats_timer_proc(struct timer_list *tl) -+#else -+static void iw_stats_timer_proc(unsigned long data) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+ struct ndis_device *wnd = from_timer(wnd, tl, iw_stats_timer); -+#else -+ struct ndis_device *wnd = (struct ndis_device *)data; -+#endif -+ -+ ENTER2("%d", wnd->iw_stats_interval); -+ if (wnd->iw_stats_interval > 0) { -+ set_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work); -+ queue_work(wrapndis_wq, &wnd->ndis_work); -+ } -+ mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval); -+} -+ -+static void add_iw_stats_timer(struct ndis_device *wnd) -+{ -+ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan) -+ return; -+ if (wnd->iw_stats_interval < 0) -+ wnd->iw_stats_interval *= -1; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+ timer_setup(&wnd->iw_stats_timer, iw_stats_timer_proc, 0); -+#else -+ wnd->iw_stats_timer.data = (unsigned long)wnd; -+ wnd->iw_stats_timer.function = iw_stats_timer_proc; -+#endif -+ mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval); -+} -+ -+static void del_iw_stats_timer(struct ndis_device *wnd) -+{ -+ ENTER2("%d", wnd->iw_stats_interval); -+ wnd->iw_stats_interval *= -1; -+ del_timer_sync(&wnd->iw_stats_timer); -+ EXIT2(return); -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+static void hangcheck_proc(struct timer_list *tl) -+#else -+static void hangcheck_proc(unsigned long data) -+#endif -+{ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+ struct ndis_device *wnd = from_timer(wnd, tl, hangcheck_timer); -+#else -+ struct ndis_device *wnd = (struct ndis_device *)data; -+#endif -+ -+ ENTER3("%d", wnd->hangcheck_interval); -+ if (wnd->hangcheck_interval > 0) { -+ set_bit(HANGCHECK, &wnd->ndis_pending_work); -+ queue_work(wrapndis_wq, &wnd->ndis_work); -+ } -+ mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval); -+ EXIT3(return); -+} -+ -+void hangcheck_add(struct ndis_device *wnd) -+{ -+ if (!wnd->wd->driver->ndis_driver->mp.hangcheck || -+ hangcheck_interval < 0) -+ EXIT2(return); -+ -+ if (hangcheck_interval > 0) -+ wnd->hangcheck_interval = hangcheck_interval * HZ; -+ if (wnd->hangcheck_interval < 0) -+ wnd->hangcheck_interval *= -1; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+ timer_setup(&wnd->hangcheck_timer, hangcheck_proc, 0); -+#else -+ wnd->hangcheck_timer.data = (unsigned long)wnd; -+ wnd->hangcheck_timer.function = hangcheck_proc; -+#endif -+ mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval); -+ EXIT2(return); -+} -+ -+void hangcheck_del(struct ndis_device *wnd) -+{ -+ ENTER2("%d", wnd->hangcheck_interval); -+ if (wnd->hangcheck_interval > 0) -+ wnd->hangcheck_interval *= -1; -+ del_timer_sync(&wnd->hangcheck_timer); -+ EXIT2(return); -+} -+ -+/* worker procedure to take care of setting/checking various states */ -+static void wrapndis_worker(struct work_struct *work) -+{ -+ struct ndis_device *wnd; -+ -+ wnd = container_of(work, struct ndis_device, ndis_work); -+ WORKTRACE("0x%lx", wnd->ndis_pending_work); -+ -+ if (test_and_clear_bit(NETIF_WAKEQ, &wnd->ndis_pending_work)) { -+ netif_tx_lock_bh(wnd->net_dev); -+ netif_wake_queue(wnd->net_dev); -+ netif_tx_unlock_bh(wnd->net_dev); -+ } -+ -+ if (test_and_clear_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work)) -+ link_status_off(wnd); -+ -+ if (test_and_clear_bit(LINK_STATUS_ON, &wnd->ndis_pending_work)) -+ link_status_on(wnd); -+ -+ if (test_and_clear_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work)) -+ update_iw_stats(wnd); -+ -+ if (test_and_clear_bit(SET_MULTICAST_LIST, -+ &wnd->ndis_pending_work)) -+ set_multicast_list(wnd); -+ -+ if (test_and_clear_bit(HANGCHECK, &wnd->ndis_pending_work)) { -+ struct miniport *mp; -+ BOOLEAN reset; -+ KIRQL irql; -+ -+ mp = &wnd->wd->driver->ndis_driver->mp; -+ irql = serialize_lock_irql(wnd); -+ reset = LIN2WIN1(mp->hangcheck, wnd->nmb->mp_ctx); -+ serialize_unlock_irql(wnd, irql); -+ if (reset) { -+ TRACE2("%s needs reset", wnd->net_dev->name); -+ mp_reset(wnd); -+ } -+ } -+ WORKEXIT(return); -+} -+ -+NDIS_STATUS ndis_reinit(struct ndis_device *wnd) -+{ -+ NDIS_STATUS status; -+ -+ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; -+ status = mp_set_power_state(wnd, NdisDeviceStateD3); -+ if (status != NDIS_STATUS_SUCCESS) { -+ ERROR("halting device %s failed: %08X", wnd->net_dev->name, -+ status); -+ return status; -+ } -+ status = mp_set_power_state(wnd, NdisDeviceStateD0); -+ if (status != NDIS_STATUS_SUCCESS) -+ ERROR("starting device %s failed: %08X", wnd->net_dev->name, -+ status); -+ return status; -+} -+ -+#ifdef CONFIG_WIRELESS_EXT -+static void get_encryption_capa(struct ndis_device *wnd, char *buf, -+ const int buf_len) -+{ -+ int i, mode; -+ NDIS_STATUS res; -+ struct ndis_assoc_info ndis_assoc_info; -+ struct ndis_add_key ndis_key; -+ struct ndis_capability *c; -+ -+ ENTER1("%p", wnd); -+ /* set network type to g, b, or a, in that order */ -+ res = mp_query(wnd, OID_802_11_NETWORK_TYPES_SUPPORTED, buf, buf_len); -+ if (res == NDIS_STATUS_SUCCESS) { -+ struct network_type_list *net_types; -+ unsigned long types = 0; -+ net_types = (typeof(net_types))buf; -+ for (i = 0; i < net_types->num; i++) { -+ TRACE2("%d", net_types->types[i]); -+ set_bit(net_types->types[i], &types); -+ } -+ if (test_bit(Ndis802_11OFDM24, &types)) -+ mode = Ndis802_11OFDM24; -+ else if (test_bit(Ndis802_11DS, &types)) -+ mode = Ndis802_11DS; -+ else if (test_bit(Ndis802_11OFDM5, &types)) -+ mode = Ndis802_11OFDM5; -+ else -+ mode = Ndis802_11DS; -+ mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, mode); -+ } -+ /* check if WEP is supported */ -+ if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, -+ IW_AUTH_CIPHER_NONE) == 0 && -+ get_ndis_encr_mode(wnd) == Ndis802_11Encryption1KeyAbsent) -+ set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr); -+ -+ /* check if WPA is supported */ -+ if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPA) == 0 && -+ get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPA) -+ set_bit(Ndis802_11AuthModeWPA, &wnd->capa.encr); -+ else -+ EXIT1(return); -+ -+ if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPAPSK) == 0 && -+ get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPAPSK) -+ set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.encr); -+ -+ /* check for highest encryption */ -+ mode = 0; -+ if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_CCMP, -+ IW_AUTH_CIPHER_NONE) == 0 && -+ (i = get_ndis_encr_mode(wnd)) > 0 && -+ (i == Ndis802_11Encryption3KeyAbsent || -+ i == Ndis802_11Encryption3Enabled)) -+ mode = Ndis802_11Encryption3Enabled; -+ else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_TKIP, -+ IW_AUTH_CIPHER_NONE) == 0 && -+ (i = get_ndis_encr_mode(wnd)) > 0 && -+ (i == Ndis802_11Encryption2KeyAbsent || -+ i == Ndis802_11Encryption2Enabled)) -+ mode = Ndis802_11Encryption2Enabled; -+ else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, -+ IW_AUTH_CIPHER_NONE) == 0 && -+ (i = get_ndis_encr_mode(wnd)) > 0 && -+ (i == Ndis802_11Encryption1KeyAbsent || -+ i == Ndis802_11Encryption1Enabled)) -+ mode = Ndis802_11Encryption1Enabled; -+ -+ TRACE1("mode: %d", mode); -+ if (mode == 0) -+ EXIT1(return); -+ set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr); -+ if (mode == Ndis802_11Encryption1Enabled) -+ EXIT1(return); -+ -+ ndis_key.length = 32; -+ ndis_key.index = 0xC0000001; -+ ndis_key.struct_size = sizeof(ndis_key); -+ res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); -+ TRACE2("%08X, %zu", res, sizeof(ndis_key)); -+ if (res && res != NDIS_STATUS_INVALID_DATA) -+ EXIT1(return); -+ res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION, -+ &ndis_assoc_info, sizeof(ndis_assoc_info)); -+ TRACE1("%08X", res); -+ if (res == NDIS_STATUS_NOT_SUPPORTED) -+ EXIT1(return); -+ -+ set_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr); -+ if (mode == Ndis802_11Encryption3Enabled) -+ set_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr); -+ /* not all drivers support OID_802_11_CAPABILITY, so we don't -+ * know for sure if driver support WPA or WPAPSK; assume -+ * WPAPSK */ -+ set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth); -+ wnd->max_pmkids = 1; -+ -+ memset(buf, 0, buf_len); -+ c = (struct ndis_capability *)buf; -+ res = mp_query(wnd, OID_802_11_CAPABILITY, buf, buf_len); -+ if (!(res == NDIS_STATUS_SUCCESS && c->version == 2)) -+ EXIT1(return); -+ wnd->max_pmkids = c->num_PMKIDs; -+ -+ for (i = 0; i < c->num_auth_encr_pair; i++) { -+ struct ndis_auth_encr_pair *ae; -+ -+ ae = &c->auth_encr_pair[i]; -+ if ((char *)(ae + 1) > buf + buf_len) -+ break; -+ switch (ae->auth_mode) { -+ case Ndis802_11AuthModeOpen: -+ case Ndis802_11AuthModeShared: -+ case Ndis802_11AuthModeWPA: -+ case Ndis802_11AuthModeWPAPSK: -+ case Ndis802_11AuthModeWPANone: -+ case Ndis802_11AuthModeWPA2: -+ case Ndis802_11AuthModeWPA2PSK: -+ set_bit(ae->auth_mode, &wnd->capa.auth); -+ break; -+ default: -+ WARNING("unknown auth_mode: %d", ae->auth_mode); -+ break; -+ } -+ switch (ae->encr_mode) { -+ case Ndis802_11EncryptionDisabled: -+ case Ndis802_11Encryption1Enabled: -+ case Ndis802_11Encryption2Enabled: -+ case Ndis802_11Encryption3Enabled: -+ set_bit(ae->encr_mode, &wnd->capa.encr); -+ break; -+ default: -+ WARNING("unknown encr_mode: %d", ae->encr_mode); -+ break; -+ } -+ } -+ EXIT1(return); -+} -+#endif -+ -+wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, -+ struct irp *irp) -+{ -+ struct ndis_device *wnd; -+ -+ TRACE3("fdo: %p", fdo); -+ /* for now, we don't have anything interesting here, so pass it -+ * down to bus driver */ -+ wnd = fdo->reserved; -+ return IoPassIrpDown(wnd->nmb->pdo, irp); -+} -+WIN_FUNC_DECL(NdisDispatchDeviceControl,2) -+ -+wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp) -+{ -+ struct io_stack_location *irp_sl; -+ struct ndis_device *wnd; -+ enum ndis_power_state state; -+ NTSTATUS status; -+ NDIS_STATUS ndis_status; -+ -+ irp_sl = IoGetCurrentIrpStackLocation(irp); -+ wnd = fdo->reserved; -+ IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn, -+ irp_sl->minor_fn, wnd); -+ if ((irp_sl->params.power.type == SystemPowerState && -+ irp_sl->params.power.state.system_state > PowerSystemWorking) || -+ (irp_sl->params.power.type == DevicePowerState && -+ irp_sl->params.power.state.device_state > PowerDeviceD0)) -+ state = NdisDeviceStateD3; -+ else -+ state = NdisDeviceStateD0; -+ switch (irp_sl->minor_fn) { -+ case IRP_MN_SET_POWER: -+ if (state == NdisDeviceStateD0) { -+ status = IoSyncForwardIrp(wnd->nmb->pdo, irp); -+ if (status != STATUS_SUCCESS) -+ break; -+ ndis_status = mp_set_power_state(wnd, state); -+ if (ndis_status != NDIS_STATUS_SUCCESS) -+ WARNING("couldn't set power to %d: %08X", -+ state, ndis_status); -+ TRACE2("%s: device resumed", wnd->net_dev->name); -+ irp->io_status.status = status = STATUS_SUCCESS; -+ IoCompleteRequest(irp, IO_NO_INCREMENT); -+ break; -+ } else { -+ ndis_status = mp_set_power_state(wnd, state); -+ /* TODO: handle error case */ -+ if (ndis_status != NDIS_STATUS_SUCCESS) -+ WARNING("setting power to %d failed: %08X", -+ state, ndis_status); -+ status = IoAsyncForwardIrp(wnd->nmb->pdo, irp); -+ } -+ break; -+ case IRP_MN_QUERY_POWER: -+ if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { -+ ndis_status = mp_query(wnd, OID_PNP_QUERY_POWER, -+ &state, sizeof(state)); -+ TRACE2("%d, %08X", state, ndis_status); -+ /* this OID must always succeed */ -+ if (ndis_status != NDIS_STATUS_SUCCESS) -+ TRACE1("query power returns %08X", ndis_status); -+ irp->io_status.status = STATUS_SUCCESS; -+ } else -+ irp->io_status.status = STATUS_SUCCESS; -+ status = IoPassIrpDown(wnd->nmb->pdo, irp); -+ break; -+ case IRP_MN_WAIT_WAKE: -+ case IRP_MN_POWER_SEQUENCE: -+ /* TODO: implement WAIT_WAKE */ -+ status = IoPassIrpDown(wnd->nmb->pdo, irp); -+ break; -+ default: -+ status = IoPassIrpDown(wnd->nmb->pdo, irp); -+ break; -+ } -+ IOEXIT(return status); -+} -+WIN_FUNC_DECL(NdisDispatchPower,2) -+ -+wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp) -+{ -+ struct io_stack_location *irp_sl; -+ struct ndis_device *wnd; -+ struct device_object *pdo; -+ NTSTATUS status; -+ -+ IOTRACE("fdo: %p, irp: %p", fdo, irp); -+ irp_sl = IoGetCurrentIrpStackLocation(irp); -+ wnd = fdo->reserved; -+ pdo = wnd->nmb->pdo; -+ switch (irp_sl->minor_fn) { -+ case IRP_MN_START_DEVICE: -+ status = IoSyncForwardIrp(pdo, irp); -+ if (status != STATUS_SUCCESS) -+ break; -+ if (ndis_start_device(wnd) == NDIS_STATUS_SUCCESS) -+ status = STATUS_SUCCESS; -+ else -+ status = STATUS_FAILURE; -+ irp->io_status.status = status; -+ IoCompleteRequest(irp, IO_NO_INCREMENT); -+ break; -+ case IRP_MN_QUERY_STOP_DEVICE: -+ /* TODO: implement in NDIS */ -+ status = IoPassIrpDown(wnd->nmb->pdo, irp); -+ break; -+ case IRP_MN_STOP_DEVICE: -+ mp_halt(wnd); -+ irp->io_status.status = STATUS_SUCCESS; -+ status = IoAsyncForwardIrp(pdo, irp); -+ break; -+ case IRP_MN_REMOVE_DEVICE: -+ TRACE1("%s", wnd->net_dev->name); -+ mp_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved, 0); -+ if (ndis_remove_device(wnd)) { -+ status = STATUS_FAILURE; -+ break; -+ } -+ /* wnd is already freed */ -+ status = IoAsyncForwardIrp(pdo, irp); -+ IoDetachDevice(fdo); -+ IoDeleteDevice(fdo); -+ break; -+ default: -+ status = IoAsyncForwardIrp(pdo, irp); -+ break; -+ } -+ IOTRACE("status: %08X", status); -+ IOEXIT(return status); -+} -+WIN_FUNC_DECL(NdisDispatchPnp,2) -+ -+static void set_task_offload(struct ndis_device *wnd, void *buf, -+ const int buf_size) -+{ -+ struct ndis_task_offload_header *task_offload_header; -+ struct ndis_task_offload *task_offload; -+ struct ndis_task_tcp_ip_checksum *csum = NULL; -+ struct ndis_task_tcp_large_send *tso = NULL; -+ NDIS_STATUS status; -+ -+ memset(buf, 0, buf_size); -+ task_offload_header = buf; -+ task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION; -+ task_offload_header->size = sizeof(*task_offload_header); -+ task_offload_header->encap_format.flags.fixed_header_size = 1; -+ task_offload_header->encap_format.header_size = sizeof(struct ethhdr); -+ task_offload_header->encap_format.encap = IEEE_802_3_Encapsulation; -+ status = mp_query(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size); -+ TRACE1("%08X", status); -+ if (status != NDIS_STATUS_SUCCESS) -+ EXIT1(return); -+ if (task_offload_header->offset_first_task == 0) -+ EXIT1(return); -+ task_offload = ((void *)task_offload_header + -+ task_offload_header->offset_first_task); -+ while (1) { -+ TRACE1("%d, %d", task_offload->version, task_offload->task); -+ switch (task_offload->task) { -+ case TcpIpChecksumNdisTask: -+ csum = (void *)task_offload->task_buf; -+ break; -+ case TcpLargeSendNdisTask: -+ tso = (void *)task_offload->task_buf; -+ break; -+ default: -+ TRACE1("%d", task_offload->task); -+ break; -+ } -+ if (task_offload->offset_next_task == 0) -+ break; -+ task_offload = (void *)task_offload + -+ task_offload->offset_next_task; -+ } -+ if (tso) -+ TRACE1("%u, %u, %d, %d", tso->max_size, tso->min_seg_count, -+ tso->tcp_opts, tso->ip_opts); -+ if (!csum) -+ EXIT1(return); -+ TRACE1("%08x, %08x", csum->v4_tx.value, csum->v4_rx.value); -+ task_offload_header->encap_format.flags.fixed_header_size = 1; -+ task_offload_header->encap_format.header_size = sizeof(struct ethhdr); -+ task_offload_header->offset_first_task = sizeof(*task_offload_header); -+ task_offload = ((void *)task_offload_header + -+ task_offload_header->offset_first_task); -+ task_offload->offset_next_task = 0; -+ task_offload->size = sizeof(*task_offload); -+ task_offload->task = TcpIpChecksumNdisTask; -+ memcpy(task_offload->task_buf, csum, sizeof(*csum)); -+ task_offload->task_buf_length = sizeof(*csum); -+ status = mp_set(wnd, OID_TCP_TASK_OFFLOAD, task_offload_header, -+ sizeof(*task_offload_header) + -+ sizeof(*task_offload) + sizeof(*csum)); -+ TRACE1("%08X", status); -+ if (status != NDIS_STATUS_SUCCESS) -+ EXIT2(return); -+ wnd->tx_csum = csum->v4_tx; -+ if (csum->v4_tx.tcp_csum && csum->v4_tx.udp_csum) { -+ if (csum->v4_tx.ip_csum) { -+ wnd->net_dev->features |= NETIF_F_HW_CSUM; -+ TRACE1("hw checksum enabled"); -+ } else { -+ wnd->net_dev->features |= NETIF_F_IP_CSUM; -+ TRACE1("IP checksum enabled"); -+ } -+ if (wnd->sg_dma_size) -+ wnd->net_dev->features |= NETIF_F_SG; -+ } -+ wnd->rx_csum = csum->v4_rx; -+ EXIT1(return); -+} -+ -+static void get_supported_oids(struct ndis_device *wnd) -+{ -+ NDIS_STATUS res; -+ int i, n, needed; -+ ndis_oid *oids; -+ -+ res = mp_query_info(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0, NULL, -+ &needed); -+ if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT || -+ res == NDIS_STATUS_INVALID_LENGTH)) -+ EXIT1(return); -+ oids = kmalloc(needed, GFP_KERNEL); -+ if (!oids) { -+ TRACE1("couldn't allocate memory"); -+ EXIT1(return); -+ } -+ res = mp_query(wnd, OID_GEN_SUPPORTED_LIST, oids, needed); -+ if (res) { -+ TRACE1("failed: %08X", res); -+ kfree(oids); -+ EXIT1(return); -+ } -+ for (i = 0, n = needed / sizeof(*oids); i < n; i++) { -+ TRACE1("oid: %08X", oids[i]); -+ /* if a wireless device didn't say so for -+ * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */ -+ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan && -+ oids[i] == OID_802_11_SSID) -+ wnd->physical_medium = NdisPhysicalMediumWirelessLan; -+ } -+ kfree(oids); -+ EXIT1(return); -+} -+ -+static void ndis_get_drvinfo(struct net_device *dev, -+ struct ethtool_drvinfo *info) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 2); -+ strcat(info->driver, "+"); -+ strncat(info->driver, wnd->wd->driver->name, -+ sizeof(info->driver) - strlen(DRIVER_NAME) - 1); -+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 2); -+ strcat(info->version, "+"); -+ strncat(info->version, wnd->wd->driver->version, -+ sizeof(info->version) - strlen(DRIVER_VERSION) - 1); -+ if (wrap_is_pci_bus(wnd->wd->dev_bus)) -+ strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev), -+ sizeof(info->bus_info) - 1); -+#ifdef ENABLE_USB -+ else -+ usb_make_path(wnd->wd->usb.udev, info->bus_info, -+ sizeof(info->bus_info) - 1); -+#endif -+ return; -+} -+ -+static u32 ndis_get_link(struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ return netif_carrier_ok(wnd->net_dev); -+} -+ -+static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ wol->supported = 0; -+ wol->wolopts = 0; -+ if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) -+ EXIT2(return); -+ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) -+ EXIT2(return); -+ /* we always suspend to D3 */ -+ if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3) -+ return; -+ wol->supported |= WAKE_MAGIC; -+ if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET) -+ wol->wolopts |= WAKE_MAGIC; -+ return; -+} -+ -+static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) -+ return -EOPNOTSUPP; -+ if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3) -+ EXIT2(return -EOPNOTSUPP); -+ TRACE2("0x%x", wol->wolopts); -+ if (wol->wolopts & WAKE_MAGIC) { -+ wnd->ndis_wolopts |= NDIS_PNP_WAKE_UP_MAGIC_PACKET; -+ if (wol->wolopts != WAKE_MAGIC) -+ WARNING("ignored wake-on-lan options: 0x%x", -+ wol->wolopts & ~WAKE_MAGIC); -+ } else if (!wol->wolopts) -+ wnd->ndis_wolopts = 0; -+ else -+ return -EOPNOTSUPP; -+ TRACE2("0x%x", wnd->ndis_wolopts); -+ return 0; -+} -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) -+static u32 ndis_get_tx_csum(struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ if (wnd->tx_csum.tcp_csum && wnd->tx_csum.udp_csum) -+ return 1; -+ else -+ return 0; -+} -+ -+static u32 ndis_get_rx_csum(struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ if (wnd->rx_csum.value) -+ return 1; -+ else -+ return 0; -+} -+ -+static int ndis_set_tx_csum(struct net_device *dev, u32 data) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ if (data && (wnd->tx_csum.value == 0)) -+ return -EOPNOTSUPP; -+ -+ if (wnd->tx_csum.ip_csum) -+ ethtool_op_set_tx_hw_csum(dev, data); -+ else -+ ethtool_op_set_tx_csum(dev, data); -+ return 0; -+} -+ -+static int ndis_set_rx_csum(struct net_device *dev, u32 data) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ -+ if (data && (wnd->tx_csum.value == 0)) -+ return -EOPNOTSUPP; -+ -+ /* TODO: enable/disable rx csum through NDIS */ -+ return 0; -+} -+ -+static u32 ndis_get_sg(struct net_device *dev) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ if (wnd->sg_dma_size) -+ return ethtool_op_get_sg(dev); -+ else -+ return 0; -+} -+ -+static int ndis_set_sg(struct net_device *dev, u32 data) -+{ -+ struct ndis_device *wnd = netdev_priv(dev); -+ if (wnd->sg_dma_size) -+ return ethtool_op_set_sg(dev, data); -+ else -+ return -EOPNOTSUPP; -+} -+#endif -+ -+static struct ethtool_ops ndis_ethtool_ops = { -+ .get_drvinfo = ndis_get_drvinfo, -+ .get_link = ndis_get_link, -+ .get_wol = ndis_get_wol, -+ .set_wol = ndis_set_wol, -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) -+ .get_tx_csum = ndis_get_tx_csum, -+ .get_rx_csum = ndis_get_rx_csum, -+ .set_tx_csum = ndis_set_tx_csum, -+ .set_rx_csum = ndis_set_rx_csum, -+ .get_sg = ndis_get_sg, -+ .set_sg = ndis_set_sg, -+#endif -+}; -+ -+static int notifier_event(struct notifier_block *notifier, unsigned long event, -+ void *ptr) -+{ -+ struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); -+ -+ ENTER2("0x%lx", event); -+ if (net_dev->ethtool_ops == &ndis_ethtool_ops -+ && event == NETDEV_CHANGENAME) { -+ struct ndis_device *wnd = netdev_priv(net_dev); -+ -+ /* called with rtnl lock held, so no need to lock */ -+ if (likely(wnd->procfs_iface)) { -+ printk(KERN_INFO "%s: interface renamed to '%s'\n", -+ DRIVER_NAME, net_dev->name); -+ wrap_procfs_remove_ndis_device(wnd); -+ wrap_procfs_add_ndis_device(wnd); -+ } -+ } -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block netdev_notifier = { -+ .notifier_call = notifier_event, -+}; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -+static const struct net_device_ops ndis_netdev_ops = { -+ .ndo_init = ndis_net_dev_init, -+ .ndo_uninit = ndis_net_dev_uninit, -+ .ndo_open = ndis_net_dev_open, -+ .ndo_stop = ndis_net_dev_close, -+ .ndo_start_xmit = tx_skbuff, -+ .ndo_change_mtu = ndis_change_mtu, -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) -+ .ndo_set_rx_mode = ndis_set_multicast_list, -+#else -+ .ndo_set_multicast_list = ndis_set_multicast_list, -+#endif -+ .ndo_set_mac_address = ndis_set_mac_address, -+ .ndo_get_stats = ndis_get_stats, -+#ifdef CONFIG_NET_POLL_CONTROLLER -+ .ndo_poll_controller = ndis_poll_controller, -+#endif -+}; -+#endif -+ -+static NDIS_STATUS ndis_start_device(struct ndis_device *wnd) -+{ -+ struct wrap_device *wd; -+ struct net_device *net_dev; -+ NDIS_STATUS status; -+ char *buf; -+ const int buf_len = 256; -+ mac_address mac; -+ struct transport_header_offset *tx_header_offset; -+ int n; -+ -+ ENTER2("%d", in_atomic()); -+ status = mp_init(wnd); -+ if (status == NDIS_STATUS_NOT_RECOGNIZED) -+ EXIT1(return NDIS_STATUS_SUCCESS); -+ if (status != NDIS_STATUS_SUCCESS) -+ EXIT1(return status); -+ wd = wnd->wd; -+ net_dev = wnd->net_dev; -+ -+ get_supported_oids(wnd); -+ memset(mac, 0, sizeof(mac)); -+ status = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac)); -+ if (memcmp(mac, "\x00\x00\x00\x00\x00\x00", sizeof(mac)) == 0) { -+ status = mp_query(wnd, OID_802_3_PERMANENT_ADDRESS, mac, -+ sizeof(mac)); -+ if (status != NDIS_STATUS_SUCCESS) { -+ ERROR("couldn't get mac address: %08X", status); -+ goto err_start; -+ } -+ } -+ TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); -+ memcpy(net_dev->dev_addr, mac, ETH_ALEN); -+ -+ strncpy(net_dev->name, if_name, IFNAMSIZ - 1); -+ net_dev->name[IFNAMSIZ - 1] = 0; -+ -+ wnd->packet_filter = NDIS_PACKET_TYPE_DIRECTED | -+ NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_MULTICAST; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) -+ net_dev->netdev_ops = &ndis_netdev_ops; -+#else -+ net_dev->init = ndis_net_dev_init; -+ net_dev->uninit = ndis_net_dev_uninit; -+ net_dev->open = ndis_net_dev_open; -+ net_dev->hard_start_xmit = tx_skbuff; -+ net_dev->stop = ndis_net_dev_close; -+ net_dev->get_stats = ndis_get_stats; -+ net_dev->change_mtu = ndis_change_mtu; -+ net_dev->set_multicast_list = ndis_set_multicast_list; -+ net_dev->set_mac_address = ndis_set_mac_address; -+#ifdef CONFIG_NET_POLL_CONTROLLER -+ net_dev->poll_controller = ndis_poll_controller; -+#endif -+#endif -+#ifdef CONFIG_WIRELESS_EXT -+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { -+ net_dev->wireless_handlers = &ndis_handler_def; -+ } -+#endif -+ net_dev->ethtool_ops = &ndis_ethtool_ops; -+ if (wnd->mp_interrupt) -+ net_dev->irq = wnd->mp_interrupt->irq; -+ net_dev->mem_start = wnd->mem_start; -+ net_dev->mem_end = wnd->mem_end; -+ status = mp_query_int(wnd, OID_802_3_MAXIMUM_LIST_SIZE, -+ &wnd->multicast_size); -+ if (status != NDIS_STATUS_SUCCESS || wnd->multicast_size < 0) -+ wnd->multicast_size = 0; -+ if (wnd->multicast_size > 0) -+ net_dev->flags |= IFF_MULTICAST; -+ else -+ net_dev->flags &= ~IFF_MULTICAST; -+ -+ buf = kmalloc(buf_len, GFP_KERNEL); -+ if (!buf) { -+ WARNING("couldn't allocate memory"); -+ goto err_start; -+ } -+ -+ set_task_offload(wnd, buf, buf_len); -+#ifdef NETIF_F_LLTX -+ net_dev->features |= NETIF_F_LLTX; -+#endif -+ -+ if (register_netdev(net_dev)) { -+ ERROR("cannot register net device %s", net_dev->name); -+ goto err_register; -+ } -+ memset(buf, 0, buf_len); -+ status = mp_query(wnd, OID_GEN_VENDOR_DESCRIPTION, buf, buf_len); -+ if (status != NDIS_STATUS_SUCCESS) { -+ WARNING("couldn't get vendor information: 0x%x", status); -+ buf[0] = 0; -+ } -+ wnd->drv_ndis_version = n = 0; -+ mp_query_int(wnd, OID_GEN_DRIVER_VERSION, &wnd->drv_ndis_version); -+ mp_query_int(wnd, OID_GEN_VENDOR_DRIVER_VERSION, &n); -+ -+ printk(KERN_INFO "%s: ethernet device " MACSTRSEP " using %sNDIS " -+ "driver: %s, version: 0x%x, NDIS version: 0x%x, vendor: '%s', " -+ "%s\n", net_dev->name, MAC2STR(net_dev->dev_addr), -+ deserialized_driver(wnd) ? "" : "serialized ", -+ wd->driver->name, n, wnd->drv_ndis_version, buf, -+ wd->conf_file_name); -+ -+ if (deserialized_driver(wnd)) { -+ /* deserialized drivers don't have a limit, but we -+ * keep max at TX_RING_SIZE */ -+ wnd->max_tx_packets = TX_RING_SIZE; -+ } else { -+ status = mp_query_int(wnd, OID_GEN_MAXIMUM_SEND_PACKETS, -+ &wnd->max_tx_packets); -+ if (status != NDIS_STATUS_SUCCESS) -+ wnd->max_tx_packets = 1; -+ if (wnd->max_tx_packets > TX_RING_SIZE) -+ wnd->max_tx_packets = TX_RING_SIZE; -+ } -+ TRACE2("maximum send packets: %d", wnd->max_tx_packets); -+ NdisAllocatePacketPoolEx(&status, &wnd->tx_packet_pool, -+ wnd->max_tx_packets, 0, -+ PROTOCOL_RESERVED_SIZE_IN_PACKET); -+ if (status != NDIS_STATUS_SUCCESS) { -+ ERROR("couldn't allocate packet pool"); -+ goto packet_pool_err; -+ } -+ NdisAllocateBufferPool(&status, &wnd->tx_buffer_pool, -+ wnd->max_tx_packets + 4); -+ if (status != NDIS_STATUS_SUCCESS) { -+ ERROR("couldn't allocate buffer pool"); -+ goto buffer_pool_err; -+ } -+ TRACE1("pool: %p", wnd->tx_buffer_pool); -+ -+ if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &n) == -+ NDIS_STATUS_SUCCESS && n > ETH_HLEN) -+ ndis_change_mtu(wnd->net_dev, n - ETH_HLEN); -+ -+ if (mp_query_int(wnd, OID_GEN_MAC_OPTIONS, &n) == NDIS_STATUS_SUCCESS) -+ TRACE2("mac options supported: 0x%x", n); -+ -+ tx_header_offset = (typeof(tx_header_offset))buf; -+ tx_header_offset->protocol_type = NDIS_PROTOCOL_ID_TCP_IP; -+ tx_header_offset->header_offset = sizeof(ETH_HLEN); -+ status = mp_set(wnd, OID_GEN_TRANSPORT_HEADER_OFFSET, -+ tx_header_offset, sizeof(*tx_header_offset)); -+ TRACE2("%08X", status); -+ -+ status = mp_query_int(wnd, OID_GEN_PHYSICAL_MEDIUM, -+ &wnd->physical_medium); -+ if (status != NDIS_STATUS_SUCCESS) -+ wnd->physical_medium = NdisPhysicalMediumUnspecified; -+ -+#ifdef CONFIG_WIRELESS_EXT -+ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { -+ mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF); -+ get_encryption_capa(wnd, buf, buf_len); -+ TRACE1("capabilities = %ld", wnd->capa.encr); -+ printk(KERN_INFO "%s: encryption modes supported: " -+ "%s%s%s%s%s%s%s\n", net_dev->name, -+ test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ? -+ "WEP" : "none", -+ -+ test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ? -+ "; TKIP with WPA" : "", -+ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? -+ ", WPA2" : "", -+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? -+ ", WPA2-PSK" : "", -+ -+ test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ? -+ "; AES/CCMP with WPA" : "", -+ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? -+ ", WPA2" : "", -+ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? -+ ", WPA2-PSK" : ""); -+ -+ set_default_iw_params(wnd); -+ } -+#endif -+ kfree(buf); -+ hangcheck_add(wnd); -+ add_iw_stats_timer(wnd); -+ EXIT1(return NDIS_STATUS_SUCCESS); -+ -+buffer_pool_err: -+ wnd->tx_buffer_pool = NULL; -+ if (wnd->tx_packet_pool) { -+ NdisFreePacketPool(wnd->tx_packet_pool); -+ wnd->tx_packet_pool = NULL; -+ } -+packet_pool_err: -+ unregister_netdev(net_dev); -+ wnd->max_tx_packets = 0; -+err_register: -+ kfree(buf); -+err_start: -+ mp_halt(wnd); -+ EXIT1(return NDIS_STATUS_FAILURE); -+} -+ -+static int ndis_remove_device(struct ndis_device *wnd) -+{ -+ s8 tx_pending; -+ int our_mutex; -+ -+ /* prevent setting essid during disassociation */ -+ memset(&wnd->essid, 0, sizeof(wnd->essid)); -+ wnd->tx_ok = 0; -+ netif_carrier_off(wnd->net_dev); -+ if (wnd->max_tx_packets) -+ unregister_netdev(wnd->net_dev); -+ /* if device is suspended, but resume failed, tx_ring_mutex -+ * may already be locked */ -+ our_mutex = mutex_trylock(&wnd->tx_ring_mutex); -+ if (!our_mutex) -+ WARNING("couldn't obtain tx_ring_mutex"); -+ spin_lock_bh(&wnd->tx_ring_lock); -+ tx_pending = wnd->tx_ring_end - wnd->tx_ring_start; -+ if (tx_pending < 0) -+ tx_pending += TX_RING_SIZE; -+ else if (tx_pending == 0 && wnd->is_tx_ring_full) -+ tx_pending = TX_RING_SIZE - 1; -+ wnd->is_tx_ring_full = 0; -+ /* throw away pending packets */ -+ while (tx_pending-- > 0) { -+ struct ndis_packet *packet; -+ -+ packet = wnd->tx_ring[wnd->tx_ring_start]; -+ free_tx_packet(wnd, packet, NDIS_STATUS_CLOSING); -+ wnd->tx_ring_start = (wnd->tx_ring_start + 1) % TX_RING_SIZE; -+ } -+ spin_unlock_bh(&wnd->tx_ring_lock); -+ if (our_mutex) -+ mutex_unlock(&wnd->tx_ring_mutex); -+ mp_halt(wnd); -+ ndis_exit_device(wnd); -+ -+ if (wnd->tx_packet_pool) { -+ NdisFreePacketPool(wnd->tx_packet_pool); -+ wnd->tx_packet_pool = NULL; -+ } -+ if (wnd->tx_buffer_pool) { -+ NdisFreeBufferPool(wnd->tx_buffer_pool); -+ wnd->tx_buffer_pool = NULL; -+ } -+ kfree(wnd->pmkids); -+ printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME, -+ wnd->net_dev->name); -+ kfree(wnd->nmb); -+ free_netdev(wnd->net_dev); -+ EXIT2(return 0); -+} -+ -+static NTSTATUS ndis_add_device(struct driver_object *drv_obj, -+ struct device_object *pdo) -+{ -+ struct device_object *fdo; -+ struct ndis_mp_block *nmb; -+ NTSTATUS status; -+ struct ndis_device *wnd; -+ struct net_device *net_dev; -+ struct wrap_device *wd; -+ unsigned long i; -+ -+ ENTER2("%p, %p", drv_obj, pdo); -+ if (strlen(if_name) >= IFNAMSIZ) { -+ ERROR("interface name '%s' is too long", if_name); -+ return STATUS_INVALID_PARAMETER; -+ } -+ net_dev = alloc_etherdev(sizeof(*wnd)); -+ if (!net_dev) { -+ ERROR("couldn't allocate device"); -+ return STATUS_RESOURCES; -+ } -+ wd = pdo->reserved; -+ if (wrap_is_pci_bus(wd->dev_bus)) -+ SET_NETDEV_DEV(net_dev, &wd->pci.pdev->dev); -+ if (wrap_is_usb_bus(wd->dev_bus)) -+ SET_NETDEV_DEV(net_dev, &wd->usb.intf->dev); -+ status = IoCreateDevice(drv_obj, 0, NULL, FILE_DEVICE_UNKNOWN, 0, -+ FALSE, &fdo); -+ if (status != STATUS_SUCCESS) { -+ free_netdev(net_dev); -+ EXIT2(return status); -+ } -+ wnd = netdev_priv(net_dev); -+ TRACE1("wnd: %p", wnd); -+ -+ nmb = kmalloc(sizeof(*nmb), GFP_KERNEL); -+ if (!nmb) { -+ WARNING("couldn't allocate memory"); -+ IoDeleteDevice(fdo); -+ free_netdev(net_dev); -+ return STATUS_RESOURCES; -+ } -+#if DEBUG >= 6 -+ /* poison nmb so if a driver accesses uninitialized pointers, we -+ * know what it is */ -+ for (i = 0; i < sizeof(*nmb) / sizeof(unsigned long); i++) -+ ((unsigned long *)nmb)[i] = i + 0x8a3fc1; -+#endif -+ -+ wnd->nmb = nmb; -+ nmb->wnd = wnd; -+ nmb->pdo = pdo; -+ wnd->wd = wd; -+ wnd->net_dev = net_dev; -+ fdo->reserved = wnd; -+ nmb->fdo = fdo; -+ if (ndis_init_device(wnd)) { -+ IoDeleteDevice(fdo); -+ kfree(nmb); -+ free_netdev(net_dev); -+ EXIT1(return STATUS_RESOURCES); -+ } -+ nmb->next_device = IoAttachDeviceToDeviceStack(fdo, pdo); -+ spin_lock_init(&wnd->tx_ring_lock); -+ mutex_init(&wnd->tx_ring_mutex); -+ mutex_init(&wnd->ndis_req_mutex); -+ wnd->ndis_req_done = 0; -+ INIT_WORK(&wnd->tx_work, tx_worker); -+ wnd->tx_ring_start = 0; -+ wnd->tx_ring_end = 0; -+ wnd->is_tx_ring_full = 0; -+ wnd->capa.encr = 0; -+ wnd->capa.auth = 0; -+ wnd->attributes = 0; -+ wnd->dma_map_count = 0; -+ wnd->dma_map_addr = NULL; -+ wnd->nick[0] = 0; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) -+ timer_setup(&wnd->hangcheck_timer, hangcheck_proc, 0); -+ timer_setup(&wnd->iw_stats_timer, hangcheck_proc, 0); -+#else -+ init_timer(&wnd->hangcheck_timer); -+ init_timer(&wnd->iw_stats_timer); -+#endif -+ wnd->scan_timestamp = 0; -+ wnd->iw_stats_interval = 10 * HZ; -+ wnd->ndis_pending_work = 0; -+ memset(&wnd->essid, 0, sizeof(wnd->essid)); -+ memset(&wnd->encr_info, 0, sizeof(wnd->encr_info)); -+ wnd->infrastructure_mode = Ndis802_11Infrastructure; -+ INIT_WORK(&wnd->ndis_work, wrapndis_worker); -+ wnd->iw_stats_enabled = TRUE; -+ -+ TRACE1("nmb: %p, pdo: %p, fdo: %p, attached: %p, next: %p", -+ nmb, pdo, fdo, fdo->attached, nmb->next_device); -+ -+ /* dispatch routines are called as Windows functions */ -+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) -+ drv_obj->major_func[i] = WIN_FUNC_PTR(IoPassIrpDown,2); -+ -+ drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(NdisDispatchPnp,2); -+ drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(NdisDispatchPower,2); -+ drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] = -+ WIN_FUNC_PTR(NdisDispatchDeviceControl,2); -+// drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = -+// WIN_FUNC_PTR(NdisDispatchDeviceControl,2); -+ EXIT2(return STATUS_SUCCESS); -+} -+ -+int init_ndis_driver(struct driver_object *drv_obj) -+{ -+ ENTER1("%p", drv_obj); -+ drv_obj->drv_ext->add_device = ndis_add_device; -+ return 0; -+} -+ -+int wrapndis_init(void) -+{ -+ wrapndis_wq = create_singlethread_workqueue("wrapndis_wq"); -+ if (!wrapndis_wq) -+ EXIT1(return -ENOMEM); -+ TRACE1("wrapndis_wq: %p", wrapndis_wq); -+ register_netdevice_notifier(&netdev_notifier); -+ return 0; -+} -+ -+void wrapndis_exit(void) -+{ -+ unregister_netdevice_notifier(&netdev_notifier); -+ if (wrapndis_wq) -+ destroy_workqueue(wrapndis_wq); -+} -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/wrapndis.h linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapndis.h ---- linux-5.6.11/3rdparty/ndiswrapper/wrapndis.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapndis.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,86 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef _WRAPNDIS_H_ -+#define _WRAPNDIS_H_ -+ -+#include "ndis.h" -+#include "pnp.h" -+ -+int wrapndis_init(void); -+void wrapndis_exit(void); -+ -+NDIS_STATUS mp_reset(struct ndis_device *wnd); -+ -+NDIS_STATUS mp_request(enum ndis_request_type request, -+ struct ndis_device *wnd, ndis_oid oid, -+ void *buf, ULONG buflen, ULONG *written, ULONG *needed); -+ -+static inline NDIS_STATUS mp_query_info(struct ndis_device *wnd, -+ ndis_oid oid, void *buf, ULONG buflen, -+ ULONG *written, ULONG *needed) -+{ -+ return mp_request(NdisRequestQueryInformation, wnd, oid, -+ buf, buflen, written, needed); -+} -+ -+static inline NDIS_STATUS mp_set_info(struct ndis_device *wnd, -+ ndis_oid oid, void *buf, ULONG buflen, -+ ULONG *written, ULONG *needed) -+{ -+ return mp_request(NdisRequestSetInformation, wnd, oid, -+ buf, buflen, written, needed); -+} -+ -+static inline NDIS_STATUS mp_query(struct ndis_device *wnd, ndis_oid oid, -+ void *buf, ULONG buflen) -+{ -+ return mp_request(NdisRequestQueryInformation, wnd, oid, -+ buf, buflen, NULL, NULL); -+} -+ -+static inline NDIS_STATUS mp_query_int(struct ndis_device *wnd, -+ ndis_oid oid, ULONG *data) -+{ -+ return mp_request(NdisRequestQueryInformation, wnd, oid, -+ data, sizeof(ULONG), NULL, NULL); -+} -+ -+static inline NDIS_STATUS mp_set(struct ndis_device *wnd, ndis_oid oid, -+ void *buf, ULONG buflen) -+{ -+ return mp_request(NdisRequestSetInformation, wnd, oid, -+ buf, buflen, NULL, NULL); -+} -+ -+static inline NDIS_STATUS mp_set_int(struct ndis_device *wnd, -+ ndis_oid oid, ULONG data) -+{ -+ return mp_request(NdisRequestSetInformation, wnd, oid, -+ &data, sizeof(ULONG), NULL, NULL); -+} -+ -+void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet, -+ NDIS_STATUS status); -+int init_ndis_driver(struct driver_object *drv_obj); -+NDIS_STATUS ndis_reinit(struct ndis_device *wnd); -+void set_media_state(struct ndis_device *wnd, enum ndis_media_state state); -+ -+void hangcheck_add(struct ndis_device *wnd); -+void hangcheck_del(struct ndis_device *wnd); -+ -+struct iw_statistics *get_iw_stats(struct net_device *dev); -+ -+#endif -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/wrapper.c linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapper.c ---- linux-5.6.11/3rdparty/ndiswrapper/wrapper.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapper.c 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,111 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#include "ndis.h" -+#include "iw_ndis.h" -+#include "loader.h" -+#include "pnp.h" -+#include "wrapper.h" -+ -+char *if_name = "wlan%d"; -+int proc_uid, proc_gid; -+int hangcheck_interval; -+static char *utils_version = UTILS_VERSION; -+int debug = DEBUG; -+ -+module_param(if_name, charp, 0400); -+MODULE_PARM_DESC(if_name, "Network interface name or template " -+ "(default: wlan%d)"); -+module_param(proc_uid, int, 0600); -+MODULE_PARM_DESC(proc_uid, "The uid of the files created in /proc " -+ "(default: 0)."); -+module_param(proc_gid, int, 0600); -+MODULE_PARM_DESC(proc_gid, "The gid of the files created in /proc " -+ "(default: 0)."); -+module_param(debug, int, 0600); -+MODULE_PARM_DESC(debug, "debug level"); -+ -+/* 0 - default value provided by NDIS driver, -+ * positive value - force hangcheck interval to that many seconds -+ * negative value - disable hangcheck -+ */ -+module_param(hangcheck_interval, int, 0600); -+MODULE_PARM_DESC(hangcheck_interval, "The interval, in seconds, for checking" -+ " if driver is hung. (default: 0)"); -+ -+module_param(utils_version, charp, 0400); -+MODULE_PARM_DESC(utils_version, "Compatible version of utils " -+ "(read only: " UTILS_VERSION ")"); -+ -+MODULE_AUTHOR("ndiswrapper team "); -+#ifdef MODULE_DESCRIPTION -+MODULE_DESCRIPTION("NDIS wrapper driver"); -+#endif -+#ifdef MODULE_VERSION -+MODULE_VERSION(DRIVER_VERSION); -+#endif -+MODULE_LICENSE("GPL"); -+ -+static void module_cleanup(void) -+{ -+ loader_exit(); -+ usb_exit(); -+ wrap_procfs_remove(); -+ wrapndis_exit(); -+ ndis_exit(); -+ ntoskernel_exit(); -+ wrapmem_exit(); -+} -+ -+static int __init wrapper_init(void) -+{ -+#ifdef TAINT_OOT_MODULE -+ add_taint(TAINT_OOT_MODULE, LOCKDEP_NOW_UNRELIABLE); -+#endif -+ printk(KERN_INFO "%s version %s loaded (smp=%s, preempt=%s)\n", -+ DRIVER_NAME, DRIVER_VERSION, -+#ifdef CONFIG_SMP -+ "yes" -+#else -+ "no" -+#endif -+ , -+#ifdef CONFIG_PREEMPT_RT -+ "rt" -+#elif defined(CONFIG_PREEMPT) -+ "yes" -+#else -+ "no" -+#endif -+ ); -+ -+ if (wrapmem_init() || ntoskernel_init() || ndis_init() || -+ wrapndis_init() || usb_init() || wrap_procfs_init() || -+ loader_init()) { -+ module_cleanup(); -+ ERROR("%s: initialization failed", DRIVER_NAME); -+ return -EINVAL; -+ } -+ EXIT1(return 0); -+} -+ -+static void __exit wrapper_exit(void) -+{ -+ ENTER1(""); -+ module_cleanup(); -+} -+ -+module_init(wrapper_init); -+module_exit(wrapper_exit); -diff -Nurp linux-5.6.11/3rdparty/ndiswrapper/wrapper.h linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapper.h ---- linux-5.6.11/3rdparty/ndiswrapper/wrapper.h 1970-01-01 02:00:00.000000000 +0200 -+++ linux-5.6.11-ndis/3rdparty/ndiswrapper/wrapper.h 2020-05-03 15:18:33.000000000 +0300 -@@ -0,0 +1,24 @@ -+/* -+ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani -+ * -+ * 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. -+ * -+ */ -+ -+#ifndef WRAPPER_H -+#define WRAPPER_H -+ -+extern char *if_name; -+extern int proc_uid; -+extern int proc_gid; -+extern int hangcheck_interval; -+ -+#endif /* WRAPPER_H */ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Kconfig.patch b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Kconfig.patch deleted file mode 100644 index f7d26e620b..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Kconfig.patch +++ /dev/null @@ -1,7 +0,0 @@ ---- linux-2.6.24.orig/3rdparty/ndiswrapper/Kconfig 1969-12-31 21:00:00.000000000 -0300 -+++ linux-2.6.24/3rdparty/ndiswrapper/Kconfig 2007-11-26 15:11:31.000000000 -0200 -@@ -0,0 +1,4 @@ -+ -+config NDISWRAPPER -+ tristate "NDIS driver wrapper support" -+ depends on PCI && USB && !X86_64_XEN diff --git a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Makefile-build-fix.patch b/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Makefile-build-fix.patch deleted file mode 100644 index b44f4b2938..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-ndiswrapper-Makefile-build-fix.patch +++ /dev/null @@ -1,45 +0,0 @@ ---- linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/Makefile.orig 2013-11-28 21:42:10.000000000 +0200 -+++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/Makefile 2013-11-30 21:41:19.550504380 +0200 -@@ -9,24 +9,10 @@ DISTFILES = \ - winnt_types.h workqueue.c wrapmem.c wrapmem.h wrapndis.c wrapndis.h \ - wrapper.c wrapper.h - --# By default, we try to compile the modules for the currently running --# kernel. But it's the first approximation, as we will re-read the --# version from the kernel sources. --KVERS_UNAME ?= $(shell uname -r) -- - # KBUILD is the path to the Linux kernel build tree. It is usually the - # same as the kernel source tree, except when the kernel was compiled in - # a separate directory. --KBUILD ?= $(shell readlink -f /lib/modules/$(KVERS_UNAME)/build) -- --ifeq (,$(KBUILD)) --$(error Kernel build tree not found - please set KBUILD to configured kernel) --endif -- --KCONFIG := $(KBUILD)/.config --ifeq (,$(wildcard $(KCONFIG))) --$(error No .config found in $(KBUILD), please set KBUILD to configured kernel) --endif -+KBUILD ?= $(srctree) - - ifneq (,$(wildcard $(KBUILD)/include/linux/version.h)) - ifneq (,$(wildcard $(KBUILD)/include/generated/uapi/linux/version.h)) -@@ -43,16 +29,9 @@ endif - ifeq (,$(wildcard $(VERSION_H))) - VERSION_H := $(KBUILD)/include/linux/version.h - endif --ifeq (,$(wildcard $(VERSION_H))) --$(error Please run 'make modules_prepare' in $(KBUILD)) --endif - - KVERS := $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' $(VERSION_H)) - --ifeq (,$(KVERS)) --$(error Cannot find UTS_RELEASE in $(VERSION_H), please report) --endif -- - INST_DIR = /lib/modules/$(KVERS)/misc - - SRC_DIR=$(shell pwd) diff --git a/kernel/tools/perf/files/patches/mageia/3rd-niswrapper-Kconfig-Makefile.patch b/kernel/tools/perf/files/patches/mageia/3rd-niswrapper-Kconfig-Makefile.patch deleted file mode 100644 index a8c40d16f9..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-niswrapper-Kconfig-Makefile.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- linux/3rdparty/Kconfig.orig 2019-05-31 23:02:53.380127780 +0300 -+++ linux/3rdparty/Kconfig 2019-05-31 23:26:48.844304457 +0300 -@@ -2,4 +2,6 @@ - - menu "External 3rdparty kernel additions" - -+source "3rdparty/ndiswrapper/Kconfig" -+ - endmenu ---- linux/3rdparty/Makefile.orig 2019-05-31 23:03:58.338529850 +0300 -+++ linux/3rdparty/Makefile 2019-05-31 23:27:35.405319287 +0300 -@@ -1,3 +1,4 @@ - # - - obj- := 3rdparty.o # Dummy rule to force built-in.o to be made -+obj-$(CONFIG_NDISWRAPPER) += ndiswrapper/ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8223de-kernel-5.6.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8223de-kernel-5.6.patch deleted file mode 100644 index e79e34d64d..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8223de-kernel-5.6.patch +++ /dev/null @@ -1,244 +0,0 @@ -diff -urp linux-5.6.3/3rdparty/rtl8723de.orig/os_dep/linux/rtw_proc.c linux-5.6.3/3rdparty/rtl8723de/os_dep/linux/rtw_proc.c ---- linux-5.6.3/3rdparty/rtl8723de.orig/os_dep/linux/rtw_proc.c 2020-04-10 17:12:12.495541693 +0300 -+++ linux-5.6.3/3rdparty/rtl8723de/os_dep/linux/rtw_proc.c 2020-04-10 17:22:51.328340275 +0300 -@@ -68,12 +68,19 @@ inline struct proc_dir_entry *rtw_proc_c - return entry; - } - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) -+inline struct proc_dir_entry *rtw_proc_create_entry(const char *name, struct proc_dir_entry *parent, -+ const struct proc_ops *pops, void * data) -+#else - inline struct proc_dir_entry *rtw_proc_create_entry(const char *name, struct proc_dir_entry *parent, - const struct file_operations *fops, void * data) -+#endif - { - struct proc_dir_entry *entry; - --#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)) -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) -+ entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUGO, parent, pops, data); -+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)) - entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUGO, parent, fops, data); - #else - entry = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUGO, parent); -@@ -219,7 +226,24 @@ static ssize_t rtw_drv_proc_write(struct - return -EROFS; - } - --static const struct file_operations rtw_drv_proc_seq_fops = { -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) -+static const struct proc_ops rtw_drv_proc_seq_ops = { -+ .proc_open = rtw_drv_proc_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = seq_release, -+ .proc_write = rtw_drv_proc_write, -+}; -+ -+static const struct proc_ops rtw_drv_proc_sseq_ops = { -+ .proc_open = rtw_drv_proc_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = single_release, -+ .proc_write = rtw_drv_proc_write, -+}; -+#else -+static const struct file_operations rtw_drv_proc_seq_ops = { - .owner = THIS_MODULE, - .open = rtw_drv_proc_open, - .read = seq_read, -@@ -228,7 +252,7 @@ static const struct file_operations rtw_ - .write = rtw_drv_proc_write, - }; - --static const struct file_operations rtw_drv_proc_sseq_fops = { -+static const struct file_operations rtw_drv_proc_sseq_ops = { - .owner = THIS_MODULE, - .open = rtw_drv_proc_open, - .read = seq_read, -@@ -236,6 +260,7 @@ static const struct file_operations rtw_ - .release = single_release, - .write = rtw_drv_proc_write, - }; -+#endif - - int rtw_drv_proc_init(void) - { -@@ -257,9 +282,9 @@ int rtw_drv_proc_init(void) - - for (i = 0; i < drv_proc_hdls_num; i++) { - if (drv_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SEQ) -- entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_seq_fops, (void *)i); -+ entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_seq_ops, (void *)i); - else if (drv_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SSEQ) -- entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_sseq_fops, (void *)i); -+ entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_sseq_ops, (void *)i); - else - entry = NULL; - -@@ -2335,7 +2360,24 @@ static ssize_t rtw_adapter_proc_write(st - return -EROFS; - } - --static const struct file_operations rtw_adapter_proc_seq_fops = { -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) -+static const struct proc_ops rtw_adapter_proc_seq_ops = { -+ .proc_open = rtw_adapter_proc_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = seq_release, -+ .proc_write = rtw_adapter_proc_write, -+}; -+ -+static const struct proc_ops rtw_adapter_proc_sseq_ops = { -+ .proc_open = rtw_adapter_proc_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = single_release, -+ .proc_write = rtw_adapter_proc_write, -+}; -+#else -+static const struct file_operations rtw_adapter_proc_seq_ops = { - .owner = THIS_MODULE, - .open = rtw_adapter_proc_open, - .read = seq_read, -@@ -2344,7 +2386,7 @@ static const struct file_operations rtw_ - .write = rtw_adapter_proc_write, - }; - --static const struct file_operations rtw_adapter_proc_sseq_fops = { -+static const struct file_operations rtw_adapter_proc_sseq_ops = { - .owner = THIS_MODULE, - .open = rtw_adapter_proc_open, - .read = seq_read, -@@ -2352,6 +2394,7 @@ static const struct file_operations rtw_ - .release = single_release, - .write = rtw_adapter_proc_write, - }; -+#endif - - int proc_get_odm_dbg_comp(struct seq_file *m, void *v) - { -@@ -2670,7 +2713,24 @@ static ssize_t rtw_odm_proc_write(struct - return -EROFS; - } - --static const struct file_operations rtw_odm_proc_seq_fops = { -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) -+static const struct proc_ops rtw_odm_proc_seq_ops = { -+ .proc_open = rtw_odm_proc_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = seq_release, -+ .proc_write = rtw_odm_proc_write, -+}; -+ -+static const struct proc_ops rtw_odm_proc_sseq_ops = { -+ .proc_open = rtw_odm_proc_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = single_release, -+ .proc_write = rtw_odm_proc_write, -+}; -+#else -+static const struct file_operations rtw_odm_proc_seq_ops = { - .owner = THIS_MODULE, - .open = rtw_odm_proc_open, - .read = seq_read, -@@ -2679,7 +2739,7 @@ static const struct file_operations rtw_ - .write = rtw_odm_proc_write, - }; - --static const struct file_operations rtw_odm_proc_sseq_fops = { -+static const struct file_operations rtw_odm_proc_sseq_ops = { - .owner = THIS_MODULE, - .open = rtw_odm_proc_open, - .read = seq_read, -@@ -2687,6 +2747,7 @@ static const struct file_operations rtw_ - .release = single_release, - .write = rtw_odm_proc_write, - }; -+#endif - - struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev) - { -@@ -2715,9 +2776,9 @@ struct proc_dir_entry *rtw_odm_proc_init - - for (i = 0; i < odm_proc_hdls_num; i++) { - if (odm_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SEQ) -- entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_seq_fops, (void *)i); -+ entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_seq_ops, (void *)i); - else if (odm_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SSEQ) -- entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_sseq_fops, (void *)i); -+ entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_sseq_ops, (void *)i); - else - entry = NULL; - -@@ -2809,7 +2870,24 @@ static ssize_t rtw_mcc_proc_write(struct - return -EROFS; - } - --static const struct file_operations rtw_mcc_proc_seq_fops = { -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) -+static const struct proc_ops rtw_mcc_proc_seq_ops = { -+ .proc_open = rtw_mcc_proc_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = seq_release, -+ .proc_write = rtw_mcc_proc_write, -+}; -+ -+static const struct file_operations rtw_mcc_proc_sseq_ops = { -+ .proc_open = rtw_mcc_proc_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = single_release, -+ .proc_write = rtw_mcc_proc_write, -+}; -+#else -+static const struct file_operations rtw_mcc_proc_seq_ops = { - .owner = THIS_MODULE, - .open = rtw_mcc_proc_open, - .read = seq_read, -@@ -2818,7 +2896,7 @@ static const struct file_operations rtw_ - .write = rtw_mcc_proc_write, - }; - --static const struct file_operations rtw_mcc_proc_sseq_fops = { -+static const struct file_operations rtw_mcc_proc_sseq_ops = { - .owner = THIS_MODULE, - .open = rtw_mcc_proc_open, - .read = seq_read, -@@ -2826,6 +2904,7 @@ static const struct file_operations rtw_ - .release = single_release, - .write = rtw_mcc_proc_write, - }; -+#endif - - struct proc_dir_entry *rtw_mcc_proc_init(struct net_device *dev) - { -@@ -2854,9 +2933,9 @@ struct proc_dir_entry *rtw_mcc_proc_init - - for (i = 0; i < mcc_proc_hdls_num; i++) { - if (mcc_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SEQ) -- entry = rtw_proc_create_entry(mcc_proc_hdls[i].name, dir_mcc, &rtw_mcc_proc_seq_fops, (void *)i); -+ entry = rtw_proc_create_entry(mcc_proc_hdls[i].name, dir_mcc, &rtw_mcc_proc_seq_ops, (void *)i); - else if (mcc_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SSEQ) -- entry = rtw_proc_create_entry(mcc_proc_hdls[i].name, dir_mcc, &rtw_mcc_proc_sseq_fops, (void *)i); -+ entry = rtw_proc_create_entry(mcc_proc_hdls[i].name, dir_mcc, &rtw_mcc_proc_sseq_ops, (void *)i); - else - entry = NULL; - -@@ -2920,9 +2999,9 @@ struct proc_dir_entry *rtw_adapter_proc_ - - for (i = 0; i < adapter_proc_hdls_num; i++) { - if (adapter_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SEQ) -- entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_seq_fops, (void *)i); -+ entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_seq_ops, (void *)i); - else if (adapter_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SSEQ) -- entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_sseq_fops, (void *)i); -+ entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_sseq_ops, (void *)i); - else - entry = NULL; - diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-Kconfig-Makefile.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-Kconfig-Makefile.patch deleted file mode 100644 index 8aa95703b1..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-Kconfig-Makefile.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- linux/3rdparty/Kconfig.orig 2019-05-31 23:30:41.568375751 +0300 -+++ linux/3rdparty/Kconfig 2019-05-31 23:33:39.796256889 +0300 -@@ -4,5 +4,6 @@ menu "External 3rdparty kernel additions" - - source "3rdparty/ndiswrapper/Kconfig" - source "3rdparty/rtl8812au/Kconfig" -+source "3rdparty/rtl8723de/Kconfig" - - endmenu ---- linux/3rdparty/Makefile.orig 2019-05-31 23:33:17.610773901 +0300 -+++ linux/3rdparty/Makefile 2019-05-31 23:33:57.608644657 +0300 -@@ -3,3 +3,4 @@ - obj- := 3rdparty.o # Dummy rule to force built-in.o to be made - obj-$(CONFIG_NDISWRAPPER) += ndiswrapper/ - obj-$(CONFIG_RTL8812AU) += rtl8812au/ -+obj-$(CONFIG_RTL8723DE) += rtl8723de/ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-add-kernel-5.8-support.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-add-kernel-5.8-support.patch deleted file mode 100644 index 6786d4bd49..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-add-kernel-5.8-support.patch +++ /dev/null @@ -1,79 +0,0 @@ ---- linux-5.8/3rdparty/rtl8723de/core/rtw_security.c -+++ linux-5.8/3rdparty/rtl8723de/core/rtw_security.c -@@ -33,6 +33,14 @@ static const char *_security_type_str[] = { - "BIP", - }; - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+struct sha256_state { -+ u64 length; -+ u32 state[8], curlen; -+ u8 buf[64]; -+}; -+#endif -+ - const char *security_type_str(u8 value) - { - #ifdef CONFIG_IEEE80211W ---- linux-5.8/3rdparty/rtl8723de/include/rtw_security.h -+++ linux-5.8/3rdparty/rtl8723de/include/rtw_security.h -@@ -246,11 +246,13 @@ struct security_priv { - #endif /* DBG_SW_SEC_CNT */ - }; - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)) - struct sha256_state { - u64 length; - u32 state[8], curlen; - u8 buf[64]; - }; -+#endif - - #define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)\ - do {\ ---- linux-5.8/3rdparty/rtl8723de/os_dep/linux/ioctl_cfg80211.c -+++ linux-5.8/3rdparty/rtl8723de/os_dep/linux/ioctl_cfg80211.c -@@ -5857,10 +5857,18 @@ static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, - #else - struct net_device *ndev, - #endif -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+ struct mgmt_frame_regs *upd) -+#else - u16 frame_type, bool reg) -+#endif - { - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - struct net_device *ndev = wdev_to_ndev(wdev); -+#endif -+/* hardcoded always true, to make it pass compilation */ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+ bool reg = true; - #endif - _adapter *adapter; - -@@ -5880,7 +5888,11 @@ static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy, - /* Wait QC Verify */ - return; - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+ switch (upd->interface_stypes) { -+#else - switch (frame_type) { -+#endif - case IEEE80211_STYPE_PROBE_REQ: /* 0x0040 */ - SET_CFG80211_REPORT_MGMT(pwdev_priv, IEEE80211_STYPE_PROBE_REQ, reg); - break; -@@ -6846,7 +6858,11 @@ static struct cfg80211_ops rtw_cfg80211_ops = { - - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) - .mgmt_tx = cfg80211_rtw_mgmt_tx, -- .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+ .update_mgmt_frame_registrations = cfg80211_rtw_mgmt_frame_register, -+#else -+ .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, -+#endif - #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) - .action = cfg80211_rtw_mgmt_tx, - #endif diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-fix-redefine.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-fix-redefine.patch deleted file mode 100644 index 5b80ce8bd4..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-fix-redefine.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- linux/3rdparty/rtl8723de/include/wifi.h.orig 2019-01-19 16:29:26.302342688 +0200 -+++ linux/3rdparty/rtl8723de/include/wifi.h 2019-01-19 16:32:25.543905828 +0200 -@@ -1003,8 +1003,9 @@ typedef enum _HT_CAP_AMPDU_DENSITY { - * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) - */ - #define IEEE80211_MIN_AMPDU_BUF 0x8 -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) - #define IEEE80211_MAX_AMPDU_BUF 0x40 -- -+#endif - - /* Spatial Multiplexing Power Save Modes */ - #define WLAN_HT_CAP_SM_PS_STATIC 0 diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-nodebug.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-nodebug.patch deleted file mode 100644 index 2f543ee4bc..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8723de-nodebug.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- ./3rdparty/rtl8723de/Makefile.orig 2019-10-08 13:51:56.729205790 +0300 -+++ ./3rdparty/rtl8723de/Makefile 2019-10-08 14:03:32.894164296 +0300 -@@ -74,7 +74,7 @@ CONFIG_APPEND_VENDOR_IE_ENABLE = n - CONFIG_RTW_NAPI = y - CONFIG_RTW_GRO = y - ########################## Debug ########################### --CONFIG_RTW_DEBUG = y -+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 = 4 diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-Kconfig-Makefile.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-Kconfig-Makefile.patch deleted file mode 100644 index 697c6958ca..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-Kconfig-Makefile.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- linux/3rdparty/Kconfig.orig 2019-05-31 23:26:48.844304457 +0300 -+++ linux/3rdparty/Kconfig 2019-05-31 23:30:41.568375751 +0300 -@@ -3,5 +3,6 @@ - menu "External 3rdparty kernel additions" - - source "3rdparty/ndiswrapper/Kconfig" -+source "3rdparty/rtl8812au/Kconfig" - - endmenu ---- linux/3rdparty/Makefile.orig 2019-05-31 23:27:35.405319287 +0300 -+++ linux/3rdparty/Makefile 2019-05-31 23:30:56.855708733 +0300 -@@ -2,3 +2,4 @@ - - obj- := 3rdparty.o # Dummy rule to force built-in.o to be made - obj-$(CONFIG_NDISWRAPPER) += ndiswrapper/ -+obj-$(CONFIG_RTL8812AU) += rtl8812au/ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.10.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.10.patch deleted file mode 100644 index da51233889..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.10.patch +++ /dev/null @@ -1,281 +0,0 @@ -From ee9619ba0c8840db6d59d11989c31e24a8f0d806 Mon Sep 17 00:00:00 2001 -From: Carlos -Date: Sun, 8 Nov 2020 12:25:43 +0000 -Subject: [PATCH] Fix kernel 5.10-rc1 - ---- - 3rdparty/rtl8812au/core/rtw_btcoex.c | 7 ++++++- - 3rdparty/rtl8812au/core/rtw_wlan_util.c | 10 ++++++---- - 3rdparty/rtl8812au/os_dep/linux/os_intfs.c | 19 +++++++++++++----- - 3rdparty/rtl8812au/os_dep/osdep_service.c | 43 +++++++++++++++++++++++++++-------------- - 4 files changed, 54 insertions(+), 25 deletions(-) - -diff --git a/3rdparty/rtl8812au/core/rtw_btcoex.c b/3rdparty/rtl8812au/core/rtw_btcoex.c -index d5b89bdc..f5e0f567 100644 ---- a/3rdparty/rtl8812au/core/rtw_btcoex.c -+++ b/3rdparty/rtl8812au/core/rtw_btcoex.c -@@ -1443,7 +1443,9 @@ u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool for - { - 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; - -@@ -1473,15 +1475,18 @@ u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool for - 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; -diff --git a/3rdparty/rtl8812au/core/rtw_wlan_util.c b/3rdparty/rtl8812au/core/rtw_wlan_util.c -index b4cecd11..e465e9b5 100644 ---- a/3rdparty/rtl8812au/core/rtw_wlan_util.c -+++ b/3rdparty/rtl8812au/core/rtw_wlan_util.c -@@ -4744,7 +4744,9 @@ int rtw_dev_nlo_info_set(struct pno_nlo_info *nlo_info, pno_ssid_t *ssid, - - int i = 0; - struct file *fp; -+#ifdef set_fs - mm_segment_t fs; -+#endif - loff_t pos = 0; - u8 *source = NULL; - long len = 0; -@@ -4780,10 +4782,10 @@ int rtw_dev_nlo_info_set(struct pno_nlo_info *nlo_info, pno_ssid_t *ssid, - 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) { -@@ -4791,10 +4793,10 @@ int rtw_dev_nlo_info_set(struct pno_nlo_info *nlo_info, pno_ssid_t *ssid, - rtw_parse_cipher_list(nlo_info, source); - rtw_mfree(source, 2048); - } -- -+#ifdef set_fs - set_fs(fs); - filp_close(fp, NULL); -- -+#endif - RTW_INFO("-%s-\n", __func__); - return 0; - } -diff --git a/3rdparty/rtl8812au/os_dep/linux/os_intfs.c b/3rdparty/rtl8812au/os_dep/linux/os_intfs.c -index 1085d6cd..a37e488b 100644 ---- a/3rdparty/rtl8812au/os_dep/linux/os_intfs.c -+++ b/3rdparty/rtl8812au/os_dep/linux/os_intfs.c -@@ -4029,7 +4029,9 @@ static int route_dump(u32 *gw_addr , int *gw_index) - struct msghdr msg; - struct iovec iov; - struct sockaddr_nl nladdr; -+#ifdef set_fs - mm_segment_t oldfs; -+#endif - char *pg; - int size = 0; - -@@ -4067,16 +4069,18 @@ static int route_dump(u32 *gw_addr , int *gw_index) - 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; - -@@ -4099,16 +4103,18 @@ static int route_dump(u32 *gw_addr , int *gw_index) - #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; - -@@ -4178,15 +4184,18 @@ static int route_dump(u32 *gw_addr , int *gw_index) - 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; - } -diff --git a/3rdparty/rtl8812au/os_dep/osdep_service.c b/3rdparty/rtl8812au/os_dep/osdep_service.c -index 7c6d1208..0769b49d 100644 ---- a/3rdparty/rtl8812au/os_dep/osdep_service.c -+++ b/3rdparty/rtl8812au/os_dep/osdep_service.c -@@ -2164,11 +2164,21 @@ static int writeFile(struct file *fp, char *buf, int len) - { - 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) -@@ -2191,19 +2201,19 @@ static int isFileReadable(const char *path, u32 *sz) - { - 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); -@@ -2215,8 +2225,9 @@ static int isFileReadable(const char *path, u32 *sz) - *sz = i_size_read(fp->f_dentry->d_inode); - #endif - } -- -+#ifdef set_fs - set_fs(oldfs); -+#endif - filp_close(fp, NULL); - } - return ret; -@@ -2232,22 +2243,23 @@ static int isFileReadable(const char *path, u32 *sz) - 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); -@@ -2271,22 +2283,23 @@ static int retriveFromFile(const char *path, u8 *buf, u32 sz) - 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); 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 deleted file mode 100644 index c53561cf98..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.12.patch +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 86a002fe3b..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-kernel-5.15.patch +++ /dev/null @@ -1,66 +0,0 @@ - -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 deleted file mode 100644 index bcf02987c2..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au-rename.patch +++ /dev/null @@ -1,78 +0,0 @@ - -Adjust driver bits so it keeps the name of the replaced driver - -Signed-off-by: Thomas Backlund - ---- - 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(+), 10 deletions(-) - -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; - exit: -- dev_info(&udev->dev, "88XXau %pM hw_info[%02x]", hw_addr, addr_offset); -+ dev_info(&udev->dev, "8812au %pM hw_info[%02x]", hw_addr, addr_offset); - return ret; - } - -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 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 - - ifeq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A)_$(CONFIG_RTL8814A), y_y_n) - --EXTRA_CFLAGS += -DDRV_NAME=\"rtl88XXau\" -+EXTRA_CFLAGS += -DDRV_NAME=\"rtl8812au\" - ifeq ($(CONFIG_USB_HCI), y) --USER_MODULE_NAME = 88XXau -+USER_MODULE_NAME = 8812au - endif - else - EXTRA_CFLAGS += -DDRV_NAME=\"rtl8812au\" -@@ -2232,11 +2232,11 @@ $(MODULE_NAME)-y += $(_PLATFORM_FILES) - - $(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o - --obj-$(CONFIG_88XXAU) := $(MODULE_NAME).o -+obj-$(CONFIG_RTL8812AU) := $(MODULE_NAME).o - - else - --export CONFIG_88XXAU = m -+export CONFIG_RTL8812AU = m - - all: modules - -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) { -- pr_info("88XXAU: rtw_cfg80211_unlink_bss: wiphy is NULL\n"); -+ pr_info("8812AU: rtw_cfg80211_unlink_bss: wiphy is NULL\n"); - return; - } - diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-5.8-fix.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-5.8-fix.patch deleted file mode 100644 index 707d15de8a..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-5.8-fix.patch +++ /dev/null @@ -1,301 +0,0 @@ -diff -up linux-5.8/3rdparty/rtl8821ce/core/rtw_security.c.kernel58 linux-5.8/3rdparty/rtl8821ce/core/rtw_security.c ---- linux-5.8/3rdparty/rtl8821ce/core/rtw_security.c.kernel58 2020-08-12 18:12:12.492276511 +0200 -+++ linux-5.8/3rdparty/rtl8821ce/core/rtw_security.c 2020-08-12 18:13:07.202678858 +0200 -@@ -2133,7 +2133,7 @@ BIP_exit: - #ifndef PLATFORM_FREEBSD - #if defined(CONFIG_TDLS) - /* compress 512-bits */ --static int sha256_compress(struct _sha256_state *md, unsigned char *buf) -+static int sha256_compress(struct sha256_state *md, unsigned char *buf) - { - u32 S[8], W[64], t0, t1; - u32 t; -@@ -2181,7 +2181,7 @@ static int sha256_compress(struct _sha25 - } - - /* Initialize the hash state */ --static void sha256_init(struct _sha256_state *md) -+static void sha256_init(struct sha256_state *md) - { - md->curlen = 0; - md->length = 0; -@@ -2202,7 +2202,7 @@ static void sha256_init(struct _sha256_s - @param inlen The length of the data (octets) - @return CRYPT_OK if successful - */ --static int sha256_process(struct _sha256_state *md, unsigned char *in, -+static int sha256_process(struct sha256_state *md, unsigned char *in, - unsigned long inlen) - { - unsigned long n; -@@ -2243,7 +2243,7 @@ static int sha256_process(struct _sha256 - @param out [out] The destination of the hash (32 bytes) - @return CRYPT_OK if successful - */ --static int sha256_done(struct _sha256_state *md, unsigned char *out) -+static int sha256_done(struct sha256_state *md, unsigned char *out) - { - int i; - -@@ -2293,7 +2293,7 @@ static int sha256_done(struct _sha256_st - static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, - u8 *mac) - { -- struct _sha256_state ctx; -+ struct sha256_state ctx; - size_t i; - - sha256_init(&ctx); -diff -up linux-5.8/3rdparty/rtl8821ce/include/rtw_security.h.kernel58 linux-5.8/3rdparty/rtl8821ce/include/rtw_security.h ---- linux-5.8/3rdparty/rtl8821ce/include/rtw_security.h.kernel58 2020-08-12 18:12:12.860279218 +0200 -+++ linux-5.8/3rdparty/rtl8821ce/include/rtw_security.h 2020-08-12 18:13:07.202678858 +0200 -@@ -249,11 +249,13 @@ struct security_priv { - #define SEC_IS_BIP_KEY_INSTALLED(sec) _FALSE - #endif - --struct _sha256_state { -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)) -+struct sha256_state { - u64 length; - u32 state[8], curlen; - u8 buf[64]; - }; -+#endif - - #define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)\ - do {\ -diff -up linux-5.8/3rdparty/rtl8821ce/os_dep/linux/ioctl_cfg80211.c.kernel58 linux-5.8/3rdparty/rtl8821ce/os_dep/linux/ioctl_cfg80211.c ---- linux-5.8/3rdparty/rtl8821ce/os_dep/linux/ioctl_cfg80211.c.kernel58 2020-08-12 18:12:12.867279269 +0200 -+++ linux-5.8/3rdparty/rtl8821ce/os_dep/linux/ioctl_cfg80211.c 2020-08-12 18:13:07.204678873 +0200 -@@ -80,7 +80,7 @@ - #endif - - /* -- * In the current design of Wi-Fi driver, it will return success to the system (e.g. supplicant) -+ * In the current design of Wi-Fi driver, it will return success to the system (e.g. supplicant) - * when Wi-Fi driver decides to abort the scan request in the scan flow by default. - * Defining this flag makes Wi-Fi driver to return -EBUSY to the system if Wi-Fi driver is too busy to do the scan. - */ -@@ -321,7 +321,7 @@ static u8 rtw_chbw_to_cfg80211_chan_def( - if (!chan) - goto exit; - -- if (bw == CHANNEL_WIDTH_20) -+ if (bw == CHANNEL_WIDTH_20) - chdef->width = ht ? NL80211_CHAN_WIDTH_20 : NL80211_CHAN_WIDTH_20_NOHT; - else if (bw == CHANNEL_WIDTH_40) - chdef->width = NL80211_CHAN_WIDTH_40; -@@ -355,7 +355,7 @@ static void rtw_get_chbw_from_cfg80211_c - rtw_warn_on(1); - *ch = 0; - return; -- } -+ } - - switch (chdef->width) { - case NL80211_CHAN_WIDTH_20_NOHT: -@@ -1577,8 +1577,8 @@ static int rtw_cfg80211_set_encryption(s - _rtw_memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); - _rtw_memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); - padapter->securitypriv.binstallGrpkey = _TRUE; -- if (param->u.crypt.idx < 4) -- _rtw_memcpy(padapter->securitypriv.iv_seq[param->u.crypt.idx], param->u.crypt.seq, 8); -+ if (param->u.crypt.idx < 4) -+ _rtw_memcpy(padapter->securitypriv.iv_seq[param->u.crypt.idx], param->u.crypt.seq, 8); - padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; - rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, _TRUE); - -@@ -1826,7 +1826,7 @@ static int cfg80211_rtw_get_key(struct w - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) - || (MLME_IS_STA(adapter) && !pairwise) - #endif -- ) { -+ ) { - /* WEP key, TX GTK/IGTK, RX GTK/IGTK(for STA mode) */ - if (is_wep_enc(sec->dot118021XGrpPrivacy)) { - if (keyid >= WEP_KEYS) -@@ -1915,7 +1915,7 @@ static int cfg80211_rtw_get_key(struct w - } - - ret = 0; -- -+ - exit: - RTW_INFO(FUNC_NDEV_FMT - GET_KEY_PARAM_FMT_S -@@ -5565,7 +5565,7 @@ release_plink_ctl: - if (del_sta) { - u8 sta_addr[ETH_ALEN]; - u8 updated = _FALSE; -- -+ - _rtw_memcpy(sta_addr, del_sta->cmn.mac_addr, ETH_ALEN); - updated = ap_free_sta(adapter, del_sta, 0, 0, 1); - rtw_mesh_expire_peer(stapriv->padapter, sta_addr); -@@ -5650,7 +5650,7 @@ static int cfg80211_rtw_dump_station(str - else - _rtw_memcpy(mac, plink->addr, ETH_ALEN); - #endif -- -+ - sinfo->filled = 0; - - if (psta) { -@@ -7307,11 +7307,22 @@ static void cfg80211_rtw_mgmt_frame_regi - #else - struct net_device *ndev, - #endif -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+ struct mgmt_frame_regs *upd) -+#else - u16 frame_type, bool reg) -+#endif -+ - { - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - struct net_device *ndev = wdev_to_ndev(wdev); - #endif -+ -+/* hardcoded always true, to make it pass compilation */ -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+ bool reg = true; -+#endif -+ - _adapter *adapter; - - struct rtw_wdev_priv *pwdev_priv; -@@ -7330,7 +7341,12 @@ static void cfg80211_rtw_mgmt_frame_regi - /* Wait QC Verify */ - return; - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+ switch (upd->interface_stypes) { -+#else - switch (frame_type) { -+#endif -+ - case IEEE80211_STYPE_PROBE_REQ: /* 0x0040 */ - SET_CFG80211_REPORT_MGMT(pwdev_priv, IEEE80211_STYPE_PROBE_REQ, reg); - break; -@@ -7682,7 +7698,7 @@ void dump_mesh_config(void *sel, const s - RTW_PRINT_SEL(sel, "path_refresh_time:%u\n", conf->path_refresh_time); - RTW_PRINT_SEL(sel, "min_discovery_timeout:%u\n", conf->min_discovery_timeout); - RTW_PRINT_SEL(sel, "dot11MeshHWMPactivePathTimeout:%u\n", conf->dot11MeshHWMPactivePathTimeout); -- RTW_PRINT_SEL(sel, "dot11MeshHWMPpreqMinInterval:%u\n", conf->dot11MeshHWMPpreqMinInterval); -+ RTW_PRINT_SEL(sel, "dot11MeshHWMPpreqMinInterval:%u\n", conf->dot11MeshHWMPpreqMinInterval); - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) - RTW_PRINT_SEL(sel, "dot11MeshHWMPperrMinInterval:%u\n", conf->dot11MeshHWMPperrMinInterval); - #endif -@@ -7697,11 +7713,11 @@ void dump_mesh_config(void *sel, const s - RTW_PRINT_SEL(sel, "dot11MeshForwarding:%d\n", conf->dot11MeshForwarding); - RTW_PRINT_SEL(sel, "rssi_threshold:%d\n", conf->rssi_threshold); - #endif -- -+ - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) - RTW_PRINT_SEL(sel, "ht_opmode:0x%04x\n", conf->ht_opmode); - #endif -- -+ - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - RTW_PRINT_SEL(sel, "dot11MeshHWMPactivePathToRootTimeout:%u\n", conf->dot11MeshHWMPactivePathToRootTimeout); - RTW_PRINT_SEL(sel, "dot11MeshHWMProotInterval:%u\n", conf->dot11MeshHWMProotInterval); -@@ -7712,7 +7728,7 @@ void dump_mesh_config(void *sel, const s - RTW_PRINT_SEL(sel, "power_mode:%s\n", nl80211_mesh_power_mode_str(conf->power_mode)); - RTW_PRINT_SEL(sel, "dot11MeshAwakeWindowDuration:%u\n", conf->dot11MeshAwakeWindowDuration); - #endif -- -+ - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) - RTW_PRINT_SEL(sel, "plink_timeout:%u\n", conf->plink_timeout); - #endif -@@ -7848,14 +7864,14 @@ static void rtw_cfg80211_mesh_cfg_set(_a - if (chk_mesh_attr(NL80211_MESHCONF_HT_OPMODE, mask)); - #endif - #endif -- -+ - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - if (chk_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask)) - mcfg->dot11MeshHWMPactivePathToRootTimeout = conf->dot11MeshHWMPactivePathToRootTimeout; - if (chk_mesh_attr(NL80211_MESHCONF_HWMP_ROOT_INTERVAL, mask)) - mcfg->dot11MeshHWMProotInterval = conf->dot11MeshHWMProotInterval; - if (chk_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask)) -- mcfg->dot11MeshHWMPconfirmationInterval = conf->dot11MeshHWMPconfirmationInterval; -+ mcfg->dot11MeshHWMPconfirmationInterval = conf->dot11MeshHWMPconfirmationInterval; - #endif - - #if 0 /* TBD */ -@@ -7913,7 +7929,7 @@ u8 *rtw_cfg80211_construct_mesh_beacon_i - #endif - if (!ch) - goto exit; -- -+ - #if defined(CONFIG_80211AC_VHT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) - vht = ht && ch > 14 && bw >= CHANNEL_WIDTH_80; /* VHT40/VHT20? */ - #endif -@@ -8244,7 +8260,7 @@ static int cfg80211_rtw_join_mesh(struct - ret = -EINVAL; - goto exit; - } -- -+ - rtw_mesh_work(&adapter->mesh_work); - - exit: -@@ -8325,7 +8341,7 @@ static int cfg80211_rtw_del_mpath(struct - } - } else { - rtw_mesh_path_flush_by_iface(adapter); -- } -+ } - - exit: - return ret; -@@ -8626,13 +8642,13 @@ int cfg80211_rtw_resume(struct wiphy *wi - //rtw_sitesurvey_cmd(padapter, NULL); - rtw_sitesurvey_cmd(padapter, &parm); - _exit_critical_bh(&pmlmepriv->lock, &irqL); -- -+ - for (PNOWakeupScanWaitCnt = 0; PNOWakeupScanWaitCnt < 10; PNOWakeupScanWaitCnt++) { - if(check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _FALSE) - break; - rtw_msleep_os(1000); - } -- -+ - _enter_critical_bh(&pmlmepriv->lock, &irqL); - cfg80211_sched_scan_results(padapter->rtw_wdev->wiphy); - _exit_critical_bh(&pmlmepriv->lock, &irqL); -@@ -8640,7 +8656,7 @@ int cfg80211_rtw_resume(struct wiphy *wi - } - RTW_DBG("<== %s\n",__func__); - return 0; -- -+ - } - #endif /* CONFIG_PNO_SUPPORT */ - -@@ -9530,7 +9546,7 @@ int rtw_hostapd_acs_dump_survey(struct w - #elif defined(CONFIG_RTW_ACS) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) - rtw_cfg80211_set_survey_info_with_clm(padapter, idx, info); - #else -- RTW_ERR("%s: unknown acs operation!\n", __func__); -+ RTW_ERR("%s: unknown acs operation!\n", __func__); - #endif - - return ret; -@@ -9631,7 +9647,11 @@ static struct cfg80211_ops rtw_cfg80211_ - - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) - .mgmt_tx = cfg80211_rtw_mgmt_tx, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) -+ .update_mgmt_frame_registrations = cfg80211_rtw_mgmt_frame_register, -+#else - .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, -+#endif - #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) - .action = cfg80211_rtw_mgmt_tx, - #endif diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-Kconfig-Makefile.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-Kconfig-Makefile.patch deleted file mode 100644 index 223599b6f3..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-Kconfig-Makefile.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- linux-5.3.orig/3rdparty/Kconfig -+++ linux-5.3/3rdparty/Kconfig -@@ -3,6 +3,7 @@ - menu "External 3rdparty kernel additions" - - source "3rdparty/ndiswrapper/Kconfig" -+source "3rdparty/rtl8821ce/Kconfig" - source "3rdparty/rtl8812au/Kconfig" - source "3rdparty/rtl8723de/Kconfig" - source "3rdparty/viahss/Kconfig" ---- linux-5.3.orig/3rdparty/Makefile -+++ linux-5.3/3rdparty/Makefile -@@ -2,6 +2,7 @@ - - obj- := 3rdparty.o # Dummy rule to force built-in.o to be made - obj-$(CONFIG_NDISWRAPPER) += ndiswrapper/ -+obj-$(CONFIG_RTL8821CE) += rtl8821ce/ - obj-$(CONFIG_RTL8812AU) += rtl8812au/ - obj-$(CONFIG_RTL8723DE) += rtl8723de/ - obj-$(CONFIG_VIAHSS) += viahss/ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.10.patch b/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.10.patch deleted file mode 100644 index 080058400c..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.10.patch +++ /dev/null @@ -1,162 +0,0 @@ -diff -urp linux-5.10/3rdparty/rtl8821ce.orig/core/rtw_btcoex.c linux-5.10/3rdparty/rtl8821ce/core/rtw_btcoex.c ---- linux-5.10/3rdparty/rtl8821ce.orig/core/rtw_btcoex.c 2021-01-19 22:18:00.924067581 +0200 -+++ linux-5.10/3rdparty/rtl8821ce/core/rtw_btcoex.c 2021-01-19 22:22:20.057518961 +0200 -@@ -1474,15 +1474,20 @@ u8 rtw_btcoex_sendmsgbysocket(_adapter * - udpmsg.msg_control = NULL; - udpmsg.msg_controllen = 0; - udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; -+ -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - 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 -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(oldfs); -+#endif - if (error < 0) { - RTW_INFO("Error when sendimg msg, error:%d\n", error); - return _FAIL; -diff -urp linux-5.10/3rdparty/rtl8821ce.orig/core/rtw_wlan_util.c linux-5.10/3rdparty/rtl8821ce/core/rtw_wlan_util.c ---- linux-5.10/3rdparty/rtl8821ce.orig/core/rtw_wlan_util.c 2021-01-19 22:18:00.937068206 +0200 -+++ linux-5.10/3rdparty/rtl8821ce/core/rtw_wlan_util.c 2021-01-19 22:22:20.067519442 +0200 -@@ -4751,8 +4751,10 @@ int rtw_dev_nlo_info_set(struct pno_nlo_ - return 0; - } - -+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 0)) - fs = get_fs(); - set_fs(KERNEL_DS); -+#endif - - source = rtw_zmalloc(2048); - -@@ -4762,7 +4764,9 @@ int rtw_dev_nlo_info_set(struct pno_nlo_ - rtw_mfree(source, 2048); - } - -+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(5, 10, 0)) - set_fs(fs); -+#endif - filp_close(fp, NULL); - - RTW_INFO("-%s-\n", __func__); -diff -urp linux-5.10/3rdparty/rtl8821ce.orig/os_dep/linux/os_intfs.c linux-5.10/3rdparty/rtl8821ce/os_dep/linux/os_intfs.c ---- linux-5.10/3rdparty/rtl8821ce.orig/os_dep/linux/os_intfs.c 2021-01-19 22:18:01.078074981 +0200 -+++ linux-5.10/3rdparty/rtl8821ce/os_dep/linux/os_intfs.c 2021-01-19 22:22:20.068519490 +0200 -@@ -4008,14 +4008,18 @@ static int route_dump(u32 *gw_addr , int - msg.msg_controllen = 0; - msg.msg_flags = MSG_DONTWAIT; - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - 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 -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(oldfs); -+#endif - - if (err < 0) - goto out_sock; -@@ -4040,14 +4044,18 @@ restart: - iov_iter_init(&msg.msg_iter, READ, &iov, 1, PAGE_SIZE); - #endif - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - 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 -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(oldfs); -+#endif - - if (err < 0) - goto out_sock_pg; -@@ -4118,14 +4126,18 @@ done: - msg.msg_controllen = 0; - msg.msg_flags = MSG_DONTWAIT; - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - 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 -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(oldfs); -+#endif - - if (err > 0) - goto restart; -diff -urp linux-5.10/3rdparty/rtl8821ce.orig/os_dep/osdep_service.c linux-5.10/3rdparty/rtl8821ce/os_dep/osdep_service.c ---- linux-5.10/3rdparty/rtl8821ce.orig/os_dep/osdep_service.c 2021-01-19 22:18:01.081075125 +0200 -+++ linux-5.10/3rdparty/rtl8821ce/os_dep/osdep_service.c 2021-01-19 22:22:20.068519490 +0200 -@@ -2200,8 +2200,10 @@ static int isFileReadable(const char *pa - if (IS_ERR(fp)) - ret = PTR_ERR(fp); - else { -+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - oldfs = get_fs(); - set_fs(KERNEL_DS); -+ #endif - - if (1 != readFile(fp, &buf, 1)) - ret = PTR_ERR(fp); -@@ -2214,7 +2216,9 @@ static int isFileReadable(const char *pa - #endif - } - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(oldfs); -+#endif - filp_close(fp, NULL); - } - return ret; -@@ -2238,10 +2242,14 @@ static int retriveFromFile(const char *p - if (0 == ret) { - RTW_INFO("%s openFile path:%s fp=%p\n", __FUNCTION__, path , fp); - -+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - oldfs = get_fs(); - set_fs(KERNEL_DS); -+ #endif - ret = readFile(fp, buf, sz); -+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(oldfs); -+ #endif - closeFile(fp); - - RTW_INFO("%s readFile, ret:%d\n", __FUNCTION__, ret); -@@ -2273,10 +2281,14 @@ static int storeToFile(const char *path, - if (0 == ret) { - RTW_INFO("%s openFile path:%s fp=%p\n", __FUNCTION__, path , fp); - -+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - oldfs = get_fs(); - set_fs(KERNEL_DS); -+ #endif - ret = writeFile(fp, buf, sz); -+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)) - set_fs(oldfs); -+ #endif - closeFile(fp); - - RTW_INFO("%s writeFile, ret:%d\n", __FUNCTION__, ret); 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 deleted file mode 100644 index f23766d9f9..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.12.patch +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 2acf771951..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8821ce-kernel-5.15.patch +++ /dev/null @@ -1,66 +0,0 @@ - -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/3rd-viahss-0.92.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-0.92.patch deleted file mode 100644 index bc9a567817..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-viahss-0.92.patch +++ /dev/null @@ -1,189 +0,0 @@ - 3rdparty/viahss/Kconfig | 14 +++++++ - 3rdparty/viahss/Makefile | 3 + - 3rdparty/viahss/README.html | 68 ++++++++++++++++++++++++++++++++++++ - 3rdparty/viahss/viahss.c | 83 ++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 168 insertions(+) -diff -Nurp linux-2.6.37/3rdparty/viahss/Kconfig linux-2.6.37.3rdparty/3rdparty/viahss/Kconfig ---- linux-2.6.37/3rdparty/viahss/Kconfig 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.37.3rdparty/3rdparty/viahss/Kconfig 2003-12-01 01:53:51.000000000 +0200 -@@ -0,0 +1,14 @@ -+config VIAHSS -+ tristate "VIA High Speed Serial" -+ depends on SERIAL_CORE && m -+ ---help--- -+ VIA High Speed Serial is a little kernel module (1 KB) which enables -+ high speed serial port modes of VIA VT82C686A or VT82C686B -+ southbridge-equipped motherboards. With this module, you can use the -+ serial port at 230400 bit/s so that you can get the full 128000 bit/s -+ from ISDN-TA. The module has been tested with both 686A and 686B -+ chipsets. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called viahss. -+ -diff -Nurp linux-2.6.37/3rdparty/viahss/Makefile linux-2.6.37.3rdparty/3rdparty/viahss/Makefile ---- linux-2.6.37/3rdparty/viahss/Makefile 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.37.3rdparty/3rdparty/viahss/Makefile 2003-12-01 01:43:23.000000000 +0200 -@@ -0,0 +1,3 @@ -+ -+obj-$(CONFIG_VIAHSS) += viahss.o -+ -diff -Nurp linux-2.6.37/3rdparty/viahss/README.html linux-2.6.37.3rdparty/3rdparty/viahss/README.html ---- linux-2.6.37/3rdparty/viahss/README.html 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.37.3rdparty/3rdparty/viahss/README.html 2003-12-01 01:58:23.000000000 +0200 -@@ -0,0 +1,68 @@ -+ -+ -+ -+ -+ High speed serial port for VIA VT82C686 chipsets for linux -+ -+ -+

Setting the serial port speed over 115,200bps

-+
-+If you have motherboard which has VIA VT82C686A or VT82C686B chipset -+you can set serial ports in high speed mode with this kernel module. -+I use module with external ISDN-TA and haven't had any problems -+so far but I cannot guarantee that you won't have buffer overflows if -+you use full 230K or 460K speed all the time (FIFO's are still 16550A size). -+ISDN with two channels maxes out at 128 Kb which means that it doesn't -+really stress serial ports at 230400. Unlike SHSMOD-patches you don't have -+to patch serial driver and module takes only 1KB of memory when it's -+loaded which should leave enough room for other programs. It should -+be also possible to make this work from userspace but accessing -+pci devices is so much easier from kernel. -+ -+

How to use module

-+Get the package -+and compile it using included makefiles. -+

For 2.4

-+If you have kernel in some other location than /usr/src/linux edit Makefile -+before compiling. You can also install module with "make install". After -+you have loaded module in kernel (use modprobe or insmod) you can set serial -+ports to use high speed modes with setserial.
-+

For 2.5/2.6

-+Copy Makefile-2.6 on top of Makefile and do make. After loading module set -+serial speed with setserial. (NOTE: This gives a warning on depracated -+method). -+ -+
-+# setserial /dev/ttyS0 spd_cust divisor 0x8002 -+

-+which sets COM1: speed to 230400. With 0x8001 you should get 460800 -+but I haven't tested it. If you want to use COM2: use ttyS1 instead of ttyS0. -+ -+After this you should set program which you are using to use 38400 bps -+speed which is now actually 230K or 460K. For more information check -+setserial man page (spd_cust). -+ -+You can use serial port work as normal if you do
-+
-+# setserial /dev/ttyS0 spd_normal

-+After this you can also remove viahss module with rmmod if you need to. Module doesn't intefere with normal serial port usage so you can leave -+it loaded if you don't need that extra 1KB which module uses. -+

Download

-+viahss-0.92.tar.gz -+ -+

Acknowledgments

-+ -+Thanks to Kimmo Rintala for help with divisor settings.
-+I also like to thank Jeff Garzik for help with VIA datasheets.
-+Port to 2.5/2.6 by Kingsly John with the help of LWN -+ -+

Version History

-+0.90 First release
-+0.91 Fixed Makefile
-+0.92 Fixed for 2.5/2.6
-+ -+

Contact

-+ -+You can reach me by email: jrauti@iki.fi -+ -+ -diff -Nurp linux-2.6.37/3rdparty/viahss/viahss.c linux-2.6.37.3rdparty/3rdparty/viahss/viahss.c ---- linux-2.6.37/3rdparty/viahss/viahss.c 1970-01-01 02:00:00.000000000 +0200 -+++ linux-2.6.37.3rdparty/3rdparty/viahss/viahss.c 2003-07-17 09:49:59.000000000 +0300 -@@ -0,0 +1,83 @@ -+/* -+ * VIA VT 82c686[AB] high speed serial port enabler -+ * Version 0.92 -+ * Copyright (c) 2000-2001 Juhani Rautiainen -+ * -+ * 0.92: -+ * Ported to 2.5/2.6 by Kingsly John -+ * - Corrected locking (no more cli() and sti()) -+ * - New makefile -+ * -+ * Can be freely distributed and used under the terms of the GNU GPL. -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+ -+const unsigned short confindex=0x3F0,confdata=0x3F1; -+const unsigned char spcidx=0xEE; -+ -+spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; -+ -+static int __init viahss_init(void) -+{ -+ struct pci_dev *pcidev = NULL; -+ unsigned char confval,val; -+ pcidev = pci_find_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); -+ if (pcidev) { -+ spin_lock_irq(&driver_lock); -+ /* start config */ -+ pci_read_config_byte(pcidev,0x85,&confval); -+ confval |= 0x2; -+ pci_write_config_byte (pcidev, 0x85,confval); -+ /* activate high speed bits */ -+ outb(spcidx,confindex); /* set index */ -+ val = (unsigned char) inb(confdata); -+ val |= 0xC0; /* both ports on high speed*/ -+ outb (spcidx,confindex); -+ outb (val,confdata); -+ /*stop config*/ -+ confval &= ~0x2; -+ pci_write_config_byte(pcidev, 0x85, confval); -+ spin_unlock_irq(&driver_lock); -+ printk (KERN_INFO "VIA VT82C686[AB] serial port high speed enabled\n"); -+ } -+ else { -+ printk (KERN_INFO "Couldn't locate VIA chipset\n"); -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+static void __exit viahss_exit(void) -+{ -+ struct pci_dev *pcidev = NULL; -+ unsigned char confval,val; -+ pcidev = pci_find_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); -+ if (pcidev) { -+ spin_lock_irq(&driver_lock); -+ /* start config */ -+ pci_read_config_byte(pcidev,0x85,&confval); -+ confval |= 0x2; -+ pci_write_config_byte (pcidev, 0x85,confval); -+ /* activate high speed bits */ -+ outb(spcidx,confindex); /* set index */ -+ val = (unsigned char) inb(confdata); -+ val &= ~0xC0; /* both ports off high speed*/ -+ outb (spcidx,confindex); -+ outb (val,confdata); -+ /*stop config*/ -+ confval &= ~0x2; -+ pci_write_config_byte(pcidev, 0x85, confval); -+ spin_unlock_irq(&driver_lock); -+ printk (KERN_INFO "VIA VT82C686[AB] serial port high speed disabled\n"); -+ } -+} -+ -+module_init(viahss_init); -+module_exit(viahss_exit); -+MODULE_DESCRIPTION("VIA VT82C686[AB] high speed serial port enabler"); -+MODULE_AUTHOR("Juhani Rautiainen "); diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-2.6.35-buildfix.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-2.6.35-buildfix.patch deleted file mode 100644 index 5ae42e926d..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-viahss-2.6.35-buildfix.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- linux-2.6.35-rc6-git-mnb0.1/3rdparty/viahss/viahss.c.orig 2010-07-30 21:17:30.000000000 +0300 -+++ linux-2.6.35-rc6-git-mnb0.1/3rdparty/viahss/viahss.c 2010-07-30 23:10:21.324978822 +0300 -@@ -25,7 +25,7 @@ static int __init viahss_init(void) - { - struct pci_dev *pcidev = NULL; - unsigned char confval,val; -- pcidev = pci_find_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); -+ pcidev = pci_get_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); - if (pcidev) { - spin_lock_irq(&driver_lock); - /* start config */ -@@ -55,7 +55,7 @@ static void __exit viahss_exit(void) - { - struct pci_dev *pcidev = NULL; - unsigned char confval,val; -- pcidev = pci_find_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); -+ pcidev = pci_get_device (PCI_VENDOR_ID_VIA,PCI_DEVICE_ID_VIA_82C686,NULL); - if (pcidev) { - spin_lock_irq(&driver_lock); - /* start config */ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-3.0-buildfix.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-3.0-buildfix.patch deleted file mode 100644 index 7db738810a..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-viahss-3.0-buildfix.patch +++ /dev/null @@ -1,19 +0,0 @@ - -fix build with 3.0 - -Signed-off-by: Thomas Backlund - - 3rdparty/viahss/viahss.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/3rdparty/viahss/viahss.c.orig 2011-07-15 02:37:27.000000000 +0300 -+++ a/3rdparty/viahss/viahss.c 2011-07-15 13:48:13.204291256 +0300 -@@ -19,7 +19,7 @@ - const unsigned short confindex=0x3F0,confdata=0x3F1; - const unsigned char spcidx=0xEE; - --spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; -+DEFINE_SPINLOCK(driver_lock); - - static int __init viahss_init(void) - { diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-Kconfig-Makefile.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-Kconfig-Makefile.patch deleted file mode 100644 index 348b2cd400..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-viahss-Kconfig-Makefile.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- linux/3rdparty/Kconfig.orig 2019-05-31 23:33:39.796256889 +0300 -+++ linux/3rdparty/Kconfig 2019-05-31 23:37:16.378970236 +0300 -@@ -5,5 +5,6 @@ menu "External 3rdparty kernel additions" - source "3rdparty/ndiswrapper/Kconfig" - source "3rdparty/rtl8812au/Kconfig" - source "3rdparty/rtl8723de/Kconfig" -+source "3rdparty/viahss/Kconfig" - - endmenu ---- linux/3rdparty/Makefile.orig 2019-05-31 23:33:57.608644657 +0300 -+++ linux/3rdparty/Makefile 2019-05-31 23:37:39.711477814 +0300 -@@ -4,3 +4,4 @@ obj- := 3rdparty.o # Dummy rule to forc - obj-$(CONFIG_NDISWRAPPER) += ndiswrapper/ - obj-$(CONFIG_RTL8812AU) += rtl8812au/ - obj-$(CONFIG_RTL8723DE) += rtl8723de/ -+obj-$(CONFIG_VIAHSS) += viahss/ diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-config.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-config.patch deleted file mode 100644 index 0d1bdbd3a0..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-viahss-config.patch +++ /dev/null @@ -1,18 +0,0 @@ -linux/config.h is gone in 2.6.21 - ---- - 3rdparty/viahss/viahss.c | 1 0 + 1 - 0 ! - 1 files changed, 1 deletion(-) - -Index: linux-2.6.21/3rdparty/viahss/viahss.c -=================================================================== ---- linux-2.6.21.orig/3rdparty/viahss/viahss.c 2003-07-17 08:49:59.000000000 +0200 -+++ linux-2.6.21/3rdparty/viahss/viahss.c 2007-05-14 17:06:56.000000000 +0200 -@@ -12,7 +12,6 @@ - */ - - #include --#include - #include - #include - #include diff --git a/kernel/tools/perf/files/patches/mageia/3rd-viahss-module-license.patch b/kernel/tools/perf/files/patches/mageia/3rd-viahss-module-license.patch deleted file mode 100644 index 540538f2f8..0000000000 --- a/kernel/tools/perf/files/patches/mageia/3rd-viahss-module-license.patch +++ /dev/null @@ -1,7 +0,0 @@ ---- linux-2.6.25/3rdparty/viahss/viahss.c.orig 2008-06-28 22:50:05.000000000 +0300 -+++ linux-2.6.25/3rdparty/viahss/viahss.c 2008-06-29 14:26:55.000000000 +0300 -@@ -80,3 +80,4 @@ module_init(viahss_init); - module_exit(viahss_exit); - MODULE_DESCRIPTION("VIA VT82C686[AB] high speed serial port enabler"); - MODULE_AUTHOR("Juhani Rautiainen "); -+MODULE_LICENSE("GPL"); diff --git a/kernel/tools/perf/files/patches/mageia/CVE-2019-12379.patch b/kernel/tools/perf/files/patches/mageia/CVE-2019-12379.patch deleted file mode 100644 index 04d16049ac..0000000000 --- a/kernel/tools/perf/files/patches/mageia/CVE-2019-12379.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 84ecc2f6eb1cb12e6d44818f94fa49b50f06e6ac Mon Sep 17 00:00:00 2001 -From: Gen Zhang -Date: Thu, 23 May 2019 08:34:52 +0800 -Subject: consolemap: Fix a memory leaking bug in drivers/tty/vt/consolemap.c - -In function con_insert_unipair(), when allocation for p2 and p1[n] -fails, ENOMEM is returned, but previously allocated p1 is not freed, -remains as leaking memory. Thus we should free p1 as well when this -allocation fails. - -Signed-off-by: Gen Zhang -Reviewed-by: Kees Cook -Signed-off-by: Greg Kroah-Hartman ---- - drivers/tty/vt/consolemap.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c -index b28aa0d289f8..79fcc96cc7c0 100644 ---- a/drivers/tty/vt/consolemap.c -+++ b/drivers/tty/vt/consolemap.c -@@ -489,7 +489,11 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) - p2 = p1[n = (unicode >> 6) & 0x1f]; - if (!p2) { - p2 = p1[n] = kmalloc_array(64, sizeof(u16), GFP_KERNEL); -- if (!p2) return -ENOMEM; -+ if (!p2) { -+ kfree(p1); -+ p->uni_pgdir[n] = NULL; -+ return -ENOMEM; -+ } - memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ - } - --- -cgit 1.2-0.3.lf.el7 - diff --git a/kernel/tools/perf/files/patches/mageia/CVE-2020-16119-DCCP-CCID-structure-use-after-free.patch b/kernel/tools/perf/files/patches/mageia/CVE-2020-16119-DCCP-CCID-structure-use-after-free.patch deleted file mode 100644 index 7eb981e458..0000000000 --- a/kernel/tools/perf/files/patches/mageia/CVE-2020-16119-DCCP-CCID-structure-use-after-free.patch +++ /dev/null @@ -1,305 +0,0 @@ -From MAILER-DAEMON Wed Oct 14 16:34:37 2020 -From: Kleber Sacilotto de Souza -To: netdev@vger.kernel.org -Cc: Gerrit Renker , "David S. Miller" , Jakub Kicinski , Thadeu Lima de Souza Cascardo , "Gustavo A. R. Silva" , "Alexander A. Klimov" , Kees Cook , Eric Dumazet , Alexey Kodanev , dccp@vger.kernel.org, linux-kernel@vger.kernel.org -Subject: [PATCH 1/2] dccp: ccid: move timers to struct dccp_sock -Date: Tue, 13 Oct 2020 19:18:48 +0200 -Message-Id: <20201013171849.236025-2-kleber.souza@canonical.com> -In-Reply-To: <20201013171849.236025-1-kleber.souza@canonical.com> -References: <20201013171849.236025-1-kleber.souza@canonical.com> -List-ID: -X-Mailing-List: linux-kernel@vger.kernel.org -MIME-Version: 1.0 -Content-Type: text/plain; charset="utf-8" -Content-Transfer-Encoding: 7bit - -From: Thadeu Lima de Souza Cascardo - -When dccps_hc_tx_ccid is freed, ccid timers may still trigger. The reason -del_timer_sync can't be used is because this relies on keeping a reference -to struct sock. But as we keep a pointer to dccps_hc_tx_ccid and free that -during disconnect, the timer should really belong to struct dccp_sock. - -This addresses CVE-2020-16119. - -Fixes: 839a6094140a (net: dccp: Convert timers to use timer_setup()) -Signed-off-by: Kleber Sacilotto de Souza -Signed-off-by: Thadeu Lima de Souza Cascardo -Acked-bd: Richard Sailer ---- - include/linux/dccp.h | 2 ++ - net/dccp/ccids/ccid2.c | 32 +++++++++++++++++++------------- - net/dccp/ccids/ccid3.c | 30 ++++++++++++++++++++---------- - 3 files changed, 41 insertions(+), 23 deletions(-) - -diff --git a/include/linux/dccp.h b/include/linux/dccp.h -index 07e547c02fd8..504afa1a4be6 100644 ---- a/include/linux/dccp.h -+++ b/include/linux/dccp.h -@@ -259,6 +259,7 @@ struct dccp_ackvec; - * @dccps_sync_scheduled - flag which signals "send out-of-band message soon" - * @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets - * @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing) -+ * @dccps_ccid_timer - used by the CCIDs - * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) - */ - struct dccp_sock { -@@ -303,6 +304,7 @@ struct dccp_sock { - __u8 dccps_sync_scheduled:1; - struct tasklet_struct dccps_xmitlet; - struct timer_list dccps_xmit_timer; -+ struct timer_list dccps_ccid_timer; - }; - - static inline struct dccp_sock *dccp_sk(const struct sock *sk) -diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c -index 3da1f77bd039..dbca1f1e2449 100644 ---- a/net/dccp/ccids/ccid2.c -+++ b/net/dccp/ccids/ccid2.c -@@ -126,21 +126,26 @@ static void dccp_tasklet_schedule(struct sock *sk) - - static void ccid2_hc_tx_rto_expire(struct timer_list *t) - { -- struct ccid2_hc_tx_sock *hc = from_timer(hc, t, tx_rtotimer); -- struct sock *sk = hc->sk; -- const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); -+ struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer); -+ struct sock *sk = (struct sock *)dp; -+ struct ccid2_hc_tx_sock *hc; -+ bool sender_was_blocked; - - bh_lock_sock(sk); -+ -+ if (inet_sk_state_load(sk) == DCCP_CLOSED) -+ goto out; -+ -+ hc = ccid_priv(dp->dccps_hc_tx_ccid); -+ sender_was_blocked = ccid2_cwnd_network_limited(hc); -+ - if (sock_owned_by_user(sk)) { -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + HZ / 5); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + HZ / 5); - goto out; - } - - ccid2_pr_debug("RTO_EXPIRE\n"); - -- if (sk->sk_state == DCCP_CLOSED) -- goto out; -- - /* back-off timer */ - hc->tx_rto <<= 1; - if (hc->tx_rto > DCCP_RTO_MAX) -@@ -166,7 +171,7 @@ static void ccid2_hc_tx_rto_expire(struct timer_list *t) - if (sender_was_blocked) - dccp_tasklet_schedule(sk); - /* restart backed-off timer */ -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - out: - bh_unlock_sock(sk); - sock_put(sk); -@@ -330,7 +335,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) - } - #endif - -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - - #ifdef CONFIG_IP_DCCP_CCID2_DEBUG - do { -@@ -700,9 +705,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - - /* restart RTO timer if not all outstanding data has been acked */ - if (hc->tx_pipe == 0) -- sk_stop_timer(sk, &hc->tx_rtotimer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - else -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - done: - /* check if incoming Acks allow pending packets to be sent */ - if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) -@@ -737,17 +742,18 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) - hc->tx_last_cong = hc->tx_lsndtime = hc->tx_cwnd_stamp = ccid2_jiffies32; - hc->tx_cwnd_used = 0; - hc->sk = sk; -- timer_setup(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, 0); -+ timer_setup(&dp->dccps_ccid_timer, ccid2_hc_tx_rto_expire, 0); - INIT_LIST_HEAD(&hc->tx_av_chunks); - return 0; - } - - static void ccid2_hc_tx_exit(struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); - int i; - -- sk_stop_timer(sk, &hc->tx_rtotimer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - - for (i = 0; i < hc->tx_seqbufc; i++) - kfree(hc->tx_seqbuf[i]); -diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c -index b9ee1a4a8955..685f4d046c0d 100644 ---- a/net/dccp/ccids/ccid3.c -+++ b/net/dccp/ccids/ccid3.c -@@ -184,17 +184,24 @@ static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hc, - - static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t) - { -- struct ccid3_hc_tx_sock *hc = from_timer(hc, t, tx_no_feedback_timer); -- struct sock *sk = hc->sk; -+ struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer); -+ struct ccid3_hc_tx_sock *hc; -+ struct sock *sk = (struct sock *)dp; - unsigned long t_nfb = USEC_PER_SEC / 5; - - bh_lock_sock(sk); -+ -+ if (inet_sk_state_load(sk) == DCCP_CLOSED) -+ goto out; -+ - if (sock_owned_by_user(sk)) { - /* Try again later. */ - /* XXX: set some sensible MIB */ - goto restart_timer; - } - -+ hc = ccid_priv(dp->dccps_hc_tx_ccid); -+ - ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk, - ccid3_tx_state_name(hc->tx_state)); - -@@ -250,8 +257,8 @@ static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t) - t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi); - - restart_timer: -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, -- jiffies + usecs_to_jiffies(t_nfb)); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, -+ jiffies + usecs_to_jiffies(t_nfb)); - out: - bh_unlock_sock(sk); - sock_put(sk); -@@ -280,7 +287,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) - return -EBADMSG; - - if (hc->tx_state == TFRC_SSTATE_NO_SENT) { -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies + -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, (jiffies + - usecs_to_jiffies(TFRC_INITIAL_TIMEOUT))); - hc->tx_last_win_count = 0; - hc->tx_t_last_win_count = now; -@@ -354,6 +361,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, unsigned int len) - static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - { - struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); -+ struct dccp_sock *dp = dccp_sk(sk); - struct tfrc_tx_hist_entry *acked; - ktime_t now; - unsigned long t_nfb; -@@ -420,7 +428,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - (unsigned int)(hc->tx_x >> 6)); - - /* unschedule no feedback timer */ -- sk_stop_timer(sk, &hc->tx_no_feedback_timer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - - /* - * As we have calculated new ipi, delta, t_nom it is possible -@@ -445,8 +453,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - "expire in %lu jiffies (%luus)\n", - dccp_role(sk), sk, usecs_to_jiffies(t_nfb), t_nfb); - -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, -- jiffies + usecs_to_jiffies(t_nfb)); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, -+ jiffies + usecs_to_jiffies(t_nfb)); - } - - static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type, -@@ -488,21 +496,23 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type, - - static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hc = ccid_priv(ccid); - - hc->tx_state = TFRC_SSTATE_NO_SENT; - hc->tx_hist = NULL; - hc->sk = sk; -- timer_setup(&hc->tx_no_feedback_timer, -+ timer_setup(&dp->dccps_ccid_timer, - ccid3_hc_tx_no_feedback_timer, 0); - return 0; - } - - static void ccid3_hc_tx_exit(struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); - -- sk_stop_timer(sk, &hc->tx_no_feedback_timer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - tfrc_tx_hist_purge(&hc->tx_hist); - } - --- -2.25.1 - - -From MAILER-DAEMON Wed Oct 14 16:34:37 2020 -From: Kleber Sacilotto de Souza -To: netdev@vger.kernel.org -Cc: Gerrit Renker , "David S. Miller" , Jakub Kicinski , Thadeu Lima de Souza Cascardo , "Gustavo A. R. Silva" , "Alexander A. Klimov" , Kees Cook , Eric Dumazet , Alexey Kodanev , dccp@vger.kernel.org, linux-kernel@vger.kernel.org -Subject: [PATCH 2/2] Revert "dccp: don't free ccid2_hc_tx_sock struct in dccp_disconnect()" -Date: Tue, 13 Oct 2020 19:18:49 +0200 -Message-Id: <20201013171849.236025-3-kleber.souza@canonical.com> -In-Reply-To: <20201013171849.236025-1-kleber.souza@canonical.com> -References: <20201013171849.236025-1-kleber.souza@canonical.com> -List-ID: -X-Mailing-List: linux-kernel@vger.kernel.org -MIME-Version: 1.0 -Content-Type: text/plain; charset="utf-8" -Content-Transfer-Encoding: 7bit - -From: Thadeu Lima de Souza Cascardo - -This reverts commit 2677d20677314101293e6da0094ede7b5526d2b1. - -This fixes an issue that after disconnect, dccps_hc_tx_ccid will still be -kept, allowing the socket to be reused as a listener socket, and the cloned -socket will free its dccps_hc_tx_ccid, leading to a later use after free, -when the listener socket is closed. - -This addresses CVE-2020-16119. - -Fixes: 2677d2067731 (dccp: don't free ccid2_hc_tx_sock struct in dccp_disconnect()) -Reported-by: Hadar Manor -Signed-off-by: Kleber Sacilotto de Souza -Signed-off-by: Thadeu Lima de Souza Cascardo -Acked-by: Richard Sailer ---- - net/dccp/proto.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/net/dccp/proto.c b/net/dccp/proto.c -index 6d705d90c614..359e848dba6c 100644 ---- a/net/dccp/proto.c -+++ b/net/dccp/proto.c -@@ -279,7 +279,9 @@ int dccp_disconnect(struct sock *sk, int flags) - - dccp_clear_xmit_timers(sk); - ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); -+ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); - dp->dccps_hc_rx_ccid = NULL; -+ dp->dccps_hc_tx_ccid = NULL; - - __skb_queue_purge(&sk->sk_receive_queue); - __skb_queue_purge(&sk->sk_write_queue); --- -2.25.1 - - diff --git a/kernel/tools/perf/files/patches/mageia/MAINTAINERS-git-github-https-github.com-for-terrelln.patch b/kernel/tools/perf/files/patches/mageia/MAINTAINERS-git-github-https-github.com-for-terrelln.patch new file mode 100644 index 0000000000..0a13fff425 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/MAINTAINERS-git-github-https-github.com-for-terrelln.patch @@ -0,0 +1,33 @@ +From 894c792e3e24c2c15d8aac15aa89ec144468e1b0 Mon Sep 17 00:00:00 2001 +From: Palmer Dabbelt +Date: Thu, 13 Oct 2022 14:46:36 -0700 +Subject: [PATCH 2/6] MAINTAINERS: git://github -> https://github.com for + terrelln + +Github deprecated the git:// links about a year ago, so let's move to +the https:// URLs instead. + +Reported-by: Conor Dooley +Link: https://github.blog/2021-09-01-improving-git-protocol-security-github/ +Signed-off-by: Palmer Dabbelt +Signed-off-by: Nick Terrell +--- + MAINTAINERS | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/MAINTAINERS b/MAINTAINERS +index e04d944005ba..4a2b7a9325dc 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -22800,7 +22800,7 @@ ZSTD + M: Nick Terrell + S: Maintained + B: https://github.com/facebook/zstd/issues +-T: git git://github.com/terrelln/linux.git ++T: git https://github.com/terrelln/linux.git + F: include/linux/zstd* + F: lib/zstd/ + F: lib/decompress_unzstd.c +-- +2.30.6 + diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs5.10-symbol-exports.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs5.10-symbol-exports.patch deleted file mode 100644 index 49e6ec396b..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-aufs5.10-symbol-exports.patch +++ /dev/null @@ -1,284 +0,0 @@ -SPDX-License-Identifier: GPL-2.0 -aufs5.x-rcN standalone patch - -diff --git a/fs/dcache.c b/fs/dcache.c -index ddca6240e0db4..30dec552278dc 100644 ---- a/fs/dcache.c -+++ b/fs/dcache.c -@@ -1390,6 +1390,7 @@ void d_walk(struct dentry *parent, void *data, - seq = 1; - goto again; - } -+EXPORT_SYMBOL_GPL(d_walk); - - struct check_mount { - struct vfsmount *mnt; -@@ -2935,6 +2936,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 547a2390baf54..18d51d0face68 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -113,6 +113,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 073ca6af500f3..b18afdf81e762 100644 ---- a/fs/fcntl.c -+++ b/fs/fcntl.c -@@ -85,6 +85,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 --git a/fs/file_table.c b/fs/file_table.c -index 709ada3151da5..27a3e3c9f2a82 100644 ---- a/fs/file_table.c -+++ b/fs/file_table.c -@@ -162,6 +162,7 @@ struct file *alloc_empty_file(int flags, const struct cred *cred) - } - return ERR_PTR(-ENFILE); - } -+EXPORT_SYMBOL_GPL(alloc_empty_file); - - /* - * Variant of alloc_empty_file() that doesn't check and modify nr_files. -@@ -376,6 +377,7 @@ void __fput_sync(struct file *file) - } - - EXPORT_SYMBOL(fput); -+EXPORT_SYMBOL_GPL(__fput_sync); - - void __init files_init(void) - { -diff --git a/fs/inode.c b/fs/inode.c -index e7f0c614a58f3..6fe0a92a4c93c 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -1776,6 +1776,7 @@ int update_time(struct inode *inode, struct timespec64 *time, int flags) - return inode->i_op->update_time(inode, time, flags); - return generic_update_time(inode, time, flags); - } -+EXPORT_SYMBOL_GPL(update_time); - - /** - * touch_atime - update the access time -diff --git a/fs/namespace.c b/fs/namespace.c -index 451dee24a546a..38078cbede431 100644 ---- a/fs/namespace.c -+++ b/fs/namespace.c -@@ -431,6 +431,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 -@@ -797,6 +798,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 -@@ -1961,6 +1963,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 a4a4b1c64d32a..86dc2efb1850c 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 9af548fb841b0..2ff09b709f7bf 100644 ---- a/fs/open.c -+++ b/fs/open.c -@@ -65,6 +65,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, - 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 75f764b434184..7582bb3fb634b 100644 ---- a/fs/read_write.c -+++ b/fs/read_write.c -@@ -503,6 +503,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) - { -@@ -613,6 +614,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 55b5356262085..c13ac0fbac318 100644 ---- a/fs/splice.c -+++ b/fs/splice.c -@@ -763,6 +763,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. -@@ -787,6 +788,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/sync.c b/fs/sync.c -index b7b5a0a0df6ff..fa5c7fba7f1ba 100644 ---- a/fs/sync.c -+++ b/fs/sync.c -@@ -39,6 +39,7 @@ int __sync_filesystem(struct super_block *sb, int wait) - sb->s_op->sync_fs(sb, wait); - return __sync_blockdev(sb->s_bdev, wait); - } -+EXPORT_SYMBOL_GPL(__sync_filesystem); - - /* - * Write out and wait upon all dirty data associated with this -diff --git a/fs/xattr.c b/fs/xattr.c -index cd7a563e8bcd4..7d989d57b0f0d 100644 ---- a/fs/xattr.c -+++ b/fs/xattr.c -@@ -360,6 +360,7 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, - *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 7f006a47790cf..be002c3a30833 100644 ---- a/kernel/locking/lockdep.c -+++ b/kernel/locking/lockdep.c -@@ -209,6 +209,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 8d6e1217c451c..0e73637adda86 100644 ---- a/kernel/task_work.c -+++ b/kernel/task_work.c -@@ -154,3 +154,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 a28045dc9e7f6..310cf38efeec7 100644 ---- a/security/security.c -+++ b/security/security.c -@@ -1093,6 +1093,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) - { -@@ -1109,6 +1110,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) -@@ -1117,6 +1119,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, -@@ -1144,6 +1147,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) - { -@@ -1151,6 +1155,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) - { -@@ -1158,6 +1163,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) - { -@@ -1258,6 +1264,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) - { -@@ -1450,6 +1457,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/mageia/fs-aufs5.10-tristate.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs5.10-tristate.patch deleted file mode 100644 index f95f4ab698..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-aufs5.10-tristate.patch +++ /dev/null @@ -1,24 +0,0 @@ - -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.10.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs5.10.patch deleted file mode 100644 index 34eab23c6a..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-aufs5.10.patch +++ /dev/null @@ -1,37866 +0,0 @@ - Documentation/ABI/testing/debugfs-aufs | 55 + - Documentation/ABI/testing/sysfs-aufs | 31 + - Documentation/filesystems/aufs/README | 401 ++++ - Documentation/filesystems/aufs/design/01intro.txt | 158 ++ - Documentation/filesystems/aufs/design/02struct.txt | 245 +++ - .../filesystems/aufs/design/03atomic_open.txt | 72 + - Documentation/filesystems/aufs/design/03lookup.txt | 100 + - Documentation/filesystems/aufs/design/04branch.txt | 61 + - .../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 | 351 ++++ - fs/aufs/cpup.c | 1432 +++++++++++++++ - 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 | 428 +++++ - fs/aufs/debug.h | 213 +++ - fs/aufs/dentry.c | 1141 ++++++++++++ - fs/aufs/dentry.h | 255 +++ - fs/aufs/dinfo.c | 541 ++++++ - fs/aufs/dir.c | 750 ++++++++ - fs/aufs/dir.h | 121 ++ - fs/aufs/dirren.c | 1303 +++++++++++++ - fs/aufs/dirren.h | 127 ++ - fs/aufs/dynop.c | 355 ++++ - fs/aufs/dynop.h | 64 + - fs/aufs/export.c | 824 +++++++++ - fs/aufs/f_op.c | 749 ++++++++ - fs/aufs/fhsm.c | 413 +++++ - fs/aufs/file.c | 850 +++++++++ - fs/aufs/file.h | 329 ++++ - fs/aufs/finfo.c | 136 ++ - fs/aufs/fstype.h | 388 ++++ - fs/aufs/hbl.h | 52 + - fs/aufs/hfsnotify.c | 275 +++ - fs/aufs/hfsplus.c | 47 + - fs/aufs/hnotify.c | 702 +++++++ - fs/aufs/i_op.c | 1489 +++++++++++++++ - fs/aufs/i_op_add.c | 923 ++++++++++ - fs/aufs/i_op_del.c | 500 +++++ - fs/aufs/i_op_ren.c | 1237 +++++++++++++ - fs/aufs/iinfo.c | 273 +++ - fs/aufs/inode.c | 516 ++++++ - fs/aufs/inode.h | 685 +++++++ - 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 | 1867 +++++++++++++++++++ - fs/aufs/opts.h | 212 +++ - fs/aufs/plink.c | 503 +++++ - fs/aufs/poll.c | 38 + - fs/aufs/posix_acl.c | 92 + - fs/aufs/procfs.c | 157 ++ - fs/aufs/rdu.c | 371 ++++ - fs/aufs/rwsem.h | 60 + - fs/aufs/sbinfo.c | 301 +++ - fs/aufs/super.c | 1034 +++++++++++ - fs/aufs/super.h | 574 ++++++ - 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 | 872 +++++++++ - fs/aufs/vfsub.h | 341 ++++ - fs/aufs/wbr_policy.c | 817 +++++++++ - fs/aufs/whout.c | 1049 +++++++++++ - fs/aufs/whout.h | 73 + - fs/aufs/wkq.c | 359 ++++ - fs/aufs/wkq.h | 76 + - fs/aufs/xattr.c | 343 ++++ - fs/aufs/xino.c | 1912 ++++++++++++++++++++ - fs/dcache.c | 2 +- - fs/fcntl.c | 4 +- - fs/inode.c | 2 +- - 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 +- - fs/sync.c | 2 +- - include/linux/fs.h | 4 + - include/linux/lockdep.h | 3 + - include/linux/mm.h | 22 + - include/linux/mm_types.h | 2 + - 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 | 2 +- - mm/filemap.c | 2 +- - mm/mmap.c | 33 +- - mm/nommu.c | 10 +- - mm/prfile.c | 86 + - 118 files changed, 36737 insertions(+), 31 deletions(-) - -diff --git a/Documentation/ABI/testing/debugfs-aufs b/Documentation/ABI/testing/debugfs-aufs -new file mode 100644 -index 000000000000..4a6694194ba6 ---- /dev/null -+++ b/Documentation/ABI/testing/debugfs-aufs -@@ -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_/xi0, xi1 ... xiN and xiN-N -+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 --git a/Documentation/ABI/testing/sysfs-aufs b/Documentation/ABI/testing/sysfs-aufs -new file mode 100644 -index 000000000000..82f9518495ea ---- /dev/null -+++ b/Documentation/ABI/testing/sysfs-aufs -@@ -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_/br0, br1 ... brN -+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_/brid0, brid1 ... bridN -+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 --git a/Documentation/filesystems/aufs/README b/Documentation/filesystems/aufs/README -new file mode 100644 -index 000000000000..3e655d357134 ---- /dev/null -+++ b/Documentation/filesystems/aufs/README -@@ -0,0 +1,401 @@ -+ -+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-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". -+- proc_mounts.patch -+ When there are many mountpoints and many mount(2)/umount(2) are -+ running, then /proc/mounts may not show the all mountpoints. This -+ patch makes /proc/mounts always show the full mountpoints list. -+ If you don't want to apply this patch and meet such problem, then you -+ need to increase the value of 'ProcMounts_Times' make-variable in -+ aufs-util.git as a second best solution. -+- 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. -+- lockdep-debug.patch -+ 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 apply this debug patch to expand several constant values. -+ If you don't know what LOCKDEP is, then you don't have apply 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 and 2015/7). -+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 --git a/Documentation/filesystems/aufs/design/01intro.txt b/Documentation/filesystems/aufs/design/01intro.txt -new file mode 100644 -index 000000000000..7f75ee4a784c ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/01intro.txt -@@ -0,0 +1,158 @@ -+ -+# Copyright (C) 2005-2020 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 --git a/Documentation/filesystems/aufs/design/02struct.txt b/Documentation/filesystems/aufs/design/02struct.txt -new file mode 100644 -index 000000000000..0a948e812796 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/02struct.txt -@@ -0,0 +1,245 @@ -+ -+# Copyright (C) 2005-2020 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 --git a/Documentation/filesystems/aufs/design/03atomic_open.txt b/Documentation/filesystems/aufs/design/03atomic_open.txt -new file mode 100644 -index 000000000000..415205649c4c ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/03atomic_open.txt -@@ -0,0 +1,72 @@ -+ -+# Copyright (C) 2015-2020 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 --git a/Documentation/filesystems/aufs/design/03lookup.txt b/Documentation/filesystems/aufs/design/03lookup.txt -new file mode 100644 -index 000000000000..0b3b22bc999f ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/03lookup.txt -@@ -0,0 +1,100 @@ -+ -+# Copyright (C) 2005-2020 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 --git a/Documentation/filesystems/aufs/design/04branch.txt b/Documentation/filesystems/aufs/design/04branch.txt -new file mode 100644 -index 000000000000..0e7bc1075f37 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/04branch.txt -@@ -0,0 +1,61 @@ -+ -+# Copyright (C) 2005-2020 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 --git a/Documentation/filesystems/aufs/design/05wbr_policy.txt b/Documentation/filesystems/aufs/design/05wbr_policy.txt -new file mode 100644 -index 000000000000..f9741c32cbf2 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/05wbr_policy.txt -@@ -0,0 +1,51 @@ -+ -+# Copyright (C) 2005-2020 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 --git a/Documentation/filesystems/aufs/design/06dirren.dot b/Documentation/filesystems/aufs/design/06dirren.dot -new file mode 100644 -index 000000000000..2d62bb6dd55f ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/06dirren.dot -@@ -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 --git a/Documentation/filesystems/aufs/design/06dirren.txt b/Documentation/filesystems/aufs/design/06dirren.txt -new file mode 100644 -index 000000000000..e23459758504 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/06dirren.txt -@@ -0,0 +1,89 @@ -+ -+# Copyright (C) 2017-2020 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 --git a/Documentation/filesystems/aufs/design/06fhsm.txt b/Documentation/filesystems/aufs/design/06fhsm.txt -new file mode 100644 -index 000000000000..5322ca3b7151 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/06fhsm.txt -@@ -0,0 +1,105 @@ -+ -+# Copyright (C) 2011-2020 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 --git a/Documentation/filesystems/aufs/design/06mmap.txt b/Documentation/filesystems/aufs/design/06mmap.txt -new file mode 100644 -index 000000000000..03b71096d508 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/06mmap.txt -@@ -0,0 +1,59 @@ -+ -+# Copyright (C) 2005-2020 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 --git a/Documentation/filesystems/aufs/design/06xattr.txt b/Documentation/filesystems/aufs/design/06xattr.txt -new file mode 100644 -index 000000000000..f4076a04a335 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/06xattr.txt -@@ -0,0 +1,81 @@ -+ -+# Copyright (C) 2014-2020 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 --git a/Documentation/filesystems/aufs/design/07export.txt b/Documentation/filesystems/aufs/design/07export.txt -new file mode 100644 -index 000000000000..fcd3a3489bf8 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/07export.txt -@@ -0,0 +1,45 @@ -+ -+# Copyright (C) 2005-2020 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 --git a/Documentation/filesystems/aufs/design/08shwh.txt b/Documentation/filesystems/aufs/design/08shwh.txt -new file mode 100644 -index 000000000000..f252e17154b1 ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/08shwh.txt -@@ -0,0 +1,39 @@ -+ -+# Copyright (C) 2005-2020 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 --git a/Documentation/filesystems/aufs/design/10dynop.txt b/Documentation/filesystems/aufs/design/10dynop.txt -new file mode 100644 -index 000000000000..2b90eecb267d ---- /dev/null -+++ b/Documentation/filesystems/aufs/design/10dynop.txt -@@ -0,0 +1,34 @@ -+ -+# Copyright (C) 2010-2020 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 --git a/MAINTAINERS b/MAINTAINERS -index 281de213ef47..ffc3c1c539ea 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -3009,6 +3009,19 @@ F: include/linux/audit.h - F: include/uapi/linux/audit.h - F: kernel/audit* - -+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 Sandonis - S: Maintained -diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index a58084c2ed7c..7be7ca3f5454 100644 ---- a/drivers/block/loop.c -+++ b/drivers/block/loop.c -@@ -765,6 +765,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/Kconfig b/fs/Kconfig -index aa4c12282301..b29bad13b249 100644 ---- a/fs/Kconfig -+++ b/fs/Kconfig -@@ -288,6 +288,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 999d1a23f036..0cd76857ca76 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -136,3 +136,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/fs/aufs/Kconfig b/fs/aufs/Kconfig -new file mode 100644 -index 000000000000..0b442aeb7b45 ---- /dev/null -+++ b/fs/aufs/Kconfig -@@ -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 --git a/fs/aufs/Makefile b/fs/aufs/Makefile -new file mode 100644 -index 000000000000..9de70de0f337 ---- /dev/null -+++ b/fs/aufs/Makefile -@@ -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 \ -+ 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 --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h -new file mode 100644 -index 000000000000..c50f959844e8 ---- /dev/null -+++ b/fs/aufs/aufs.h -@@ -0,0 +1,49 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/branch.c b/fs/aufs/branch.c -new file mode 100644 -index 000000000000..3319245c0361 ---- /dev/null -+++ b/fs/aufs/branch.c -@@ -0,0 +1,1414 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/branch.h b/fs/aufs/branch.h -new file mode 100644 -index 000000000000..5632781b7bcc ---- /dev/null -+++ b/fs/aufs/branch.h -@@ -0,0 +1,351 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 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 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 --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c -new file mode 100644 -index 000000000000..d413ad06ca89 ---- /dev/null -+++ b/fs/aufs/cpup.c -@@ -0,0 +1,1432 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 dentry *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; -+ -+ h_path.dentry = au_h_dptr(dst, bindex); -+ h_idst = d_inode(h_path.dentry); -+ br = au_sbr(dst->d_sb, bindex); -+ h_path.mnt = au_br_mnt(br); -+ h_isrc = d_inode(h_src); -+ 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.dentry, 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; -+ -+ h_dentry = h_path->dentry; -+ h_inode = d_inode(h_dentry); -+ /* forget_all_cached_acls(h_inode)); */ -+ err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); -+ AuTraceErr(err); -+ if (err == -EOPNOTSUPP) -+ err = 0; -+ if (!err) -+ err = vfsub_acl_chmod(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; -+ -+ err = vfsub_removexattr(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 inode *h_dir; -+ aufs_bindex_t bdst; -+ -+ dentry = cpg->dentry; -+ bdst = cpg->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_parent = au_h_dptr(parent, bdst); -+ dput(parent); -+ h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent); -+ 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; -+ /* 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); */ -+ -+ err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &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; -+ -+ 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); -+ if (!au_test_h_perm_sio(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; -+ -+ 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; -+ } -+ -+ if (!au_test_h_perm_sio(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 --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h -new file mode 100644 -index 000000000000..c23c1bbcee7e ---- /dev/null -+++ b/fs/aufs/cpup.h -@@ -0,0 +1,87 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c -new file mode 100644 -index 000000000000..63f40a324f1b ---- /dev/null -+++ b/fs/aufs/dbgaufs.c -@@ -0,0 +1,513 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h -new file mode 100644 -index 000000000000..ad26624a9345 ---- /dev/null -+++ b/fs/aufs/dbgaufs.h -@@ -0,0 +1,40 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c -new file mode 100644 -index 000000000000..000854da9075 ---- /dev/null -+++ b/fs/aufs/dcsub.c -@@ -0,0 +1,212 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h -new file mode 100644 -index 000000000000..9d207c2b4666 ---- /dev/null -+++ b/fs/aufs/dcsub.h -@@ -0,0 +1,124 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/debug.c b/fs/aufs/debug.c -new file mode 100644 -index 000000000000..fd0ba9d15742 ---- /dev/null -+++ b/fs/aufs/debug.c -@@ -0,0 +1,428 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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(); -+ 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 --git a/fs/aufs/debug.h b/fs/aufs/debug.h -new file mode 100644 -index 000000000000..5799794de0c2 ---- /dev/null -+++ b/fs/aufs/debug.h -@@ -0,0 +1,213 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c -new file mode 100644 -index 000000000000..1a029193315a ---- /dev/null -+++ b/fs/aufs/dentry.c -@@ -0,0 +1,1141 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 Junjiro R. Okajima -+ */ -+ -+/* -+ * lookup and dentry operations -+ */ -+ -+#include -+#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; -+ 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); -+ wh_able = !!au_br_whable(br->br_perm); -+ if (wh_able) -+ wh_found = au_wh_test(h_parent, &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_parent); -+ else -+ h_dentry = au_sio_lkup_one(args->name, h_parent); -+ 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 */ -+ -+ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); -+ opq = au_diropq_test(h_dentry); -+ 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 qstr *name, struct dentry *parent) -+{ -+ struct dentry *dentry; -+ int wkq_err; -+ -+ if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC)) -+ dentry = vfsub_lkup_one(name, parent); -+ else { -+ struct vfsub_lkup_one_args args = { -+ .errp = &dentry, -+ .name = name, -+ .parent = parent -+ }; -+ -+ 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_parent, *h_dentry; -+ struct au_branch *br; -+ -+ parent = dget_parent(dentry); -+ h_parent = au_h_dptr(parent, bindex); -+ br = au_sbr(dentry->d_sb, bindex); -+ if (wh) -+ h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); -+ else -+ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); -+ 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; -+ -+ 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_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); -+ 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 --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h -new file mode 100644 -index 000000000000..086f6ccf4b15 ---- /dev/null -+++ b/fs/aufs/dentry.h -@@ -0,0 +1,255 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 qstr *name, struct dentry *parent); -+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 --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c -new file mode 100644 -index 000000000000..aed5314e5e24 ---- /dev/null -+++ b/fs/aufs/dinfo.c -@@ -0,0 +1,541 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/dir.c b/fs/aufs/dir.c -new file mode 100644 -index 000000000000..44adae19efb1 ---- /dev/null -+++ b/fs/aufs/dir.c -@@ -0,0 +1,750 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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; -+ -+ 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_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 --git a/fs/aufs/dir.h b/fs/aufs/dir.h -new file mode 100644 -index 000000000000..75fad78d2278 ---- /dev/null -+++ b/fs/aufs/dir.h -@@ -0,0 +1,121 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/dirren.c b/fs/aufs/dirren.c -new file mode 100644 -index 000000000000..12b56c47f2dd ---- /dev/null -+++ b/fs/aufs/dirren.c -@@ -0,0 +1,1303 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2017-2020 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.dentry = vfsub_lkup_one(&hinoname, path->dentry); -+ 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; -+ } -+ hinopath.mnt = path->mnt; -+ 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.dentry, -+ 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->dentry, -+ 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 --git a/fs/aufs/dirren.h b/fs/aufs/dirren.h -new file mode 100644 -index 000000000000..ade589d2e75c ---- /dev/null -+++ b/fs/aufs/dirren.h -@@ -0,0 +1,127 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2017-2020 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 --git a/fs/aufs/dynop.c b/fs/aufs/dynop.c -new file mode 100644 -index 000000000000..5dbb7193591b ---- /dev/null -+++ b/fs/aufs/dynop.c -@@ -0,0 +1,355 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2010-2020 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 --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h -new file mode 100644 -index 000000000000..66ac96bbf2ff ---- /dev/null -+++ b/fs/aufs/dynop.h -@@ -0,0 +1,64 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2010-2020 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 --git a/fs/aufs/export.c b/fs/aufs/export.c -new file mode 100644 -index 000000000000..94005688ac0b ---- /dev/null -+++ b/fs/aufs/export.c -@@ -0,0 +1,824 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 Junjiro R. Okajima -+ */ -+ -+/* -+ * export via nfs -+ */ -+ -+#include -+#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, parent, 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 { -+ struct writeback_control wbc = { -+ .sync_mode = WB_SYNC_ALL, -+ .nr_to_write = 0 /* metadata only */ -+ }; -+ -+ err = sync_inode(h_inode, &wbc); -+ } -+ -+ 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 --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c -new file mode 100644 -index 000000000000..7e9298b963aa ---- /dev/null -+++ b/fs/aufs/f_op.c -@@ -0,0 +1,749 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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; -+} -+ -+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 --git a/fs/aufs/fhsm.c b/fs/aufs/fhsm.c -new file mode 100644 -index 000000000000..cb054052cf9a ---- /dev/null -+++ b/fs/aufs/fhsm.c -@@ -0,0 +1,413 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2011-2020 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 --git a/fs/aufs/file.c b/fs/aufs/file.c -new file mode 100644 -index 000000000000..3911b2e7e46f ---- /dev/null -+++ b/fs/aufs/file.c -@@ -0,0 +1,850 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/file.h b/fs/aufs/file.h -new file mode 100644 -index 000000000000..8bf8e67650d0 ---- /dev/null -+++ b/fs/aufs/file.h -@@ -0,0 +1,329 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c -new file mode 100644 -index 000000000000..e2d6859850b6 ---- /dev/null -+++ b/fs/aufs/finfo.c -@@ -0,0 +1,136 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h -new file mode 100644 -index 000000000000..7c001dae1859 ---- /dev/null -+++ b/fs/aufs/fstype.h -@@ -0,0 +1,388 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/hbl.h b/fs/aufs/hbl.h -new file mode 100644 -index 000000000000..571efb1e2300 ---- /dev/null -+++ b/fs/aufs/hbl.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2017-2020 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..db3a2605521b ---- /dev/null -+++ b/fs/aufs/hfsnotify.c -@@ -0,0 +1,275 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c -new file mode 100644 -index 000000000000..3d4fed48bf16 ---- /dev/null -+++ b/fs/aufs/hfsplus.c -@@ -0,0 +1,47 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2010-2020 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 --git a/fs/aufs/hnotify.c b/fs/aufs/hnotify.c -new file mode 100644 -index 000000000000..ea1060fb7de0 ---- /dev/null -+++ b/fs/aufs/hnotify.c -@@ -0,0 +1,702 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c -new file mode 100644 -index 000000000000..42bc497e2630 ---- /dev/null -+++ b/fs/aufs/i_op.c -@@ -0,0 +1,1489 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 Junjiro R. Okajima -+ */ -+ -+/* -+ * inode operations (except add/del/rename) -+ */ -+ -+#include -+#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)); -+ -+ 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. -+ */ -+ 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_inode, mask); -+ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) -+ err = h_inode->i_op->permission(h_inode, mask); -+ AuTraceErr(err); -+ } else { -+ /* AuLabel(h_inode->permission); */ -+ err = h_inode->i_op->permission(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 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 dentry *dentry, struct iattr *ia) -+{ -+ int err; -+ struct inode *inode, *delegated; -+ struct super_block *sb; -+ struct file *file; -+ struct au_icpup_args *a; -+ -+ inode = d_inode(dentry); -+ IMustLock(inode); -+ -+ err = setattr_prepare(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)) -+ err = vfsub_acl_chmod(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; -+ -+ 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; -+ -+ inode_unlock(a->h_inode); -+ switch (arg->type) { -+ case AU_XATTR_SET: -+ AuDebugOn(d_is_negative(h_path.dentry)); -+ err = vfsub_setxattr(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_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(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(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 --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c -new file mode 100644 -index 000000000000..853c99e200da ---- /dev/null -+++ b/fs/aufs/i_op_add.c -@@ -0,0 +1,923 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 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 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 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 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 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_parent = au_h_dptr(parent, bindex); -+ h_dentry = vfs_tmpfile(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 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 --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c -new file mode 100644 -index 000000000000..05f5d4219b41 ---- /dev/null -+++ b/fs/aufs/i_op_del.c -@@ -0,0 +1,500 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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; -+ -+ 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; -+ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1) -+ && au_test_h_perm(d_inode(h_parent), -+ MAY_EXEC | MAY_WRITE))) -+ goto out; -+ -+ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent); -+ 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 --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c -new file mode 100644 -index 000000000000..37c52390034a ---- /dev/null -+++ b/fs/aufs/i_op_ren.c -@@ -0,0 +1,1237 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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; -+ -+ a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, -+ a->src_h_parent); -+ 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; -+ -+ a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, -+ a->dst_h_parent); -+ 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 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 --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c -new file mode 100644 -index 000000000000..5a837d7d0a33 ---- /dev/null -+++ b/fs/aufs/iinfo.c -@@ -0,0 +1,273 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/inode.c b/fs/aufs/inode.c -new file mode 100644 -index 000000000000..c071e525f499 ---- /dev/null -+++ b/fs/aufs/inode.c -@@ -0,0 +1,516 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 inode *h_inode, int mask) -+{ -+ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) -+ return 0; -+ return inode_permission(h_inode, mask); -+} -+ -+int au_test_h_perm_sio(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_inode, mask); -+} -diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h -new file mode 100644 -index 000000000000..7f1992a3ef5c ---- /dev/null -+++ b/fs/aufs/inode.h -@@ -0,0 +1,685 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 inode *h_inode, int mask); -+int au_test_h_perm_sio(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 inode *dir, struct dentry *dentry, umode_t mode, -+ dev_t dev); -+int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); -+int aufs_create(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 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 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 inode *src_dir, struct dentry *src_dentry, -+ struct inode *dir, struct dentry *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 dentry *h_dst, struct dentry *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 dentry *h_dst, struct dentry *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); -+int aufs_set_acl(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 --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c -new file mode 100644 -index 000000000000..9d0e969217a9 ---- /dev/null -+++ b/fs/aufs/ioctl.c -@@ -0,0 +1,207 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/lcnt.h b/fs/aufs/lcnt.h -new file mode 100644 -index 000000000000..c7db43d9e260 ---- /dev/null -+++ b/fs/aufs/lcnt.h -@@ -0,0 +1,173 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2018-2020 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 --git a/fs/aufs/loop.c b/fs/aufs/loop.c -new file mode 100644 -index 000000000000..a8b63acc6204 ---- /dev/null -+++ b/fs/aufs/loop.c -@@ -0,0 +1,135 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/loop.h b/fs/aufs/loop.h -new file mode 100644 -index 000000000000..94f4f80ae33b ---- /dev/null -+++ b/fs/aufs/loop.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk -new file mode 100644 -index 000000000000..7bc9eef3ffec ---- /dev/null -+++ b/fs/aufs/magic.mk -@@ -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 --git a/fs/aufs/module.c b/fs/aufs/module.c -new file mode 100644 -index 000000000000..18039801580f ---- /dev/null -+++ b/fs/aufs/module.c -@@ -0,0 +1,259 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/module.h b/fs/aufs/module.h -new file mode 100644 -index 000000000000..cf4679c65542 ---- /dev/null -+++ b/fs/aufs/module.h -@@ -0,0 +1,153 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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) - kmalloc_index(new_sz); -+#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 --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c -new file mode 100644 -index 000000000000..d28a33f4a944 ---- /dev/null -+++ b/fs/aufs/mvdown.c -@@ -0,0 +1,693 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2011-2020 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 --git a/fs/aufs/opts.c b/fs/aufs/opts.c -new file mode 100644 -index 000000000000..26ecf5604117 ---- /dev/null -+++ b/fs/aufs/opts.c -@@ -0,0 +1,1867 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 Junjiro R. Okajima -+ */ -+ -+/* -+ * mount options/flags -+ */ -+ -+#include -+#include /* a distribution requires */ -+#include -+#include "aufs.h" -+ -+/* ---------------------------------------------------------------------- */ -+ -+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_rdblk_def, Opt_rdhash_def, -+ Opt_xino, Opt_noxino, -+ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, -+ Opt_trunc_xino_path, Opt_itrunc_xino, -+ Opt_trunc_xib, Opt_notrunc_xib, -+ Opt_shwh, Opt_noshwh, -+ Opt_plink, Opt_noplink, Opt_list_plink, -+ Opt_udba, -+ Opt_dio, Opt_nodio, -+ Opt_diropq_a, Opt_diropq_w, -+ Opt_warn_perm, Opt_nowarn_perm, -+ Opt_wbr_copyup, Opt_wbr_create, -+ Opt_fhsm_sec, -+ Opt_verbose, Opt_noverbose, -+ Opt_sum, Opt_nosum, Opt_wsum, -+ Opt_dirperm1, Opt_nodirperm1, -+ Opt_dirren, Opt_nodirren, -+ Opt_acl, Opt_noacl, -+ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err -+}; -+ -+static match_table_t options = { -+ {Opt_br, "br=%s"}, -+ {Opt_br, "br:%s"}, -+ -+ {Opt_add, "add=%d:%s"}, -+ {Opt_add, "add:%d:%s"}, -+ {Opt_add, "ins=%d:%s"}, -+ {Opt_add, "ins:%d:%s"}, -+ {Opt_append, "append=%s"}, -+ {Opt_append, "append:%s"}, -+ {Opt_prepend, "prepend=%s"}, -+ {Opt_prepend, "prepend:%s"}, -+ -+ {Opt_del, "del=%s"}, -+ {Opt_del, "del:%s"}, -+ /* {Opt_idel, "idel:%d"}, */ -+ {Opt_mod, "mod=%s"}, -+ {Opt_mod, "mod:%s"}, -+ /* {Opt_imod, "imod:%d:%s"}, */ -+ -+ {Opt_dirwh, "dirwh=%d"}, -+ -+ {Opt_xino, "xino=%s"}, -+ {Opt_noxino, "noxino"}, -+ {Opt_trunc_xino, "trunc_xino"}, -+ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, -+ {Opt_notrunc_xino, "notrunc_xino"}, -+ {Opt_trunc_xino_path, "trunc_xino=%s"}, -+ {Opt_itrunc_xino, "itrunc_xino=%d"}, -+ /* {Opt_zxino, "zxino=%s"}, */ -+ {Opt_trunc_xib, "trunc_xib"}, -+ {Opt_notrunc_xib, "notrunc_xib"}, -+ -+#ifdef CONFIG_PROC_FS -+ {Opt_plink, "plink"}, -+#else -+ {Opt_ignore_silent, "plink"}, -+#endif -+ -+ {Opt_noplink, "noplink"}, -+ -+#ifdef CONFIG_AUFS_DEBUG -+ {Opt_list_plink, "list_plink"}, -+#endif -+ -+ {Opt_udba, "udba=%s"}, -+ -+ {Opt_dio, "dio"}, -+ {Opt_nodio, "nodio"}, -+ -+#ifdef CONFIG_AUFS_DIRREN -+ {Opt_dirren, "dirren"}, -+ {Opt_nodirren, "nodirren"}, -+#else -+ {Opt_ignore, "dirren"}, -+ {Opt_ignore_silent, "nodirren"}, -+#endif -+ -+#ifdef CONFIG_AUFS_FHSM -+ {Opt_fhsm_sec, "fhsm_sec=%d"}, -+#else -+ {Opt_ignore, "fhsm_sec=%d"}, -+#endif -+ -+ {Opt_diropq_a, "diropq=always"}, -+ {Opt_diropq_a, "diropq=a"}, -+ {Opt_diropq_w, "diropq=whiteouted"}, -+ {Opt_diropq_w, "diropq=w"}, -+ -+ {Opt_warn_perm, "warn_perm"}, -+ {Opt_nowarn_perm, "nowarn_perm"}, -+ -+ /* keep them temporary */ -+ {Opt_ignore_silent, "nodlgt"}, -+ {Opt_ignore, "clean_plink"}, -+ -+#ifdef CONFIG_AUFS_SHWH -+ {Opt_shwh, "shwh"}, -+#endif -+ {Opt_noshwh, "noshwh"}, -+ -+ {Opt_dirperm1, "dirperm1"}, -+ {Opt_nodirperm1, "nodirperm1"}, -+ -+ {Opt_verbose, "verbose"}, -+ {Opt_verbose, "v"}, -+ {Opt_noverbose, "noverbose"}, -+ {Opt_noverbose, "quiet"}, -+ {Opt_noverbose, "q"}, -+ {Opt_noverbose, "silent"}, -+ -+ {Opt_sum, "sum"}, -+ {Opt_nosum, "nosum"}, -+ {Opt_wsum, "wsum"}, -+ -+ {Opt_rdcache, "rdcache=%d"}, -+ {Opt_rdblk, "rdblk=%d"}, -+ {Opt_rdblk_def, "rdblk=def"}, -+ {Opt_rdhash, "rdhash=%d"}, -+ {Opt_rdhash_def, "rdhash=def"}, -+ -+ {Opt_wbr_create, "create=%s"}, -+ {Opt_wbr_create, "create_policy=%s"}, -+ {Opt_wbr_copyup, "cpup=%s"}, -+ {Opt_wbr_copyup, "copyup=%s"}, -+ {Opt_wbr_copyup, "copyup_policy=%s"}, -+ -+ /* generic VFS flag */ -+#ifdef CONFIG_FS_POSIX_ACL -+ {Opt_acl, "acl"}, -+ {Opt_noacl, "noacl"}, -+#else -+ {Opt_ignore, "acl"}, -+ {Opt_ignore_silent, "noacl"}, -+#endif -+ -+ /* internal use for the scripts */ -+ {Opt_ignore_silent, "si=%s"}, -+ -+ {Opt_br, "dirs=%s"}, -+ {Opt_ignore, "debug=%d"}, -+ {Opt_ignore, "delete=whiteout"}, -+ {Opt_ignore, "delete=all"}, -+ {Opt_ignore, "imap=%s"}, -+ -+ /* temporary workaround, due to old mount(8)? */ -+ {Opt_ignore_silent, "relatime"}, -+ -+ {Opt_err, NULL} -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+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; -+} -+ -+static int noinline_for_stack 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} -+}; -+ -+static int noinline_for_stack 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; -+} -+ -+static int noinline_for_stack -+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} -+}; -+ -+static int noinline_for_stack 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); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; -+ -+static void dump_opts(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: -+ case Opt_idel: -+ u.del = &opt->del; -+ AuDbg("del {%s, %p}\n", -+ u.del->pathname, u.del->h_path.dentry); -+ break; -+ case Opt_mod: -+ 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 %u\n", opt->rdblk); -+ break; -+ case Opt_rdblk_def: -+ AuDbg("rdblk_def\n"); -+ break; -+ case Opt_rdhash: -+ AuDbg("rdhash %u\n", opt->rdhash); -+ break; -+ case Opt_rdhash_def: -+ AuDbg("rdhash_def\n"); -+ break; -+ case Opt_xino: -+ u.xino = &opt->xino; -+ AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); -+ break; -+ case Opt_trunc_xino: -+ AuLabel(trunc_xino); -+ break; -+ case Opt_notrunc_xino: -+ AuLabel(notrunc_xino); -+ break; -+ case Opt_trunc_xino_path: -+ 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_trunc_xib: -+ AuLabel(trunc_xib); -+ break; -+ case Opt_notrunc_xib: -+ AuLabel(notrunc_xib); -+ break; -+ case Opt_shwh: -+ AuLabel(shwh); -+ break; -+ case Opt_noshwh: -+ AuLabel(noshwh); -+ break; -+ case Opt_dirperm1: -+ AuLabel(dirperm1); -+ break; -+ case Opt_nodirperm1: -+ AuLabel(nodirperm1); -+ break; -+ case Opt_plink: -+ AuLabel(plink); -+ break; -+ case Opt_noplink: -+ AuLabel(noplink); -+ 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_dio: -+ AuLabel(dio); -+ break; -+ case Opt_nodio: -+ AuLabel(nodio); -+ break; -+ case Opt_diropq_a: -+ AuLabel(diropq_a); -+ break; -+ case Opt_diropq_w: -+ AuLabel(diropq_w); -+ break; -+ case Opt_warn_perm: -+ AuLabel(warn_perm); -+ break; -+ case Opt_nowarn_perm: -+ AuLabel(nowarn_perm); -+ break; -+ case Opt_verbose: -+ AuLabel(verbose); -+ break; -+ case Opt_noverbose: -+ AuLabel(noverbose); -+ break; -+ case Opt_sum: -+ AuLabel(sum); -+ break; -+ case Opt_nosum: -+ AuLabel(nosum); -+ 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: -+ case AuWbrCreate_PMFSV: -+ AuDbg("%d sec\n", u.create->mfs_second); -+ break; -+ case AuWbrCreate_MFSRR: -+ case AuWbrCreate_TDMFS: -+ AuDbg("%llu watermark\n", -+ u.create->mfsrr_watermark); -+ break; -+ case AuWbrCreate_MFSRRV: -+ case AuWbrCreate_TDMFSV: -+ 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; -+ case Opt_dirren: -+ AuLabel(dirren); -+ break; -+ case Opt_nodirren: -+ AuLabel(nodirren); -+ break; -+ case Opt_acl: -+ AuLabel(acl); -+ break; -+ case Opt_noacl: -+ AuLabel(noacl); -+ break; -+ default: -+ BUG(); -+ } -+ opt++; -+ } -+#endif -+} -+ -+void au_opts_free(struct au_opts *opts) -+{ -+ struct au_opt *opt; -+ -+ opt = opts->opt; -+ while (opt->type != Opt_tail) { -+ switch (opt->type) { -+ case Opt_add: -+ case Opt_append: -+ case Opt_prepend: -+ path_put(&opt->add.path); -+ break; -+ case Opt_del: -+ case Opt_idel: -+ path_put(&opt->del.h_path); -+ break; -+ case Opt_mod: -+ case Opt_imod: -+ dput(opt->mod.h_root); -+ break; -+ case Opt_xino: -+ fput(opt->xino.file); -+ break; -+ } -+ opt++; -+ } -+} -+ -+static int 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 = br_perm_val(p); -+ } -+ -+ err = vfsub_kern_path(add->pathname, lkup_dirflags, &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_opts_parse_del(struct au_opt_del *del, substring_t args[]) -+{ -+ int err; -+ -+ del->pathname = args[0].from; -+ AuDbg("del path %s\n", del->pathname); -+ -+ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); -+ if (unlikely(err)) -+ pr_err("lookup failed %s (%d)\n", del->pathname, err); -+ -+ return err; -+} -+ -+#if 0 /* reserved for future use */ -+static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, -+ struct au_opt_del *del, substring_t args[]) -+{ -+ int err; -+ struct dentry *root; -+ -+ err = -EINVAL; -+ root = sb->s_root; -+ aufs_read_lock(root, AuLock_FLUSH); -+ if (bindex < 0 || au_sbbot(sb) < bindex) { -+ pr_err("out of bounds, %d\n", 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); -+ return err; -+} -+#endif -+ -+static int noinline_for_stack -+au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) -+{ -+ int err; -+ struct path path; -+ char *p; -+ -+ err = -EINVAL; -+ mod->path = args[0].from; -+ p = strchr(mod->path, '='); -+ if (unlikely(!p)) { -+ pr_err("no permission %s\n", args[0].from); -+ goto out; -+ } -+ -+ *p++ = 0; -+ err = vfsub_kern_path(mod->path, lkup_dirflags, &path); -+ if (unlikely(err)) { -+ pr_err("lookup failed %s (%d)\n", mod->path, err); -+ goto out; -+ } -+ -+ mod->perm = br_perm_val(p); -+ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); -+ mod->h_root = dget(path.dentry); -+ path_put(&path); -+ -+out: -+ return err; -+} -+ -+#if 0 /* reserved for future use */ -+static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, -+ struct au_opt_mod *mod, substring_t args[]) -+{ -+ int err; -+ struct dentry *root; -+ -+ err = -EINVAL; -+ root = sb->s_root; -+ aufs_read_lock(root, AuLock_FLUSH); -+ if (bindex < 0 || au_sbbot(sb) < bindex) { -+ pr_err("out of bounds, %d\n", bindex); -+ goto out; -+ } -+ -+ err = 0; -+ mod->perm = br_perm_val(args[1].from); -+ AuDbg("mod path %s, perm 0x%x, %s\n", -+ mod->path, mod->perm, args[1].from); -+ mod->h_root = dget(au_h_dptr(root, bindex)); -+ -+out: -+ aufs_read_unlock(root, !AuLock_IR); -+ return err; -+} -+#endif -+ -+static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, -+ substring_t args[]) -+{ -+ int err; -+ struct file *file; -+ -+ file = au_xino_create(sb, args[0].from, /*silent*/0, /*wbrtop*/0); -+ err = PTR_ERR(file); -+ if (IS_ERR(file)) -+ goto out; -+ -+ err = -EINVAL; -+ if (unlikely(file->f_path.dentry->d_sb == sb)) { -+ fput(file); -+ pr_err("%s must be outside\n", args[0].from); -+ goto out; -+ } -+ -+ err = 0; -+ xino->file = file; -+ xino->path = args[0].from; -+ -+out: -+ return err; -+} -+ -+static int noinline_for_stack -+au_opts_parse_xino_itrunc_path(struct super_block *sb, -+ struct au_opt_xino_itrunc *xino_itrunc, -+ substring_t args[]) -+{ -+ int err; -+ aufs_bindex_t bbot, bindex; -+ struct path path; -+ struct dentry *root; -+ -+ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); -+ if (unlikely(err)) { -+ pr_err("lookup failed %s (%d)\n", args[0].from, err); -+ goto out; -+ } -+ -+ xino_itrunc->bindex = -1; -+ root = sb->s_root; -+ aufs_read_lock(root, AuLock_FLUSH); -+ bbot = au_sbbot(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)) { -+ pr_err("no such branch %s\n", args[0].from); -+ err = -EINVAL; -+ } -+ -+out: -+ return err; -+} -+ -+/* called without aufs lock */ -+int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) -+{ -+ int err, n, token; -+ aufs_bindex_t bindex; -+ unsigned char skipped; -+ struct dentry *root; -+ struct au_opt *opt, *opt_tail; -+ char *opt_str; -+ /* reduce the stack space */ -+ union { -+ struct au_opt_xino_itrunc *xino_itrunc; -+ struct au_opt_wbr_create *create; -+ } u; -+ struct { -+ substring_t args[MAX_OPT_ARGS]; -+ } *a; -+ -+ err = -ENOMEM; -+ a = kmalloc(sizeof(*a), GFP_NOFS); -+ if (unlikely(!a)) -+ goto out; -+ -+ root = sb->s_root; -+ err = 0; -+ bindex = 0; -+ opt = opts->opt; -+ opt_tail = opt + opts->max_opt - 1; -+ opt->type = Opt_tail; -+ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { -+ err = -EINVAL; -+ skipped = 0; -+ token = match_token(opt_str, options, a->args); -+ switch (token) { -+ case Opt_br: -+ err = 0; -+ while (!err && (opt_str = strsep(&a->args[0].from, ":")) -+ && *opt_str) { -+ err = opt_add(opt, opt_str, opts->sb_flags, -+ bindex++); -+ if (unlikely(!err && ++opt > opt_tail)) { -+ err = -E2BIG; -+ break; -+ } -+ opt->type = Opt_tail; -+ skipped = 1; -+ } -+ break; -+ case Opt_add: -+ if (unlikely(match_int(&a->args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ bindex = n; -+ err = opt_add(opt, a->args[1].from, opts->sb_flags, -+ bindex); -+ if (!err) -+ opt->type = token; -+ break; -+ case Opt_append: -+ err = opt_add(opt, a->args[0].from, opts->sb_flags, -+ /*dummy bindex*/1); -+ if (!err) -+ opt->type = token; -+ break; -+ case Opt_prepend: -+ err = opt_add(opt, a->args[0].from, opts->sb_flags, -+ /*bindex*/0); -+ if (!err) -+ opt->type = token; -+ break; -+ case Opt_del: -+ err = au_opts_parse_del(&opt->del, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+#if 0 /* reserved for future use */ -+ case Opt_idel: -+ del->pathname = "(indexed)"; -+ if (unlikely(match_int(&args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ err = au_opts_parse_idel(sb, n, &opt->del, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+#endif -+ case Opt_mod: -+ err = au_opts_parse_mod(&opt->mod, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+#ifdef IMOD /* reserved for future use */ -+ case Opt_imod: -+ u.mod->path = "(indexed)"; -+ if (unlikely(match_int(&a->args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ err = au_opts_parse_imod(sb, n, &opt->mod, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+#endif -+ case Opt_xino: -+ err = au_opts_parse_xino(sb, &opt->xino, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+ -+ case Opt_trunc_xino_path: -+ err = au_opts_parse_xino_itrunc_path -+ (sb, &opt->xino_itrunc, a->args); -+ if (!err) -+ opt->type = token; -+ break; -+ -+ case Opt_itrunc_xino: -+ u.xino_itrunc = &opt->xino_itrunc; -+ if (unlikely(match_int(&a->args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ u.xino_itrunc->bindex = n; -+ aufs_read_lock(root, AuLock_FLUSH); -+ if (n < 0 || au_sbbot(sb) < n) { -+ pr_err("out of bounds, %d\n", n); -+ aufs_read_unlock(root, !AuLock_IR); -+ break; -+ } -+ aufs_read_unlock(root, !AuLock_IR); -+ err = 0; -+ opt->type = token; -+ break; -+ -+ case Opt_dirwh: -+ if (unlikely(match_int(&a->args[0], &opt->dirwh))) -+ break; -+ err = 0; -+ opt->type = token; -+ break; -+ -+ case Opt_rdcache: -+ if (unlikely(match_int(&a->args[0], &n))) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ if (unlikely(n > AUFS_RDCACHE_MAX)) { -+ pr_err("rdcache must be smaller than %d\n", -+ AUFS_RDCACHE_MAX); -+ break; -+ } -+ opt->rdcache = n; -+ err = 0; -+ opt->type = token; -+ break; -+ case Opt_rdblk: -+ if (unlikely(match_int(&a->args[0], &n) -+ || n < 0 -+ || n > KMALLOC_MAX_SIZE)) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ if (unlikely(n && n < NAME_MAX)) { -+ pr_err("rdblk must be larger than %d\n", -+ NAME_MAX); -+ break; -+ } -+ opt->rdblk = n; -+ err = 0; -+ opt->type = token; -+ break; -+ case Opt_rdhash: -+ if (unlikely(match_int(&a->args[0], &n) -+ || n < 0 -+ || n * sizeof(struct hlist_head) -+ > KMALLOC_MAX_SIZE)) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ opt->rdhash = n; -+ err = 0; -+ opt->type = token; -+ break; -+ -+ case Opt_trunc_xino: -+ case Opt_notrunc_xino: -+ case Opt_noxino: -+ case Opt_trunc_xib: -+ case Opt_notrunc_xib: -+ case Opt_shwh: -+ case Opt_noshwh: -+ case Opt_dirperm1: -+ case Opt_nodirperm1: -+ case Opt_plink: -+ case Opt_noplink: -+ case Opt_list_plink: -+ case Opt_dio: -+ case Opt_nodio: -+ case Opt_diropq_a: -+ case Opt_diropq_w: -+ case Opt_warn_perm: -+ case Opt_nowarn_perm: -+ case Opt_verbose: -+ case Opt_noverbose: -+ case Opt_sum: -+ case Opt_nosum: -+ case Opt_wsum: -+ case Opt_rdblk_def: -+ case Opt_rdhash_def: -+ case Opt_dirren: -+ case Opt_nodirren: -+ case Opt_acl: -+ case Opt_noacl: -+ err = 0; -+ opt->type = token; -+ break; -+ -+ case Opt_udba: -+ opt->udba = udba_val(a->args[0].from); -+ if (opt->udba >= 0) { -+ err = 0; -+ opt->type = token; -+ } else -+ pr_err("wrong value, %s\n", opt_str); -+ break; -+ -+ case Opt_wbr_create: -+ u.create = &opt->wbr_create; -+ u.create->wbr_create -+ = au_wbr_create_val(a->args[0].from, u.create); -+ if (u.create->wbr_create >= 0) { -+ err = 0; -+ opt->type = token; -+ } else -+ pr_err("wrong value, %s\n", opt_str); -+ break; -+ case Opt_wbr_copyup: -+ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); -+ if (opt->wbr_copyup >= 0) { -+ err = 0; -+ opt->type = token; -+ } else -+ pr_err("wrong value, %s\n", opt_str); -+ break; -+ -+ case Opt_fhsm_sec: -+ if (unlikely(match_int(&a->args[0], &n) -+ || n < 0)) { -+ pr_err("bad integer in %s\n", opt_str); -+ break; -+ } -+ if (sysaufs_brs) { -+ opt->fhsm_second = n; -+ opt->type = token; -+ } else -+ pr_warn("ignored %s\n", opt_str); -+ err = 0; -+ break; -+ -+ case Opt_ignore: -+ pr_warn("ignored %s\n", opt_str); -+ fallthrough; -+ case Opt_ignore_silent: -+ skipped = 1; -+ err = 0; -+ break; -+ case Opt_err: -+ pr_err("unknown option %s\n", opt_str); -+ break; -+ } -+ -+ if (!err && !skipped) { -+ if (unlikely(++opt > opt_tail)) { -+ err = -E2BIG; -+ opt--; -+ opt->type = Opt_tail; -+ break; -+ } -+ opt->type = Opt_tail; -+ } -+ } -+ -+ au_kfree_rcu(a); -+ dump_opts(opts); -+ if (unlikely(err)) -+ au_opts_free(opts); -+ -+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: -+ au_opt_set(sbinfo->si_mntflags, PLINK); -+ break; -+ case Opt_noplink: -+ 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: -+ au_opt_set(sbinfo->si_mntflags, DIO); -+ au_fset_opts(opts->flags, REFRESH_DYAOP); -+ break; -+ case Opt_nodio: -+ 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: -+ au_opt_set(sbinfo->si_mntflags, WARN_PERM); -+ break; -+ case Opt_nowarn_perm: -+ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); -+ break; -+ -+ case Opt_verbose: -+ au_opt_set(sbinfo->si_mntflags, VERBOSE); -+ break; -+ case Opt_noverbose: -+ au_opt_clr(sbinfo->si_mntflags, VERBOSE); -+ break; -+ -+ case Opt_sum: -+ au_opt_set(sbinfo->si_mntflags, SUM); -+ break; -+ case Opt_wsum: -+ au_opt_clr(sbinfo->si_mntflags, SUM); -+ au_opt_set(sbinfo->si_mntflags, SUM_W); -+ break; -+ case Opt_nosum: -+ au_opt_clr(sbinfo->si_mntflags, SUM); -+ au_opt_clr(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_rdblk_def: -+ sbinfo->si_rdblk = AUFS_RDBLK_DEF; -+ break; -+ case Opt_rdhash: -+ sbinfo->si_rdhash = opt->rdhash; -+ break; -+ case Opt_rdhash_def: -+ sbinfo->si_rdhash = AUFS_RDHASH_DEF; -+ break; -+ -+ case Opt_shwh: -+ au_opt_set(sbinfo->si_mntflags, SHWH); -+ break; -+ case Opt_noshwh: -+ au_opt_clr(sbinfo->si_mntflags, SHWH); -+ break; -+ -+ case Opt_dirperm1: -+ au_opt_set(sbinfo->si_mntflags, DIRPERM1); -+ break; -+ case Opt_nodirperm1: -+ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); -+ break; -+ -+ case Opt_trunc_xino: -+ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); -+ break; -+ case Opt_notrunc_xino: -+ 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: -+ au_fset_opts(opts->flags, TRUNC_XIB); -+ break; -+ case Opt_notrunc_xib: -+ au_fclr_opts(opts->flags, TRUNC_XIB); -+ break; -+ -+ case Opt_dirren: -+ err = 1; -+ 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); -+ break; -+ case Opt_nodirren: -+ err = 1; -+ 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: -+ sb->s_flags |= SB_POSIXACL; -+ break; -+ case Opt_noacl: -+ 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 (unlikely(err)) -+ break; -+ -+ *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 --git a/fs/aufs/opts.h b/fs/aufs/opts.h -new file mode 100644 -index 000000000000..5e00aeac6d21 ---- /dev/null -+++ b/fs/aufs/opts.h -@@ -0,0 +1,212 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 Junjiro R. Okajima -+ */ -+ -+/* -+ * mount options/flags -+ */ -+ -+#ifndef __AUFS_OPTS_H__ -+#define __AUFS_OPTS_H__ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+struct file; -+ -+/* ---------------------------------------------------------------------- */ -+ -+/* 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 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 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; -+ }; -+}; -+ -+/* 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 */ -+void au_optstr_br_perm(au_br_perm_str_t *str, int perm); -+const char *au_optstr_udba(int udba); -+const char *au_optstr_wbr_copyup(int wbr_copyup); -+const char *au_optstr_wbr_create(int wbr_create); -+ -+void au_opts_free(struct au_opts *opts); -+struct super_block; -+int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); -+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); -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_OPTS_H__ */ -diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c -new file mode 100644 -index 000000000000..1c67183bebfb ---- /dev/null -+++ b/fs/aufs/plink.c -@@ -0,0 +1,503 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 dentry *h_parent; -+ struct au_branch *br; -+}; -+ -+static struct dentry *au_do_plink_lkup(struct qstr *tgtname, -+ struct dentry *h_parent, -+ struct au_branch *br) -+{ -+ struct dentry *h_dentry; -+ struct inode *h_inode; -+ -+ h_inode = d_inode(h_parent); -+ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2); -+ h_dentry = vfsub_lkup_one(tgtname, h_parent); -+ 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_parent, a->br); -+} -+ -+/* 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, *h_parent; -+ struct au_branch *br; -+ 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_parent = br->br_wbr->wbr_plink; -+ 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_parent = h_parent, -+ .br = br -+ }; -+ -+ 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_parent, br); -+ -+ return h_dentry; -+} -+ -+/* create a pseudo-link */ -+static int do_whplink(struct qstr *tgt, struct dentry *h_parent, -+ struct dentry *h_dentry, struct au_branch *br) -+{ -+ int err; -+ struct path h_path = { -+ .mnt = au_br_mnt(br) -+ }; -+ struct inode *h_dir, *delegated; -+ -+ h_dir = d_inode(h_parent); -+ inode_lock_nested(h_dir, AuLsc_I_CHILD2); -+again: -+ h_path.dentry = vfsub_lkup_one(tgt, h_parent); -+ 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 dentry *h_parent; -+ struct dentry *h_dentry; -+ struct au_branch *br; -+}; -+ -+static void call_do_whplink(void *args) -+{ -+ struct do_whplink_args *a = args; -+ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); -+} -+ -+static int whplink(struct dentry *h_dentry, struct inode *inode, -+ aufs_bindex_t bindex, struct au_branch *br) -+{ -+ int err, wkq_err; -+ struct au_wbr *wbr; -+ struct dentry *h_parent; -+ char a[PLINK_NAME_LEN]; -+ struct qstr tgtname = QSTR_INIT(a, 0); -+ -+ wbr = au_sbr(inode->i_sb, bindex)->br_wbr; -+ h_parent = wbr->wbr_plink; -+ 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_parent = h_parent, -+ .h_dentry = h_dentry, -+ .br = br -+ }; -+ wkq_err = au_wkq_wait(call_do_whplink, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } else -+ err = do_whplink(&tgtname, h_parent, h_dentry, br); -+ -+ 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, au_sbr(sb, 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 --git a/fs/aufs/poll.c b/fs/aufs/poll.c -new file mode 100644 -index 000000000000..ff7697c334b4 ---- /dev/null -+++ b/fs/aufs/poll.c -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/posix_acl.c b/fs/aufs/posix_acl.c -new file mode 100644 -index 000000000000..946c2247e78d ---- /dev/null -+++ b/fs/aufs/posix_acl.c -@@ -0,0 +1,92 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2014-2020 Junjiro R. Okajima -+ */ -+ -+/* -+ * posix acl operations -+ */ -+ -+#include -+#include "aufs.h" -+ -+struct posix_acl *aufs_get_acl(struct inode *inode, int type) -+{ -+ struct posix_acl *acl; -+ int err; -+ aufs_bindex_t bindex; -+ struct inode *h_inode; -+ struct super_block *sb; -+ -+ acl = NULL; -+ sb = inode->i_sb; -+ si_read_lock(sb, AuLock_FLUSH); -+ ii_read_lock_child(inode); -+ if (!(sb->s_flags & SB_POSIXACL)) -+ goto out; -+ -+ 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 out; -+ } -+ -+ /* 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); -+ -+out: -+ ii_read_unlock(inode); -+ si_read_unlock(sb); -+ -+ AuTraceErrPtr(acl); -+ return acl; -+} -+ -+int aufs_set_acl(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 --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c -new file mode 100644 -index 000000000000..055e9bcc9af4 ---- /dev/null -+++ b/fs/aufs/procfs.c -@@ -0,0 +1,157 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2010-2020 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 --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c -new file mode 100644 -index 000000000000..bef4607f057e ---- /dev/null -+++ b/fs/aufs/rdu.c -@@ -0,0 +1,371 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h -new file mode 100644 -index 000000000000..ab5af8236699 ---- /dev/null -+++ b/fs/aufs/rwsem.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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)) -+/* rwsem_is_locked() is unusable */ -+#define AuRwMustReadLock(rw) AuDebugOn(!lockdep_recursing(current) \ -+ && debug_locks \ -+ && !lockdep_is_held_type(rw, 1)) -+#define AuRwMustWriteLock(rw) AuDebugOn(!lockdep_recursing(current) \ -+ && debug_locks \ -+ && !lockdep_is_held_type(rw, 0)) -+#define AuRwMustAnyLock(rw) AuDebugOn(!lockdep_recursing(current) \ -+ && debug_locks \ -+ && !lockdep_is_held(rw)) -+#define AuRwDestroy(rw) AuDebugOn(!lockdep_recursing(current) \ -+ && debug_locks \ -+ && lockdep_is_held(rw)) -+ -+#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 --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c -new file mode 100644 -index 000000000000..26c6afab5df6 ---- /dev/null -+++ b/fs/aufs/sbinfo.c -@@ -0,0 +1,301 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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); -+} -+ -+int au_si_alloc(struct super_block *sb) -+{ -+ int err, i; -+ struct au_sbinfo *sbinfo; -+ -+ 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; -+ sb->s_fs_info = sbinfo; -+ si_pid_set(sb); -+ return 0; /* success */ -+ -+out_br: -+ au_kfree_try_rcu(sbinfo->si_branch); -+out_sbinfo: -+ au_kfree_rcu(sbinfo); -+out: -+ return 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 --git a/fs/aufs/super.c b/fs/aufs/super.c -new file mode 100644 -index 000000000000..589dd0122020 ---- /dev/null -+++ b/fs/aufs/super.c -@@ -0,0 +1,1034 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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, wait); -+ 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; -+} -+ -+static 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); -+} -+ -+/* 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 aufs_remount_fs(struct super_block *sb, int *flags, char *data) -+{ -+ int err, do_dx; -+ unsigned int mntflags; -+ struct au_opts opts = { -+ .opt = NULL -+ }; -+ struct dentry *root; -+ struct inode *inode; -+ struct au_sbinfo *sbinfo; -+ -+ err = 0; -+ root = sb->s_root; -+ if (!data || !*data) { -+ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); -+ if (!err) { -+ di_write_lock_child(root); -+ err = au_opts_verify(sb, *flags, /*pending*/0); -+ aufs_write_unlock(root); -+ } -+ goto out; -+ } -+ -+ err = -ENOMEM; -+ opts.opt = (void *)__get_free_page(GFP_NOFS); -+ if (unlikely(!opts.opt)) -+ goto out; -+ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); -+ opts.flags = AuOpts_REMOUNT; -+ opts.sb_flags = *flags; -+ -+ /* parse it before aufs lock */ -+ err = au_opts_parse(sb, data, &opts); -+ if (unlikely(err)) -+ goto out_opts; -+ -+ sbinfo = au_sbi(sb); -+ inode = d_inode(root); -+ inode_lock(inode); -+ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); -+ if (unlikely(err)) -+ goto out_mtx; -+ di_write_lock_child(root); -+ -+ /* au_opts_remount() may return an error */ -+ err = au_opts_remount(sb, &opts); -+ au_opts_free(&opts); -+ -+ if (au_ftest_opts(opts.flags, REFRESH)) -+ au_remount_refresh(sb, au_ftest_opts(opts.flags, REFRESH_IDOP)); -+ -+ if (au_ftest_opts(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_mtx: -+ inode_unlock(inode); -+out_opts: -+ free_page((unsigned long)opts.opt); -+out: -+ err = cvt_err(err); -+ AuTraceErr(err); -+ return err; -+} -+ -+static 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, -+ .remount_fs = aufs_remount_fs -+}; -+ -+/* ---------------------------------------------------------------------- */ -+ -+static int 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 int aufs_fill_super(struct super_block *sb, void *raw_data, -+ int silent __maybe_unused) -+{ -+ int err; -+ struct au_opts opts = { -+ .opt = NULL -+ }; -+ struct au_sbinfo *sbinfo; -+ struct dentry *root; -+ struct inode *inode; -+ char *arg = raw_data; -+ -+ if (unlikely(!arg || !*arg)) { -+ err = -EINVAL; -+ pr_err("no arg\n"); -+ goto out; -+ } -+ -+ err = -ENOMEM; -+ opts.opt = (void *)__get_free_page(GFP_NOFS); -+ if (unlikely(!opts.opt)) -+ goto out; -+ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); -+ opts.sb_flags = sb->s_flags; -+ -+ err = au_si_alloc(sb); -+ if (unlikely(err)) -+ goto out_opts; -+ sbinfo = au_sbi(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 = alloc_root(sb); -+ if (unlikely(err)) { -+ si_write_unlock(sb); -+ goto out_info; -+ } -+ root = sb->s_root; -+ inode = d_inode(root); -+ -+ /* -+ * actually we can parse options regardless aufs lock here. -+ * but at remount time, parsing must be done before aufs lock. -+ * so we follow the same rule. -+ */ -+ ii_write_lock_parent(inode); -+ aufs_write_unlock(root); -+ err = au_opts_parse(sb, arg, &opts); -+ if (unlikely(err)) -+ goto out_root; -+ -+ /* lock vfs_inode first, then aufs. */ -+ inode_lock(inode); -+ aufs_write_lock(root); -+ err = au_opts_mount(sb, &opts); -+ au_opts_free(&opts); -+ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { -+ sb->s_d_op = &aufs_dop_noreval; -+ 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_opts; /* success */ -+ -+out_root: -+ dput(root); -+ sb->s_root = NULL; -+out_info: -+ kobject_put(&sbinfo->si_kobj); -+ sb->s_fs_info = NULL; -+out_opts: -+ free_page((unsigned long)opts.opt); -+out: -+ AuTraceErr(err); -+ err = cvt_err(err); -+ AuTraceErr(err); -+ return err; -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags, -+ const char *dev_name __maybe_unused, -+ void *raw_data) -+{ -+ struct dentry *root; -+ -+ /* all timestamps always follow the ones on the branch */ -+ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ -+ root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super); -+ if (IS_ERR(root)) -+ goto out; -+ -+ au_sbilist_add(root->d_sb); -+ -+out: -+ return root; -+} -+ -+static void aufs_kill_sb(struct super_block *sb) -+{ -+ struct au_sbinfo *sbinfo; -+ -+ sbinfo = au_sbi(sb); -+ if (sbinfo) { -+ au_sbilist_del(sb); -+ aufs_write_lock(sb->s_root); -+ 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); -+ au_dr_opt_flush(sb); -+ sbinfo->si_sb = NULL; -+ aufs_write_unlock(sb->s_root); -+ au_nwt_flush(&sbinfo->si_nowait); -+ } -+ 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, -+ .mount = aufs_mount, -+ .kill_sb = aufs_kill_sb, -+ /* no need to __module_get() and module_put(). */ -+ .owner = THIS_MODULE, -+}; -diff --git a/fs/aufs/super.h b/fs/aufs/super.h -new file mode 100644 -index 000000000000..f840eedbd572 ---- /dev/null -+++ b/fs/aufs/super.h -@@ -0,0 +1,574 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 */ -+extern struct file_system_type aufs_fs_type; -+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); -+ -+/* sbinfo.c */ -+void au_si_free(struct kobject *kobj); -+int 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 --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c -new file mode 100644 -index 000000000000..88d64b34555e ---- /dev/null -+++ b/fs/aufs/sysaufs.c -@@ -0,0 +1,80 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h -new file mode 100644 -index 000000000000..0d14752482cf ---- /dev/null -+++ b/fs/aufs/sysaufs.h -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c -new file mode 100644 -index 000000000000..955ed071a12a ---- /dev/null -+++ b/fs/aufs/sysfs.c -@@ -0,0 +1,338 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c -new file mode 100644 -index 000000000000..d51b95163e24 ---- /dev/null -+++ b/fs/aufs/sysrq.c -@@ -0,0 +1,136 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c -new file mode 100644 -index 000000000000..6cc7ecf0b0e1 ---- /dev/null -+++ b/fs/aufs/vdir.c -@@ -0,0 +1,883 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c -new file mode 100644 -index 000000000000..fa29c543cc28 ---- /dev/null -+++ b/fs/aufs/vfsub.c -@@ -0,0 +1,872 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 Junjiro R. Okajima -+ */ -+ -+/* -+ * sub-routines for VFS -+ */ -+ -+#include -+#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 wait) -+{ -+ int err; -+ -+ lockdep_off(); -+ down_read(&h_sb->s_umount); -+ err = __sync_filesystem(h_sb, wait); -+ 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; -+ -+ /* 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 dentry *parent, int len) -+{ -+ struct path path = { -+ .mnt = NULL -+ }; -+ -+ path.dentry = lookup_one_len_unlocked(name, parent, len); -+ if (IS_ERR(path.dentry)) -+ goto out; -+ if (d_is_positive(path.dentry)) -+ 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 dentry *parent, -+ int len) -+{ -+ struct path path = { -+ .mnt = NULL -+ }; -+ -+ /* VFS checks it too, but by WARN_ON_ONCE() */ -+ IMustLock(d_inode(parent)); -+ -+ path.dentry = lookup_one_len(name, parent, len); -+ if (IS_ERR(path.dentry)) -+ goto out; -+ if (d_is_positive(path.dentry)) -+ 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->parent); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+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; -+ -+ 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; -+ -+ lockdep_off(); -+ err = vfs_create(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; -+ -+ 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; -+ -+ lockdep_off(); -+ err = vfs_symlink(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; -+ -+ 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; -+ -+ lockdep_off(); -+ err = vfs_mknod(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; -+ -+ 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; -+ -+ lockdep_off(); -+ err = vfs_link(src_dentry, 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 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; -+ -+ lockdep_off(); -+ err = vfs_rename(src_dir, src_dentry, dir, path->dentry, -+ delegated_inode, flags); -+ 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; -+ -+ 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; -+ -+ lockdep_off(); -+ err = vfs_mkdir(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; -+ -+ IMustLock(dir); -+ -+ d = path->dentry; -+ path->dentry = d->d_parent; -+ err = security_path_rmdir(path, d); -+ path->dentry = d; -+ if (unlikely(err)) -+ goto out; -+ -+ lockdep_off(); -+ err = vfs_rmdir(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; -+ -+ 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 = locks_verify_truncate(h_inode, h_file, length); -+ if (!err) -+ err = security_path_truncate(h_path); -+ if (!err) { -+ lockdep_off(); -+ err = do_truncate(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; -+ -+ do_sio = au_test_h_perm_sio(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; -+ -+ do_sio = au_test_h_perm_sio(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; -+ -+ h_inode = d_inode(a->path->dentry); -+ IMustLock(h_inode); -+ -+ *a->errp = -EPERM; -+ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { -+ lockdep_off(); -+ *a->errp = notify_change(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; -+ 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); -+ } -+ -+ lockdep_off(); -+ *a->errp = vfs_unlink(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 --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h -new file mode 100644 -index 000000000000..7d8993052cd5 ---- /dev/null -+++ b/fs/aufs/vfsub.h -@@ -0,0 +1,341 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 wait); -+ -+/* ---------------------------------------------------------------------- */ -+ -+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 dentry *parent, int len); -+struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, -+ int len); -+ -+struct vfsub_lkup_one_args { -+ struct dentry **errp; -+ struct qstr *name; -+ struct dentry *parent; -+}; -+ -+static inline struct dentry *vfsub_lkup_one(struct qstr *name, -+ struct dentry *parent) -+{ -+ return vfsub_lookup_one_len(name->name, parent, 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 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 inode *h_inode, umode_t h_mode) -+{ -+ int err; -+ -+ err = posix_acl_chmod(h_inode, h_mode); -+ if (err == -EOPNOTSUPP) -+ err = 0; -+ return err; -+} -+#else -+AuStubInt0(vfsub_acl_chmod, 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 dentry *dentry, const char *name, -+ const void *value, size_t size, int flags) -+{ -+ int err; -+ -+ lockdep_off(); -+ err = vfs_setxattr(dentry, name, value, size, flags); -+ lockdep_on(); -+ -+ return err; -+} -+ -+static inline int vfsub_removexattr(struct dentry *dentry, const char *name) -+{ -+ int err; -+ -+ lockdep_off(); -+ err = vfs_removexattr(dentry, name); -+ lockdep_on(); -+ -+ return err; -+} -+ -+#endif /* __KERNEL__ */ -+#endif /* __AUFS_VFSUB_H__ */ -diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c -new file mode 100644 -index 000000000000..a18045b12573 ---- /dev/null -+++ b/fs/aufs/wbr_policy.c -@@ -0,0 +1,817 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/whout.c b/fs/aufs/whout.c -new file mode 100644 -index 000000000000..9363954c4b06 ---- /dev/null -+++ b/fs/aufs/whout.c -@@ -0,0 +1,1049 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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_parent. -+ * @try_sio specifies the necessary of super-io. -+ */ -+int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio) -+{ -+ int err; -+ struct dentry *wh_dentry; -+ -+ if (!try_sio) -+ wh_dentry = vfsub_lkup_one(wh_name, h_parent); -+ else -+ wh_dentry = au_sio_lkup_one(wh_name, h_parent); -+ 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_dentry sets opaque or not. -+ */ -+int au_diropq_test(struct dentry *h_dentry) -+{ -+ int err; -+ struct inode *h_dir; -+ -+ h_dir = d_inode(h_dentry); -+ err = au_wh_test(h_dentry, &diropq_name, -+ au_test_h_perm_sio(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; -+ -+ 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); -+ -+ qs.name = name; -+ for (i = 0; i < 3; i++) { -+ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); -+ dentry = au_sio_lkup_one(&qs, h_parent); -+ 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 dentry *h_parent, struct qstr *wh, -+ struct au_branch *br) -+{ -+ int err; -+ struct path h_path = { -+ .mnt = au_br_mnt(br) -+ }; -+ -+ err = 0; -+ h_path.dentry = vfsub_lkup_one(wh, h_parent); -+ if (IS_ERR(h_path.dentry)) -+ err = PTR_ERR(h_path.dentry); -+ else { -+ if (d_is_reg(h_path.dentry)) -+ err = do_unlink_wh(d_inode(h_parent), &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, *h_dentry; -+ struct super_block *sb; -+ struct au_branch *br; -+ int err; -+ -+ sb = dentry->d_sb; -+ br = au_sbr(sb, bindex); -+ h_dentry = au_h_dptr(dentry, bindex); -+ opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry); -+ 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 { -+ struct path tmp = { -+ .dentry = opq_dentry, -+ .mnt = au_br_mnt(br) -+ }; -+ err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &tmp); -+ 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; -+ -+ h_dentry = au_h_dptr(dentry, bindex); -+ if (!au_test_h_perm_sio(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; -+ -+ err = au_wh_name_alloc(&wh_name, base_name); -+ wh_dentry = ERR_PTR(err); -+ if (!err) { -+ wh_dentry = vfsub_lkup_one(&wh_name, h_parent); -+ 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 dentry *h_dentry, struct au_nhash *whlist, -+ aufs_bindex_t bindex, struct au_branch *br) -+{ -+ 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_dentry, &wh_name, br); -+ 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 dentry *h_dentry; -+ struct au_nhash *whlist; -+ aufs_bindex_t bindex; -+ struct au_branch *br; -+}; -+ -+static void call_del_wh_children(void *args) -+{ -+ struct del_wh_children_args *a = args; -+ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); -+} -+ -+/* ---------------------------------------------------------------------- */ -+ -+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 h_tmp; -+ struct inode *wh_inode, *h_dir; -+ struct au_branch *br; -+ -+ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ -+ IMustLock(h_dir); -+ -+ br = au_sbr(dir->i_sb, bindex); -+ 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(wh_inode, MAY_EXEC | MAY_WRITE)) -+ err = del_wh_children(wh_dentry, whlist, bindex, br); -+ else { -+ int wkq_err; -+ struct del_wh_children_args args = { -+ .errp = &err, -+ .h_dentry = wh_dentry, -+ .whlist = whlist, -+ .bindex = bindex, -+ .br = br -+ }; -+ -+ wkq_err = au_wkq_wait(call_del_wh_children, &args); -+ if (unlikely(wkq_err)) -+ err = wkq_err; -+ } -+ inode_unlock(wh_inode); -+ -+ if (!err) { -+ h_tmp.dentry = wh_dentry; -+ h_tmp.mnt = au_br_mnt(br); -+ h_nlink = h_dir->i_nlink; -+ err = vfsub_rmdir(h_dir, &h_tmp); -+ /* 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 --git a/fs/aufs/whout.h b/fs/aufs/whout.h -new file mode 100644 -index 000000000000..dc4eb41e70dd ---- /dev/null -+++ b/fs/aufs/whout.h -@@ -0,0 +1,73 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 dentry *h_parent, struct qstr *wh_name, int try_sio); -+int au_diropq_test(struct dentry *h_dentry); -+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 --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c -new file mode 100644 -index 000000000000..288f5cf4b200 ---- /dev/null -+++ b/fs/aufs/wkq.c -@@ -0,0 +1,359 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h -new file mode 100644 -index 000000000000..850085fdd2d2 ---- /dev/null -+++ b/fs/aufs/wkq.h -@@ -0,0 +1,76 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2005-2020 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 --git a/fs/aufs/xattr.c b/fs/aufs/xattr.c -new file mode 100644 -index 000000000000..a71145b741b1 ---- /dev/null -+++ b/fs/aufs/xattr.c -@@ -0,0 +1,343 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2014-2020 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 dentry *h_dst, struct dentry *h_src, -+ char *name, char **buf, unsigned int ignore_flags, -+ unsigned int verbose) -+{ -+ int err; -+ ssize_t ssz; -+ struct inode *h_idst; -+ -+ ssz = vfs_getxattr_alloc(h_src, 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)) -+ && (!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_idst = d_inode(h_dst); -+ inode_unlock(h_idst); -+ err = vfsub_setxattr(h_dst, 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 dentry *h_dst, struct dentry *h_src, int ignore_flags, -+ unsigned int verbose) -+{ -+ int err, unlocked, acl_access, acl_default; -+ ssize_t ssz; -+ 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_isrc = d_inode(h_src); -+ h_idst = d_inode(h_dst); -+ 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, 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, 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(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 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 --git a/fs/aufs/xino.c b/fs/aufs/xino.c -new file mode 100644 -index 000000000000..753e92a3d6d7 ---- /dev/null -+++ b/fs/aufs/xino.c -@@ -0,0 +1,1912 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2005-2020 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 == 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, *parent; -+ struct inode *dir, *delegated; -+ struct qstr *name; -+ struct path path; -+ int err, do_unlock; -+ struct au_xino_lock_dir ldir; -+ -+ do_unlock = 1; -+ au_xino_lock_dir(sb, base, &ldir); -+ dentry = base->dentry; -+ parent = dentry->d_parent; /* dir inode is locked */ -+ dir = d_inode(parent); -+ IMustLock(dir); -+ -+ name = &dentry->d_name; -+ path.dentry = vfsub_lookup_one_len(name->name, parent, 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(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 --git a/fs/dcache.c b/fs/dcache.c -index ea0485861d93..ddca6240e0db 100644 ---- a/fs/dcache.c -+++ b/fs/dcache.c -@@ -1285,7 +1285,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 19ac5baad50f..073ca6af500f 100644 ---- a/fs/fcntl.c -+++ b/fs/fcntl.c -@@ -32,7 +32,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; -@@ -63,6 +63,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/inode.c b/fs/inode.c -index 9d78c37b00b8..e7f0c614a58f 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -1770,7 +1770,7 @@ EXPORT_SYMBOL(generic_update_time); - * This does the actual work of updating an inodes time or version. Must have - * had called mnt_want_write() before calling this. - */ --static int update_time(struct inode *inode, struct timespec64 *time, int flags) -+int update_time(struct inode *inode, struct timespec64 *time, int flags) - { - if (inode->i_op->update_time) - return inode->i_op->update_time(inode, time, flags); -diff --git a/fs/namespace.c b/fs/namespace.c -index cebaa3e81794..451dee24a546 100644 ---- a/fs/namespace.c -+++ b/fs/namespace.c -@@ -792,6 +792,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/proc/base.c b/fs/proc/base.c -index b362523a9829..669448bb8a73 100644 ---- a/fs/proc/base.c -+++ b/fs/proc/base.c -@@ -2184,7 +2184,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 ee5a235b3056..80a46dcede7b 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; -@@ -1855,7 +1858,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/fs/splice.c b/fs/splice.c -index 866d5c2367b2..55b535626208 100644 ---- a/fs/splice.c -+++ b/fs/splice.c -@@ -756,8 +756,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"); -@@ -767,9 +767,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) - { - int ret; - -diff --git a/fs/sync.c b/fs/sync.c -index 1373a610dc78..b7b5a0a0df6f 100644 ---- a/fs/sync.c -+++ b/fs/sync.c -@@ -28,7 +28,7 @@ - * wait == 1 case since in that case write_inode() functions do - * sync_dirty_buffer() and thus effectively write one block at a time. - */ --static int __sync_filesystem(struct super_block *sb, int wait) -+int __sync_filesystem(struct super_block *sb, int wait) - { - if (wait) - sync_inodes_sb(sb); -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 8667d0cdc71e..837dd6e727e4 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -1332,6 +1332,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); -@@ -1843,6 +1844,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); -@@ -2328,6 +2330,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; -@@ -2564,6 +2567,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 f5594879175a..93bb86198167 100644 ---- a/include/linux/lockdep.h -+++ b/include/linux/lockdep.h -@@ -241,6 +241,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. - * -@@ -375,6 +377,7 @@ static inline void lockdep_unregister_key(struct lock_class_key *key) - - #define lockdep_depth(tsk) (0) - -+#define lockdep_is_held(lock) (1) - #define lockdep_is_held_type(l, r) (1) - - #define lockdep_assert_held(l) do { (void)(l); } while (0) -diff --git a/include/linux/mm.h b/include/linux/mm.h -index db6ae4d3fb4e..1a632192d9d9 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -1712,6 +1712,28 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, - unmap_mapping_range(mapping, holebegin, holelen, 0); - } - -+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 */ -+ - 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 5a9238f6caad..ad387c3cb14f 100644 ---- a/include/linux/mm_types.h -+++ b/include/linux/mm_types.h -@@ -280,6 +280,7 @@ 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 */ -+ struct file *vm_prfile; /* the virtual backing file or NULL */ - - int vm_usage; /* region usage count (access under nommu_region_sem) */ - bool vm_icache_flushed : 1; /* true if the icache has been flushed for -@@ -359,6 +360,7 @@ 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). */ -+ struct file *vm_prfile; /* shadow of vm_file */ - void * vm_private_data; /* was vm_pte (shared mem) */ - - #ifdef CONFIG_SWAP -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/include/uapi/linux/aufs_type.h b/include/uapi/linux/aufs_type.h -new file mode 100644 -index 000000000000..a1f4e7081d06 ---- /dev/null -+++ b/include/uapi/linux/aufs_type.h -@@ -0,0 +1,439 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * Copyright (C) 2005-2020 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.x-rcN" -+ -+/* 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/fork.c b/kernel/fork.c -index 6d266388d380..dd7f13c3bee7 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -554,7 +554,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, - struct inode *inode = file_inode(file); - struct address_space *mapping = file->f_mapping; - -- get_file(file); -+ vma_get_file(tmp); - if (tmp->vm_flags & VM_DENYWRITE) - put_write_access(inode); - i_mmap_lock_write(mapping); -diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c -index c1418b47f625..7f006a47790c 100644 ---- a/kernel/locking/lockdep.c -+++ b/kernel/locking/lockdep.c -@@ -188,7 +188,7 @@ static - struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; - static 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; - -@@ -209,6 +209,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/mm/Makefile b/mm/Makefile -index d73aed0fc99c..93076a66ad6a 100644 ---- a/mm/Makefile -+++ b/mm/Makefile -@@ -52,7 +52,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ - mm_init.o percpu.o slab_common.o \ - compaction.o vmacache.o \ - interval_tree.o list_lru.o workingset.o \ -- debug.o gup.o $(mmu-y) -+ prfile.o debug.o gup.o $(mmu-y) - - # Give 'page_alloc' its own module-parameter namespace - page-alloc-y := page_alloc.o -diff --git a/mm/filemap.c b/mm/filemap.c -index 0b2067b3c328..3334207431c7 100644 ---- a/mm/filemap.c -+++ b/mm/filemap.c -@@ -2909,7 +2909,7 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) - vm_fault_t ret = VM_FAULT_LOCKED; - - sb_start_pagefault(inode->i_sb); -- file_update_time(vmf->vma->vm_file); -+ vma_file_update_time(vmf->vma); - lock_page(page); - if (page->mapping != inode->i_mapping) { - unlock_page(page); -diff --git a/mm/mmap.c b/mm/mmap.c -index 5c8b4485860d..59f2f758d77e 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -179,7 +179,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; -@@ -951,7 +951,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); -@@ -1897,8 +1897,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr, - return addr; - - unmap_and_free_vma: -+ vma_fput(vma); - vma->vm_file = NULL; -- fput(file); - - /* Undo any partial mapping done by a device driver. */ - unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); -@@ -2757,7 +2757,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); -@@ -2776,7 +2776,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)); -@@ -2969,7 +2969,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, - struct vm_area_struct *vma; - unsigned long populate = 0; - unsigned long ret = -EINVAL; -- struct file *file; -+ struct file *file, *prfile; - - pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", - current->comm, current->pid); -@@ -3044,10 +3044,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, - } - } - -- file = get_file(vma->vm_file); -+ 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); - out: - mmap_write_unlock(mm); - if (populate) -@@ -3334,7 +3351,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 0faf39b32cdb..78ecad7204c8 100644 ---- a/mm/nommu.c -+++ b/mm/nommu.c -@@ -533,7 +533,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 */ -@@ -665,7 +665,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); - } -@@ -1188,7 +1188,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; -@@ -1265,10 +1265,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..00d51187c325 ---- /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-2020 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-aufs5.15-symbol-exports.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-symbol-exports.patch deleted file mode 100644 index 32dab496c6..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-symbol-exports.patch +++ /dev/null @@ -1,260 +0,0 @@ - - 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 deleted file mode 100644 index f95f4ab698..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-aufs5.15-tristate.patch +++ /dev/null @@ -1,24 +0,0 @@ - -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 deleted file mode 100644 index 3484d64f6f..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-aufs5.15.patch +++ /dev/null @@ -1,38061 +0,0 @@ - - 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 deleted file mode 100644 index c366d5b71a..0000000000 --- a/kernel/tools/perf/files/patches/mageia/fs-procfs-do-not-list-TID-0-in-proc-pid-task.patch +++ /dev/null @@ -1,36 +0,0 @@ -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/hack-broken-rtla-cleaner.patch b/kernel/tools/perf/files/patches/mageia/hack-broken-rtla-cleaner.patch new file mode 100644 index 0000000000..09fb63d82b --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/hack-broken-rtla-cleaner.patch @@ -0,0 +1,17 @@ + tools/tracing/rtla/Makefile | 5 ----- + 1 file changed, 5 deletions(-) + +--- linux-6.1/tools/tracing/rtla/Makefile.orig ++++ linux-6.1/tools/tracing/rtla/Makefile +@@ -124,11 +124,6 @@ install: doc_install + + .PHONY: clean tarball + clean: doc_clean +- @test ! -f rtla || rm rtla +- @test ! -f rtla-static || rm rtla-static +- @test ! -f src/rtla.o || rm src/rtla.o +- @test ! -f $(TARBALL) || rm -f $(TARBALL) +- @rm -rf *~ $(OBJ) *.tar.$(CEXT) + + tarball: clean + rm -rf $(NAME)-$(VERSION) && mkdir $(NAME)-$(VERSION) diff --git a/kernel/tools/perf/files/patches/mageia/iwlwifi-cfg-Add-missing-MODULE_FIRMWARE-for-pnvm.patch b/kernel/tools/perf/files/patches/mageia/iwlwifi-cfg-Add-missing-MODULE_FIRMWARE-for-pnvm.patch new file mode 100644 index 0000000000..713de9712d --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/iwlwifi-cfg-Add-missing-MODULE_FIRMWARE-for-pnvm.patch @@ -0,0 +1,40 @@ +From: Takashi Iwai +Subject: [PATCH] iwlwifi: cfg: Add missing MODULE_FIRMWARE() for *.pnvm +Date: Wed, 5 Apr 2023 08:35:46 +0200 + +A few models require *.pnvm files while we don't declare them via +MODULE_FIRMWARE(). This resulted in the breakage of WiFi on the +system that relies on the information from modinfo (e.g. openSUSE +installer image). + +This patch adds those missing MODULE_FIRMWARE() entries for *.pnvm +files. + +Link: https://bugzilla.opensuse.org/show_bug.cgi?id=1207553 +Signed-off-by: Takashi Iwai +--- + +The fix is obviously ad hoc. + +Here I added the lines with the explicit string since *_PRE definition +contains the tailing dash and can't be used for *.pnvm file. + +Alternatively, we may put a single line + MODULE_FIRMWARE("iwlwifi-*.pnvm"); +to catch all, too. + + drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +index 3bdd6774716d..3c6dc3601784 100644 +--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c ++++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +@@ -426,3 +426,7 @@ + MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); + MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); + MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); ++ ++MODULE_FIRMWARE("iwlwifi-so-a0-gf4-a0.pnvm"); ++MODULE_FIRMWARE("iwlwifi-so-a0-gf-a0.pnvm"); ++MODULE_FIRMWARE("iwlwifi-ty-a0-gf-a0.pnvm"); diff --git a/kernel/tools/perf/files/patches/mageia/lib-zstd-Fix-comment-typo.patch b/kernel/tools/perf/files/patches/mageia/lib-zstd-Fix-comment-typo.patch new file mode 100644 index 0000000000..41837b1014 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/lib-zstd-Fix-comment-typo.patch @@ -0,0 +1,29 @@ +From 19d7df98472851e1d2d11e00c177988d0f49683d Mon Sep 17 00:00:00 2001 +From: Xin Gao +Date: Mon, 17 Oct 2022 15:18:59 -0700 +Subject: [PATCH 4/6] lib: zstd: Fix comment typo + +The double `when' is duplicated in line 999, remove one. + +Signed-off-by: Xin Gao +Signed-off-by: Nick Terrell +--- + lib/zstd/decompress/zstd_decompress.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/zstd/decompress/zstd_decompress.c b/lib/zstd/decompress/zstd_decompress.c +index b4d81d84479a..6928e85f9d19 100644 +--- a/lib/zstd/decompress/zstd_decompress.c ++++ b/lib/zstd/decompress/zstd_decompress.c +@@ -996,7 +996,7 @@ size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t sr + size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; } + + /* +- * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed, ++ * Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, + * we allow taking a partial block as the input. Currently only raw uncompressed blocks can + * be streamed. + * +-- +2.30.6 + diff --git a/kernel/tools/perf/files/patches/mageia/lib-zstd-clean-up-double-word-in-comment.patch b/kernel/tools/perf/files/patches/mageia/lib-zstd-clean-up-double-word-in-comment.patch new file mode 100644 index 0000000000..4290a3c352 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/lib-zstd-clean-up-double-word-in-comment.patch @@ -0,0 +1,38 @@ +From 88a309465b3f05a100c3b81966982c0f9f5d23a6 Mon Sep 17 00:00:00 2001 +From: Tom Rix +Date: Thu, 20 Jan 2022 05:20:06 -0800 +Subject: [PATCH 1/6] lib: zstd: clean up double word in comment. + +Remove the second 'a' and 'into'. + +Signed-off-by: Tom Rix +Signed-off-by: Nick Terrell +--- + include/linux/zstd_lib.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/zstd_lib.h b/include/linux/zstd_lib.h +index b8c7dbf98390..6b91758b61af 100644 +--- a/include/linux/zstd_lib.h ++++ b/include/linux/zstd_lib.h +@@ -1330,7 +1330,7 @@ ZSTDLIB_API size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, + + /*! ZSTD_mergeBlockDelimiters() : + * Given an array of ZSTD_Sequence, remove all sequences that represent block delimiters/last literals +- * by merging them into into the literals of the next sequence. ++ * by merging them into the literals of the next sequence. + * + * As such, the final generated result has no explicit representation of block boundaries, + * and the final last literals segment is not represented in the sequences. +@@ -1377,7 +1377,7 @@ ZSTDLIB_API size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size + /*! ZSTD_writeSkippableFrame() : + * Generates a zstd skippable frame containing data given by src, and writes it to dst buffer. + * +- * Skippable frames begin with a a 4-byte magic number. There are 16 possible choices of magic number, ++ * Skippable frames begin with a 4-byte magic number. There are 16 possible choices of magic number, + * ranging from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15. + * As such, the parameter magicVariant controls the exact skippable frame magic number variant used, so + * the magic number used will be ZSTD_MAGIC_SKIPPABLE_START + magicVariant. +-- +2.30.6 + diff --git a/kernel/tools/perf/files/patches/mageia/lib-zstd-fix-repeated-words-in-comments.patch b/kernel/tools/perf/files/patches/mageia/lib-zstd-fix-repeated-words-in-comments.patch new file mode 100644 index 0000000000..cce0a6a19e --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/lib-zstd-fix-repeated-words-in-comments.patch @@ -0,0 +1,29 @@ +From 7486f5c6e7b197400678f1bb603ac9e4027fb830 Mon Sep 17 00:00:00 2001 +From: Jilin Yuan +Date: Fri, 2 Sep 2022 09:32:12 +0800 +Subject: [PATCH 3/6] lib: zstd: fix repeated words in comments + +Delete the redundant word 'the'. + +Signed-off-by: Jilin Yuan +Signed-off-by: Nick Terrell +--- + lib/zstd/compress/zstd_compress.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/zstd/compress/zstd_compress.c b/lib/zstd/compress/zstd_compress.c +index a4e916008b3a..73fff4c60149 100644 +--- a/lib/zstd/compress/zstd_compress.c ++++ b/lib/zstd/compress/zstd_compress.c +@@ -4441,7 +4441,7 @@ static size_t ZSTD_validateSequence(U32 offCode, U32 matchLength, + size_t posInSrc, U32 windowLog, size_t dictSize, U32 minMatch) { + size_t offsetBound; + U32 windowSize = 1 << windowLog; +- /* posInSrc represents the amount of data the the decoder would decode up to this point. ++ /* posInSrc represents the amount of data the decoder would decode up to this point. + * As long as the amount of data decoded is less than or equal to window size, offsets may be + * larger than the total length of output decoded in order to reference the dict, even larger than + * window size. After output surpasses windowSize, we're limited to windowSize offsets again. +-- +2.30.6 + diff --git a/kernel/tools/perf/files/patches/mageia/mmc-sdio-Add-rename-SDIO-ID-of-the-RTL8723DS-SDIO-wi.patch b/kernel/tools/perf/files/patches/mageia/mmc-sdio-Add-rename-SDIO-ID-of-the-RTL8723DS-SDIO-wi.patch new file mode 100644 index 0000000000..4f38f16dc6 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/mmc-sdio-Add-rename-SDIO-ID-of-the-RTL8723DS-SDIO-wi.patch @@ -0,0 +1,42 @@ +From 09fcdbd28404b7e02cc9fc4862ae5b43b76867c0 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Mon, 22 May 2023 22:24:24 +0200 +Subject: [PATCH] mmc: sdio: Add/rename SDIO ID of the RTL8723DS SDIO wifi + cards + +RTL8723DS comes in two variant and each of them has their own SDIO ID: +- 0xd723 can connect two antennas. The WiFi part is still 1x1 so the + second antenna can be dedicated to Bluetooth +- 0xd724 can only connect one antenna so it's shared between WiFi and + Bluetooth + +Add a new entry for the single antenna RTL8723DS (0xd724) which can be +found on the MangoPi MQ-Quad. Also rename the existing RTL8723DS entry +(0xd723) so it's name reflects that it's the variant with support for +two antennas. + +Reviewed-by: Ping-Ke Shih +Signed-off-by: Martin Blumenstingl +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/20230522202425.1827005-4-martin.blumenstingl@googlemail.com +--- + include/linux/mmc/sdio_ids.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h +index c653accdc7fd..7fada7a714fe 100644 +--- a/include/linux/mmc/sdio_ids.h ++++ b/include/linux/mmc/sdio_ids.h +@@ -121,7 +121,8 @@ + #define SDIO_DEVICE_ID_REALTEK_RTW8822BS 0xb822 + #define SDIO_DEVICE_ID_REALTEK_RTW8821CS 0xc821 + #define SDIO_DEVICE_ID_REALTEK_RTW8822CS 0xc822 +-#define SDIO_DEVICE_ID_REALTEK_RTW8723DS 0xd723 ++#define SDIO_DEVICE_ID_REALTEK_RTW8723DS_2ANT 0xd723 ++#define SDIO_DEVICE_ID_REALTEK_RTW8723DS_1ANT 0xd724 + #define SDIO_DEVICE_ID_REALTEK_RTW8821DS 0xd821 + + #define SDIO_VENDOR_ID_SIANO 0x039a +-- +2.41.0 + diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-pci-id-for-6235.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-pci-id-for-6235.patch new file mode 100644 index 0000000000..f34dd94215 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-iwlwifi-add-new-pci-id-for-6235.patch @@ -0,0 +1,31 @@ +From: Alex Hung +Subject: [PATCH] iwlwifi: add new pci id for 6235 +Date: Mon, 22 Mar 2021 01:11:21 -0600 + +lspci output: +Network controller [0280]: Intel Corporation Centrino Advanced-N6235 + [8086:088f] (rev 24) + Subsystem: Intel Corporation Centrino Advanced-N 6235 [8086:526a] + +Cc: stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org +Signed-off-by: Alex Hung +--- + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +index ffaf973..f85fe36 100644 +--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c ++++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +@@ -200,6 +200,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { + {IWL_PCI_DEVICE(0x088E, 0x446A, iwl6035_2agn_sff_cfg)}, + {IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)}, + {IWL_PCI_DEVICE(0x088F, 0x5260, iwl6035_2agn_cfg)}, ++ {IWL_PCI_DEVICE(0x088F, 0x526A, iwl6035_2agn_cfg)}, + + /* 105 Series */ + {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, +-- +2.7.4 + + diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-6.2-git.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-6.2-git.patch new file mode 100644 index 0000000000..e13bb5d884 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-6.2-git.patch @@ -0,0 +1,2377 @@ + + drivers/net/wireless/realtek/rtw88/Kconfig | 47 +++++++++ + drivers/net/wireless/realtek/rtw88/Makefile | 15 +++ + drivers/net/wireless/realtek/rtw88/coex.c | 3 + drivers/net/wireless/realtek/rtw88/debug.c | 15 +++ + drivers/net/wireless/realtek/rtw88/fw.c | 31 +++--- + drivers/net/wireless/realtek/rtw88/fw.h | 11 ++ + drivers/net/wireless/realtek/rtw88/hci.h | 9 - + drivers/net/wireless/realtek/rtw88/mac.c | 21 ++++ + drivers/net/wireless/realtek/rtw88/mac80211.c | 2 + drivers/net/wireless/realtek/rtw88/main.c | 12 +- + drivers/net/wireless/realtek/rtw88/main.h | 12 +- + drivers/net/wireless/realtek/rtw88/phy.c | 6 - + drivers/net/wireless/realtek/rtw88/ps.c | 2 + drivers/net/wireless/realtek/rtw88/reg.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8723d.c | 28 +++++ + drivers/net/wireless/realtek/rtw88/rtw8723d.h | 13 ++ + drivers/net/wireless/realtek/rtw88/rtw8723du.c | 36 +++++++ + drivers/net/wireless/realtek/rtw88/rtw8821c.c | 18 +++ + drivers/net/wireless/realtek/rtw88/rtw8821c.h | 21 ++++ + drivers/net/wireless/realtek/rtw88/rtw8821cu.c | 50 ++++++++++ + drivers/net/wireless/realtek/rtw88/rtw8822b.c | 19 +++ + drivers/net/wireless/realtek/rtw88/rtw8822bu.c | 90 ++++++++++++++++++ + drivers/net/wireless/realtek/rtw88/rtw8822c.c | 24 ++++ + drivers/net/wireless/realtek/rtw88/rtw8822cu.c | 44 ++++++++ + drivers/net/wireless/realtek/rtw88/tx.h | 31 ++++++ + drivers/net/wireless/realtek/rtw88/usb.c | 911 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/wireless/realtek/rtw88/usb.h | 107 +++++++++++++++++++++ + drivers/net/wireless/realtek/rtw88/util.c | 103 ++++++++++++++++++++ + drivers/net/wireless/realtek/rtw88/util.h | 12 +- + 29 files changed, 1650 insertions(+), 44 deletions(-) + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/coex.c linux-6.2/drivers/net/wireless/realtek/rtw88/coex.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/coex.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/coex.c 2022-12-24 00:49:25.771376835 +0200 +@@ -633,7 +633,7 @@ static struct sk_buff *rtw_coex_info_req + struct rtw_coex *coex = &rtwdev->coex; + struct sk_buff *skb_resp = NULL; + +- mutex_lock(&coex->mutex); ++ lockdep_assert_held(&rtwdev->mutex); + + rtw_fw_query_bt_mp_info(rtwdev, req); + +@@ -650,7 +650,6 @@ static struct sk_buff *rtw_coex_info_req + } + + out: +- mutex_unlock(&coex->mutex); + return skb_resp; + } + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/debug.c linux-6.2/drivers/net/wireless/realtek/rtw88/debug.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/debug.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/debug.c 2022-12-24 00:49:25.771376835 +0200 +@@ -144,7 +144,9 @@ static int rtw_debugfs_get_rf_read(struc + addr = debugfs_priv->rf_addr; + mask = debugfs_priv->rf_mask; + ++ mutex_lock(&rtwdev->mutex); + val = rtw_read_rf(rtwdev, path, addr, mask); ++ mutex_unlock(&rtwdev->mutex); + + seq_printf(m, "rf_read path:%d addr:0x%08x mask:0x%08x val=0x%08x\n", + path, addr, mask, val); +@@ -390,7 +392,9 @@ static ssize_t rtw_debugfs_set_h2c(struc + return -EINVAL; + } + ++ mutex_lock(&rtwdev->mutex); + rtw_fw_h2c_cmd_dbg(rtwdev, param); ++ mutex_unlock(&rtwdev->mutex); + + return count; + } +@@ -414,7 +418,9 @@ static ssize_t rtw_debugfs_set_rf_write( + return count; + } + ++ mutex_lock(&rtwdev->mutex); + rtw_write_rf(rtwdev, path, addr, mask, val); ++ mutex_unlock(&rtwdev->mutex); + rtw_dbg(rtwdev, RTW_DBG_DEBUGFS, + "write_rf path:%d addr:0x%08x mask:0x%08x, val:0x%08x\n", + path, addr, mask, val); +@@ -519,6 +525,8 @@ static int rtw_debug_get_rf_dump(struct + u32 addr, offset, data; + u8 path; + ++ mutex_lock(&rtwdev->mutex); ++ + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { + seq_printf(m, "RF path:%d\n", path); + for (addr = 0; addr < 0x100; addr += 4) { +@@ -533,6 +541,8 @@ static int rtw_debug_get_rf_dump(struct + seq_puts(m, "\n"); + } + ++ mutex_unlock(&rtwdev->mutex); ++ + return 0; + } + +@@ -831,7 +841,9 @@ static int rtw_debugfs_get_coex_info(str + struct rtw_debugfs_priv *debugfs_priv = m->private; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + ++ mutex_lock(&rtwdev->mutex); + rtw_coex_display_coex_info(rtwdev, m); ++ mutex_unlock(&rtwdev->mutex); + + return 0; + } +@@ -1026,6 +1038,8 @@ static void dump_gapk_status(struct rtw_ + dm_info->dm_flags & BIT(RTW_DM_CAP_TXGAPK) ? '-' : '+', + rtw_dm_cap_strs[RTW_DM_CAP_TXGAPK]); + ++ mutex_lock(&rtwdev->mutex); ++ + for (path = 0; path < rtwdev->hal.rf_path_num; path++) { + val = rtw_read_rf(rtwdev, path, RF_GAINTX, RFREG_MASK); + seq_printf(m, "path %d:\n0x%x = 0x%x\n", path, RF_GAINTX, val); +@@ -1035,6 +1049,7 @@ static void dump_gapk_status(struct rtw_ + txgapk->rf3f_fs[path][i], i); + seq_puts(m, "\n"); + } ++ mutex_unlock(&rtwdev->mutex); + } + + static int rtw_debugfs_get_dm_cap(struct seq_file *m, void *v) +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/fw.c linux-6.2/drivers/net/wireless/realtek/rtw88/fw.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/fw.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/fw.c 2022-12-24 00:49:25.771376835 +0200 +@@ -311,10 +311,10 @@ EXPORT_SYMBOL(rtw_fw_c2h_cmd_isr); + static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, + u8 *h2c) + { ++ struct rtw_h2c_cmd *h2c_cmd = (struct rtw_h2c_cmd *)h2c; + u8 box; + u8 box_state; + u32 box_reg, box_ex_reg; +- int idx; + int ret; + + rtw_dbg(rtwdev, RTW_DBG_FW, +@@ -322,7 +322,7 @@ static void rtw_fw_send_h2c_command(stru + h2c[3], h2c[2], h2c[1], h2c[0], + h2c[7], h2c[6], h2c[5], h2c[4]); + +- spin_lock(&rtwdev->h2c.lock); ++ lockdep_assert_held(&rtwdev->mutex); + + box = rtwdev->h2c.last_box_num; + switch (box) { +@@ -344,7 +344,7 @@ static void rtw_fw_send_h2c_command(stru + break; + default: + WARN(1, "invalid h2c mail box number\n"); +- goto out; ++ return; + } + + ret = read_poll_timeout_atomic(rtw_read8, box_state, +@@ -353,19 +353,14 @@ static void rtw_fw_send_h2c_command(stru + + if (ret) { + rtw_err(rtwdev, "failed to send h2c command\n"); +- goto out; ++ return; + } + +- for (idx = 0; idx < 4; idx++) +- rtw_write8(rtwdev, box_reg + idx, h2c[idx]); +- for (idx = 0; idx < 4; idx++) +- rtw_write8(rtwdev, box_ex_reg + idx, h2c[idx + 4]); ++ rtw_write32(rtwdev, box_ex_reg, le32_to_cpu(h2c_cmd->msg_ext)); ++ rtw_write32(rtwdev, box_reg, le32_to_cpu(h2c_cmd->msg)); + + if (++rtwdev->h2c.last_box_num >= 4) + rtwdev->h2c.last_box_num = 0; +- +-out: +- spin_unlock(&rtwdev->h2c.lock); + } + + void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c) +@@ -377,15 +372,13 @@ static void rtw_fw_send_h2c_packet(struc + { + int ret; + +- spin_lock(&rtwdev->h2c.lock); ++ lockdep_assert_held(&rtwdev->mutex); + + FW_OFFLOAD_H2C_SET_SEQ_NUM(h2c_pkt, rtwdev->h2c.seq); + ret = rtw_hci_write_data_h2c(rtwdev, h2c_pkt, H2C_PKT_SIZE); + if (ret) + rtw_err(rtwdev, "failed to send h2c packet\n"); + rtwdev->h2c.seq++; +- +- spin_unlock(&rtwdev->h2c.lock); + } + + void +@@ -823,6 +816,16 @@ void rtw_fw_set_nlo_info(struct rtw_dev + + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); + } ++ ++void rtw_fw_set_recover_bt_device(struct rtw_dev *rtwdev) ++{ ++ u8 h2c_pkt[H2C_PKT_SIZE] = {0}; ++ ++ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_RECOVER_BT_DEV); ++ SET_RECOVER_BT_DEV_EN(h2c_pkt, 1); ++ ++ rtw_fw_send_h2c_command(rtwdev, h2c_pkt); ++} + + void rtw_fw_set_pg_info(struct rtw_dev *rtwdev) + { +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/fw.h linux-6.2/drivers/net/wireless/realtek/rtw88/fw.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/fw.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/fw.h 2022-12-24 00:49:25.771376835 +0200 +@@ -81,6 +81,11 @@ struct rtw_c2h_adaptivity { + u8 option; + } __packed; + ++struct rtw_h2c_cmd { ++ __le32 msg; ++ __le32 msg_ext; ++} __packed; ++ + enum rtw_rsvd_packet_type { + RSVD_BEACON, + RSVD_DUMMY, +@@ -550,6 +555,8 @@ static inline void rtw_h2c_pkt_set_heade + #define H2C_CMD_AOAC_GLOBAL_INFO 0x82 + #define H2C_CMD_NLO_INFO 0x8C + ++#define H2C_CMD_RECOVER_BT_DEV 0xD1 ++ + #define SET_H2C_CMD_ID_CLASS(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(7, 0)) + +@@ -749,6 +756,9 @@ static inline void rtw_h2c_pkt_set_heade + #define SET_NLO_LOC_NLO_INFO(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16)) + ++#define SET_RECOVER_BT_DEV_EN(h2c_pkt, value) \ ++ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8)) ++ + #define GET_FW_DUMP_LEN(_header) \ + le32_get_bits(*((__le32 *)(_header) + 0x00), GENMASK(15, 0)) + #define GET_FW_DUMP_SEQ(_header) \ +@@ -838,6 +848,7 @@ void rtw_fw_set_aoac_global_info_cmd(str + u8 group_key_enc); + + void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable); ++void rtw_fw_set_recover_bt_device(struct rtw_dev *rtwdev); + void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev, + struct cfg80211_ssid *ssid); + void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/hci.h linux-6.2/drivers/net/wireless/realtek/rtw88/hci.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/hci.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/hci.h 2022-12-24 00:49:25.771376835 +0200 +@@ -166,12 +166,11 @@ static inline u32 + rtw_read_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, + u32 addr, u32 mask) + { +- unsigned long flags; + u32 val; + +- spin_lock_irqsave(&rtwdev->rf_lock, flags); ++ lockdep_assert_held(&rtwdev->mutex); ++ + val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask); +- spin_unlock_irqrestore(&rtwdev->rf_lock, flags); + + return val; + } +@@ -180,11 +179,9 @@ static inline void + rtw_write_rf(struct rtw_dev *rtwdev, enum rtw_rf_path rf_path, + u32 addr, u32 mask, u32 data) + { +- unsigned long flags; ++ lockdep_assert_held(&rtwdev->mutex); + +- spin_lock_irqsave(&rtwdev->rf_lock, flags); + rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data); +- spin_unlock_irqrestore(&rtwdev->rf_lock, flags); + } + + static inline u32 +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/Kconfig linux-6.2/drivers/net/wireless/realtek/rtw88/Kconfig +--- linux-6.1/drivers/net/wireless/realtek/rtw88/Kconfig 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/Kconfig 2022-12-24 00:49:25.770376835 +0200 +@@ -16,6 +16,9 @@ config RTW88_CORE + config RTW88_PCI + tristate + ++config RTW88_USB ++ tristate ++ + config RTW88_8822B + tristate + +@@ -39,6 +42,17 @@ config RTW88_8822BE + + 802.11ac PCIe wireless network adapter + ++config RTW88_8822BU ++ tristate "Realtek 8822BU USB wireless network adapter" ++ depends on USB ++ select RTW88_CORE ++ select RTW88_USB ++ select RTW88_8822B ++ help ++ Select this option will enable support for 8822BU chipset ++ ++ 802.11ac USB wireless network adapter ++ + config RTW88_8822CE + tristate "Realtek 8822CE PCI wireless network adapter" + depends on PCI +@@ -50,6 +64,17 @@ config RTW88_8822CE + + 802.11ac PCIe wireless network adapter + ++config RTW88_8822CU ++ tristate "Realtek 8822CU USB wireless network adapter" ++ depends on USB ++ select RTW88_CORE ++ select RTW88_USB ++ select RTW88_8822C ++ help ++ Select this option will enable support for 8822CU chipset ++ ++ 802.11ac USB wireless network adapter ++ + config RTW88_8723DE + tristate "Realtek 8723DE PCI wireless network adapter" + depends on PCI +@@ -61,6 +86,17 @@ config RTW88_8723DE + + 802.11n PCIe wireless network adapter + ++config RTW88_8723DU ++ tristate "Realtek 8723DU USB wireless network adapter" ++ depends on USB ++ select RTW88_CORE ++ select RTW88_USB ++ select RTW88_8723D ++ help ++ Select this option will enable support for 8723DU chipset ++ ++ 802.11n USB wireless network adapter ++ + config RTW88_8821CE + tristate "Realtek 8821CE PCI wireless network adapter" + depends on PCI +@@ -72,6 +108,17 @@ config RTW88_8821CE + + 802.11ac PCIe wireless network adapter + ++config RTW88_8821CU ++ tristate "Realtek 8821CU USB wireless network adapter" ++ depends on USB ++ select RTW88_CORE ++ select RTW88_USB ++ select RTW88_8821C ++ help ++ Select this option will enable support for 8821CU chipset ++ ++ 802.11ac USB wireless network adapter ++ + config RTW88_DEBUG + bool "Realtek rtw88 debug support" + depends on RTW88_CORE +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/mac80211.c linux-6.2/drivers/net/wireless/realtek/rtw88/mac80211.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/mac80211.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/mac80211.c 2022-12-24 00:49:25.772376835 +0200 +@@ -487,8 +487,8 @@ static int rtw_ops_sta_remove(struct iee + { + struct rtw_dev *rtwdev = hw->priv; + +- rtw_fw_beacon_filter_config(rtwdev, false, vif); + mutex_lock(&rtwdev->mutex); ++ rtw_fw_beacon_filter_config(rtwdev, false, vif); + rtw_sta_remove(rtwdev, sta, true); + mutex_unlock(&rtwdev->mutex); + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/mac.c linux-6.2/drivers/net/wireless/realtek/rtw88/mac.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/mac.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/mac.c 2022-12-24 00:49:25.772376835 +0200 +@@ -906,7 +906,8 @@ out: + return ret; + } + +-int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) ++static ++int _rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) + { + if (rtw_chip_wcpu_11n(rtwdev)) + return __rtw_download_firmware_legacy(rtwdev, fw); +@@ -914,6 +915,21 @@ int rtw_download_firmware(struct rtw_dev + return __rtw_download_firmware(rtwdev, fw); + } + ++int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) ++{ ++ int ret; ++ ++ ret = _rtw_download_firmware(rtwdev, fw); ++ if (ret) ++ return ret; ++ ++ if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE && ++ rtwdev->chip->id == RTW_CHIP_TYPE_8821C) ++ rtw_fw_set_recover_bt_device(rtwdev); ++ ++ return 0; ++} ++ + static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) + { + const struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn; +@@ -1032,6 +1048,9 @@ static int txdma_queue_mapping(struct rt + if (rtw_chip_wcpu_11ac(rtwdev)) + rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); + ++ if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB) ++ rtw_write8_set(rtwdev, REG_TXDMA_PQ_MAP, BIT_RXDMA_ARBBW_EN); ++ + return 0; + } + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/main.c linux-6.2/drivers/net/wireless/realtek/rtw88/main.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/main.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/main.c 2022-12-24 00:49:25.772376835 +0200 +@@ -1731,7 +1731,8 @@ static void rtw_load_firmware_cb(const s + update_firmware_info(rtwdev, fw); + complete_all(&fw->completion); + +- rtw_info(rtwdev, "Firmware version %u.%u.%u, H2C version %u\n", ++ rtw_info(rtwdev, "%sFirmware version %u.%u.%u, H2C version %u\n", ++ fw->type == RTW_WOWLAN_FW ? "WOW " : "", + fw->version, fw->sub_version, fw->sub_index, fw->h2c_version); + } + +@@ -1757,6 +1758,7 @@ static int rtw_load_firmware(struct rtw_ + return -ENOENT; + } + ++ fw->type = type; + fw->rtwdev = rtwdev; + init_completion(&fw->completion); + +@@ -1781,6 +1783,10 @@ static int rtw_chip_parameter_setup(stru + rtwdev->hci.rpwm_addr = 0x03d9; + rtwdev->hci.cpwm_addr = 0x03da; + break; ++ case RTW_HCI_TYPE_USB: ++ rtwdev->hci.rpwm_addr = 0xfe58; ++ rtwdev->hci.cpwm_addr = 0xfe57; ++ break; + default: + rtw_err(rtwdev, "unsupported hci type\n"); + return -EINVAL; +@@ -2065,13 +2071,10 @@ int rtw_core_init(struct rtw_dev *rtwdev + skb_queue_head_init(&rtwdev->coex.queue); + skb_queue_head_init(&rtwdev->tx_report.queue); + +- spin_lock_init(&rtwdev->rf_lock); +- spin_lock_init(&rtwdev->h2c.lock); + spin_lock_init(&rtwdev->txq_lock); + spin_lock_init(&rtwdev->tx_report.q_lock); + + mutex_init(&rtwdev->mutex); +- mutex_init(&rtwdev->coex.mutex); + mutex_init(&rtwdev->hal.tx_power_mutex); + + init_waitqueue_head(&rtwdev->coex.wait); +@@ -2143,7 +2146,6 @@ void rtw_core_deinit(struct rtw_dev *rtw + } + + mutex_destroy(&rtwdev->mutex); +- mutex_destroy(&rtwdev->coex.mutex); + mutex_destroy(&rtwdev->hal.tx_power_mutex); + } + EXPORT_SYMBOL(rtw_core_deinit); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/main.h linux-6.2/drivers/net/wireless/realtek/rtw88/main.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/main.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/main.h 2022-12-24 00:49:25.773376835 +0200 +@@ -871,6 +871,10 @@ struct rtw_chip_ops { + bool is_tx2_path); + void (*config_txrx_mode)(struct rtw_dev *rtwdev, u8 tx_path, + u8 rx_path, bool is_tx2_path); ++ /* for USB/SDIO only */ ++ void (*fill_txdesc_checksum)(struct rtw_dev *rtwdev, ++ struct rtw_tx_pkt_info *pkt_info, ++ u8 *txdesc); + + /* for coex */ + void (*coex_set_init)(struct rtw_dev *rtwdev); +@@ -1501,8 +1505,6 @@ struct rtw_coex_stat { + }; + + struct rtw_coex { +- /* protects coex info request section */ +- struct mutex mutex; + struct sk_buff_head queue; + wait_queue_head_t wait; + +@@ -1851,6 +1853,7 @@ struct rtw_fw_state { + u16 h2c_version; + u32 feature; + u32 feature_ext; ++ enum rtw_fw_type type; + }; + + enum rtw_sar_sources { +@@ -1994,9 +1997,6 @@ struct rtw_dev { + /* ensures exclusive access from mac80211 callbacks */ + struct mutex mutex; + +- /* read/write rf register */ +- spinlock_t rf_lock; +- + /* watch dog every 2 sec */ + struct delayed_work watch_dog_work; + u32 watch_dog_cnt; +@@ -2022,8 +2022,6 @@ struct rtw_dev { + struct { + /* incicate the mail box to use with fw */ + u8 last_box_num; +- /* protect to send h2c to fw */ +- spinlock_t lock; + u32 seq; + } h2c; + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/Makefile linux-6.2/drivers/net/wireless/realtek/rtw88/Makefile +--- linux-6.1/drivers/net/wireless/realtek/rtw88/Makefile 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/Makefile 2022-12-24 00:49:25.770376835 +0200 +@@ -26,23 +26,38 @@ rtw88_8822b-objs := rtw8822b.o rtw8822b + obj-$(CONFIG_RTW88_8822BE) += rtw88_8822be.o + rtw88_8822be-objs := rtw8822be.o + ++obj-$(CONFIG_RTW88_8822BU) += rtw88_8822bu.o ++rtw88_8822bu-objs := rtw8822bu.o ++ + obj-$(CONFIG_RTW88_8822C) += rtw88_8822c.o + rtw88_8822c-objs := rtw8822c.o rtw8822c_table.o + + obj-$(CONFIG_RTW88_8822CE) += rtw88_8822ce.o + rtw88_8822ce-objs := rtw8822ce.o + ++obj-$(CONFIG_RTW88_8822CU) += rtw88_8822cu.o ++rtw88_8822cu-objs := rtw8822cu.o ++ + obj-$(CONFIG_RTW88_8723D) += rtw88_8723d.o + rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o + + obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o + rtw88_8723de-objs := rtw8723de.o + ++obj-$(CONFIG_RTW88_8723DU) += rtw88_8723du.o ++rtw88_8723du-objs := rtw8723du.o ++ + obj-$(CONFIG_RTW88_8821C) += rtw88_8821c.o + rtw88_8821c-objs := rtw8821c.o rtw8821c_table.o + + obj-$(CONFIG_RTW88_8821CE) += rtw88_8821ce.o + rtw88_8821ce-objs := rtw8821ce.o + ++obj-$(CONFIG_RTW88_8821CU) += rtw88_8821cu.o ++rtw88_8821cu-objs := rtw8821cu.o ++ + obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o + rtw88_pci-objs := pci.o ++ ++obj-$(CONFIG_RTW88_USB) += rtw88_usb.o ++rtw88_usb-objs := usb.o +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/phy.c linux-6.2/drivers/net/wireless/realtek/rtw88/phy.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/phy.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/phy.c 2022-12-24 00:49:25.773376835 +0200 +@@ -300,7 +300,7 @@ static void rtw_phy_stat_rssi(struct rtw + + data.rtwdev = rtwdev; + data.min_rssi = U8_MAX; +- rtw_iterate_stas_atomic(rtwdev, rtw_phy_stat_rssi_iter, &data); ++ rtw_iterate_stas(rtwdev, rtw_phy_stat_rssi_iter, &data); + + dm_info->pre_min_rssi = dm_info->min_rssi; + dm_info->min_rssi = data.min_rssi; +@@ -544,7 +544,7 @@ static void rtw_phy_ra_info_update(struc + if (rtwdev->watch_dog_cnt & 0x3) + return; + +- rtw_iterate_stas_atomic(rtwdev, rtw_phy_ra_info_update_iter, rtwdev); ++ rtw_iterate_stas(rtwdev, rtw_phy_ra_info_update_iter, rtwdev); + } + + static u32 rtw_phy_get_rrsr_mask(struct rtw_dev *rtwdev, u8 rate_idx) +@@ -597,7 +597,7 @@ static void rtw_phy_rrsr_update(struct r + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + dm_info->rrsr_mask_min = RRSR_RATE_ORDER_MAX; +- rtw_iterate_stas_atomic(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev); ++ rtw_iterate_stas(rtwdev, rtw_phy_rrsr_mask_min_iter, rtwdev); + rtw_write32(rtwdev, REG_RRSR, dm_info->rrsr_val_init & dm_info->rrsr_mask_min); + } + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/ps.c linux-6.2/drivers/net/wireless/realtek/rtw88/ps.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/ps.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/ps.c 2022-12-24 00:49:25.773376835 +0200 +@@ -61,7 +61,7 @@ int rtw_leave_ips(struct rtw_dev *rtwdev + return ret; + } + +- rtw_iterate_vifs_atomic(rtwdev, rtw_restore_port_cfg_iter, rtwdev); ++ rtw_iterate_vifs(rtwdev, rtw_restore_port_cfg_iter, rtwdev); + + rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE); + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/reg.h linux-6.2/drivers/net/wireless/realtek/rtw88/reg.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/reg.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/reg.h 2022-12-24 00:49:25.773376835 +0200 +@@ -184,6 +184,7 @@ + #define BIT_TXDMA_VIQ_MAP(x) \ + (((x) & BIT_MASK_TXDMA_VIQ_MAP) << BIT_SHIFT_TXDMA_VIQ_MAP) + #define REG_TXDMA_PQ_MAP 0x010C ++#define BIT_RXDMA_ARBBW_EN BIT(0) + #define BIT_SHIFT_TXDMA_BEQ_MAP 8 + #define BIT_MASK_TXDMA_BEQ_MAP 0x3 + #define BIT_TXDMA_BEQ_MAP(x) \ +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8723d.c linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8723d.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8723d.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8723d.c 2022-12-24 00:49:25.773376835 +0200 +@@ -210,6 +210,12 @@ static void rtw8723de_efuse_parsing(stru + ether_addr_copy(efuse->addr, map->e.mac_addr); + } + ++static void rtw8723du_efuse_parsing(struct rtw_efuse *efuse, ++ struct rtw8723d_efuse *map) ++{ ++ ether_addr_copy(efuse->addr, map->u.mac_addr); ++} ++ + static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) + { + struct rtw_efuse *efuse = &rtwdev->efuse; +@@ -239,6 +245,9 @@ static int rtw8723d_read_efuse(struct rt + case RTW_HCI_TYPE_PCIE: + rtw8723de_efuse_parsing(efuse, map); + break; ++ case RTW_HCI_TYPE_USB: ++ rtw8723du_efuse_parsing(efuse, map); ++ break; + default: + /* unsupported now */ + return -ENOTSUPP; +@@ -1945,6 +1954,24 @@ static void rtw8723d_pwr_track(struct rt + dm_info->pwr_trk_triggered = false; + } + ++static void rtw8723d_fill_txdesc_checksum(struct rtw_dev *rtwdev, ++ struct rtw_tx_pkt_info *pkt_info, ++ u8 *txdesc) ++{ ++ size_t words = 32 / 2; /* calculate the first 32 bytes (16 words) */ ++ __le16 chksum = 0; ++ __le16 *data = (__le16 *)(txdesc); ++ ++ SET_TX_DESC_TXDESC_CHECKSUM(txdesc, 0x0000); ++ ++ while (words--) ++ chksum ^= *data++; ++ ++ chksum = ~chksum; ++ ++ SET_TX_DESC_TXDESC_CHECKSUM(txdesc, __le16_to_cpu(chksum)); ++} ++ + static struct rtw_chip_ops rtw8723d_ops = { + .phy_set_param = rtw8723d_phy_set_param, + .read_efuse = rtw8723d_read_efuse, +@@ -1965,6 +1992,7 @@ static struct rtw_chip_ops rtw8723d_ops + .config_bfee = NULL, + .set_gid_table = NULL, + .cfg_csi_rate = NULL, ++ .fill_txdesc_checksum = rtw8723d_fill_txdesc_checksum, + + .coex_set_init = rtw8723d_coex_cfg_init, + .coex_set_ant_switch = NULL, +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8723d.h linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8723d.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8723d.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8723d.h 2022-12-24 00:49:25.773376835 +0200 +@@ -41,6 +41,14 @@ struct rtw8723de_efuse { + u8 sub_device_id[2]; + }; + ++struct rtw8723du_efuse { ++ u8 res4[48]; /* 0xd0 */ ++ u8 vender_id[2]; /* 0x100 */ ++ u8 product_id[2]; /* 0x102 */ ++ u8 usb_option; /* 0x104 */ ++ u8 mac_addr[ETH_ALEN]; /* 0x107 */ ++}; ++ + struct rtw8723d_efuse { + __le16 rtl_id; + u8 rsvd[2]; +@@ -69,7 +77,10 @@ struct rtw8723d_efuse { + u8 rfe_option; + u8 country_code[2]; + u8 res[3]; +- struct rtw8723de_efuse e; ++ union { ++ struct rtw8723de_efuse e; ++ struct rtw8723du_efuse u; ++ }; + }; + + extern const struct rtw_chip_info rtw8723d_hw_spec; +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8723du.c linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8723du.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8723du.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8723du.c 2022-12-24 00:49:25.773376835 +0200 +@@ -0,0 +1,36 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2018-2019 Realtek Corporation ++ */ ++ ++#include ++#include ++#include "main.h" ++#include "rtw8723d.h" ++#include "usb.h" ++ ++static const struct usb_device_id rtw_8723du_id_table[] = { ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd723, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8723d_hw_spec) }, /* 8723DU 1*1 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd611, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8723d_hw_spec) }, /* Edimax EW-7611ULB V2 */ ++ { }, ++}; ++MODULE_DEVICE_TABLE(usb, rtw_8723du_id_table); ++ ++static int rtw8723du_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ return rtw_usb_probe(intf, id); ++} ++ ++static struct usb_driver rtw_8723du_driver = { ++ .name = "rtw_8723du", ++ .id_table = rtw_8723du_id_table, ++ .probe = rtw8723du_probe, ++ .disconnect = rtw_usb_disconnect, ++}; ++module_usb_driver(rtw_8723du_driver); ++ ++MODULE_AUTHOR("Hans Ulli Kroll "); ++MODULE_DESCRIPTION("Realtek 802.11n wireless 8723du driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8821c.c linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8821c.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8821c.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8821c.c 2022-12-24 00:49:25.774376835 +0200 +@@ -26,6 +26,12 @@ static void rtw8821ce_efuse_parsing(stru + ether_addr_copy(efuse->addr, map->e.mac_addr); + } + ++static void rtw8821cu_efuse_parsing(struct rtw_efuse *efuse, ++ struct rtw8821c_efuse *map) ++{ ++ ether_addr_copy(efuse->addr, map->u.mac_addr); ++} ++ + enum rtw8821ce_rf_set { + SWITCH_TO_BTG, + SWITCH_TO_WLG, +@@ -68,6 +74,9 @@ static int rtw8821c_read_efuse(struct rt + case RTW_HCI_TYPE_PCIE: + rtw8821ce_efuse_parsing(efuse, map); + break; ++ case RTW_HCI_TYPE_USB: ++ rtw8821cu_efuse_parsing(efuse, map); ++ break; + default: + /* unsupported now */ + return -ENOTSUPP; +@@ -1148,6 +1157,13 @@ static void rtw8821c_phy_cck_pd_set(stru + dm_info->cck_pd_default + new_lvl * 2); + } + ++static void rtw8821c_fill_txdesc_checksum(struct rtw_dev *rtwdev, ++ struct rtw_tx_pkt_info *pkt_info, ++ u8 *txdesc) ++{ ++ fill_txdesc_checksum_common(txdesc, 16); ++} ++ + static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { + {0x0086, + RTW_PWR_CUT_ALL_MSK, +@@ -1521,6 +1537,7 @@ static const struct rtw_rfe_def rtw8821c + [2] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), + [4] = RTW_DEF_RFE_EXT(8821c, 0, 0, 2), + [6] = RTW_DEF_RFE(8821c, 0, 0), ++ [34] = RTW_DEF_RFE(8821c, 0, 0), + }; + + static struct rtw_hw_reg rtw8821c_dig[] = { +@@ -1595,6 +1612,7 @@ static struct rtw_chip_ops rtw8821c_ops + .config_bfee = rtw8821c_bf_config_bfee, + .set_gid_table = rtw_bf_set_gid_table, + .cfg_csi_rate = rtw_bf_cfg_csi_rate, ++ .fill_txdesc_checksum = rtw8821c_fill_txdesc_checksum, + + .coex_set_init = rtw8821c_coex_cfg_init, + .coex_set_ant_switch = rtw8821c_coex_cfg_ant_switch, +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8821c.h linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8821c.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8821c.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8821c.h 2022-12-24 00:49:25.774376835 +0200 +@@ -9,6 +9,26 @@ + + #define RCR_VHT_ACK BIT(26) + ++struct rtw8821cu_efuse { ++ u8 res4[4]; /* 0xd0 */ ++ u8 usb_optional_function; ++ u8 res5[0x1e]; ++ u8 res6[2]; ++ u8 serial[0x0b]; /* 0xf5 */ ++ u8 vid; /* 0x100 */ ++ u8 res7; ++ u8 pid; ++ u8 res8[4]; ++ u8 mac_addr[ETH_ALEN]; /* 0x107 */ ++ u8 res9[2]; ++ u8 vendor_name[0x07]; ++ u8 res10[2]; ++ u8 device_name[0x14]; ++ u8 res11[0xcf]; ++ u8 package_type; /* 0x1fb */ ++ u8 res12[0x4]; ++}; ++ + struct rtw8821ce_efuse { + u8 mac_addr[ETH_ALEN]; /* 0xd0 */ + u8 vender_id[2]; +@@ -73,6 +93,7 @@ struct rtw8821c_efuse { + u8 res[3]; + union { + struct rtw8821ce_efuse e; ++ struct rtw8821cu_efuse u; + }; + }; + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8821cu.c linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8821cu.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8821cu.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8821cu.c 2022-12-24 00:49:25.774376835 +0200 +@@ -0,0 +1,50 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2018-2019 Realtek Corporation ++ */ ++ ++#include ++#include ++#include "main.h" ++#include "rtw8821c.h" ++#include "usb.h" ++ ++static const struct usb_device_id rtw_8821cu_id_table[] = { ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82b, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb820, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc821, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc820, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82a, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82b, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8821CU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc811, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8811CU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x8811, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* 8811CU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2006, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8821c_hw_spec) }, /* TOTOLINK A650UA v3 */ ++ {}, ++}; ++MODULE_DEVICE_TABLE(usb, rtw_8821cu_id_table); ++ ++static int rtw_8821cu_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ return rtw_usb_probe(intf, id); ++} ++ ++static struct usb_driver rtw_8821cu_driver = { ++ .name = "rtw_8821cu", ++ .id_table = rtw_8821cu_id_table, ++ .probe = rtw_8821cu_probe, ++ .disconnect = rtw_usb_disconnect, ++}; ++module_usb_driver(rtw_8821cu_driver); ++ ++MODULE_AUTHOR("Hans Ulli Kroll "); ++MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821cu driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8822b.c linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8822b.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8822b.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8822b.c 2022-12-24 00:49:25.774376835 +0200 +@@ -26,6 +26,12 @@ static void rtw8822be_efuse_parsing(stru + ether_addr_copy(efuse->addr, map->e.mac_addr); + } + ++static void rtw8822bu_efuse_parsing(struct rtw_efuse *efuse, ++ struct rtw8822b_efuse *map) ++{ ++ ether_addr_copy(efuse->addr, map->u.mac_addr); ++} ++ + static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) + { + struct rtw_efuse *efuse = &rtwdev->efuse; +@@ -56,6 +62,9 @@ static int rtw8822b_read_efuse(struct rt + case RTW_HCI_TYPE_PCIE: + rtw8822be_efuse_parsing(efuse, map); + break; ++ case RTW_HCI_TYPE_USB: ++ rtw8822bu_efuse_parsing(efuse, map); ++ break; + default: + /* unsupported now */ + return -ENOTSUPP; +@@ -1588,6 +1597,15 @@ static void rtw8822b_adaptivity(struct r + rtw_phy_set_edcca_th(rtwdev, l2h, h2l); + } + ++static void rtw8822b_fill_txdesc_checksum(struct rtw_dev *rtwdev, ++ struct rtw_tx_pkt_info *pkt_info, ++ u8 *txdesc) ++{ ++ size_t words = 32 / 2; /* calculate the first 32 bytes (16 words) */ ++ ++ fill_txdesc_checksum_common(txdesc, words); ++} ++ + static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = { + {0x0086, + RTW_PWR_CUT_ALL_MSK, +@@ -2163,6 +2181,7 @@ static struct rtw_chip_ops rtw8822b_ops + .cfg_csi_rate = rtw_bf_cfg_csi_rate, + .adaptivity_init = rtw8822b_adaptivity_init, + .adaptivity = rtw8822b_adaptivity, ++ .fill_txdesc_checksum = rtw8822b_fill_txdesc_checksum, + + .coex_set_init = rtw8822b_coex_cfg_init, + .coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch, +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8822bu.c linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8822bu.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8822bu.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8822bu.c 2022-12-24 00:49:25.774376835 +0200 +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2018-2019 Realtek Corporation ++ */ ++ ++#include ++#include ++#include "main.h" ++#include "rtw8822b.h" ++#include "usb.h" ++ ++static const struct usb_device_id rtw_8822bu_id_table[] = { ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb812, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb82c, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0x2102, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* CCNC */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xb822, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822ULC */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xc822, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822UTC */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xd822, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xe822, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xf822, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Edimax EW-7822UAD */ ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xb81a, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Default ID */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1841, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS AC1300 USB-AC55 B1 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x184c, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS U2 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x19aa, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS - USB-AC58 rev A1 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x1870, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0B05, 0x1874, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* ASUS */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331e, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Dlink - DWA-181 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331c, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Dlink - DWA-182 - D1 */ ++ {USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x331f, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec)}, /* Dlink - DWA-183 D Ver */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Linksys WUSB6400M */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0045, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Linksys WUSB3600 v2 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x012d, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T3U v1 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0138, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T3U Plus v1 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0115, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-Link Archer T4U V3 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x012e, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0116, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0117, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TP-LINK */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9055, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Netgear A6150 */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0025, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* Hawking HW12ACU */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x04ca, 0x8602, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* LiteOn */ ++ { USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x808a, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822b_hw_spec) }, /* TRENDnet TEW-808UBM */ ++ {}, ++}; ++MODULE_DEVICE_TABLE(usb, rtw_8822bu_id_table); ++ ++static int rtw8822bu_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ return rtw_usb_probe(intf, id); ++} ++ ++static struct usb_driver rtw_8822bu_driver = { ++ .name = "rtw_8822bu", ++ .id_table = rtw_8822bu_id_table, ++ .probe = rtw8822bu_probe, ++ .disconnect = rtw_usb_disconnect, ++}; ++module_usb_driver(rtw_8822bu_driver); ++ ++MODULE_AUTHOR("Realtek Corporation"); ++MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822bu driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8822c.c linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8822c.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8822c.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8822c.c 2022-12-24 00:49:25.775376835 +0200 +@@ -29,6 +29,12 @@ static void rtw8822ce_efuse_parsing(stru + ether_addr_copy(efuse->addr, map->e.mac_addr); + } + ++static void rtw8822cu_efuse_parsing(struct rtw_efuse *efuse, ++ struct rtw8822c_efuse *map) ++{ ++ ether_addr_copy(efuse->addr, map->u.mac_addr); ++} ++ + static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) + { + struct rtw_efuse *efuse = &rtwdev->efuse; +@@ -58,6 +64,9 @@ static int rtw8822c_read_efuse(struct rt + case RTW_HCI_TYPE_PCIE: + rtw8822ce_efuse_parsing(efuse, map); + break; ++ case RTW_HCI_TYPE_USB: ++ rtw8822cu_efuse_parsing(efuse, map); ++ break; + default: + /* unsupported now */ + return -ENOTSUPP; +@@ -4557,6 +4566,18 @@ static void rtw8822c_adaptivity(struct r + rtw_phy_set_edcca_th(rtwdev, l2h, h2l); + } + ++static void rtw8822c_fill_txdesc_checksum(struct rtw_dev *rtwdev, ++ struct rtw_tx_pkt_info *pkt_info, ++ u8 *txdesc) ++{ ++ const struct rtw_chip_info *chip = rtwdev->chip; ++ size_t words; ++ ++ words = (pkt_info->pkt_offset * 8 + chip->tx_pkt_desc_sz) / 2; ++ ++ fill_txdesc_checksum_common(txdesc, words); ++} ++ + static const struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = { + {0x0086, + RTW_PWR_CUT_ALL_MSK, +@@ -4895,6 +4916,8 @@ static const struct rtw_rfe_def rtw8822c + [0] = RTW_DEF_RFE(8822c, 0, 0), + [1] = RTW_DEF_RFE(8822c, 0, 0), + [2] = RTW_DEF_RFE(8822c, 0, 0), ++ [3] = RTW_DEF_RFE(8822c, 0, 0), ++ [4] = RTW_DEF_RFE(8822c, 0, 0), + [5] = RTW_DEF_RFE(8822c, 0, 5), + [6] = RTW_DEF_RFE(8822c, 0, 0), + }; +@@ -4978,6 +5001,7 @@ static struct rtw_chip_ops rtw8822c_ops + .cfo_track = rtw8822c_cfo_track, + .config_tx_path = rtw8822c_config_tx_path, + .config_txrx_mode = rtw8822c_config_trx_mode, ++ .fill_txdesc_checksum = rtw8822c_fill_txdesc_checksum, + + .coex_set_init = rtw8822c_coex_cfg_init, + .coex_set_ant_switch = NULL, +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8822cu.c linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8822cu.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/rtw8822cu.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/rtw8822cu.c 2022-12-24 00:49:25.775376835 +0200 +@@ -0,0 +1,44 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2018-2019 Realtek Corporation ++ */ ++ ++#include ++#include ++#include "main.h" ++#include "rtw8822c.h" ++#include "usb.h" ++ ++static const struct usb_device_id rtw_8822cu_id_table[] = { ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82c, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc812, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xc82e, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd820, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(RTW_USB_VENDOR_ID_REALTEK, 0xd82b, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, ++ { USB_DEVICE_AND_INTERFACE_INFO(0x13b1, 0x0043, 0xff, 0xff, 0xff), ++ .driver_info = (kernel_ulong_t)&(rtw8822c_hw_spec) }, /* Alpha - Alpha */ ++ {}, ++}; ++MODULE_DEVICE_TABLE(usb, rtw_8822cu_id_table); ++ ++static int rtw8822bu_probe(struct usb_interface *intf, ++ const struct usb_device_id *id) ++{ ++ return rtw_usb_probe(intf, id); ++} ++ ++static struct usb_driver rtw_8822cu_driver = { ++ .name = "rtw_8822cu", ++ .id_table = rtw_8822cu_id_table, ++ .probe = rtw8822bu_probe, ++ .disconnect = rtw_usb_disconnect, ++}; ++module_usb_driver(rtw_8822cu_driver); ++ ++MODULE_AUTHOR("Realtek Corporation"); ++MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822cu driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/tx.h linux-6.2/drivers/net/wireless/realtek/rtw88/tx.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/tx.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/tx.h 2022-12-24 00:49:25.775376835 +0200 +@@ -71,6 +71,14 @@ + le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(15)) + #define SET_TX_DESC_BT_NULL(txdesc, value) \ + le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(23)) ++#define SET_TX_DESC_TXDESC_CHECKSUM(txdesc, value) \ ++ le32p_replace_bits((__le32 *)(txdesc) + 0x07, value, GENMASK(15, 0)) ++#define SET_TX_DESC_DMA_TXAGG_NUM(txdesc, value) \ ++ le32p_replace_bits((__le32 *)(txdesc) + 0x07, value, GENMASK(31, 24)) ++#define GET_TX_DESC_PKT_OFFSET(txdesc) \ ++ le32_get_bits(*((__le32 *)(txdesc) + 0x01), GENMASK(28, 24)) ++#define GET_TX_DESC_QSEL(txdesc) \ ++ le32_get_bits(*((__le32 *)(txdesc) + 0x01), GENMASK(12, 8)) + + enum rtw_tx_desc_queue_select { + TX_DESC_QSEL_TID0 = 0, +@@ -123,4 +131,27 @@ rtw_tx_write_data_h2c_get(struct rtw_dev + struct rtw_tx_pkt_info *pkt_info, + u8 *buf, u32 size); + ++static inline ++void fill_txdesc_checksum_common(u8 *txdesc, size_t words) ++{ ++ __le16 chksum = 0; ++ __le16 *data = (__le16 *)(txdesc); ++ ++ SET_TX_DESC_TXDESC_CHECKSUM(txdesc, 0x0000); ++ ++ while (words--) ++ chksum ^= *data++; ++ ++ SET_TX_DESC_TXDESC_CHECKSUM(txdesc, __le16_to_cpu(chksum)); ++} ++ ++static inline void rtw_tx_fill_txdesc_checksum(struct rtw_dev *rtwdev, ++ struct rtw_tx_pkt_info *pkt_info, ++ u8 *txdesc) ++{ ++ const struct rtw_chip_info *chip = rtwdev->chip; ++ ++ chip->ops->fill_txdesc_checksum(rtwdev, pkt_info, txdesc); ++} ++ + #endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/usb.c linux-6.2/drivers/net/wireless/realtek/rtw88/usb.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/usb.c 2022-12-24 00:49:25.775376835 +0200 +@@ -0,0 +1,911 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2018-2019 Realtek Corporation ++ */ ++ ++#include ++#include ++#include ++#include "main.h" ++#include "debug.h" ++#include "reg.h" ++#include "tx.h" ++#include "rx.h" ++#include "fw.h" ++#include "ps.h" ++#include "usb.h" ++ ++#define RTW_USB_MAX_RXQ_LEN 512 ++ ++struct rtw_usb_txcb { ++ struct rtw_dev *rtwdev; ++ struct sk_buff_head tx_ack_queue; ++}; ++ ++static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb, ++ struct sk_buff *skb, int agg_num) ++{ ++ struct rtw_dev *rtwdev = rtwusb->rtwdev; ++ struct rtw_tx_pkt_info pkt_info; ++ ++ SET_TX_DESC_DMA_TXAGG_NUM(skb->data, agg_num); ++ pkt_info.pkt_offset = GET_TX_DESC_PKT_OFFSET(skb->data); ++ rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data); ++} ++ ++static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ struct usb_device *udev = rtwusb->udev; ++ __le32 *data; ++ unsigned long flags; ++ int idx, ret; ++ static int count; ++ ++ spin_lock_irqsave(&rtwusb->usb_lock, flags); ++ ++ idx = rtwusb->usb_data_index; ++ rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1); ++ ++ spin_unlock_irqrestore(&rtwusb->usb_lock, flags); ++ ++ data = &rtwusb->usb_data[idx]; ++ ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ RTW_USB_CMD_REQ, RTW_USB_CMD_READ, addr, ++ RTW_USB_VENQT_CMD_IDX, data, len, 1000); ++ if (ret < 0 && ret != -ENODEV && count++ < 4) ++ rtw_err(rtwdev, "read register 0x%x failed with %d\n", ++ addr, ret); ++ ++ return le32_to_cpu(*data); ++} ++ ++static u8 rtw_usb_read8(struct rtw_dev *rtwdev, u32 addr) ++{ ++ return (u8)rtw_usb_read(rtwdev, addr, 1); ++} ++ ++static u16 rtw_usb_read16(struct rtw_dev *rtwdev, u32 addr) ++{ ++ return (u16)rtw_usb_read(rtwdev, addr, 2); ++} ++ ++static u32 rtw_usb_read32(struct rtw_dev *rtwdev, u32 addr) ++{ ++ return (u32)rtw_usb_read(rtwdev, addr, 4); ++} ++ ++static void rtw_usb_write(struct rtw_dev *rtwdev, u32 addr, u32 val, int len) ++{ ++ struct rtw_usb *rtwusb = (struct rtw_usb *)rtwdev->priv; ++ struct usb_device *udev = rtwusb->udev; ++ unsigned long flags; ++ __le32 *data; ++ int idx, ret; ++ static int count; ++ ++ spin_lock_irqsave(&rtwusb->usb_lock, flags); ++ ++ idx = rtwusb->usb_data_index; ++ rtwusb->usb_data_index = (idx + 1) & (RTW_USB_MAX_RXTX_COUNT - 1); ++ ++ spin_unlock_irqrestore(&rtwusb->usb_lock, flags); ++ ++ data = &rtwusb->usb_data[idx]; ++ ++ *data = cpu_to_le32(val); ++ ++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ RTW_USB_CMD_REQ, RTW_USB_CMD_WRITE, ++ addr, 0, data, len, 30000); ++ if (ret < 0 && ret != -ENODEV && count++ < 4) ++ rtw_err(rtwdev, "write register 0x%x failed with %d\n", ++ addr, ret); ++} ++ ++static void rtw_usb_write8(struct rtw_dev *rtwdev, u32 addr, u8 val) ++{ ++ rtw_usb_write(rtwdev, addr, val, 1); ++} ++ ++static void rtw_usb_write16(struct rtw_dev *rtwdev, u32 addr, u16 val) ++{ ++ rtw_usb_write(rtwdev, addr, val, 2); ++} ++ ++static void rtw_usb_write32(struct rtw_dev *rtwdev, u32 addr, u32 val) ++{ ++ rtw_usb_write(rtwdev, addr, val, 4); ++} ++ ++static int rtw_usb_parse(struct rtw_dev *rtwdev, ++ struct usb_interface *interface) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ struct usb_host_interface *host_interface = &interface->altsetting[0]; ++ struct usb_interface_descriptor *interface_desc = &host_interface->desc; ++ struct usb_endpoint_descriptor *endpoint; ++ struct usb_device *usbd = interface_to_usbdev(interface); ++ int num_out_pipes = 0; ++ int i; ++ u8 num; ++ ++ for (i = 0; i < interface_desc->bNumEndpoints; i++) { ++ endpoint = &host_interface->endpoint[i].desc; ++ num = usb_endpoint_num(endpoint); ++ ++ if (usb_endpoint_dir_in(endpoint) && ++ usb_endpoint_xfer_bulk(endpoint)) { ++ if (rtwusb->pipe_in) { ++ rtw_err(rtwdev, "IN pipes overflow\n"); ++ return -EINVAL; ++ } ++ ++ rtwusb->pipe_in = num; ++ } ++ ++ if (usb_endpoint_dir_in(endpoint) && ++ usb_endpoint_xfer_int(endpoint)) { ++ if (rtwusb->pipe_interrupt) { ++ rtw_err(rtwdev, "INT pipes overflow\n"); ++ return -EINVAL; ++ } ++ ++ rtwusb->pipe_interrupt = num; ++ } ++ ++ if (usb_endpoint_dir_out(endpoint) && ++ usb_endpoint_xfer_bulk(endpoint)) { ++ if (num_out_pipes >= ARRAY_SIZE(rtwusb->out_ep)) { ++ rtw_err(rtwdev, "OUT pipes overflow\n"); ++ return -EINVAL; ++ } ++ ++ rtwusb->out_ep[num_out_pipes++] = num; ++ } ++ } ++ ++ switch (usbd->speed) { ++ case USB_SPEED_LOW: ++ case USB_SPEED_FULL: ++ rtwusb->bulkout_size = RTW_USB_FULL_SPEED_BULK_SIZE; ++ break; ++ case USB_SPEED_HIGH: ++ rtwusb->bulkout_size = RTW_USB_HIGH_SPEED_BULK_SIZE; ++ break; ++ case USB_SPEED_SUPER: ++ rtwusb->bulkout_size = RTW_USB_SUPER_SPEED_BULK_SIZE; ++ break; ++ default: ++ rtw_err(rtwdev, "failed to detect usb speed\n"); ++ return -EINVAL; ++ } ++ ++ rtwdev->hci.bulkout_num = num_out_pipes; ++ ++ switch (num_out_pipes) { ++ case 4: ++ case 3: ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = 2; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = 2; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = 2; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = 2; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID4] = 1; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID5] = 1; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID6] = 0; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID7] = 0; ++ break; ++ case 2: ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID0] = 1; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID1] = 1; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID2] = 1; ++ rtwusb->qsel_to_ep[TX_DESC_QSEL_TID3] = 1; ++ break; ++ case 1: ++ break; ++ default: ++ rtw_err(rtwdev, "failed to get out_pipes(%d)\n", num_out_pipes); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void rtw_usb_write_port_tx_complete(struct urb *urb) ++{ ++ struct rtw_usb_txcb *txcb = urb->context; ++ struct rtw_dev *rtwdev = txcb->rtwdev; ++ struct ieee80211_hw *hw = rtwdev->hw; ++ ++ while (true) { ++ struct sk_buff *skb = skb_dequeue(&txcb->tx_ack_queue); ++ struct ieee80211_tx_info *info; ++ struct rtw_usb_tx_data *tx_data; ++ ++ if (!skb) ++ break; ++ ++ info = IEEE80211_SKB_CB(skb); ++ tx_data = rtw_usb_get_tx_data(skb); ++ ++ /* enqueue to wait for tx report */ ++ if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { ++ rtw_tx_report_enqueue(rtwdev, skb, tx_data->sn); ++ continue; ++ } ++ ++ /* always ACK for others, then they won't be marked as drop */ ++ ieee80211_tx_info_clear_status(info); ++ if (info->flags & IEEE80211_TX_CTL_NO_ACK) ++ info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; ++ else ++ info->flags |= IEEE80211_TX_STAT_ACK; ++ ++ ieee80211_tx_status_irqsafe(hw, skb); ++ } ++ ++ kfree(txcb); ++} ++ ++static int qsel_to_ep(struct rtw_usb *rtwusb, unsigned int qsel) ++{ ++ if (qsel >= ARRAY_SIZE(rtwusb->qsel_to_ep)) ++ return 0; ++ ++ return rtwusb->qsel_to_ep[qsel]; ++} ++ ++static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *skb, ++ usb_complete_t cb, void *context) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ struct usb_device *usbd = rtwusb->udev; ++ struct urb *urb; ++ unsigned int pipe; ++ int ret; ++ int ep = qsel_to_ep(rtwusb, qsel); ++ ++ pipe = usb_sndbulkpipe(usbd, rtwusb->out_ep[ep]); ++ urb = usb_alloc_urb(0, GFP_ATOMIC); ++ if (!urb) ++ return -ENOMEM; ++ ++ usb_fill_bulk_urb(urb, usbd, pipe, skb->data, skb->len, cb, context); ++ ret = usb_submit_urb(urb, GFP_ATOMIC); ++ ++ usb_free_urb(urb); ++ ++ return ret; ++} ++ ++static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list) ++{ ++ struct rtw_dev *rtwdev = rtwusb->rtwdev; ++ struct rtw_usb_txcb *txcb; ++ struct sk_buff *skb_head; ++ struct sk_buff *skb_iter; ++ int agg_num = 0; ++ unsigned int align_next = 0; ++ ++ if (skb_queue_empty(list)) ++ return false; ++ ++ txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC); ++ if (!txcb) ++ return false; ++ ++ txcb->rtwdev = rtwdev; ++ skb_queue_head_init(&txcb->tx_ack_queue); ++ ++ skb_iter = skb_dequeue(list); ++ ++ if (skb_queue_empty(list)) { ++ skb_head = skb_iter; ++ goto queue; ++ } ++ ++ skb_head = dev_alloc_skb(RTW_USB_MAX_XMITBUF_SZ); ++ if (!skb_head) { ++ skb_head = skb_iter; ++ goto queue; ++ } ++ ++ while (skb_iter) { ++ unsigned long flags; ++ ++ skb_put(skb_head, align_next); ++ skb_put_data(skb_head, skb_iter->data, skb_iter->len); ++ ++ align_next = ALIGN(skb_iter->len, 8) - skb_iter->len; ++ ++ agg_num++; ++ ++ skb_queue_tail(&txcb->tx_ack_queue, skb_iter); ++ ++ spin_lock_irqsave(&list->lock, flags); ++ ++ skb_iter = skb_peek(list); ++ ++ if (skb_iter && skb_iter->len + skb_head->len <= RTW_USB_MAX_XMITBUF_SZ) ++ __skb_unlink(skb_iter, list); ++ else ++ skb_iter = NULL; ++ spin_unlock_irqrestore(&list->lock, flags); ++ } ++ ++ if (agg_num > 1) ++ rtw_usb_fill_tx_checksum(rtwusb, skb_head, agg_num); ++ ++queue: ++ skb_queue_tail(&txcb->tx_ack_queue, skb_head); ++ ++ rtw_usb_write_port(rtwdev, GET_TX_DESC_QSEL(skb_head->data), skb_head, ++ rtw_usb_write_port_tx_complete, txcb); ++ ++ return true; ++} ++ ++static void rtw_usb_tx_handler(struct work_struct *work) ++{ ++ struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, tx_work); ++ int i, limit; ++ ++ for (i = ARRAY_SIZE(rtwusb->tx_queue) - 1; i >= 0; i--) { ++ for (limit = 0; limit < 200; limit++) { ++ struct sk_buff_head *list = &rtwusb->tx_queue[i]; ++ ++ if (!rtw_usb_tx_agg_skb(rtwusb, list)) ++ break; ++ } ++ } ++} ++ ++static void rtw_usb_tx_queue_purge(struct rtw_usb *rtwusb) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) ++ skb_queue_purge(&rtwusb->tx_queue[i]); ++} ++ ++static void rtw_usb_write_port_complete(struct urb *urb) ++{ ++ struct sk_buff *skb = urb->context; ++ ++ dev_kfree_skb_any(skb); ++} ++ ++static int rtw_usb_write_data(struct rtw_dev *rtwdev, ++ struct rtw_tx_pkt_info *pkt_info, ++ u8 *buf) ++{ ++ const struct rtw_chip_info *chip = rtwdev->chip; ++ struct sk_buff *skb; ++ unsigned int desclen, headsize, size; ++ u8 qsel; ++ int ret = 0; ++ ++ size = pkt_info->tx_pkt_size; ++ qsel = pkt_info->qsel; ++ desclen = chip->tx_pkt_desc_sz; ++ headsize = pkt_info->offset ? pkt_info->offset : desclen; ++ ++ skb = dev_alloc_skb(headsize + size); ++ if (unlikely(!skb)) ++ return -ENOMEM; ++ ++ skb_reserve(skb, headsize); ++ skb_put_data(skb, buf, size); ++ skb_push(skb, headsize); ++ memset(skb->data, 0, headsize); ++ rtw_tx_fill_tx_desc(pkt_info, skb); ++ rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); ++ ++ ret = rtw_usb_write_port(rtwdev, qsel, skb, ++ rtw_usb_write_port_complete, skb); ++ if (unlikely(ret)) ++ rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret); ++ ++ return ret; ++} ++ ++static int rtw_usb_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, ++ u32 size) ++{ ++ const struct rtw_chip_info *chip = rtwdev->chip; ++ struct rtw_usb *rtwusb; ++ struct rtw_tx_pkt_info pkt_info = {0}; ++ u32 len, desclen; ++ ++ rtwusb = rtw_get_usb_priv(rtwdev); ++ ++ pkt_info.tx_pkt_size = size; ++ pkt_info.qsel = TX_DESC_QSEL_BEACON; ++ ++ desclen = chip->tx_pkt_desc_sz; ++ len = desclen + size; ++ if (len % rtwusb->bulkout_size == 0) { ++ len += RTW_USB_PACKET_OFFSET_SZ; ++ pkt_info.offset = desclen + RTW_USB_PACKET_OFFSET_SZ; ++ pkt_info.pkt_offset = 1; ++ } else { ++ pkt_info.offset = desclen; ++ } ++ ++ return rtw_usb_write_data(rtwdev, &pkt_info, buf); ++} ++ ++static int rtw_usb_write_data_h2c(struct rtw_dev *rtwdev, u8 *buf, u32 size) ++{ ++ struct rtw_tx_pkt_info pkt_info = {0}; ++ ++ pkt_info.tx_pkt_size = size; ++ pkt_info.qsel = TX_DESC_QSEL_H2C; ++ ++ return rtw_usb_write_data(rtwdev, &pkt_info, buf); ++} ++ ++static u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb) ++{ ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; ++ __le16 fc = hdr->frame_control; ++ u8 qsel; ++ ++ if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) ++ qsel = TX_DESC_QSEL_MGMT; ++ else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK) ++ qsel = skb->priority; ++ else ++ qsel = TX_DESC_QSEL_BEACON; ++ ++ return qsel; ++} ++ ++static int rtw_usb_tx_write(struct rtw_dev *rtwdev, ++ struct rtw_tx_pkt_info *pkt_info, ++ struct sk_buff *skb) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ const struct rtw_chip_info *chip = rtwdev->chip; ++ struct rtw_usb_tx_data *tx_data; ++ u8 *pkt_desc; ++ int ep; ++ ++ pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); ++ memset(pkt_desc, 0, chip->tx_pkt_desc_sz); ++ pkt_info->qsel = rtw_usb_tx_queue_mapping_to_qsel(skb); ++ ep = qsel_to_ep(rtwusb, pkt_info->qsel); ++ rtw_tx_fill_tx_desc(pkt_info, skb); ++ rtw_tx_fill_txdesc_checksum(rtwdev, pkt_info, skb->data); ++ tx_data = rtw_usb_get_tx_data(skb); ++ tx_data->sn = pkt_info->sn; ++ ++ skb_queue_tail(&rtwusb->tx_queue[ep], skb); ++ ++ return 0; ++} ++ ++static void rtw_usb_tx_kick_off(struct rtw_dev *rtwdev) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ ++ queue_work(rtwusb->txwq, &rtwusb->tx_work); ++} ++ ++static void rtw_usb_rx_handler(struct work_struct *work) ++{ ++ struct rtw_usb *rtwusb = container_of(work, struct rtw_usb, rx_work); ++ struct rtw_dev *rtwdev = rtwusb->rtwdev; ++ const struct rtw_chip_info *chip = rtwdev->chip; ++ struct rtw_rx_pkt_stat pkt_stat; ++ struct ieee80211_rx_status rx_status; ++ struct sk_buff *skb; ++ u32 pkt_desc_sz = chip->rx_pkt_desc_sz; ++ u32 pkt_offset; ++ u8 *rx_desc; ++ int limit; ++ ++ for (limit = 0; limit < 200; limit++) { ++ skb = skb_dequeue(&rtwusb->rx_queue); ++ if (!skb) ++ break; ++ ++ rx_desc = skb->data; ++ chip->ops->query_rx_desc(rtwdev, rx_desc, &pkt_stat, ++ &rx_status); ++ pkt_offset = pkt_desc_sz + pkt_stat.drv_info_sz + ++ pkt_stat.shift; ++ ++ if (pkt_stat.is_c2h) { ++ skb_put(skb, pkt_stat.pkt_len + pkt_offset); ++ rtw_fw_c2h_cmd_rx_irqsafe(rtwdev, pkt_offset, skb); ++ continue; ++ } ++ ++ if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) { ++ rtw_err(rtwdev, "failed to get rx_queue, overflow\n"); ++ dev_kfree_skb_any(skb); ++ continue; ++ } ++ ++ skb_put(skb, pkt_stat.pkt_len); ++ skb_reserve(skb, pkt_offset); ++ memcpy(skb->cb, &rx_status, sizeof(rx_status)); ++ ieee80211_rx_irqsafe(rtwdev->hw, skb); ++ } ++} ++ ++static void rtw_usb_read_port_complete(struct urb *urb); ++ ++static void rtw_usb_rx_resubmit(struct rtw_usb *rtwusb, struct rx_usb_ctrl_block *rxcb) ++{ ++ struct rtw_dev *rtwdev = rtwusb->rtwdev; ++ int error; ++ ++ rxcb->rx_skb = alloc_skb(RTW_USB_MAX_RECVBUF_SZ, GFP_ATOMIC); ++ if (!rxcb->rx_skb) ++ return; ++ ++ usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev, ++ usb_rcvbulkpipe(rtwusb->udev, rtwusb->pipe_in), ++ rxcb->rx_skb->data, RTW_USB_MAX_RECVBUF_SZ, ++ rtw_usb_read_port_complete, rxcb); ++ ++ error = usb_submit_urb(rxcb->rx_urb, GFP_ATOMIC); ++ if (error) { ++ kfree_skb(rxcb->rx_skb); ++ if (error != -ENODEV) ++ rtw_err(rtwdev, "Err sending rx data urb %d\n", ++ error); ++ } ++} ++ ++static void rtw_usb_read_port_complete(struct urb *urb) ++{ ++ struct rx_usb_ctrl_block *rxcb = urb->context; ++ struct rtw_dev *rtwdev = rxcb->rtwdev; ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ struct sk_buff *skb = rxcb->rx_skb; ++ ++ if (urb->status == 0) { ++ if (urb->actual_length >= RTW_USB_MAX_RECVBUF_SZ || ++ urb->actual_length < 24) { ++ rtw_err(rtwdev, "failed to get urb length:%d\n", ++ urb->actual_length); ++ if (skb) ++ dev_kfree_skb_any(skb); ++ } else { ++ skb_queue_tail(&rtwusb->rx_queue, skb); ++ queue_work(rtwusb->rxwq, &rtwusb->rx_work); ++ } ++ rtw_usb_rx_resubmit(rtwusb, rxcb); ++ } else { ++ switch (urb->status) { ++ case -EINVAL: ++ case -EPIPE: ++ case -ENODEV: ++ case -ESHUTDOWN: ++ case -ENOENT: ++ case -EPROTO: ++ case -EILSEQ: ++ case -ETIME: ++ case -ECOMM: ++ case -EOVERFLOW: ++ case -EINPROGRESS: ++ break; ++ default: ++ rtw_err(rtwdev, "status %d\n", urb->status); ++ break; ++ } ++ if (skb) ++ dev_kfree_skb_any(skb); ++ } ++} ++ ++static void rtw_usb_cancel_rx_bufs(struct rtw_usb *rtwusb) ++{ ++ struct rx_usb_ctrl_block *rxcb; ++ int i; ++ ++ for (i = 0; i < RTW_USB_RXCB_NUM; i++) { ++ rxcb = &rtwusb->rx_cb[i]; ++ if (rxcb->rx_urb) ++ usb_kill_urb(rxcb->rx_urb); ++ } ++} ++ ++static void rtw_usb_free_rx_bufs(struct rtw_usb *rtwusb) ++{ ++ struct rx_usb_ctrl_block *rxcb; ++ int i; ++ ++ for (i = 0; i < RTW_USB_RXCB_NUM; i++) { ++ rxcb = &rtwusb->rx_cb[i]; ++ if (rxcb->rx_urb) { ++ usb_kill_urb(rxcb->rx_urb); ++ usb_free_urb(rxcb->rx_urb); ++ } ++ } ++} ++ ++static int rtw_usb_alloc_rx_bufs(struct rtw_usb *rtwusb) ++{ ++ int i; ++ ++ for (i = 0; i < RTW_USB_RXCB_NUM; i++) { ++ struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; ++ ++ rxcb->n = i; ++ rxcb->rtwdev = rtwusb->rtwdev; ++ rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!rxcb->rx_urb) ++ goto err; ++ } ++ ++ return 0; ++err: ++ rtw_usb_free_rx_bufs(rtwusb); ++ return -ENOMEM; ++} ++ ++static int rtw_usb_setup(struct rtw_dev *rtwdev) ++{ ++ /* empty function for rtw_hci_ops */ ++ return 0; ++} ++ ++static int rtw_usb_start(struct rtw_dev *rtwdev) ++{ ++ return 0; ++} ++ ++static void rtw_usb_stop(struct rtw_dev *rtwdev) ++{ ++} ++ ++static void rtw_usb_deep_ps(struct rtw_dev *rtwdev, bool enter) ++{ ++ /* empty function for rtw_hci_ops */ ++} ++ ++static void rtw_usb_link_ps(struct rtw_dev *rtwdev, bool enter) ++{ ++ /* empty function for rtw_hci_ops */ ++} ++ ++static void rtw_usb_interface_cfg(struct rtw_dev *rtwdev) ++{ ++ /* empty function for rtw_hci_ops */ ++} ++ ++static struct rtw_hci_ops rtw_usb_ops = { ++ .tx_write = rtw_usb_tx_write, ++ .tx_kick_off = rtw_usb_tx_kick_off, ++ .setup = rtw_usb_setup, ++ .start = rtw_usb_start, ++ .stop = rtw_usb_stop, ++ .deep_ps = rtw_usb_deep_ps, ++ .link_ps = rtw_usb_link_ps, ++ .interface_cfg = rtw_usb_interface_cfg, ++ ++ .write8 = rtw_usb_write8, ++ .write16 = rtw_usb_write16, ++ .write32 = rtw_usb_write32, ++ .read8 = rtw_usb_read8, ++ .read16 = rtw_usb_read16, ++ .read32 = rtw_usb_read32, ++ ++ .write_data_rsvd_page = rtw_usb_write_data_rsvd_page, ++ .write_data_h2c = rtw_usb_write_data_h2c, ++}; ++ ++static int rtw_usb_init_rx(struct rtw_dev *rtwdev) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ int i; ++ ++ rtwusb->rxwq = create_singlethread_workqueue("rtw88_usb: rx wq"); ++ if (!rtwusb->rxwq) { ++ rtw_err(rtwdev, "failed to create RX work queue\n"); ++ return -ENOMEM; ++ } ++ ++ skb_queue_head_init(&rtwusb->rx_queue); ++ ++ INIT_WORK(&rtwusb->rx_work, rtw_usb_rx_handler); ++ ++ for (i = 0; i < RTW_USB_RXCB_NUM; i++) { ++ struct rx_usb_ctrl_block *rxcb = &rtwusb->rx_cb[i]; ++ ++ rtw_usb_rx_resubmit(rtwusb, rxcb); ++ } ++ ++ return 0; ++} ++ ++static void rtw_usb_deinit_rx(struct rtw_dev *rtwdev) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ ++ skb_queue_purge(&rtwusb->rx_queue); ++ ++ flush_workqueue(rtwusb->rxwq); ++ destroy_workqueue(rtwusb->rxwq); ++} ++ ++static int rtw_usb_init_tx(struct rtw_dev *rtwdev) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ int i; ++ ++ rtwusb->txwq = create_singlethread_workqueue("rtw88_usb: tx wq"); ++ if (!rtwusb->txwq) { ++ rtw_err(rtwdev, "failed to create TX work queue\n"); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) ++ skb_queue_head_init(&rtwusb->tx_queue[i]); ++ ++ INIT_WORK(&rtwusb->tx_work, rtw_usb_tx_handler); ++ ++ return 0; ++} ++ ++static void rtw_usb_deinit_tx(struct rtw_dev *rtwdev) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ ++ rtw_usb_tx_queue_purge(rtwusb); ++ flush_workqueue(rtwusb->txwq); ++ destroy_workqueue(rtwusb->txwq); ++} ++ ++static int rtw_usb_intf_init(struct rtw_dev *rtwdev, ++ struct usb_interface *intf) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf)); ++ int ret; ++ ++ rtwusb->udev = udev; ++ ret = rtw_usb_parse(rtwdev, intf); ++ if (ret) ++ return ret; ++ ++ rtwusb->usb_data = kcalloc(RTW_USB_MAX_RXTX_COUNT, sizeof(u32), ++ GFP_KERNEL); ++ if (!rtwusb->usb_data) ++ return -ENOMEM; ++ ++ usb_set_intfdata(intf, rtwdev->hw); ++ ++ SET_IEEE80211_DEV(rtwdev->hw, &intf->dev); ++ spin_lock_init(&rtwusb->usb_lock); ++ ++ return 0; ++} ++ ++static void rtw_usb_intf_deinit(struct rtw_dev *rtwdev, ++ struct usb_interface *intf) ++{ ++ struct rtw_usb *rtwusb = rtw_get_usb_priv(rtwdev); ++ ++ usb_put_dev(rtwusb->udev); ++ usb_set_intfdata(intf, NULL); ++} ++ ++int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) ++{ ++ struct rtw_dev *rtwdev; ++ struct ieee80211_hw *hw; ++ struct rtw_usb *rtwusb; ++ int drv_data_size; ++ int ret; ++ ++ drv_data_size = sizeof(struct rtw_dev) + sizeof(struct rtw_usb); ++ hw = ieee80211_alloc_hw(drv_data_size, &rtw_ops); ++ if (!hw) ++ return -ENOMEM; ++ ++ rtwdev = hw->priv; ++ rtwdev->hw = hw; ++ rtwdev->dev = &intf->dev; ++ rtwdev->chip = (struct rtw_chip_info *)id->driver_info; ++ rtwdev->hci.ops = &rtw_usb_ops; ++ rtwdev->hci.type = RTW_HCI_TYPE_USB; ++ ++ rtwusb = rtw_get_usb_priv(rtwdev); ++ rtwusb->rtwdev = rtwdev; ++ ++ ret = rtw_usb_alloc_rx_bufs(rtwusb); ++ if (ret) ++ return ret; ++ ++ ret = rtw_core_init(rtwdev); ++ if (ret) ++ goto err_release_hw; ++ ++ ret = rtw_usb_intf_init(rtwdev, intf); ++ if (ret) { ++ rtw_err(rtwdev, "failed to init USB interface\n"); ++ goto err_deinit_core; ++ } ++ ++ ret = rtw_usb_init_tx(rtwdev); ++ if (ret) { ++ rtw_err(rtwdev, "failed to init USB TX\n"); ++ goto err_destroy_usb; ++ } ++ ++ ret = rtw_usb_init_rx(rtwdev); ++ if (ret) { ++ rtw_err(rtwdev, "failed to init USB RX\n"); ++ goto err_destroy_txwq; ++ } ++ ++ ret = rtw_chip_info_setup(rtwdev); ++ if (ret) { ++ rtw_err(rtwdev, "failed to setup chip information\n"); ++ goto err_destroy_rxwq; ++ } ++ ++ ret = rtw_register_hw(rtwdev, rtwdev->hw); ++ if (ret) { ++ rtw_err(rtwdev, "failed to register hw\n"); ++ goto err_destroy_rxwq; ++ } ++ ++ return 0; ++ ++err_destroy_rxwq: ++ rtw_usb_deinit_rx(rtwdev); ++ ++err_destroy_txwq: ++ rtw_usb_deinit_tx(rtwdev); ++ ++err_destroy_usb: ++ rtw_usb_intf_deinit(rtwdev, intf); ++ ++err_deinit_core: ++ rtw_core_deinit(rtwdev); ++ ++err_release_hw: ++ ieee80211_free_hw(hw); ++ ++ return ret; ++} ++EXPORT_SYMBOL(rtw_usb_probe); ++ ++void rtw_usb_disconnect(struct usb_interface *intf) ++{ ++ struct ieee80211_hw *hw = usb_get_intfdata(intf); ++ struct rtw_dev *rtwdev; ++ struct rtw_usb *rtwusb; ++ ++ if (!hw) ++ return; ++ ++ rtwdev = hw->priv; ++ rtwusb = rtw_get_usb_priv(rtwdev); ++ ++ rtw_usb_cancel_rx_bufs(rtwusb); ++ ++ rtw_unregister_hw(rtwdev, hw); ++ rtw_usb_deinit_tx(rtwdev); ++ rtw_usb_deinit_rx(rtwdev); ++ ++ if (rtwusb->udev->state != USB_STATE_NOTATTACHED) ++ usb_reset_device(rtwusb->udev); ++ ++ rtw_usb_free_rx_bufs(rtwusb); ++ ++ rtw_usb_intf_deinit(rtwdev, intf); ++ rtw_core_deinit(rtwdev); ++ ieee80211_free_hw(hw); ++} ++EXPORT_SYMBOL(rtw_usb_disconnect); ++ ++MODULE_AUTHOR("Realtek Corporation"); ++MODULE_DESCRIPTION("Realtek 802.11ac wireless USB driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/usb.h linux-6.2/drivers/net/wireless/realtek/rtw88/usb.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/usb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/usb.h 2022-12-24 00:49:25.775376835 +0200 +@@ -0,0 +1,107 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2018-2019 Realtek Corporation ++ */ ++ ++#ifndef __RTW_USB_H_ ++#define __RTW_USB_H_ ++ ++#define FW_8192C_START_ADDRESS 0x1000 ++#define FW_8192C_END_ADDRESS 0x5fff ++ ++#define RTW_USB_MAX_RXTX_COUNT 128 ++#define RTW_USB_VENQT_MAX_BUF_SIZE 254 ++#define MAX_USBCTRL_VENDORREQ_TIMES 10 ++ ++#define RTW_USB_CMD_READ 0xc0 ++#define RTW_USB_CMD_WRITE 0x40 ++#define RTW_USB_CMD_REQ 0x05 ++ ++#define RTW_USB_VENQT_CMD_IDX 0x00 ++ ++#define RTW_USB_SUPER_SPEED_BULK_SIZE 1024 ++#define RTW_USB_HIGH_SPEED_BULK_SIZE 512 ++#define RTW_USB_FULL_SPEED_BULK_SIZE 64 ++ ++#define RTW_USB_TX_SEL_HQ BIT(0) ++#define RTW_USB_TX_SEL_LQ BIT(1) ++#define RTW_USB_TX_SEL_NQ BIT(2) ++#define RTW_USB_TX_SEL_EQ BIT(3) ++ ++#define RTW_USB_BULK_IN_ADDR 0x80 ++#define RTW_USB_INT_IN_ADDR 0x81 ++ ++#define RTW_USB_HW_QUEUE_ENTRY 8 ++ ++#define RTW_USB_PACKET_OFFSET_SZ 8 ++#define RTW_USB_MAX_XMITBUF_SZ (1024 * 20) ++#define RTW_USB_MAX_RECVBUF_SZ 32768 ++ ++#define RTW_USB_RECVBUFF_ALIGN_SZ 8 ++ ++#define RTW_USB_RXAGG_SIZE 6 ++#define RTW_USB_RXAGG_TIMEOUT 10 ++ ++#define RTW_USB_RXCB_NUM 4 ++ ++#define RTW_USB_EP_MAX 4 ++ ++#define TX_DESC_QSEL_MAX 20 ++ ++#define RTW_USB_VENDOR_ID_REALTEK 0x0bda ++ ++static inline struct rtw_usb *rtw_get_usb_priv(struct rtw_dev *rtwdev) ++{ ++ return (struct rtw_usb *)rtwdev->priv; ++} ++ ++struct rx_usb_ctrl_block { ++ struct rtw_dev *rtwdev; ++ struct urb *rx_urb; ++ struct sk_buff *rx_skb; ++ int n; ++}; ++ ++struct rtw_usb_tx_data { ++ u8 sn; ++}; ++ ++struct rtw_usb { ++ struct rtw_dev *rtwdev; ++ struct usb_device *udev; ++ ++ /* protects usb_data_index */ ++ spinlock_t usb_lock; ++ __le32 *usb_data; ++ unsigned int usb_data_index; ++ ++ u32 bulkout_size; ++ u8 pipe_interrupt; ++ u8 pipe_in; ++ u8 out_ep[RTW_USB_EP_MAX]; ++ u8 qsel_to_ep[TX_DESC_QSEL_MAX]; ++ u8 usb_txagg_num; ++ ++ struct workqueue_struct *txwq, *rxwq; ++ ++ struct sk_buff_head tx_queue[RTW_USB_EP_MAX]; ++ struct work_struct tx_work; ++ ++ struct rx_usb_ctrl_block rx_cb[RTW_USB_RXCB_NUM]; ++ struct sk_buff_head rx_queue; ++ struct work_struct rx_work; ++}; ++ ++static inline struct rtw_usb_tx_data *rtw_usb_get_tx_data(struct sk_buff *skb) ++{ ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ ++ BUILD_BUG_ON(sizeof(struct rtw_usb_tx_data) > ++ sizeof(info->status.status_driver_data)); ++ ++ return (struct rtw_usb_tx_data *)info->status.status_driver_data; ++} ++ ++int rtw_usb_probe(struct usb_interface *intf, const struct usb_device_id *id); ++void rtw_usb_disconnect(struct usb_interface *intf); ++ ++#endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/util.c linux-6.2/drivers/net/wireless/realtek/rtw88/util.c +--- linux-6.1/drivers/net/wireless/realtek/rtw88/util.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/util.c 2022-12-24 00:49:25.775376835 +0200 +@@ -105,3 +105,106 @@ void rtw_desc_to_mcsrate(u16 rate, u8 *m + *mcs = rate - DESC_RATEMCS0; + } + } ++ ++struct rtw_stas_entry { ++ struct list_head list; ++ struct ieee80211_sta *sta; ++}; ++ ++struct rtw_iter_stas_data { ++ struct rtw_dev *rtwdev; ++ struct list_head list; ++}; ++ ++static void rtw_collect_sta_iter(void *data, struct ieee80211_sta *sta) ++{ ++ struct rtw_iter_stas_data *iter_stas = data; ++ struct rtw_stas_entry *stas_entry; ++ ++ stas_entry = kmalloc(sizeof(*stas_entry), GFP_ATOMIC); ++ if (!stas_entry) ++ return; ++ ++ stas_entry->sta = sta; ++ list_add_tail(&stas_entry->list, &iter_stas->list); ++} ++ ++void rtw_iterate_stas(struct rtw_dev *rtwdev, ++ void (*iterator)(void *data, ++ struct ieee80211_sta *sta), ++ void *data) ++{ ++ struct rtw_iter_stas_data iter_data; ++ struct rtw_stas_entry *sta_entry, *tmp; ++ ++ /* &rtwdev->mutex makes sure no stations can be removed between ++ * collecting the stations and iterating over them. ++ */ ++ lockdep_assert_held(&rtwdev->mutex); ++ ++ iter_data.rtwdev = rtwdev; ++ INIT_LIST_HEAD(&iter_data.list); ++ ++ ieee80211_iterate_stations_atomic(rtwdev->hw, rtw_collect_sta_iter, ++ &iter_data); ++ ++ list_for_each_entry_safe(sta_entry, tmp, &iter_data.list, ++ list) { ++ list_del_init(&sta_entry->list); ++ iterator(data, sta_entry->sta); ++ kfree(sta_entry); ++ } ++} ++ ++struct rtw_vifs_entry { ++ struct list_head list; ++ struct ieee80211_vif *vif; ++ u8 mac[ETH_ALEN]; ++}; ++ ++struct rtw_iter_vifs_data { ++ struct rtw_dev *rtwdev; ++ struct list_head list; ++}; ++ ++static void rtw_collect_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) ++{ ++ struct rtw_iter_vifs_data *iter_stas = data; ++ struct rtw_vifs_entry *vifs_entry; ++ ++ vifs_entry = kmalloc(sizeof(*vifs_entry), GFP_ATOMIC); ++ if (!vifs_entry) ++ return; ++ ++ vifs_entry->vif = vif; ++ ether_addr_copy(vifs_entry->mac, mac); ++ list_add_tail(&vifs_entry->list, &iter_stas->list); ++} ++ ++void rtw_iterate_vifs(struct rtw_dev *rtwdev, ++ void (*iterator)(void *data, u8 *mac, ++ struct ieee80211_vif *vif), ++ void *data) ++{ ++ struct rtw_iter_vifs_data iter_data; ++ struct rtw_vifs_entry *vif_entry, *tmp; ++ ++ /* &rtwdev->mutex makes sure no interfaces can be removed between ++ * collecting the interfaces and iterating over them. ++ */ ++ lockdep_assert_held(&rtwdev->mutex); ++ ++ iter_data.rtwdev = rtwdev; ++ INIT_LIST_HEAD(&iter_data.list); ++ ++ ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, ++ IEEE80211_IFACE_ITER_NORMAL, ++ rtw_collect_vif_iter, &iter_data); ++ ++ list_for_each_entry_safe(vif_entry, tmp, &iter_data.list, ++ list) { ++ list_del_init(&vif_entry->list); ++ iterator(data, vif_entry->mac, vif_entry->vif); ++ kfree(vif_entry); ++ } ++} +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw88/util.h linux-6.2/drivers/net/wireless/realtek/rtw88/util.h +--- linux-6.1/drivers/net/wireless/realtek/rtw88/util.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw88/util.h 2022-12-24 00:49:25.775376835 +0200 +@@ -7,9 +7,6 @@ + + struct rtw_dev; + +-#define rtw_iterate_vifs(rtwdev, iterator, data) \ +- ieee80211_iterate_active_interfaces(rtwdev->hw, \ +- IEEE80211_IFACE_ITER_NORMAL, iterator, data) + #define rtw_iterate_vifs_atomic(rtwdev, iterator, data) \ + ieee80211_iterate_active_interfaces_atomic(rtwdev->hw, \ + IEEE80211_IFACE_ITER_NORMAL, iterator, data) +@@ -20,6 +17,15 @@ struct rtw_dev; + #define rtw_iterate_keys_rcu(rtwdev, vif, iterator, data) \ + ieee80211_iter_keys_rcu((rtwdev)->hw, vif, iterator, data) + ++void rtw_iterate_vifs(struct rtw_dev *rtwdev, ++ void (*iterator)(void *data, u8 *mac, ++ struct ieee80211_vif *vif), ++ void *data); ++void rtw_iterate_stas(struct rtw_dev *rtwdev, ++ void (*iterator)(void *data, ++ struct ieee80211_sta *sta), ++ void *data); ++ + static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr) + { + __le16 fc = hdr->frame_control; diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-add-8723de-alias.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-add-8723de-alias.patch new file mode 100644 index 0000000000..17540ff279 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-add-8723de-alias.patch @@ -0,0 +1,14 @@ + +Replace 3rdparty 8723de driver by the new rtw88 driver. + +Add a module alias to keep upgrade path. + +Signed-off-by: Thomas Backlund + +--- a/drivers/net/wireless/realtek/rtw88/rtw8723de.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8723de.c +@@ -28,3 +28,4 @@ module_pci_driver(rtw_8723de_driver); + MODULE_AUTHOR("Realtek Corporation"); + MODULE_DESCRIPTION("Realtek 802.11n wireless 8723de driver"); + MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_ALIAS("8723de"); diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-add-r8822be-alias.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-add-r8822be-alias.patch new file mode 100644 index 0000000000..8e44bd0c73 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-rtw88-add-r8822be-alias.patch @@ -0,0 +1,14 @@ + +The staging driver rtlwifi/r8822be.ko.xz is being replaced by the new rtw88 driver. + +Add a module alias to keep upgrade path. + +Signed-off-by: Thomas Backlund + +--- a/drivers/net/wireless/realtek/rtw88/rtw8822be.c ++++ b/drivers/net/wireless/realtek/rtw88/rtw8822be.c +@@ -28,3 +28,4 @@ module_pci_driver(rtw_8822be_driver); + MODULE_AUTHOR("Realtek Corporation"); + MODULE_DESCRIPTION("Realtek 802.11ac wireless 8822be driver"); + MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_ALIAS("r8822be"); diff --git a/kernel/tools/perf/files/patches/mageia/net-wireless-rtw89-6.2-git.patch b/kernel/tools/perf/files/patches/mageia/net-wireless-rtw89-6.2-git.patch new file mode 100644 index 0000000000..6941b5b6db --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/net-wireless-rtw89-6.2-git.patch @@ -0,0 +1,40911 @@ + + drivers/net/wireless/realtek/rtw89/Kconfig | 14 + drivers/net/wireless/realtek/rtw89/Makefile | 11 + drivers/net/wireless/realtek/rtw89/chan.c | 40 + drivers/net/wireless/realtek/rtw89/coex.c | 9 + drivers/net/wireless/realtek/rtw89/core.c | 100 + drivers/net/wireless/realtek/rtw89/core.h | 238 + + drivers/net/wireless/realtek/rtw89/debug.c | 1050 +++++++ + drivers/net/wireless/realtek/rtw89/debug.h | 2 + drivers/net/wireless/realtek/rtw89/fw.c | 792 +++++- + drivers/net/wireless/realtek/rtw89/fw.h | 731 +++++ + drivers/net/wireless/realtek/rtw89/mac.c | 764 ++++- + drivers/net/wireless/realtek/rtw89/mac.h | 120 + drivers/net/wireless/realtek/rtw89/mac80211.c | 70 + drivers/net/wireless/realtek/rtw89/pci.c | 41 + drivers/net/wireless/realtek/rtw89/pci.h | 12 + drivers/net/wireless/realtek/rtw89/phy.c | 356 ++ + drivers/net/wireless/realtek/rtw89/phy.h | 87 + drivers/net/wireless/realtek/rtw89/ps.c | 2 + drivers/net/wireless/realtek/rtw89/ps.h | 1 + drivers/net/wireless/realtek/rtw89/reg.h | 466 +++ + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 179 - + drivers/net/wireless/realtek/rtw89/rtw8852a.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2445 ++++++++++++++++++ + drivers/net/wireless/realtek/rtw89/rtw8852b.h | 137 + + drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c | 4174 +++++++++++++++++++++++++++++++ + drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h | 25 + drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.c | 794 ++++++ + drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.h | 62 + drivers/net/wireless/realtek/rtw89/rtw8852b_table.c |22877 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/wireless/realtek/rtw89/rtw8852b_table.h | 30 + drivers/net/wireless/realtek/rtw89/rtw8852be.c | 64 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 232 - + drivers/net/wireless/realtek/rtw89/rtw8852c.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c | 25 + drivers/net/wireless/realtek/rtw89/rtw8852c_table.c | 988 ++++++- + drivers/net/wireless/realtek/rtw89/txrx.h | 4 + drivers/net/wireless/realtek/rtw89/util.h | 11 + drivers/net/wireless/realtek/rtw89/wow.c | 859 ++++++ + drivers/net/wireless/realtek/rtw89/wow.h | 21 + 39 files changed, 37041 insertions(+), 794 deletions(-) + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/chan.c linux-6.2/drivers/net/wireless/realtek/rtw89/chan.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/chan.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/chan.c 2022-12-24 00:49:25.775376835 +0200 +@@ -4,6 +4,7 @@ + + #include "chan.h" + #include "debug.h" ++#include "util.h" + + static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band, + u8 center_chan) +@@ -108,8 +109,8 @@ bool rtw89_assign_entity_chan(struct rtw + const struct rtw89_chan *new) + { + struct rtw89_hal *hal = &rtwdev->hal; +- struct rtw89_chan *chan = &hal->chan[idx]; +- struct rtw89_chan_rcd *rcd = &hal->chan_rcd[idx]; ++ struct rtw89_chan *chan = &hal->sub[idx].chan; ++ struct rtw89_chan_rcd *rcd = &hal->sub[idx].rcd; + bool band_changed; + + rcd->prev_primary_channel = chan->primary_channel; +@@ -127,7 +128,7 @@ static void __rtw89_config_entity_chande + { + struct rtw89_hal *hal = &rtwdev->hal; + +- hal->chandef[idx] = *chandef; ++ hal->sub[idx].chandef = *chandef; + + if (from_stack) + set_bit(idx, hal->entity_map); +@@ -195,6 +196,7 @@ int rtw89_chanctx_ops_add(struct rtw89_d + rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); + rtw89_set_channel(rtwdev); + cfg->idx = idx; ++ hal->sub[idx].cfg = cfg; + return 0; + } + +@@ -203,8 +205,34 @@ void rtw89_chanctx_ops_remove(struct rtw + { + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; ++ struct rtw89_vif *rtwvif; ++ u8 drop, roll; + +- clear_bit(cfg->idx, hal->entity_map); ++ drop = cfg->idx; ++ if (drop != RTW89_SUB_ENTITY_0) ++ goto out; ++ ++ roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, drop + 1); ++ ++ /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */ ++ if (roll == NUM_OF_RTW89_SUB_ENTITY) ++ goto out; ++ ++ /* RTW89_SUB_ENTITY_0 is going to release, and another exists. ++ * Make another roll down to RTW89_SUB_ENTITY_0 to replace. ++ */ ++ hal->sub[roll].cfg->idx = RTW89_SUB_ENTITY_0; ++ hal->sub[RTW89_SUB_ENTITY_0] = hal->sub[roll]; ++ ++ rtw89_for_each_rtwvif(rtwdev, rtwvif) { ++ if (rtwvif->sub_entity_idx == roll) ++ rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; ++ } ++ ++ drop = roll; ++ ++out: ++ clear_bit(drop, hal->entity_map); + rtw89_set_channel(rtwdev); + } + +@@ -225,6 +253,9 @@ int rtw89_chanctx_ops_assign_vif(struct + struct rtw89_vif *rtwvif, + struct ieee80211_chanctx_conf *ctx) + { ++ struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; ++ ++ rtwvif->sub_entity_idx = cfg->idx; + return 0; + } + +@@ -232,4 +263,5 @@ void rtw89_chanctx_ops_unassign_vif(stru + struct rtw89_vif *rtwvif, + struct ieee80211_chanctx_conf *ctx) + { ++ rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; + } +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/coex.c linux-6.2/drivers/net/wireless/realtek/rtw89/coex.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/coex.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/coex.c 2022-12-24 00:49:25.776376835 +0200 +@@ -1809,13 +1809,18 @@ static void _set_rf_trx_para(struct rtw8 + struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_bt_info *bt = &btc->cx.bt; ++ struct rtw89_btc_bt_link_info *b = &bt->link_info; + struct rtw89_btc_rf_trx_para para; + u32 wl_stb_chg = 0; + u8 level_id = 0; + + if (!dm->freerun) { +- dm->trx_para_level = 0; +- chip->ops->btc_bt_aci_imp(rtwdev); ++ /* fix LNA2 = level-5 for BT ACI issue at BTG */ ++ if ((btc->dm.wl_btg_rx && b->profile_cnt.now != 0) || ++ dm->bt_only == 1) ++ dm->trx_para_level = 1; ++ else ++ dm->trx_para_level = 0; + } + + level_id = (u8)dm->trx_para_level; +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/core.c linux-6.2/drivers/net/wireless/realtek/rtw89/core.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/core.c 2022-12-31 22:58:05.366710726 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/core.c 2022-12-24 00:49:25.776376835 +0200 +@@ -171,7 +171,7 @@ bool rtw89_ra_report_to_bitrate(struct r + return true; + } + +-static struct ieee80211_supported_band rtw89_sband_2ghz = { ++static const struct ieee80211_supported_band rtw89_sband_2ghz = { + .band = NL80211_BAND_2GHZ, + .channels = rtw89_channels_2ghz, + .n_channels = ARRAY_SIZE(rtw89_channels_2ghz), +@@ -181,7 +181,7 @@ static struct ieee80211_supported_band r + .vht_cap = {0}, + }; + +-static struct ieee80211_supported_band rtw89_sband_5ghz = { ++static const struct ieee80211_supported_band rtw89_sband_5ghz = { + .band = NL80211_BAND_5GHZ, + .channels = rtw89_channels_5ghz, + .n_channels = ARRAY_SIZE(rtw89_channels_5ghz), +@@ -193,7 +193,7 @@ static struct ieee80211_supported_band r + .vht_cap = {0}, + }; + +-static struct ieee80211_supported_band rtw89_sband_6ghz = { ++static const struct ieee80211_supported_band rtw89_sband_6ghz = { + .band = NL80211_BAND_6GHZ, + .channels = rtw89_channels_6ghz, + .n_channels = ARRAY_SIZE(rtw89_channels_6ghz), +@@ -1196,7 +1196,11 @@ static void rtw89_core_parse_phy_status_ + if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6) + return; + /* sign conversion for S(12,2) */ +- cfo = sign_extend32(RTW89_GET_PHY_STS_IE01_CFO(addr), 11); ++ if (rtwdev->chip->cfo_src_fd) ++ cfo = sign_extend32(RTW89_GET_PHY_STS_IE01_FD_CFO(addr), 11); ++ else ++ cfo = sign_extend32(RTW89_GET_PHY_STS_IE01_PREMB_CFO(addr), 11); ++ + rtw89_phy_cfo_parse(rtwdev, cfo, phy_ppdu); + } + +@@ -1255,6 +1259,9 @@ static int rtw89_core_rx_parse_phy_sts(s + if (phy_ppdu->ie < RTW89_CCK_PKT) + return -EINVAL; + ++ if (!phy_ppdu->to_self) ++ return 0; ++ + pos = (u8 *)phy_ppdu->buf + PHY_STS_HDR_LEN; + end = (u8 *)phy_ppdu->buf + phy_ppdu->len; + while (pos < end) { +@@ -1398,6 +1405,9 @@ static void rtw89_vif_rx_stats_iter(void + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + const u8 *bssid = iter_data->bssid; + ++ if (!vif->bss_conf.bssid) ++ return; ++ + if (ieee80211_is_trigger(hdr->frame_control)) { + rtw89_stats_trigger_frame(rtwdev, vif, skb); + return; +@@ -1470,6 +1480,27 @@ static void rtw89_core_hw_to_sband_rate( + rx_status->rate_idx -= 4; + } + ++static void rtw89_core_update_radiotap(struct rtw89_dev *rtwdev, ++ struct sk_buff *skb, ++ struct ieee80211_rx_status *rx_status) ++{ ++ static const struct ieee80211_radiotap_he known_he = { ++ .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | ++ IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN), ++ .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN), ++ }; ++ struct ieee80211_radiotap_he *he; ++ ++ if (!(rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR)) ++ return; ++ ++ if (rx_status->encoding == RX_ENC_HE) { ++ rx_status->flag |= RX_FLAG_RADIOTAP_HE; ++ he = skb_push(skb, sizeof(*he)); ++ *he = known_he; ++ } ++} ++ + static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct rtw89_rx_desc_info *desc_info, +@@ -1484,6 +1515,7 @@ static void rtw89_core_rx_to_mac80211(st + + rtw89_core_hw_to_sband_rate(rx_status); + rtw89_core_rx_stats(rtwdev, phy_ppdu, desc_info, skb_ppdu); ++ rtw89_core_update_radiotap(rtwdev, skb_ppdu, rx_status); + /* In low power mode, it does RX in thread context. */ + local_bh_disable(); + ieee80211_rx_napi(rtwdev->hw, NULL, skb_ppdu, napi); +@@ -2201,6 +2233,9 @@ static void rtw89_track_work(struct work + track_work.work); + bool tfc_changed; + ++ if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags)) ++ return; ++ + mutex_lock(&rtwdev->mutex); + + if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) +@@ -2227,6 +2262,7 @@ static void rtw89_track_work(struct work + rtw89_phy_ra_update(rtwdev); + rtw89_phy_cfo_track(rtwdev); + rtw89_phy_tx_path_div_track(rtwdev); ++ rtw89_phy_ul_tb_ctrl_track(rtwdev); + + if (rtwdev->lps_enabled && !rtwdev->btc.lps) + rtw89_enter_lps_track(rtwdev); +@@ -2375,6 +2411,8 @@ void rtw89_vif_type_mapping(struct ieee8 + rtwvif->self_role = RTW89_SELF_ROLE_CLIENT; + rtwvif->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL; + break; ++ case NL80211_IFTYPE_MONITOR: ++ break; + default: + WARN_ON(1); + break; +@@ -2410,6 +2448,8 @@ int rtw89_core_sta_add(struct rtw89_dev + } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { + rtwsta->mac_id = rtw89_core_acquire_bit_map(rtwdev->mac_id_map, + RTW89_MAX_MAC_ID_NUM); ++ if (rtwsta->mac_id == RTW89_MAX_MAC_ID_NUM) ++ return -ENOSPC; + } + + return 0; +@@ -2548,6 +2588,7 @@ int rtw89_core_sta_assoc(struct rtw89_de + rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, + BTC_ROLE_MSTS_STA_CONN_END); + rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template); ++ rtw89_phy_ul_tb_assoc(rtwdev, rtwvif); + } + + return ret; +@@ -2933,6 +2974,41 @@ void rtw89_core_update_beacon_work(struc + mutex_unlock(&rtwdev->mutex); + } + ++int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond) ++{ ++ struct completion *cmpl = &wait->completion; ++ unsigned long timeout; ++ unsigned int cur; ++ ++ cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond); ++ if (cur != RTW89_WAIT_COND_IDLE) ++ return -EBUSY; ++ ++ timeout = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT); ++ if (timeout == 0) { ++ atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE); ++ return -ETIMEDOUT; ++ } ++ ++ if (wait->data.err) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond, ++ const struct rtw89_completion_data *data) ++{ ++ unsigned int cur; ++ ++ cur = atomic_cmpxchg(&wait->cond, cond, RTW89_WAIT_COND_IDLE); ++ if (cur != cond) ++ return; ++ ++ wait->data = *data; ++ complete(&wait->completion); ++} ++ + int rtw89_core_start(struct rtw89_dev *rtwdev) + { + int ret; +@@ -2957,7 +3033,7 @@ int rtw89_core_start(struct rtw89_dev *r + return ret; + + rtw89_phy_init_bb_reg(rtwdev); +- rtw89_phy_init_rf_reg(rtwdev); ++ rtw89_phy_init_rf_reg(rtwdev, false); + + rtw89_btc_ntfy_init(rtwdev, BTC_MODE_NORMAL); + +@@ -3037,6 +3113,7 @@ int rtw89_core_init(struct rtw89_dev *rt + continue; + INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]); + } ++ INIT_LIST_HEAD(&rtwdev->wow.pkt_list); + INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work); + INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); + INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work); +@@ -3053,6 +3130,8 @@ int rtw89_core_init(struct rtw89_dev *rt + mutex_init(&rtwdev->rf_mutex); + rtwdev->total_sta_assoc = 0; + ++ rtw89_init_wait(&rtwdev->mcc.wait); ++ + INIT_WORK(&rtwdev->c2h_work, rtw89_fw_c2h_work); + INIT_WORK(&rtwdev->ips_work, rtw89_ips_work); + skb_queue_head_init(&rtwdev->c2h_queue); +@@ -3251,6 +3330,7 @@ static int rtw89_core_register_hw(struct + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ++ ieee80211_hw_set(hw, WANT_MONITOR_VIF); + + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +@@ -3268,6 +3348,10 @@ static int rtw89_core_register_hw(struct + hw->wiphy->max_scan_ssids = RTW89_SCANOFLD_MAX_SSID; + hw->wiphy->max_scan_ie_len = RTW89_SCANOFLD_MAX_IE_LEN; + ++#ifdef CONFIG_PM ++ hw->wiphy->wowlan = rtwdev->chip->wowlan_stub; ++#endif ++ + hw->wiphy->tid_config_support.vif |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL); + hw->wiphy->tid_config_support.peer |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL); + hw->wiphy->tid_config_support.vif |= BIT(NL80211_TID_CONFIG_ATTR_AMSDU_CTRL); +@@ -3336,6 +3420,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_ + u32 bus_data_size, + const struct rtw89_chip_info *chip) + { ++ const struct firmware *firmware; + struct ieee80211_hw *hw; + struct rtw89_dev *rtwdev; + struct ieee80211_ops *ops; +@@ -3343,7 +3428,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_ + u32 early_feat_map = 0; + bool no_chanctx; + +- rtw89_early_fw_feature_recognize(device, chip, &early_feat_map); ++ firmware = rtw89_early_fw_feature_recognize(device, chip, &early_feat_map); + + ops = kmemdup(&rtw89_ops, sizeof(rtw89_ops), GFP_KERNEL); + if (!ops) +@@ -3370,6 +3455,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_ + rtwdev->dev = device; + rtwdev->ops = ops; + rtwdev->chip = chip; ++ rtwdev->fw.firmware = firmware; + + rtw89_debug(rtwdev, RTW89_DBG_FW, "probe driver %s chanctx\n", + no_chanctx ? "without" : "with"); +@@ -3378,6 +3464,7 @@ struct rtw89_dev *rtw89_alloc_ieee80211_ + + err: + kfree(ops); ++ release_firmware(firmware); + return NULL; + } + EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw); +@@ -3385,6 +3472,7 @@ EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw); + void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev) + { + kfree(rtwdev->ops); ++ release_firmware(rtwdev->fw.firmware); + ieee80211_free_hw(rtwdev->hw); + } + EXPORT_SYMBOL(rtw89_free_ieee80211_hw); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/core.h linux-6.2/drivers/net/wireless/realtek/rtw89/core.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/core.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/core.h 2022-12-24 00:49:25.777376835 +0200 +@@ -35,6 +35,7 @@ extern const struct ieee80211_ops rtw89_ + #define RSSI_FACTOR 1 + #define RTW89_RSSI_RAW_TO_DBM(rssi) ((s8)((rssi) >> RSSI_FACTOR) - MAX_RSSI) + #define RTW89_TX_DIV_RSSI_RAW_TH (2 << RSSI_FACTOR) ++#define RTW89_RADIOTAP_ROOM ALIGN(sizeof(struct ieee80211_radiotap_he), 64) + + #define RTW89_HTC_MASK_VARIANT GENMASK(1, 0) + #define RTW89_HTC_VARIANT_HE 3 +@@ -84,6 +85,7 @@ enum rtw89_subband { + RTW89_CH_6G_BAND_IDX7, /* Ultra-high */ + + RTW89_SUBBAND_NR, ++ RTW89_SUBBAND_2GHZ_5GHZ_NR = RTW89_CH_5G_BAND_4 + 1, + }; + + enum rtw89_gain_offset { +@@ -177,7 +179,9 @@ enum rtw89_upd_mode { + RTW89_ROLE_REMOVE, + RTW89_ROLE_TYPE_CHANGE, + RTW89_ROLE_INFO_CHANGE, +- RTW89_ROLE_CON_DISCONN ++ RTW89_ROLE_CON_DISCONN, ++ RTW89_ROLE_BAND_SW, ++ RTW89_ROLE_FW_RESTORE, + }; + + enum rtw89_self_role { +@@ -476,6 +480,20 @@ enum rtw89_regulation_type { + RTW89_REGD_NUM, + }; + ++enum rtw89_fw_pkt_ofld_type { ++ RTW89_PKT_OFLD_TYPE_PROBE_RSP = 0, ++ RTW89_PKT_OFLD_TYPE_PS_POLL = 1, ++ RTW89_PKT_OFLD_TYPE_NULL_DATA = 2, ++ RTW89_PKT_OFLD_TYPE_QOS_NULL = 3, ++ RTW89_PKT_OFLD_TYPE_CTS2SELF = 4, ++ RTW89_PKT_OFLD_TYPE_ARP_RSP = 5, ++ RTW89_PKT_OFLD_TYPE_NDP = 6, ++ RTW89_PKT_OFLD_TYPE_EAPOL_KEY = 7, ++ RTW89_PKT_OFLD_TYPE_SA_QUERY = 8, ++ RTW89_PKT_OFLD_TYPE_PROBE_REQ = 12, ++ RTW89_PKT_OFLD_TYPE_NUM, ++}; ++ + struct rtw89_txpwr_byrate { + s8 cck[RTW89_RATE_CCK_MAX]; + s8 ofdm[RTW89_RATE_OFDM_MAX]; +@@ -490,6 +508,8 @@ enum rtw89_bandwidth_section_num { + RTW89_BW80_SEC_NUM = 2, + }; + ++#define RTW89_TXPWR_LMT_PAGE_SIZE 40 ++ + struct rtw89_txpwr_limit { + s8 cck_20m[RTW89_BF_NUM]; + s8 cck_40m[RTW89_BF_NUM]; +@@ -504,6 +524,8 @@ struct rtw89_txpwr_limit { + + #define RTW89_RU_SEC_NUM 8 + ++#define RTW89_TXPWR_LMT_RU_PAGE_SIZE 24 ++ + struct rtw89_txpwr_limit_ru { + s8 ru26[RTW89_RU_SEC_NUM]; + s8 ru52[RTW89_RU_SEC_NUM]; +@@ -631,6 +653,13 @@ enum rtw89_sc_offset { + RTW89_SC_40_LOWER = 10, + }; + ++enum rtw89_wow_flags { ++ RTW89_WOW_FLAG_EN_MAGIC_PKT, ++ RTW89_WOW_FLAG_EN_REKEY_PKT, ++ RTW89_WOW_FLAG_EN_DISCONNECT, ++ RTW89_WOW_FLAG_NUM, ++}; ++ + struct rtw89_chan { + u8 channel; + u8 primary_channel; +@@ -2192,6 +2221,7 @@ struct rtw89_sta { + + struct rtw89_efuse { + bool valid; ++ bool power_k_valid; + u8 xtal_cap; + u8 addr[ETH_ALEN]; + u8 rfe_type; +@@ -2210,6 +2240,8 @@ struct rtw89_phy_rate_pattern { + struct rtw89_vif { + struct list_head list; + struct rtw89_dev *rtwdev; ++ enum rtw89_sub_entity_idx sub_entity_idx; ++ + u8 mac_id; + u8 port; + u8 mac_addr[ETH_ALEN]; +@@ -2232,6 +2264,8 @@ struct rtw89_vif { + bool wowlan_magic; + bool is_hesta; + bool last_a_ctrl; ++ bool dyn_tb_bedge_en; ++ u8 def_tri_idx; + struct work_struct update_beacon_work; + struct rtw89_addr_cam_entry addr_cam; + struct rtw89_bssid_cam_entry bssid_cam; +@@ -2280,6 +2314,16 @@ struct rtw89_hci_ops { + */ + void (*recovery_start)(struct rtw89_dev *rtwdev); + void (*recovery_complete)(struct rtw89_dev *rtwdev); ++ ++ void (*ctrl_txdma_ch)(struct rtw89_dev *rtwdev, bool enable); ++ void (*ctrl_txdma_fw_ch)(struct rtw89_dev *rtwdev, bool enable); ++ void (*ctrl_trxhci)(struct rtw89_dev *rtwdev, bool enable); ++ int (*poll_txdma_ch)(struct rtw89_dev *rtwdev); ++ void (*clr_idx_all)(struct rtw89_dev *rtwdev); ++ void (*clear)(struct rtw89_dev *rtwdev, struct pci_dev *pdev); ++ void (*disable_intr)(struct rtw89_dev *rtwdev); ++ void (*enable_intr)(struct rtw89_dev *rtwdev); ++ int (*rst_bdram)(struct rtw89_dev *rtwdev); + }; + + struct rtw89_hci_info { +@@ -2357,7 +2401,6 @@ struct rtw89_chip_ops { + void (*btc_set_wl_pri)(struct rtw89_dev *rtwdev, u8 map, bool state); + void (*btc_set_wl_txpwr_ctrl)(struct rtw89_dev *rtwdev, u32 txpwr_val); + s8 (*btc_get_bt_rssi)(struct rtw89_dev *rtwdev, s8 val); +- void (*btc_bt_aci_imp)(struct rtw89_dev *rtwdev); + void (*btc_update_bt_cnt)(struct rtw89_dev *rtwdev); + void (*btc_wl_s1_standby)(struct rtw89_dev *rtwdev, bool state); + void (*btc_set_policy)(struct rtw89_dev *rtwdev, u16 policy_type); +@@ -2384,6 +2427,7 @@ enum rtw89_dma_ch { + enum rtw89_qta_mode { + RTW89_QTA_SCC, + RTW89_QTA_DLFW, ++ RTW89_QTA_WOW, + + /* keep last */ + RTW89_QTA_INVALID, +@@ -2607,6 +2651,11 @@ struct rtw89_dig_regs { + struct rtw89_reg_def p1_s20_pagcugc_en; + }; + ++struct rtw89_phy_ul_tb_info { ++ bool dyn_tb_tri_en; ++ u8 def_if_bandedge; ++}; ++ + struct rtw89_chip_info { + enum rtw89_core_chip_id chip_id; + const struct rtw89_chip_ops *ops; +@@ -2618,10 +2667,13 @@ struct rtw89_chip_info { + u32 rsvd_ple_ofst; + const struct rtw89_hfc_param_ini *hfc_param_ini; + const struct rtw89_dle_mem *dle_mem; ++ u8 wde_qempty_acq_num; ++ u8 wde_qempty_mgq_sel; + u32 rf_base_addr[2]; + u8 support_chanctx_num; + u8 support_bands; + bool support_bw160; ++ bool support_ul_tb_ctrl; + bool hw_sec_hdr; + u8 rf_path_num; + u8 tx_nss; +@@ -2714,11 +2766,13 @@ struct rtw89_chip_info { + u32 c2h_ctrl_reg; + const u32 *c2h_regs; + const struct rtw89_page_regs *page_regs; ++ bool cfo_src_fd; + const struct rtw89_reg_def *dcfo_comp; + u8 dcfo_comp_sft; + const struct rtw89_imr_info *imr_info; + const struct rtw89_rrsr_cfgs *rrsr_cfgs; + u32 dma_ch_mask; ++ const struct wiphy_wowlan_support *wowlan_stub; + }; + + union rtw89_bus_info { +@@ -2760,6 +2814,28 @@ struct rtw89_mac_info { + u8 cpwm_seq_num; + }; + ++#define RTW89_COMPLETION_BUF_SIZE 24 ++#define RTW89_WAIT_COND_IDLE UINT_MAX ++ ++struct rtw89_completion_data { ++ bool err; ++ u8 buf[RTW89_COMPLETION_BUF_SIZE]; ++}; ++ ++struct rtw89_wait_info { ++ atomic_t cond; ++ struct completion completion; ++ struct rtw89_completion_data data; ++}; ++ ++#define RTW89_WAIT_FOR_COND_TIMEOUT msecs_to_jiffies(100) ++ ++static inline void rtw89_init_wait(struct rtw89_wait_info *wait) ++{ ++ init_completion(&wait->completion); ++ atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE); ++} ++ + enum rtw89_fw_type { + RTW89_FW_NORMAL = 1, + RTW89_FW_WOWLAN = 3, +@@ -2879,6 +2955,13 @@ enum rtw89_entity_mode { + RTW89_ENTITY_MODE_SCC, + }; + ++struct rtw89_sub_entity { ++ struct cfg80211_chan_def chandef; ++ struct rtw89_chan chan; ++ struct rtw89_chan_rcd rcd; ++ struct rtw89_chanctx_cfg *cfg; ++}; ++ + struct rtw89_hal { + u32 rx_fltr; + u8 cv; +@@ -2892,13 +2975,10 @@ struct rtw89_hal { + bool support_igi; + + DECLARE_BITMAP(entity_map, NUM_OF_RTW89_SUB_ENTITY); +- struct cfg80211_chan_def chandef[NUM_OF_RTW89_SUB_ENTITY]; ++ struct rtw89_sub_entity sub[NUM_OF_RTW89_SUB_ENTITY]; + + bool entity_active; + enum rtw89_entity_mode entity_mode; +- +- struct rtw89_chan chan[NUM_OF_RTW89_SUB_ENTITY]; +- struct rtw89_chan_rcd chan_rcd[NUM_OF_RTW89_SUB_ENTITY]; + }; + + #define RTW89_MAX_MAC_ID_NUM 128 +@@ -2915,6 +2995,9 @@ enum rtw89_flags { + RTW89_FLAG_LOW_POWER_MODE, + RTW89_FLAG_INACTIVE_PS, + RTW89_FLAG_CRASH_SIMULATING, ++ RTW89_FLAG_WOWLAN, ++ RTW89_FLAG_FORBIDDEN_TRACK_WROK, ++ RTW89_FLAG_CHANGING_INTERFACE, + + NUM_OF_RTW89_FLAGS, + }; +@@ -2943,6 +3026,7 @@ struct rtw89_pkt_drop_params { + u8 port; + u8 mbssid; + bool tf_trs; ++ u32 macid_band_sel[4]; + }; + + struct rtw89_pkt_stat { +@@ -2976,7 +3060,7 @@ struct rtw89_dack_info { + #define RTW89_IQK_CHS_NR 2 + #define RTW89_IQK_PATH_NR 4 + +-struct rtw89_mcc_info { ++struct rtw89_rfk_mcc_info { + u8 ch[RTW89_IQK_CHS_NR]; + u8 band[RTW89_IQK_CHS_NR]; + u8 table_idx; +@@ -3044,6 +3128,7 @@ struct rtw89_dpk_bkup_para { + struct rtw89_dpk_info { + bool is_dpk_enable; + bool is_dpk_reload_en; ++ u8 dpk_gs[RTW89_PHY_MAX]; + u16 dc_i[RTW89_DPK_RF_PATH][RTW89_DPK_BKUP_NUM]; + u16 dc_q[RTW89_DPK_RF_PATH][RTW89_DPK_BKUP_NUM]; + u8 corr_val[RTW89_DPK_RF_PATH][RTW89_DPK_BKUP_NUM]; +@@ -3159,6 +3244,14 @@ struct rtw89_cfo_tracking_info { + u8 lock_cnt; + }; + ++enum rtw89_tssi_alimk_band { ++ TSSI_ALIMK_2G = 0, ++ TSSI_ALIMK_5GL, ++ TSSI_ALIMK_5GM, ++ TSSI_ALIMK_5GH, ++ TSSI_ALIMK_MAX ++}; ++ + /* 2GL, 2GH, 5GL1, 5GH1, 5GM1, 5GM2, 5GH1, 5GH2 */ + #define TSSI_TRIM_CH_GROUP_NUM 8 + #define TSSI_TRIM_CH_GROUP_NUM_6G 16 +@@ -3169,6 +3262,8 @@ struct rtw89_cfo_tracking_info { + #define TSSI_MCS_6G_CH_GROUP_NUM 32 + #define TSSI_MCS_CH_GROUP_NUM \ + (TSSI_MCS_2G_CH_GROUP_NUM + TSSI_MCS_5G_CH_GROUP_NUM) ++#define TSSI_MAX_CH_NUM 67 ++#define TSSI_ALIMK_VALUE_NUM 8 + + struct rtw89_tssi_info { + u8 thermal[RF_PATH_MAX]; +@@ -3181,6 +3276,11 @@ struct rtw89_tssi_info { + bool tssi_tracking_check[RF_PATH_MAX]; + u8 default_txagc_offset[RF_PATH_MAX]; + u32 base_thermal[RF_PATH_MAX]; ++ bool check_backup_aligmk[RF_PATH_MAX][TSSI_MAX_CH_NUM]; ++ u32 alignment_backup_by_ch[RF_PATH_MAX][TSSI_MAX_CH_NUM][TSSI_ALIMK_VALUE_NUM]; ++ u32 alignment_value[RF_PATH_MAX][TSSI_ALIMK_MAX][TSSI_ALIMK_VALUE_NUM]; ++ bool alignment_done[RF_PATH_MAX][TSSI_ALIMK_MAX]; ++ u32 tssi_alimk_time; + }; + + struct rtw89_power_trim_info { +@@ -3421,8 +3521,40 @@ struct rtw89_phy_bb_gain_info { + + struct rtw89_phy_efuse_gain { + bool offset_valid; ++ bool comp_valid; + s8 offset[RF_PATH_MAX][RTW89_GAIN_OFFSET_NR]; /* S(8, 0) */ + s8 offset_base[RTW89_PHY_MAX]; /* S(8, 4) */ ++ s8 rssi_base[RTW89_PHY_MAX]; /* S(8, 4) */ ++ s8 comp[RF_PATH_MAX][RTW89_SUBBAND_NR]; /* S(8, 0) */ ++}; ++ ++#define RTW89_MAX_PATTERN_NUM 18 ++#define RTW89_MAX_PATTERN_MASK_SIZE 4 ++#define RTW89_MAX_PATTERN_SIZE 128 ++ ++struct rtw89_wow_cam_info { ++ bool r_w; ++ u8 idx; ++ u32 mask[RTW89_MAX_PATTERN_MASK_SIZE]; ++ u16 crc; ++ bool negative_pattern_match; ++ bool skip_mac_hdr; ++ bool uc; ++ bool mc; ++ bool bc; ++ bool valid; ++}; ++ ++struct rtw89_wow_param { ++ struct ieee80211_vif *wow_vif; ++ DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM); ++ struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM]; ++ u8 pattern_cnt; ++ struct list_head pkt_list; ++}; ++ ++struct rtw89_mcc_info { ++ struct rtw89_wait_info wait; + }; + + struct rtw89_dev { +@@ -3435,6 +3567,7 @@ struct rtw89_dev { + const struct rtw89_chip_info *chip; + const struct rtw89_pci_info *pci_info; + struct rtw89_hal hal; ++ struct rtw89_mcc_info mcc; + struct rtw89_mac_info mac; + struct rtw89_fw_info fw; + struct rtw89_hci_info hci; +@@ -3478,7 +3611,7 @@ struct rtw89_dev { + struct rtw89_dack_info dack; + struct rtw89_iqk_info iqk; + struct rtw89_dpk_info dpk; +- struct rtw89_mcc_info mcc; ++ struct rtw89_rfk_mcc_info rfk_mcc; + struct rtw89_lck_info lck; + struct rtw89_rx_dck_info rx_dck; + bool is_tssi_mode[RF_PATH_MAX]; +@@ -3495,6 +3628,7 @@ struct rtw89_dev { + struct rtw89_phy_ch_info ch_info; + struct rtw89_phy_bb_gain_info bb_gain; + struct rtw89_phy_efuse_gain efuse_gain; ++ struct rtw89_phy_ul_tb_info ul_tb_info; + + struct delayed_work track_work; + struct delayed_work coex_act1_work; +@@ -3513,6 +3647,8 @@ struct rtw89_dev { + enum rtw89_ps_mode ps_mode; + bool lps_enabled; + ++ struct rtw89_wow_param wow; ++ + /* napi structure */ + struct net_device netdev; + struct napi_struct napi; +@@ -3595,6 +3731,66 @@ static inline void rtw89_hci_recovery_co + rtwdev->hci.ops->recovery_complete(rtwdev); + } + ++static inline void rtw89_hci_enable_intr(struct rtw89_dev *rtwdev) ++{ ++ if (rtwdev->hci.ops->enable_intr) ++ rtwdev->hci.ops->enable_intr(rtwdev); ++} ++ ++static inline void rtw89_hci_disable_intr(struct rtw89_dev *rtwdev) ++{ ++ if (rtwdev->hci.ops->disable_intr) ++ rtwdev->hci.ops->disable_intr(rtwdev); ++} ++ ++static inline void rtw89_hci_ctrl_txdma_ch(struct rtw89_dev *rtwdev, bool enable) ++{ ++ if (rtwdev->hci.ops->ctrl_txdma_ch) ++ rtwdev->hci.ops->ctrl_txdma_ch(rtwdev, enable); ++} ++ ++static inline void rtw89_hci_ctrl_txdma_fw_ch(struct rtw89_dev *rtwdev, bool enable) ++{ ++ if (rtwdev->hci.ops->ctrl_txdma_fw_ch) ++ rtwdev->hci.ops->ctrl_txdma_fw_ch(rtwdev, enable); ++} ++ ++static inline void rtw89_hci_ctrl_trxhci(struct rtw89_dev *rtwdev, bool enable) ++{ ++ if (rtwdev->hci.ops->ctrl_trxhci) ++ rtwdev->hci.ops->ctrl_trxhci(rtwdev, enable); ++} ++ ++static inline int rtw89_hci_poll_txdma_ch(struct rtw89_dev *rtwdev) ++{ ++ int ret = 0; ++ ++ if (rtwdev->hci.ops->poll_txdma_ch) ++ ret = rtwdev->hci.ops->poll_txdma_ch(rtwdev); ++ return ret; ++} ++ ++static inline void rtw89_hci_clr_idx_all(struct rtw89_dev *rtwdev) ++{ ++ if (rtwdev->hci.ops->clr_idx_all) ++ rtwdev->hci.ops->clr_idx_all(rtwdev); ++} ++ ++static inline int rtw89_hci_rst_bdram(struct rtw89_dev *rtwdev) ++{ ++ int ret = 0; ++ ++ if (rtwdev->hci.ops->rst_bdram) ++ ret = rtwdev->hci.ops->rst_bdram(rtwdev); ++ return ret; ++} ++ ++static inline void rtw89_hci_clear(struct rtw89_dev *rtwdev, struct pci_dev *pdev) ++{ ++ if (rtwdev->hci.ops->clear) ++ rtwdev->hci.ops->clear(rtwdev, pdev); ++} ++ + static inline u8 rtw89_read8(struct rtw89_dev *rtwdev, u32 addr) + { + return rtwdev->hci.ops->read8(rtwdev, addr); +@@ -3948,7 +4144,7 @@ const struct cfg80211_chan_def *rtw89_ch + { + struct rtw89_hal *hal = &rtwdev->hal; + +- return &hal->chandef[idx]; ++ return &hal->sub[idx].chandef; + } + + static inline +@@ -3957,7 +4153,7 @@ const struct rtw89_chan *rtw89_chan_get( + { + struct rtw89_hal *hal = &rtwdev->hal; + +- return &hal->chan[idx]; ++ return &hal->sub[idx].chan; + } + + static inline +@@ -3966,7 +4162,7 @@ const struct rtw89_chan_rcd *rtw89_chan_ + { + struct rtw89_hal *hal = &rtwdev->hal; + +- return &hal->chan_rcd[idx]; ++ return &hal->sub[idx].rcd; + } + + static inline void rtw89_chip_fem_setup(struct rtw89_dev *rtwdev) +@@ -4221,6 +4417,23 @@ static inline struct rtw89_fw_suit *rtw8 + return &fw_info->normal; + } + ++static inline struct sk_buff *rtw89_alloc_skb_for_rx(struct rtw89_dev *rtwdev, ++ unsigned int length) ++{ ++ struct sk_buff *skb; ++ ++ if (rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR) { ++ skb = dev_alloc_skb(length + RTW89_RADIOTAP_ROOM); ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, RTW89_RADIOTAP_ROOM); ++ return skb; ++ } ++ ++ return dev_alloc_skb(length); ++} ++ + int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel); + int rtw89_h2c_tx(struct rtw89_dev *rtwdev, +@@ -4289,6 +4502,9 @@ int rtw89_regd_init(struct rtw89_dev *rt + void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request); + void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev, + struct rtw89_traffic_stats *stats); ++int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond); ++void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond, ++ const struct rtw89_completion_data *data); + int rtw89_core_start(struct rtw89_dev *rtwdev); + void rtw89_core_stop(struct rtw89_dev *rtwdev); + void rtw89_core_update_beacon_work(struct work_struct *work); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/debug.c linux-6.2/drivers/net/wireless/realtek/rtw89/debug.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/debug.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/debug.c 2022-12-24 00:49:25.778376835 +0200 +@@ -8,6 +8,7 @@ + #include "debug.h" + #include "fw.h" + #include "mac.h" ++#include "pci.h" + #include "ps.h" + #include "reg.h" + #include "sar.h" +@@ -51,6 +52,22 @@ struct rtw89_debugfs_priv { + }; + }; + ++static const u16 rtw89_rate_info_bw_to_mhz_map[] = { ++ [RATE_INFO_BW_20] = 20, ++ [RATE_INFO_BW_40] = 40, ++ [RATE_INFO_BW_80] = 80, ++ [RATE_INFO_BW_160] = 160, ++ [RATE_INFO_BW_320] = 320, ++}; ++ ++static u16 rtw89_rate_info_bw_to_mhz(enum rate_info_bw bw) ++{ ++ if (bw < ARRAY_SIZE(rtw89_rate_info_bw_to_mhz_map)) ++ return rtw89_rate_info_bw_to_mhz_map[bw]; ++ ++ return 0; ++} ++ + static int rtw89_debugfs_single_show(struct seq_file *m, void *v) + { + struct rtw89_debugfs_priv *debugfs_priv = m->private; +@@ -464,7 +481,7 @@ static const struct txpwr_map __txpwr_ma + }; + + static u8 __print_txpwr_ent(struct seq_file *m, const struct txpwr_ent *ent, +- const u8 *buf, const u8 cur) ++ const s8 *buf, const u8 cur) + { + char *fmt; + +@@ -493,8 +510,9 @@ static int __print_txpwr_map(struct seq_ + const struct txpwr_map *map) + { + u8 fct = rtwdev->chip->txpwr_factor_mac; +- u8 *buf, cur, i; + u32 val, addr; ++ s8 *buf, tmp; ++ u8 cur, i; + int ret; + + buf = vzalloc(map->addr_to - map->addr_from + 4); +@@ -507,8 +525,11 @@ static int __print_txpwr_map(struct seq_ + val = MASKDWORD; + + cur = addr - map->addr_from; +- for (i = 0; i < 4; i++, val >>= 8) +- buf[cur + i] = FIELD_GET(MASKBYTE0, val) >> fct; ++ for (i = 0; i < 4; i++, val >>= 8) { ++ /* signed 7 bits, and reserved BIT(7) */ ++ tmp = sign_extend32(val, 6); ++ buf[cur + i] = tmp >> fct; ++ } + } + + for (cur = 0, i = 0; i < map->size; i++) +@@ -770,13 +791,34 @@ rtw89_debug_priv_mac_mem_dump_get(struct + { + struct rtw89_debugfs_priv *debugfs_priv = m->private; + struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; ++ bool grant_read = false; ++ ++ if (debugfs_priv->mac_mem.sel >= RTW89_MAC_MEM_NUM) ++ return -ENOENT; ++ ++ if (rtwdev->chip->chip_id == RTL8852C) { ++ switch (debugfs_priv->mac_mem.sel) { ++ case RTW89_MAC_MEM_TXD_FIFO_0_V1: ++ case RTW89_MAC_MEM_TXD_FIFO_1_V1: ++ case RTW89_MAC_MEM_TXDATA_FIFO_0: ++ case RTW89_MAC_MEM_TXDATA_FIFO_1: ++ grant_read = true; ++ break; ++ default: ++ break; ++ } ++ } + + mutex_lock(&rtwdev->mutex); + rtw89_leave_ps_mode(rtwdev); ++ if (grant_read) ++ rtw89_write32_set(rtwdev, R_AX_TCR1, B_AX_TCR_FORCE_READ_TXDFIFO); + rtw89_debug_dump_mac_mem(m, rtwdev, + debugfs_priv->mac_mem.sel, + debugfs_priv->mac_mem.start, + debugfs_priv->mac_mem.len); ++ if (grant_read) ++ rtw89_write32_clr(rtwdev, R_AX_TCR1, B_AX_TCR_FORCE_READ_TXDFIFO); + mutex_unlock(&rtwdev->mutex); + + return 0; +@@ -947,7 +989,9 @@ static int rtw89_debug_mac_dump_dle_dbg( + static int rtw89_debug_mac_dump_dmac_dbg(struct rtw89_dev *rtwdev, + struct seq_file *m) + { +- int ret; ++ const struct rtw89_chip_info *chip = rtwdev->chip; ++ u32 dmac_err; ++ int i, ret; + + ret = rtw89_mac_check_mac_en(rtwdev, 0, RTW89_DMAC_SEL); + if (ret) { +@@ -955,98 +999,347 @@ static int rtw89_debug_mac_dump_dmac_dbg + return ret; + } + +- seq_printf(m, "R_AX_DMAC_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_DMAC_ERR_ISR)); +- seq_printf(m, "[0]R_AX_WDRLS_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_WDRLS_ERR_ISR)); +- seq_printf(m, "[1]R_AX_SEC_ERR_IMR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_ERR_IMR_ISR)); +- seq_printf(m, "[2.1]R_AX_MPDU_TX_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_ISR)); +- seq_printf(m, "[2.2]R_AX_MPDU_RX_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_ISR)); +- seq_printf(m, "[3]R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); +- seq_printf(m, "[4]R_AX_WDE_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); +- seq_printf(m, "[5.1]R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); +- seq_printf(m, "[5.2]R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); +- seq_printf(m, "[6]R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); +- seq_printf(m, "[7]R_AX_PKTIN_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); +- seq_printf(m, "[8.1]R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); +- seq_printf(m, "[8.2]R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); +- seq_printf(m, "[8.3]R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); +- seq_printf(m, "[10]R_AX_CPUIO_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_CPUIO_ERR_ISR)); +- seq_printf(m, "[11.1]R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); +- seq_printf(m, "[11.2]R_AX_BBRPT_CHINFO_ERR_IMR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR_ISR)); +- seq_printf(m, "[11.3]R_AX_BBRPT_DFS_ERR_IMR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR_ISR)); +- seq_printf(m, "[11.4]R_AX_LA_ERRFLAG=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_LA_ERRFLAG)); ++ dmac_err = rtw89_read32(rtwdev, R_AX_DMAC_ERR_ISR); ++ seq_printf(m, "R_AX_DMAC_ERR_ISR=0x%08x\n", dmac_err); ++ seq_printf(m, "R_AX_DMAC_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_DMAC_ERR_IMR)); ++ ++ if (dmac_err) { ++ seq_printf(m, "R_AX_WDE_ERR_FLAG_CFG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDE_ERR_FLAG_CFG_NUM1)); ++ seq_printf(m, "R_AX_PLE_ERR_FLAG_CFG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_CFG_NUM1)); ++ if (chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_PLE_ERRFLAG_MSG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_ERRFLAG_MSG)); ++ seq_printf(m, "R_AX_WDE_ERRFLAG_MSG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDE_ERRFLAG_MSG)); ++ seq_printf(m, "R_AX_PLE_DBGERR_LOCKEN=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_DBGERR_LOCKEN)); ++ seq_printf(m, "R_AX_PLE_DBGERR_STS=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_DBGERR_STS)); ++ } ++ } ++ ++ if (dmac_err & B_AX_WDRLS_ERR_FLAG) { ++ seq_printf(m, "R_AX_WDRLS_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDRLS_ERR_IMR)); ++ seq_printf(m, "R_AX_WDRLS_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDRLS_ERR_ISR)); ++ if (chip->chip_id == RTL8852C) ++ seq_printf(m, "R_AX_RPQ_RXBD_IDX=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX_V1)); ++ else ++ seq_printf(m, "R_AX_RPQ_RXBD_IDX=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); ++ } ++ ++ if (dmac_err & B_AX_WSEC_ERR_FLAG) { ++ if (chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_SEC_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_ERROR_FLAG_IMR)); ++ seq_printf(m, "R_AX_SEC_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_ERROR_FLAG)); ++ seq_printf(m, "R_AX_SEC_ENG_CTRL=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); ++ seq_printf(m, "R_AX_SEC_MPDU_PROC=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); ++ seq_printf(m, "R_AX_SEC_CAM_ACCESS=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); ++ seq_printf(m, "R_AX_SEC_CAM_RDATA=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); ++ seq_printf(m, "R_AX_SEC_DEBUG1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_DEBUG1)); ++ seq_printf(m, "R_AX_SEC_TX_DEBUG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); ++ seq_printf(m, "R_AX_SEC_RX_DEBUG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); ++ ++ rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, ++ B_AX_DBG_SEL0, 0x8B); ++ rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, ++ B_AX_DBG_SEL1, 0x8B); ++ rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, ++ B_AX_SEL_0XC0_MASK, 1); ++ for (i = 0; i < 0x10; i++) { ++ rtw89_write32_mask(rtwdev, R_AX_SEC_ENG_CTRL, ++ B_AX_SEC_DBG_PORT_FIELD_MASK, i); ++ seq_printf(m, "sel=%x,R_AX_SEC_DEBUG2=0x%08x\n", ++ i, rtw89_read32(rtwdev, R_AX_SEC_DEBUG2)); ++ } ++ } else { ++ seq_printf(m, "R_AX_SEC_ERR_IMR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); ++ seq_printf(m, "R_AX_SEC_ENG_CTRL=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); ++ seq_printf(m, "R_AX_SEC_MPDU_PROC=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); ++ seq_printf(m, "R_AX_SEC_CAM_ACCESS=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); ++ seq_printf(m, "R_AX_SEC_CAM_RDATA=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); ++ seq_printf(m, "R_AX_SEC_CAM_WDATA=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_WDATA)); ++ seq_printf(m, "R_AX_SEC_TX_DEBUG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); ++ seq_printf(m, "R_AX_SEC_RX_DEBUG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); ++ seq_printf(m, "R_AX_SEC_TRX_PKT_CNT=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_TRX_PKT_CNT)); ++ seq_printf(m, "R_AX_SEC_TRX_BLK_CNT=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_TRX_BLK_CNT)); ++ } ++ } ++ ++ if (dmac_err & B_AX_MPDU_ERR_FLAG) { ++ seq_printf(m, "R_AX_MPDU_TX_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_IMR)); ++ seq_printf(m, "R_AX_MPDU_TX_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_ISR)); ++ seq_printf(m, "R_AX_MPDU_RX_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_IMR)); ++ seq_printf(m, "R_AX_MPDU_RX_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_ISR)); ++ } ++ ++ if (dmac_err & B_AX_STA_SCHEDULER_ERR_FLAG) { ++ seq_printf(m, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); ++ seq_printf(m, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); ++ } ++ ++ if (dmac_err & B_AX_WDE_DLE_ERR_FLAG) { ++ seq_printf(m, "R_AX_WDE_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); ++ seq_printf(m, "R_AX_WDE_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); ++ seq_printf(m, "R_AX_PLE_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); ++ seq_printf(m, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); ++ } ++ ++ if (dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) { ++ if (chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_TXPKTCTL_B0_ERRFLAG_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_IMR)); ++ seq_printf(m, "R_AX_TXPKTCTL_B0_ERRFLAG_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_ISR)); ++ seq_printf(m, "R_AX_TXPKTCTL_B1_ERRFLAG_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_B1_ERRFLAG_IMR)); ++ seq_printf(m, "R_AX_TXPKTCTL_B1_ERRFLAG_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_B1_ERRFLAG_ISR)); ++ } else { ++ seq_printf(m, "R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); ++ seq_printf(m, "R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); ++ } ++ } ++ ++ if (dmac_err & B_AX_PLE_DLE_ERR_FLAG) { ++ seq_printf(m, "R_AX_WDE_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); ++ seq_printf(m, "R_AX_WDE_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); ++ seq_printf(m, "R_AX_PLE_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); ++ seq_printf(m, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); ++ seq_printf(m, "R_AX_WD_CPUQ_OP_0=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_0)); ++ seq_printf(m, "R_AX_WD_CPUQ_OP_1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_1)); ++ seq_printf(m, "R_AX_WD_CPUQ_OP_2=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_2)); ++ seq_printf(m, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS)); ++ seq_printf(m, "R_AX_PL_CPUQ_OP_0=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_0)); ++ seq_printf(m, "R_AX_PL_CPUQ_OP_1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_1)); ++ seq_printf(m, "R_AX_PL_CPUQ_OP_2=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_2)); ++ seq_printf(m, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); ++ if (chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_RX_CTRL0=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RX_CTRL0)); ++ seq_printf(m, "R_AX_RX_CTRL1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RX_CTRL1)); ++ seq_printf(m, "R_AX_RX_CTRL2=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RX_CTRL2)); ++ } else { ++ seq_printf(m, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); ++ seq_printf(m, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); ++ seq_printf(m, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); ++ } ++ } ++ ++ if (dmac_err & B_AX_PKTIN_ERR_FLAG) { ++ seq_printf(m, "R_AX_PKTIN_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PKTIN_ERR_IMR)); ++ seq_printf(m, "R_AX_PKTIN_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); ++ } ++ ++ if (dmac_err & B_AX_DISPATCH_ERR_FLAG) { ++ seq_printf(m, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); ++ seq_printf(m, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); ++ seq_printf(m, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); ++ seq_printf(m, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); ++ seq_printf(m, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); ++ seq_printf(m, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); ++ } ++ ++ if (dmac_err & B_AX_BBRPT_ERR_FLAG) { ++ if (chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_BBRPT_COM_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR)); ++ seq_printf(m, "R_AX_BBRPT_COM_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_ISR)); ++ seq_printf(m, "R_AX_BBRPT_CHINFO_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_ISR)); ++ seq_printf(m, "R_AX_BBRPT_CHINFO_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR)); ++ seq_printf(m, "R_AX_BBRPT_DFS_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR)); ++ seq_printf(m, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); ++ } else { ++ seq_printf(m, "R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); ++ seq_printf(m, "R_AX_BBRPT_CHINFO_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_ISR)); ++ seq_printf(m, "R_AX_BBRPT_CHINFO_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR)); ++ seq_printf(m, "R_AX_BBRPT_DFS_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR)); ++ seq_printf(m, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); ++ } ++ } ++ ++ if (dmac_err & B_AX_HAXIDMA_ERR_FLAG && chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK)); ++ seq_printf(m, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_HAXI_IDCT)); ++ } + + return 0; + } + +-static int rtw89_debug_mac_dump_cmac_dbg(struct rtw89_dev *rtwdev, +- struct seq_file *m) ++static int rtw89_debug_mac_dump_cmac_err(struct rtw89_dev *rtwdev, ++ struct seq_file *m, ++ enum rtw89_mac_idx band) + { ++ const struct rtw89_chip_info *chip = rtwdev->chip; ++ u32 offset = 0; ++ u32 cmac_err; + int ret; + +- ret = rtw89_mac_check_mac_en(rtwdev, 0, RTW89_CMAC_SEL); ++ ret = rtw89_mac_check_mac_en(rtwdev, band, RTW89_CMAC_SEL); + if (ret) { +- seq_puts(m, "[CMAC] : CMAC 0 not enabled\n"); ++ if (band) ++ seq_puts(m, "[CMAC] : CMAC1 not enabled\n"); ++ else ++ seq_puts(m, "[CMAC] : CMAC0 not enabled\n"); + return ret; + } + +- seq_printf(m, "R_AX_CMAC_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR)); +- seq_printf(m, "[0]R_AX_SCHEDULE_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_ISR)); +- seq_printf(m, "[1]R_AX_PTCL_ISR0=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PTCL_ISR0)); +- seq_printf(m, "[3]R_AX_DLE_CTRL=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_DLE_CTRL)); +- seq_printf(m, "[4]R_AX_PHYINFO_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR)); +- seq_printf(m, "[5]R_AX_TXPWR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TXPWR_ISR)); +- seq_printf(m, "[6]R_AX_RMAC_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_RMAC_ERR_ISR)); +- seq_printf(m, "[7]R_AX_TMAC_ERR_IMR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR)); ++ if (band) ++ offset = RTW89_MAC_AX_BAND_REG_OFFSET; + +- ret = rtw89_mac_check_mac_en(rtwdev, 1, RTW89_CMAC_SEL); +- if (ret) { +- seq_puts(m, "[CMAC] : CMAC 1 not enabled\n"); +- return ret; ++ cmac_err = rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR + offset); ++ seq_printf(m, "R_AX_CMAC_ERR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR + offset)); ++ seq_printf(m, "R_AX_CMAC_FUNC_EN [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_CMAC_FUNC_EN + offset)); ++ seq_printf(m, "R_AX_CK_EN [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_CK_EN + offset)); ++ ++ if (cmac_err & B_AX_SCHEDULE_TOP_ERR_IND) { ++ seq_printf(m, "R_AX_SCHEDULE_ERR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_IMR + offset)); ++ seq_printf(m, "R_AX_SCHEDULE_ERR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_ISR + offset)); ++ } ++ ++ if (cmac_err & B_AX_PTCL_TOP_ERR_IND) { ++ seq_printf(m, "R_AX_PTCL_IMR0 [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PTCL_IMR0 + offset)); ++ seq_printf(m, "R_AX_PTCL_ISR0 [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PTCL_ISR0 + offset)); ++ } ++ ++ if (cmac_err & B_AX_DMA_TOP_ERR_IND) { ++ if (chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_RX_ERR_FLAG [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_RX_ERR_FLAG + offset)); ++ seq_printf(m, "R_AX_RX_ERR_FLAG_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_RX_ERR_FLAG_IMR + offset)); ++ } else { ++ seq_printf(m, "R_AX_DLE_CTRL [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_DLE_CTRL + offset)); ++ } ++ } ++ ++ if (cmac_err & B_AX_DMA_TOP_ERR_IND || cmac_err & B_AX_WMAC_RX_ERR_IND) { ++ if (chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_PHYINFO_ERR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR + offset)); ++ seq_printf(m, "R_AX_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR + offset)); ++ } else { ++ seq_printf(m, "R_AX_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR + offset)); ++ } + } + +- seq_printf(m, "R_AX_CMAC_ERR_ISR_C1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR_C1)); +- seq_printf(m, "[0]R_AX_SCHEDULE_ERR_ISR_C1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_ISR_C1)); +- seq_printf(m, "[1]R_AX_PTCL_ISR0_C1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PTCL_ISR0_C1)); +- seq_printf(m, "[3]R_AX_DLE_CTRL_C1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_DLE_CTRL_C1)); +- seq_printf(m, "[4]R_AX_PHYINFO_ERR_ISR_C1=0x%02x\n", +- rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR_C1)); +- seq_printf(m, "[5]R_AX_TXPWR_ISR_C1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TXPWR_ISR_C1)); +- seq_printf(m, "[6]R_AX_RMAC_ERR_ISR_C1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_RMAC_ERR_ISR_C1)); +- seq_printf(m, "[7]R_AX_TMAC_ERR_IMR_ISR_C1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR_C1)); ++ if (cmac_err & B_AX_TXPWR_CTRL_ERR_IND) { ++ seq_printf(m, "R_AX_TXPWR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TXPWR_IMR + offset)); ++ seq_printf(m, "R_AX_TXPWR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TXPWR_ISR + offset)); ++ } ++ ++ if (cmac_err & B_AX_WMAC_TX_ERR_IND) { ++ if (chip->chip_id == RTL8852C) { ++ seq_printf(m, "R_AX_TRXPTCL_ERROR_INDICA [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TRXPTCL_ERROR_INDICA + offset)); ++ seq_printf(m, "R_AX_TRXPTCL_ERROR_INDICA_MASK [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TRXPTCL_ERROR_INDICA_MASK + offset)); ++ } else { ++ seq_printf(m, "R_AX_TMAC_ERR_IMR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR + offset)); ++ } ++ seq_printf(m, "R_AX_DBGSEL_TRXPTCL [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL + offset)); ++ } ++ ++ seq_printf(m, "R_AX_CMAC_ERR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_CMAC_ERR_IMR + offset)); ++ ++ return 0; ++} ++ ++static int rtw89_debug_mac_dump_cmac_dbg(struct rtw89_dev *rtwdev, ++ struct seq_file *m) ++{ ++ rtw89_debug_mac_dump_cmac_err(rtwdev, m, RTW89_MAC_0); ++ if (rtwdev->dbcc_en) ++ rtw89_debug_mac_dump_cmac_err(rtwdev, m, RTW89_MAC_1); + + return 0; + } +@@ -1073,6 +1366,303 @@ static const struct rtw89_mac_dbg_port_i + .rd_msk = B_AX_PTCL_DBG_INFO_MASK + }; + ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx0_5 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0xD, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx6 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x5, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx7 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x9, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx8 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x3, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_tx9_C = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x1, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_txD = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x0, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx0 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0xB, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx1 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x4, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx3 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x8, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx4 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x7, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx5_8 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x1, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_tx9 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x3, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_txA_C = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x0, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx0 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x8, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx1_2 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x0, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx3 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x6, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx4 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x0, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_hdt_rx5 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 2, ++ .sel_msk = B_AX_DISPATCHER_DBG_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x0, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_rx_p0_0 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x3, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_rx_p0_1 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x6, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_rx_p0_2 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x0, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_cdt_rx_p1 = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x8, ++ .end = 0xE, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_stf_ctrl = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x5, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_addr_ctrl = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x6, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_wde_intf = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x0, ++ .end = 0xF, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_ple_intf = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x9, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ ++static const struct rtw89_mac_dbg_port_info dbg_port_dspt_flow_ctrl = { ++ .sel_addr = R_AX_DISPATCHER_DBG_PORT, ++ .sel_byte = 1, ++ .sel_msk = B_AX_DISPATCHER_CH_SEL_MASK, ++ .srt = 0x0, ++ .end = 0x3, ++ .rd_addr = R_AX_DBG_PORT_SEL, ++ .rd_byte = 4, ++ .rd_msk = B_AX_DEBUG_ST_MASK ++}; ++ + static const struct rtw89_mac_dbg_port_info dbg_port_sch_c0 = { + .sel_addr = R_AX_SCH_DBG_SEL, + .sel_byte = 1, +@@ -1483,7 +2073,7 @@ static const struct rtw89_mac_dbg_port_i + static const struct rtw89_mac_dbg_port_info dbg_port_pcie_txdma = { + .sel_addr = R_AX_PCIE_DBG_CTRL, + .sel_byte = 2, +- .sel_msk = B_AX_DBG_SEL_MASK, ++ .sel_msk = B_AX_PCIE_DBG_SEL_MASK, + .srt = 0x00, + .end = 0x03, + .rd_addr = R_AX_DBG_PORT_SEL, +@@ -1494,7 +2084,7 @@ static const struct rtw89_mac_dbg_port_i + static const struct rtw89_mac_dbg_port_info dbg_port_pcie_rxdma = { + .sel_addr = R_AX_PCIE_DBG_CTRL, + .sel_byte = 2, +- .sel_msk = B_AX_DBG_SEL_MASK, ++ .sel_msk = B_AX_PCIE_DBG_SEL_MASK, + .srt = 0x00, + .end = 0x04, + .rd_addr = R_AX_DBG_PORT_SEL, +@@ -1505,7 +2095,7 @@ static const struct rtw89_mac_dbg_port_i + static const struct rtw89_mac_dbg_port_info dbg_port_pcie_cvt = { + .sel_addr = R_AX_PCIE_DBG_CTRL, + .sel_byte = 2, +- .sel_msk = B_AX_DBG_SEL_MASK, ++ .sel_msk = B_AX_PCIE_DBG_SEL_MASK, + .srt = 0x00, + .end = 0x01, + .rd_addr = R_AX_DBG_PORT_SEL, +@@ -1516,7 +2106,7 @@ static const struct rtw89_mac_dbg_port_i + static const struct rtw89_mac_dbg_port_info dbg_port_pcie_cxpl = { + .sel_addr = R_AX_PCIE_DBG_CTRL, + .sel_byte = 2, +- .sel_msk = B_AX_DBG_SEL_MASK, ++ .sel_msk = B_AX_PCIE_DBG_SEL_MASK, + .srt = 0x00, + .end = 0x05, + .rd_addr = R_AX_DBG_PORT_SEL, +@@ -1527,7 +2117,7 @@ static const struct rtw89_mac_dbg_port_i + static const struct rtw89_mac_dbg_port_info dbg_port_pcie_io = { + .sel_addr = R_AX_PCIE_DBG_CTRL, + .sel_byte = 2, +- .sel_msk = B_AX_DBG_SEL_MASK, ++ .sel_msk = B_AX_PCIE_DBG_SEL_MASK, + .srt = 0x00, + .end = 0x05, + .rd_addr = R_AX_DBG_PORT_SEL, +@@ -1538,7 +2128,7 @@ static const struct rtw89_mac_dbg_port_i + static const struct rtw89_mac_dbg_port_info dbg_port_pcie_misc = { + .sel_addr = R_AX_PCIE_DBG_CTRL, + .sel_byte = 2, +- .sel_msk = B_AX_DBG_SEL_MASK, ++ .sel_msk = B_AX_PCIE_DBG_SEL_MASK, + .srt = 0x00, + .end = 0x06, + .rd_addr = R_AX_DBG_PORT_SEL, +@@ -1562,6 +2152,7 @@ rtw89_debug_mac_dbg_port_sel(struct seq_ + struct rtw89_dev *rtwdev, u32 sel) + { + const struct rtw89_mac_dbg_port_info *info; ++ u32 index; + u32 val32; + u16 val16; + u8 val8; +@@ -1837,6 +2428,235 @@ rtw89_debug_mac_dbg_port_sel(struct seq_ + info = &dbg_port_pktinfo; + seq_puts(m, "Enable pktinfo dump.\n"); + break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX0: ++ rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, ++ B_AX_DBG_SEL0, 0x80); ++ rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, ++ B_AX_SEL_0XC0_MASK, 1); ++ fallthrough; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX1: ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX2: ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX3: ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX4: ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX5: ++ info = &dbg_port_dspt_hdt_tx0_5; ++ index = sel - RTW89_DBG_PORT_SEL_DSPT_HDT_TX0; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 0); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, index); ++ seq_printf(m, "Enable Dispatcher hdt tx%x dump.\n", index); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX6: ++ info = &dbg_port_dspt_hdt_tx6; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 0); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 6); ++ seq_puts(m, "Enable Dispatcher hdt tx6 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX7: ++ info = &dbg_port_dspt_hdt_tx7; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 0); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 7); ++ seq_puts(m, "Enable Dispatcher hdt tx7 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX8: ++ info = &dbg_port_dspt_hdt_tx8; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 0); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 8); ++ seq_puts(m, "Enable Dispatcher hdt tx8 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TX9: ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TXA: ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TXB: ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TXC: ++ info = &dbg_port_dspt_hdt_tx9_C; ++ index = sel + 9 - RTW89_DBG_PORT_SEL_DSPT_HDT_TX9; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 0); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, index); ++ seq_printf(m, "Enable Dispatcher hdt tx%x dump.\n", index); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_TXD: ++ info = &dbg_port_dspt_hdt_txD; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 0); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 0xD); ++ seq_puts(m, "Enable Dispatcher hdt txD dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX0: ++ info = &dbg_port_dspt_cdt_tx0; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 1); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 0); ++ seq_puts(m, "Enable Dispatcher cdt tx0 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX1: ++ info = &dbg_port_dspt_cdt_tx1; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 1); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 1); ++ seq_puts(m, "Enable Dispatcher cdt tx1 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX3: ++ info = &dbg_port_dspt_cdt_tx3; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 1); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 3); ++ seq_puts(m, "Enable Dispatcher cdt tx3 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX4: ++ info = &dbg_port_dspt_cdt_tx4; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 1); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 4); ++ seq_puts(m, "Enable Dispatcher cdt tx4 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX5: ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX6: ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX7: ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX8: ++ info = &dbg_port_dspt_cdt_tx5_8; ++ index = sel + 5 - RTW89_DBG_PORT_SEL_DSPT_CDT_TX5; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 1); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, index); ++ seq_printf(m, "Enable Dispatcher cdt tx%x dump.\n", index); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TX9: ++ info = &dbg_port_dspt_cdt_tx9; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 1); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 9); ++ seq_puts(m, "Enable Dispatcher cdt tx9 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TXA: ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TXB: ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_TXC: ++ info = &dbg_port_dspt_cdt_txA_C; ++ index = sel + 0xA - RTW89_DBG_PORT_SEL_DSPT_CDT_TXA; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 1); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, index); ++ seq_printf(m, "Enable Dispatcher cdt tx%x dump.\n", index); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_RX0: ++ info = &dbg_port_dspt_hdt_rx0; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 2); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 0); ++ seq_puts(m, "Enable Dispatcher hdt rx0 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_RX1: ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_RX2: ++ info = &dbg_port_dspt_hdt_rx1_2; ++ index = sel + 1 - RTW89_DBG_PORT_SEL_DSPT_HDT_RX1; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 2); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, index); ++ seq_printf(m, "Enable Dispatcher hdt rx%x dump.\n", index); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_RX3: ++ info = &dbg_port_dspt_hdt_rx3; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 2); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 3); ++ seq_puts(m, "Enable Dispatcher hdt rx3 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_RX4: ++ info = &dbg_port_dspt_hdt_rx4; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 2); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 4); ++ seq_puts(m, "Enable Dispatcher hdt rx4 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_HDT_RX5: ++ info = &dbg_port_dspt_hdt_rx5; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 2); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 5); ++ seq_puts(m, "Enable Dispatcher hdt rx5 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_0: ++ info = &dbg_port_dspt_cdt_rx_p0_0; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 3); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 0); ++ seq_puts(m, "Enable Dispatcher cdt rx part0 0 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0: ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_1: ++ info = &dbg_port_dspt_cdt_rx_p0_1; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 3); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 1); ++ seq_puts(m, "Enable Dispatcher cdt rx part0 1 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_2: ++ info = &dbg_port_dspt_cdt_rx_p0_2; ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 3); ++ rtw89_write16_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_CH_SEL_MASK, 2); ++ seq_puts(m, "Enable Dispatcher cdt rx part0 2 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P1: ++ info = &dbg_port_dspt_cdt_rx_p1; ++ rtw89_write8_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 3); ++ seq_puts(m, "Enable Dispatcher cdt rx part1 dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_STF_CTRL: ++ info = &dbg_port_dspt_stf_ctrl; ++ rtw89_write8_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 4); ++ seq_puts(m, "Enable Dispatcher stf control dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_ADDR_CTRL: ++ info = &dbg_port_dspt_addr_ctrl; ++ rtw89_write8_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 5); ++ seq_puts(m, "Enable Dispatcher addr control dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_WDE_INTF: ++ info = &dbg_port_dspt_wde_intf; ++ rtw89_write8_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 6); ++ seq_puts(m, "Enable Dispatcher wde interface dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_PLE_INTF: ++ info = &dbg_port_dspt_ple_intf; ++ rtw89_write8_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 7); ++ seq_puts(m, "Enable Dispatcher ple interface dump.\n"); ++ break; ++ case RTW89_DBG_PORT_SEL_DSPT_FLOW_CTRL: ++ info = &dbg_port_dspt_flow_ctrl; ++ rtw89_write8_mask(rtwdev, info->sel_addr, ++ B_AX_DISPATCHER_INTN_SEL_MASK, 8); ++ seq_puts(m, "Enable Dispatcher flow control dump.\n"); ++ break; + case RTW89_DBG_PORT_SEL_PCIE_TXDMA: + info = &dbg_port_pcie_txdma; + val32 = rtw89_read32(rtwdev, R_AX_DBG_CTRL); +@@ -1889,7 +2709,7 @@ rtw89_debug_mac_dbg_port_sel(struct seq_ + info = &dbg_port_pcie_misc2; + val16 = rtw89_read16(rtwdev, R_AX_PCIE_DBG_CTRL); + val16 = u16_replace_bits(val16, PCIE_MISC2_DBG_SEL, +- B_AX_DBG_SEL_MASK); ++ B_AX_PCIE_DBG_SEL_MASK); + rtw89_write16(rtwdev, R_AX_PCIE_DBG_CTRL, val16); + seq_puts(m, "Enable pcie misc2 dump.\n"); + break; +@@ -1915,6 +2735,10 @@ static bool is_dbg_port_valid(struct rtw + sel >= RTW89_DBG_PORT_SEL_WDE_BUFMGN_FREEPG && + sel <= RTW89_DBG_PORT_SEL_PKTINFO) + return false; ++ if (rtw89_mac_check_mac_en(rtwdev, 0, RTW89_DMAC_SEL) && ++ sel >= RTW89_DBG_PORT_SEL_DSPT_HDT_TX0 && ++ sel <= RTW89_DBG_PORT_SEL_DSPT_FLOW_CTRL) ++ return false; + if (rtw89_mac_check_mac_en(rtwdev, 0, RTW89_CMAC_SEL) && + sel >= RTW89_DBG_PORT_SEL_PTCL_C0 && + sel <= RTW89_DBG_PORT_SEL_TXTF_INFOH_C0) +@@ -1985,6 +2809,50 @@ static int rtw89_debug_mac_dbg_port_dump + case_DBG_SEL(PLE_QUEMGN_QLNKTBL); + case_DBG_SEL(PLE_QUEMGN_QEMPTY); + case_DBG_SEL(PKTINFO); ++ case_DBG_SEL(DSPT_HDT_TX0); ++ case_DBG_SEL(DSPT_HDT_TX1); ++ case_DBG_SEL(DSPT_HDT_TX2); ++ case_DBG_SEL(DSPT_HDT_TX3); ++ case_DBG_SEL(DSPT_HDT_TX4); ++ case_DBG_SEL(DSPT_HDT_TX5); ++ case_DBG_SEL(DSPT_HDT_TX6); ++ case_DBG_SEL(DSPT_HDT_TX7); ++ case_DBG_SEL(DSPT_HDT_TX8); ++ case_DBG_SEL(DSPT_HDT_TX9); ++ case_DBG_SEL(DSPT_HDT_TXA); ++ case_DBG_SEL(DSPT_HDT_TXB); ++ case_DBG_SEL(DSPT_HDT_TXC); ++ case_DBG_SEL(DSPT_HDT_TXD); ++ case_DBG_SEL(DSPT_HDT_TXE); ++ case_DBG_SEL(DSPT_HDT_TXF); ++ case_DBG_SEL(DSPT_CDT_TX0); ++ case_DBG_SEL(DSPT_CDT_TX1); ++ case_DBG_SEL(DSPT_CDT_TX3); ++ case_DBG_SEL(DSPT_CDT_TX4); ++ case_DBG_SEL(DSPT_CDT_TX5); ++ case_DBG_SEL(DSPT_CDT_TX6); ++ case_DBG_SEL(DSPT_CDT_TX7); ++ case_DBG_SEL(DSPT_CDT_TX8); ++ case_DBG_SEL(DSPT_CDT_TX9); ++ case_DBG_SEL(DSPT_CDT_TXA); ++ case_DBG_SEL(DSPT_CDT_TXB); ++ case_DBG_SEL(DSPT_CDT_TXC); ++ case_DBG_SEL(DSPT_HDT_RX0); ++ case_DBG_SEL(DSPT_HDT_RX1); ++ case_DBG_SEL(DSPT_HDT_RX2); ++ case_DBG_SEL(DSPT_HDT_RX3); ++ case_DBG_SEL(DSPT_HDT_RX4); ++ case_DBG_SEL(DSPT_HDT_RX5); ++ case_DBG_SEL(DSPT_CDT_RX_P0); ++ case_DBG_SEL(DSPT_CDT_RX_P0_0); ++ case_DBG_SEL(DSPT_CDT_RX_P0_1); ++ case_DBG_SEL(DSPT_CDT_RX_P0_2); ++ case_DBG_SEL(DSPT_CDT_RX_P1); ++ case_DBG_SEL(DSPT_STF_CTRL); ++ case_DBG_SEL(DSPT_ADDR_CTRL); ++ case_DBG_SEL(DSPT_WDE_INTF); ++ case_DBG_SEL(DSPT_PLE_INTF); ++ case_DBG_SEL(DSPT_FLOW_CTRL); + case_DBG_SEL(PCIE_TXDMA); + case_DBG_SEL(PCIE_RXDMA); + case_DBG_SEL(PCIE_CVT); +@@ -2354,6 +3222,7 @@ static void rtw89_sta_info_get_iter(void + else + seq_printf(m, "Legacy %d", rate->legacy); + seq_printf(m, "%s", rtwsta->ra_report.might_fallback_legacy ? " FB_G" : ""); ++ seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(rate->bw)); + seq_printf(m, "\t(hw_rate=0x%x)", rtwsta->ra_report.hw_rate); + seq_printf(m, "\t==> agg_wait=%d (%d)\n", rtwsta->max_agg_wait, + sta->deflink.agg.max_rc_amsdu_len); +@@ -2379,6 +3248,7 @@ static void rtw89_sta_info_get_iter(void + he_gi_str[rate->he_gi] : "N/A"); + break; + } ++ seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(status->bw)); + seq_printf(m, "\t(hw_rate=0x%x)\n", rtwsta->rx_hw_rate); + + rssi = ewma_rssi_read(&rtwsta->avg_rssi); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/debug.h linux-6.2/drivers/net/wireless/realtek/rtw89/debug.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/debug.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/debug.h 2022-12-24 00:49:25.778376835 +0200 +@@ -26,6 +26,8 @@ enum rtw89_debug_mask { + RTW89_DBG_HW_SCAN = BIT(15), + RTW89_DBG_SAR = BIT(16), + RTW89_DBG_STATE = BIT(17), ++ RTW89_DBG_WOW = BIT(18), ++ RTW89_DBG_UL_TB = BIT(19), + + RTW89_DBG_UNEXP = BIT(31), + }; +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/fw.c linux-6.2/drivers/net/wireless/realtek/rtw89/fw.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/fw.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/fw.c 2022-12-24 00:49:25.778376835 +0200 +@@ -11,6 +11,9 @@ + #include "phy.h" + #include "reg.h" + ++static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev, ++ struct sk_buff *skb); ++ + static struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len, + bool header) + { +@@ -85,15 +88,31 @@ static int rtw89_fw_hdr_parser(struct rt + { + struct rtw89_fw_hdr_section_info *section_info; + const u8 *fw_end = fw + len; ++ const u8 *fwdynhdr; + const u8 *bin; ++ u32 base_hdr_len; + u32 i; + + if (!info) + return -EINVAL; + + info->section_num = GET_FW_HDR_SEC_NUM(fw); +- info->hdr_len = RTW89_FW_HDR_SIZE + +- info->section_num * RTW89_FW_SECTION_HDR_SIZE; ++ base_hdr_len = RTW89_FW_HDR_SIZE + ++ info->section_num * RTW89_FW_SECTION_HDR_SIZE; ++ info->dynamic_hdr_en = GET_FW_HDR_DYN_HDR(fw); ++ ++ if (info->dynamic_hdr_en) { ++ info->hdr_len = GET_FW_HDR_LEN(fw); ++ info->dynamic_hdr_len = info->hdr_len - base_hdr_len; ++ fwdynhdr = fw + base_hdr_len; ++ if (GET_FW_DYNHDR_LEN(fwdynhdr) != info->dynamic_hdr_len) { ++ rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n"); ++ return -EINVAL; ++ } ++ } else { ++ info->hdr_len = base_hdr_len; ++ info->dynamic_hdr_len = 0; ++ } + + bin = fw + info->hdr_len; + +@@ -254,29 +273,42 @@ static void rtw89_fw_recognize_features( + } + } + +-void rtw89_early_fw_feature_recognize(struct device *device, +- const struct rtw89_chip_info *chip, +- u32 *early_feat_map) +-{ +- union { +- struct rtw89_mfw_hdr mfw_hdr; +- u8 fw_hdr[RTW89_FW_HDR_SIZE]; +- } buf = {}; ++const struct firmware * ++rtw89_early_fw_feature_recognize(struct device *device, ++ const struct rtw89_chip_info *chip, ++ u32 *early_feat_map) ++{ ++ union rtw89_compat_fw_hdr buf = {}; + const struct firmware *firmware; ++ bool full_req = false; + u32 ver_code; + int ret; + int i; + +- ret = request_partial_firmware_into_buf(&firmware, chip->fw_name, +- device, &buf, sizeof(buf), 0); ++ /* If SECURITY_LOADPIN_ENFORCE is enabled, reading partial files will ++ * be denied (-EPERM). Then, we don't get right firmware things as ++ * expected. So, in this case, we have to request full firmware here. ++ */ ++ if (IS_ENABLED(CONFIG_SECURITY_LOADPIN_ENFORCE)) ++ full_req = true; ++ ++ if (full_req) ++ ret = request_firmware(&firmware, chip->fw_name, device); ++ else ++ ret = request_partial_firmware_into_buf(&firmware, chip->fw_name, ++ device, &buf, sizeof(buf), ++ 0); ++ + if (ret) { + dev_err(device, "failed to early request firmware: %d\n", ret); +- return; ++ return NULL; + } + +- ver_code = buf.mfw_hdr.sig != RTW89_MFW_SIG ? +- RTW89_FW_HDR_VER_CODE(&buf.fw_hdr) : +- RTW89_MFW_HDR_VER_CODE(&buf.mfw_hdr); ++ if (full_req) ++ ver_code = rtw89_compat_fw_hdr_ver_code(firmware->data); ++ else ++ ver_code = rtw89_compat_fw_hdr_ver_code(&buf); ++ + if (!ver_code) + goto out; + +@@ -291,7 +323,11 @@ void rtw89_early_fw_feature_recognize(st + } + + out: ++ if (full_req) ++ return firmware; ++ + release_firmware(firmware); ++ return NULL; + } + + int rtw89_fw_recognize(struct rtw89_dev *rtwdev) +@@ -515,6 +551,11 @@ int rtw89_fw_download(struct rtw89_dev * + u8 val; + int ret; + ++ rtw89_mac_disable_cpu(rtwdev); ++ ret = rtw89_mac_enable_cpu(rtwdev, 0, true); ++ if (ret) ++ return ret; ++ + if (!fw || !len) { + rtw89_err(rtwdev, "fw type %d isn't recognized\n", type); + return -ENOENT; +@@ -534,7 +575,7 @@ int rtw89_fw_download(struct rtw89_dev * + goto fwdl_err; + } + +- ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len); ++ ret = rtw89_fw_download_hdr(rtwdev, fw, info.hdr_len - info.dynamic_hdr_len); + if (ret) { + ret = -EBUSY; + goto fwdl_err; +@@ -593,6 +634,13 @@ int rtw89_load_firmware(struct rtw89_dev + fw->rtwdev = rtwdev; + init_completion(&fw->completion); + ++ if (fw->firmware) { ++ rtw89_debug(rtwdev, RTW89_DBG_FW, ++ "full firmware has been early requested\n"); ++ complete_all(&fw->completion); ++ return 0; ++ } ++ + ret = request_firmware_nowait(THIS_MODULE, true, fw_name, rtwdev->dev, + GFP_KERNEL, fw, rtw89_load_firmware_cb); + if (ret) { +@@ -609,8 +657,14 @@ void rtw89_unload_firmware(struct rtw89_ + + rtw89_wait_firmware_completion(rtwdev); + +- if (fw->firmware) ++ if (fw->firmware) { + release_firmware(fw->firmware); ++ ++ /* assign NULL back in case rtw89_free_ieee80211_hw() ++ * try to release the same one again. ++ */ ++ fw->firmware = NULL; ++ } + } + + #define H2C_CAM_LEN 60 +@@ -848,6 +902,56 @@ fail: + return ret; + } + ++static int rtw89_fw_h2c_add_wow_fw_ofld(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, ++ enum rtw89_fw_pkt_ofld_type type, ++ u8 *id) ++{ ++ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct rtw89_pktofld_info *info; ++ struct sk_buff *skb; ++ int ret; ++ ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ ++ switch (type) { ++ case RTW89_PKT_OFLD_TYPE_PS_POLL: ++ skb = ieee80211_pspoll_get(rtwdev->hw, vif); ++ break; ++ case RTW89_PKT_OFLD_TYPE_PROBE_RSP: ++ skb = ieee80211_proberesp_get(rtwdev->hw, vif); ++ break; ++ case RTW89_PKT_OFLD_TYPE_NULL_DATA: ++ skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, false); ++ break; ++ case RTW89_PKT_OFLD_TYPE_QOS_NULL: ++ skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, true); ++ break; ++ default: ++ goto err; ++ } ++ ++ if (!skb) ++ goto err; ++ ++ list_add_tail(&info->list, &rtw_wow->pkt_list); ++ ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, skb); ++ kfree_skb(skb); ++ ++ if (ret) ++ return ret; ++ ++ *id = info->id; ++ return 0; ++ ++err: ++ kfree(info); ++ return -ENOMEM; ++} ++ + #define H2C_GENERAL_PKT_LEN 6 + #define H2C_GENERAL_PKT_ID_UND 0xff + int rtw89_fw_h2c_general_pkt(struct rtw89_dev *rtwdev, u8 macid) +@@ -2192,7 +2296,7 @@ fail: + int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev) + { + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); +- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc; ++ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_fw_h2c_rf_get_mccch *mccch; + struct sk_buff *skb; + int ret; +@@ -2205,10 +2309,10 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw8 + skb_put(skb, sizeof(*mccch)); + mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data; + +- mccch->ch_0 = cpu_to_le32(mcc_info->ch[0]); +- mccch->ch_1 = cpu_to_le32(mcc_info->ch[1]); +- mccch->band_0 = cpu_to_le32(mcc_info->band[0]); +- mccch->band_1 = cpu_to_le32(mcc_info->band[1]); ++ mccch->ch_0 = cpu_to_le32(rfk_mcc->ch[0]); ++ mccch->ch_1 = cpu_to_le32(rfk_mcc->ch[1]); ++ mccch->band_0 = cpu_to_le32(rfk_mcc->band[0]); ++ mccch->band_1 = cpu_to_le32(rfk_mcc->band[1]); + mccch->current_channel = cpu_to_le32(chan->channel); + mccch->current_band_type = cpu_to_le32(chan->band_type); + +@@ -2311,8 +2415,43 @@ void rtw89_fw_free_all_early_h2c(struct + mutex_unlock(&rtwdev->mutex); + } + ++static void rtw89_fw_c2h_parse_attr(struct sk_buff *c2h) ++{ ++ struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(c2h); ++ ++ attr->category = RTW89_GET_C2H_CATEGORY(c2h->data); ++ attr->class = RTW89_GET_C2H_CLASS(c2h->data); ++ attr->func = RTW89_GET_C2H_FUNC(c2h->data); ++ attr->len = RTW89_GET_C2H_LEN(c2h->data); ++} ++ ++static bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev, ++ struct sk_buff *c2h) ++{ ++ struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(c2h); ++ u8 category = attr->category; ++ u8 class = attr->class; ++ u8 func = attr->func; ++ ++ switch (category) { ++ default: ++ return false; ++ case RTW89_C2H_CAT_MAC: ++ return rtw89_mac_c2h_chk_atomic(rtwdev, class, func); ++ } ++} ++ + void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h) + { ++ rtw89_fw_c2h_parse_attr(c2h); ++ if (!rtw89_fw_c2h_chk_atomic(rtwdev, c2h)) ++ goto enqueue; ++ ++ rtw89_fw_c2h_cmd_handle(rtwdev, c2h); ++ dev_kfree_skb_any(c2h); ++ return; ++ ++enqueue: + skb_queue_tail(&rtwdev->c2h_queue, c2h); + ieee80211_queue_work(rtwdev->hw, &rtwdev->c2h_work); + } +@@ -2320,10 +2459,11 @@ void rtw89_fw_c2h_irqsafe(struct rtw89_d + static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev, + struct sk_buff *skb) + { +- u8 category = RTW89_GET_C2H_CATEGORY(skb->data); +- u8 class = RTW89_GET_C2H_CLASS(skb->data); +- u8 func = RTW89_GET_C2H_FUNC(skb->data); +- u16 len = RTW89_GET_C2H_LEN(skb->data); ++ struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb); ++ u8 category = attr->category; ++ u8 class = attr->class; ++ u8 func = attr->func; ++ u16 len = attr->len; + bool dump = true; + + if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) +@@ -2565,6 +2705,9 @@ static void rtw89_hw_scan_add_chan(struc + struct rtw89_mac_chinfo *ch_info) + { + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; ++ struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; ++ struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; ++ struct cfg80211_scan_request *req = rtwvif->scan_req; + struct rtw89_pktofld_info *info; + u8 band, probe_count = 0; + +@@ -2576,13 +2719,13 @@ static void rtw89_hw_scan_add_chan(struc + ch_info->tx_pwr_idx = 0; + ch_info->tx_null = false; + ch_info->pause_data = false; ++ ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE; + + if (ssid_num) { + ch_info->num_pkt = ssid_num; + band = rtw89_hw_to_nl80211_band(ch_info->ch_band); + + list_for_each_entry(info, &scan_info->pkt_list[band], list) { +- ch_info->probe_id = info->id; + ch_info->pkt_id[probe_count] = info->id; + if (++probe_count >= ssid_num) + break; +@@ -2591,9 +2734,16 @@ static void rtw89_hw_scan_add_chan(struc + rtw89_err(rtwdev, "SSID num differs from list len\n"); + } + ++ if (ch_info->ch_band == RTW89_BAND_6G) { ++ if (ssid_num == 1 && req->ssids[0].ssid_len == 0) { ++ ch_info->tx_pkt = false; ++ if (!req->duration_mandatory) ++ ch_info->period -= RTW89_DWELL_TIME; ++ } ++ } ++ + switch (chan_type) { + case RTW89_CHAN_OPERATE: +- ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE; + ch_info->central_ch = scan_info->op_chan; + ch_info->pri_ch = scan_info->op_pri_ch; + ch_info->ch_band = scan_info->op_band; +@@ -2602,8 +2752,9 @@ static void rtw89_hw_scan_add_chan(struc + ch_info->num_pkt = 0; + break; + case RTW89_CHAN_DFS: +- ch_info->period = max_t(u8, ch_info->period, +- RTW89_DFS_CHAN_TIME); ++ if (ch_info->ch_band != RTW89_BAND_6G) ++ ch_info->period = max_t(u8, ch_info->period, ++ RTW89_DFS_CHAN_TIME); + ch_info->dwell_time = RTW89_DWELL_TIME; + break; + case RTW89_CHAN_ACTIVE: +@@ -2637,8 +2788,13 @@ static int rtw89_hw_scan_add_chan_list(s + goto out; + } + +- ch_info->period = req->duration_mandatory ? +- req->duration : RTW89_CHANNEL_TIME; ++ if (req->duration_mandatory) ++ ch_info->period = req->duration; ++ else if (channel->band == NL80211_BAND_6GHZ) ++ ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME; ++ else ++ ch_info->period = RTW89_CHANNEL_TIME; ++ + ch_info->ch_band = rtw89_nl80211_to_hw_band(channel->band); + ch_info->central_ch = channel->hw_value; + ch_info->pri_ch = channel->hw_value; +@@ -2757,6 +2913,7 @@ void rtw89_hw_scan_complete(struct rtw89 + + if (rtwvif->net_type != RTW89_NET_TYPE_NO_LINK) + rtw89_store_op_chan(rtwdev, false); ++ rtw89_set_channel(rtwdev); + } + + void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) +@@ -2862,6 +3019,7 @@ int rtw89_fw_h2c_pkt_drop(struct rtw89_d + case RTW89_PKT_DROP_SEL_MACID_BK_ONCE: + case RTW89_PKT_DROP_SEL_MACID_VI_ONCE: + case RTW89_PKT_DROP_SEL_MACID_VO_ONCE: ++ case RTW89_PKT_DROP_SEL_BAND_ONCE: + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_FW, +@@ -2877,6 +3035,14 @@ int rtw89_fw_h2c_pkt_drop(struct rtw89_d + RTW89_SET_FWCMD_PKT_DROP_PORT(skb->data, params->port); + RTW89_SET_FWCMD_PKT_DROP_MBSSID(skb->data, params->mbssid); + RTW89_SET_FWCMD_PKT_DROP_ROLE_A_INFO_TF_TRS(skb->data, params->tf_trs); ++ RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_0(skb->data, ++ params->macid_band_sel[0]); ++ RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_1(skb->data, ++ params->macid_band_sel[1]); ++ RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_2(skb->data, ++ params->macid_band_sel[2]); ++ RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_3(skb->data, ++ params->macid_band_sel[3]); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, +@@ -2896,3 +3062,563 @@ fail: + dev_kfree_skb_any(skb); + return ret; + } ++ ++#define H2C_KEEP_ALIVE_LEN 4 ++int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, ++ bool enable) ++{ ++ struct sk_buff *skb; ++ u8 pkt_id = 0; ++ int ret; ++ ++ if (enable) { ++ ret = rtw89_fw_h2c_add_wow_fw_ofld(rtwdev, rtwvif, ++ RTW89_PKT_OFLD_TYPE_NULL_DATA, &pkt_id); ++ if (ret) ++ return -EPERM; ++ } ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_KEEP_ALIVE_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_KEEP_ALIVE_LEN); ++ ++ RTW89_SET_KEEP_ALIVE_ENABLE(skb->data, enable); ++ RTW89_SET_KEEP_ALIVE_PKT_NULL_ID(skb->data, pkt_id); ++ RTW89_SET_KEEP_ALIVE_PERIOD(skb->data, 5); ++ RTW89_SET_KEEP_ALIVE_MACID(skb->data, rtwvif->mac_id); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MAC_WOW, ++ H2C_FUNC_KEEP_ALIVE, 0, 1, ++ H2C_KEEP_ALIVE_LEN); ++ ++ ret = rtw89_h2c_tx(rtwdev, skb, false); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to send h2c\n"); ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ dev_kfree_skb_any(skb); ++ ++ return ret; ++} ++ ++#define H2C_DISCONNECT_DETECT_LEN 8 ++int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, bool enable) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct sk_buff *skb; ++ u8 macid = rtwvif->mac_id; ++ int ret; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DISCONNECT_DETECT_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_DISCONNECT_DETECT_LEN); ++ ++ if (test_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags)) { ++ RTW89_SET_DISCONNECT_DETECT_ENABLE(skb->data, enable); ++ RTW89_SET_DISCONNECT_DETECT_DISCONNECT(skb->data, !enable); ++ RTW89_SET_DISCONNECT_DETECT_MAC_ID(skb->data, macid); ++ RTW89_SET_DISCONNECT_DETECT_CHECK_PERIOD(skb->data, 100); ++ RTW89_SET_DISCONNECT_DETECT_TRY_PKT_COUNT(skb->data, 5); ++ } ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MAC_WOW, ++ H2C_FUNC_DISCONNECT_DETECT, 0, 1, ++ H2C_DISCONNECT_DETECT_LEN); ++ ++ ret = rtw89_h2c_tx(rtwdev, skb, false); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to send h2c\n"); ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ dev_kfree_skb_any(skb); ++ ++ return ret; ++} ++ ++#define H2C_WOW_GLOBAL_LEN 8 ++int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, ++ bool enable) ++{ ++ struct sk_buff *skb; ++ u8 macid = rtwvif->mac_id; ++ int ret; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_GLOBAL_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_WOW_GLOBAL_LEN); ++ ++ RTW89_SET_WOW_GLOBAL_ENABLE(skb->data, enable); ++ RTW89_SET_WOW_GLOBAL_MAC_ID(skb->data, macid); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MAC_WOW, ++ H2C_FUNC_WOW_GLOBAL, 0, 1, ++ H2C_WOW_GLOBAL_LEN); ++ ++ ret = rtw89_h2c_tx(rtwdev, skb, false); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to send h2c\n"); ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ dev_kfree_skb_any(skb); ++ ++ return ret; ++} ++ ++#define H2C_WAKEUP_CTRL_LEN 4 ++int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, ++ bool enable) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct sk_buff *skb; ++ u8 macid = rtwvif->mac_id; ++ int ret; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WAKEUP_CTRL_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_WAKEUP_CTRL_LEN); ++ ++ if (rtw_wow->pattern_cnt) ++ RTW89_SET_WOW_WAKEUP_CTRL_PATTERN_MATCH_ENABLE(skb->data, enable); ++ if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) ++ RTW89_SET_WOW_WAKEUP_CTRL_MAGIC_ENABLE(skb->data, enable); ++ if (test_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags)) ++ RTW89_SET_WOW_WAKEUP_CTRL_DEAUTH_ENABLE(skb->data, enable); ++ ++ RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(skb->data, macid); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MAC_WOW, ++ H2C_FUNC_WAKEUP_CTRL, 0, 1, ++ H2C_WAKEUP_CTRL_LEN); ++ ++ ret = rtw89_h2c_tx(rtwdev, skb, false); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to send h2c\n"); ++ goto fail; ++ } ++ ++ return 0; ++ ++fail: ++ dev_kfree_skb_any(skb); ++ ++ return ret; ++} ++ ++#define H2C_WOW_CAM_UPD_LEN 24 ++int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, ++ struct rtw89_wow_cam_info *cam_info) ++{ ++ struct sk_buff *skb; ++ int ret; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_WOW_CAM_UPD_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, "failed to alloc skb for keep alive\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_WOW_CAM_UPD_LEN); ++ ++ RTW89_SET_WOW_CAM_UPD_R_W(skb->data, cam_info->r_w); ++ RTW89_SET_WOW_CAM_UPD_IDX(skb->data, cam_info->idx); ++ if (cam_info->valid) { ++ RTW89_SET_WOW_CAM_UPD_WKFM1(skb->data, cam_info->mask[0]); ++ RTW89_SET_WOW_CAM_UPD_WKFM2(skb->data, cam_info->mask[1]); ++ RTW89_SET_WOW_CAM_UPD_WKFM3(skb->data, cam_info->mask[2]); ++ RTW89_SET_WOW_CAM_UPD_WKFM4(skb->data, cam_info->mask[3]); ++ RTW89_SET_WOW_CAM_UPD_CRC(skb->data, cam_info->crc); ++ RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(skb->data, ++ cam_info->negative_pattern_match); ++ RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(skb->data, ++ cam_info->skip_mac_hdr); ++ RTW89_SET_WOW_CAM_UPD_UC(skb->data, cam_info->uc); ++ RTW89_SET_WOW_CAM_UPD_MC(skb->data, cam_info->mc); ++ RTW89_SET_WOW_CAM_UPD_BC(skb->data, cam_info->bc); ++ } ++ RTW89_SET_WOW_CAM_UPD_VALID(skb->data, cam_info->valid); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MAC_WOW, ++ H2C_FUNC_WOW_CAM_UPD, 0, 1, ++ H2C_WOW_CAM_UPD_LEN); ++ ++ ret = rtw89_h2c_tx(rtwdev, skb, false); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to send h2c\n"); ++ goto fail; ++ } ++ ++ return 0; ++fail: ++ dev_kfree_skb_any(skb); ++ ++ return ret; ++} ++ ++static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, ++ struct rtw89_wait_info *wait, unsigned int cond) ++{ ++ int ret; ++ ++ ret = rtw89_h2c_tx(rtwdev, skb, false); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to send h2c\n"); ++ dev_kfree_skb_any(skb); ++ return -EBUSY; ++ } ++ ++ return rtw89_wait_for_cond(wait, cond); ++} ++ ++#define H2C_ADD_MCC_LEN 16 ++int rtw89_fw_h2c_add_mcc(struct rtw89_dev *rtwdev, ++ const struct rtw89_fw_mcc_add_req *p) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct sk_buff *skb; ++ unsigned int cond; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_ADD_MCC_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for add mcc\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_ADD_MCC_LEN); ++ RTW89_SET_FWCMD_ADD_MCC_MACID(skb->data, p->macid); ++ RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG0(skb->data, p->central_ch_seg0); ++ RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG1(skb->data, p->central_ch_seg1); ++ RTW89_SET_FWCMD_ADD_MCC_PRIMARY_CH(skb->data, p->primary_ch); ++ RTW89_SET_FWCMD_ADD_MCC_BANDWIDTH(skb->data, p->bandwidth); ++ RTW89_SET_FWCMD_ADD_MCC_GROUP(skb->data, p->group); ++ RTW89_SET_FWCMD_ADD_MCC_C2H_RPT(skb->data, p->c2h_rpt); ++ RTW89_SET_FWCMD_ADD_MCC_DIS_TX_NULL(skb->data, p->dis_tx_null); ++ RTW89_SET_FWCMD_ADD_MCC_DIS_SW_RETRY(skb->data, p->dis_sw_retry); ++ RTW89_SET_FWCMD_ADD_MCC_IN_CURR_CH(skb->data, p->in_curr_ch); ++ RTW89_SET_FWCMD_ADD_MCC_SW_RETRY_COUNT(skb->data, p->sw_retry_count); ++ RTW89_SET_FWCMD_ADD_MCC_TX_NULL_EARLY(skb->data, p->tx_null_early); ++ RTW89_SET_FWCMD_ADD_MCC_BTC_IN_2G(skb->data, p->btc_in_2g); ++ RTW89_SET_FWCMD_ADD_MCC_PTA_EN(skb->data, p->pta_en); ++ RTW89_SET_FWCMD_ADD_MCC_RFK_BY_PASS(skb->data, p->rfk_by_pass); ++ RTW89_SET_FWCMD_ADD_MCC_CH_BAND_TYPE(skb->data, p->ch_band_type); ++ RTW89_SET_FWCMD_ADD_MCC_DURATION(skb->data, p->duration); ++ RTW89_SET_FWCMD_ADD_MCC_COURTESY_EN(skb->data, p->courtesy_en); ++ RTW89_SET_FWCMD_ADD_MCC_COURTESY_NUM(skb->data, p->courtesy_num); ++ RTW89_SET_FWCMD_ADD_MCC_COURTESY_TARGET(skb->data, p->courtesy_target); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_ADD_MCC, 0, 0, ++ H2C_ADD_MCC_LEN); ++ ++ cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_ADD_MCC); ++ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++} ++ ++#define H2C_START_MCC_LEN 12 ++int rtw89_fw_h2c_start_mcc(struct rtw89_dev *rtwdev, ++ const struct rtw89_fw_mcc_start_req *p) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct sk_buff *skb; ++ unsigned int cond; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_START_MCC_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for start mcc\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_START_MCC_LEN); ++ RTW89_SET_FWCMD_START_MCC_GROUP(skb->data, p->group); ++ RTW89_SET_FWCMD_START_MCC_BTC_IN_GROUP(skb->data, p->btc_in_group); ++ RTW89_SET_FWCMD_START_MCC_OLD_GROUP_ACTION(skb->data, p->old_group_action); ++ RTW89_SET_FWCMD_START_MCC_OLD_GROUP(skb->data, p->old_group); ++ RTW89_SET_FWCMD_START_MCC_NOTIFY_CNT(skb->data, p->notify_cnt); ++ RTW89_SET_FWCMD_START_MCC_NOTIFY_RXDBG_EN(skb->data, p->notify_rxdbg_en); ++ RTW89_SET_FWCMD_START_MCC_MACID(skb->data, p->macid); ++ RTW89_SET_FWCMD_START_MCC_TSF_LOW(skb->data, p->tsf_low); ++ RTW89_SET_FWCMD_START_MCC_TSF_HIGH(skb->data, p->tsf_high); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_START_MCC, 0, 0, ++ H2C_START_MCC_LEN); ++ ++ cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_START_MCC); ++ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++} ++ ++#define H2C_STOP_MCC_LEN 4 ++int rtw89_fw_h2c_stop_mcc(struct rtw89_dev *rtwdev, u8 group, u8 macid, ++ bool prev_groups) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct sk_buff *skb; ++ unsigned int cond; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_STOP_MCC_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for stop mcc\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_STOP_MCC_LEN); ++ RTW89_SET_FWCMD_STOP_MCC_MACID(skb->data, macid); ++ RTW89_SET_FWCMD_STOP_MCC_GROUP(skb->data, group); ++ RTW89_SET_FWCMD_STOP_MCC_PREV_GROUPS(skb->data, prev_groups); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_STOP_MCC, 0, 0, ++ H2C_STOP_MCC_LEN); ++ ++ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_STOP_MCC); ++ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++} ++ ++#define H2C_DEL_MCC_GROUP_LEN 4 ++int rtw89_fw_h2c_del_mcc_group(struct rtw89_dev *rtwdev, u8 group, ++ bool prev_groups) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct sk_buff *skb; ++ unsigned int cond; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DEL_MCC_GROUP_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for del mcc group\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_DEL_MCC_GROUP_LEN); ++ RTW89_SET_FWCMD_DEL_MCC_GROUP_GROUP(skb->data, group); ++ RTW89_SET_FWCMD_DEL_MCC_GROUP_PREV_GROUPS(skb->data, prev_groups); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_DEL_MCC_GROUP, 0, 0, ++ H2C_DEL_MCC_GROUP_LEN); ++ ++ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_DEL_MCC_GROUP); ++ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++} ++ ++#define H2C_RESET_MCC_GROUP_LEN 4 ++int rtw89_fw_h2c_reset_mcc_group(struct rtw89_dev *rtwdev, u8 group) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct sk_buff *skb; ++ unsigned int cond; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_RESET_MCC_GROUP_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for reset mcc group\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_RESET_MCC_GROUP_LEN); ++ RTW89_SET_FWCMD_RESET_MCC_GROUP_GROUP(skb->data, group); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_RESET_MCC_GROUP, 0, 0, ++ H2C_RESET_MCC_GROUP_LEN); ++ ++ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_RESET_MCC_GROUP); ++ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++} ++ ++#define H2C_MCC_REQ_TSF_LEN 4 ++int rtw89_fw_h2c_mcc_req_tsf(struct rtw89_dev *rtwdev, ++ const struct rtw89_fw_mcc_tsf_req *req, ++ struct rtw89_mac_mcc_tsf_rpt *rpt) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct rtw89_mac_mcc_tsf_rpt *tmp; ++ struct sk_buff *skb; ++ unsigned int cond; ++ int ret; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_REQ_TSF_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for mcc req tsf\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_MCC_REQ_TSF_LEN); ++ RTW89_SET_FWCMD_MCC_REQ_TSF_GROUP(skb->data, req->group); ++ RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_X(skb->data, req->macid_x); ++ RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_Y(skb->data, req->macid_y); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_MCC_REQ_TSF, 0, 0, ++ H2C_MCC_REQ_TSF_LEN); ++ ++ cond = RTW89_MCC_WAIT_COND(req->group, H2C_FUNC_MCC_REQ_TSF); ++ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++ if (ret) ++ return ret; ++ ++ tmp = (struct rtw89_mac_mcc_tsf_rpt *)wait->data.buf; ++ *rpt = *tmp; ++ ++ return 0; ++} ++ ++#define H2C_MCC_MACID_BITMAP_DSC_LEN 4 ++int rtw89_fw_h2c_mcc_macid_bitamp(struct rtw89_dev *rtwdev, u8 group, u8 macid, ++ u8 *bitmap) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct sk_buff *skb; ++ unsigned int cond; ++ u8 map_len; ++ u8 h2c_len; ++ ++ BUILD_BUG_ON(RTW89_MAX_MAC_ID_NUM % 8); ++ map_len = RTW89_MAX_MAC_ID_NUM / 8; ++ h2c_len = H2C_MCC_MACID_BITMAP_DSC_LEN + map_len; ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, h2c_len); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for mcc macid bitmap\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, h2c_len); ++ RTW89_SET_FWCMD_MCC_MACID_BITMAP_GROUP(skb->data, group); ++ RTW89_SET_FWCMD_MCC_MACID_BITMAP_MACID(skb->data, macid); ++ RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP_LENGTH(skb->data, map_len); ++ RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP(skb->data, bitmap, map_len); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_MCC_MACID_BITMAP, 0, 0, ++ h2c_len); ++ ++ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_MACID_BITMAP); ++ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++} ++ ++#define H2C_MCC_SYNC_LEN 4 ++int rtw89_fw_h2c_mcc_sync(struct rtw89_dev *rtwdev, u8 group, u8 source, ++ u8 target, u8 offset) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct sk_buff *skb; ++ unsigned int cond; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_SYNC_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for mcc sync\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_MCC_SYNC_LEN); ++ RTW89_SET_FWCMD_MCC_SYNC_GROUP(skb->data, group); ++ RTW89_SET_FWCMD_MCC_SYNC_MACID_SOURCE(skb->data, source); ++ RTW89_SET_FWCMD_MCC_SYNC_MACID_TARGET(skb->data, target); ++ RTW89_SET_FWCMD_MCC_SYNC_SYNC_OFFSET(skb->data, offset); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_MCC_SYNC, 0, 0, ++ H2C_MCC_SYNC_LEN); ++ ++ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_SYNC); ++ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++} ++ ++#define H2C_MCC_SET_DURATION_LEN 20 ++int rtw89_fw_h2c_mcc_set_duration(struct rtw89_dev *rtwdev, ++ const struct rtw89_fw_mcc_duration *p) ++{ ++ struct rtw89_wait_info *wait = &rtwdev->mcc.wait; ++ struct sk_buff *skb; ++ unsigned int cond; ++ ++ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_MCC_SET_DURATION_LEN); ++ if (!skb) { ++ rtw89_err(rtwdev, ++ "failed to alloc skb for mcc set duration\n"); ++ return -ENOMEM; ++ } ++ ++ skb_put(skb, H2C_MCC_SET_DURATION_LEN); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_GROUP(skb->data, p->group); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_BTC_IN_GROUP(skb->data, p->btc_in_group); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_START_MACID(skb->data, p->start_macid); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_X(skb->data, p->macid_x); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_Y(skb->data, p->macid_y); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_LOW(skb->data, ++ p->start_tsf_low); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_HIGH(skb->data, ++ p->start_tsf_high); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_X(skb->data, p->duration_x); ++ RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_Y(skb->data, p->duration_y); ++ ++ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, ++ H2C_CAT_MAC, ++ H2C_CL_MCC, ++ H2C_FUNC_MCC_SET_DURATION, 0, 0, ++ H2C_MCC_SET_DURATION_LEN); ++ ++ cond = RTW89_MCC_WAIT_COND(p->group, H2C_FUNC_MCC_SET_DURATION); ++ return rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); ++} +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/fw.h linux-6.2/drivers/net/wireless/realtek/rtw89/fw.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/fw.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/fw.h 2022-12-24 00:49:25.778376835 +0200 +@@ -176,6 +176,8 @@ struct rtw89_fw_hdr_section_info { + struct rtw89_fw_bin_info { + u8 section_num; + u32 hdr_len; ++ bool dynamic_hdr_en; ++ u32 dynamic_hdr_len; + struct rtw89_fw_hdr_section_info section_info[FWDL_SECTION_MAX_NUM]; + }; + +@@ -197,6 +199,7 @@ struct rtw89_h2creg_sch_tx_en { + + #define RTW89_H2C_MAX_SIZE 2048 + #define RTW89_CHANNEL_TIME 45 ++#define RTW89_CHANNEL_TIME_6G 20 + #define RTW89_DFS_CHAN_TIME 105 + #define RTW89_OFF_CHAN_TIME 100 + #define RTW89_DWELL_TIME 20 +@@ -494,6 +497,8 @@ static inline void RTW89_SET_EDCA_PARAM( + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 16)) + #define GET_FW_HDR_SUBINDEX(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(31, 24)) ++#define GET_FW_HDR_LEN(fwhdr) \ ++ le32_get_bits(*((const __le32 *)(fwhdr) + 3), GENMASK(23, 16)) + #define GET_FW_HDR_MONTH(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(7, 0)) + #define GET_FW_HDR_DATE(fwhdr) \ +@@ -506,8 +511,16 @@ static inline void RTW89_SET_EDCA_PARAM( + le32_get_bits(*((const __le32 *)(fwhdr) + 5), GENMASK(31, 0)) + #define GET_FW_HDR_SEC_NUM(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 6), GENMASK(15, 8)) ++#define GET_FW_HDR_DYN_HDR(fwhdr) \ ++ le32_get_bits(*((const __le32 *)(fwhdr) + 7), BIT(16)) + #define GET_FW_HDR_CMD_VERSERION(fwhdr) \ + le32_get_bits(*((const __le32 *)(fwhdr) + 7), GENMASK(31, 24)) ++ ++#define GET_FW_DYNHDR_LEN(fwdynhdr) \ ++ le32_get_bits(*((const __le32 *)(fwdynhdr)), GENMASK(31, 0)) ++#define GET_FW_DYNHDR_COUNT(fwdynhdr) \ ++ le32_get_bits(*((const __le32 *)(fwdynhdr) + 1), GENMASK(31, 0)) ++ + static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val) + { + le32p_replace_bits((__le32 *)fwhdr + 7, val, GENMASK(15, 0)); +@@ -1860,6 +1873,231 @@ static inline void RTW89_SET_FWCMD_PKT_D + le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(15, 8)); + } + ++static inline void RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_0(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 2, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_1(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_2(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 4, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_PKT_DROP_MACID_BAND_SEL_3(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 5, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_KEEP_ALIVE_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(1, 0)); ++} ++ ++static inline void RTW89_SET_KEEP_ALIVE_PKT_NULL_ID(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_KEEP_ALIVE_PERIOD(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(24, 16)); ++} ++ ++static inline void RTW89_SET_KEEP_ALIVE_MACID(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); ++} ++ ++static inline void RTW89_SET_DISCONNECT_DETECT_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(0)); ++} ++ ++static inline void RTW89_SET_DISCONNECT_DETECT_TRYOK_BCNFAIL_COUNT_EN(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(1)); ++} ++ ++static inline void RTW89_SET_DISCONNECT_DETECT_DISCONNECT(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(2)); ++} ++ ++static inline void RTW89_SET_DISCONNECT_DETECT_MAC_ID(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_DISCONNECT_DETECT_CHECK_PERIOD(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)); ++} ++ ++static inline void RTW89_SET_DISCONNECT_DETECT_TRY_PKT_COUNT(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); ++} ++ ++static inline void RTW89_SET_DISCONNECT_DETECT_TRYOK_BCNFAIL_COUNT_LIMIT(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(7, 0)); ++} ++ ++static inline void RTW89_SET_WOW_GLOBAL_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(0)); ++} ++ ++static inline void RTW89_SET_WOW_GLOBAL_DROP_ALL_PKT(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(1)); ++} ++ ++static inline void RTW89_SET_WOW_GLOBAL_RX_PARSE_AFTER_WAKE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(2)); ++} ++ ++static inline void RTW89_SET_WOW_GLOBAL_WAKE_BAR_PULLED(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(3)); ++} ++ ++static inline void RTW89_SET_WOW_GLOBAL_MAC_ID(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_WOW_GLOBAL_PAIRWISE_SEC_ALGO(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)); ++} ++ ++static inline void RTW89_SET_WOW_GLOBAL_GROUP_SEC_ALGO(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); ++} ++ ++static inline void RTW89_SET_WOW_GLOBAL_REMOTECTRL_INFO_CONTENT(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_PATTERN_MATCH_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(0)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAGIC_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(1)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_HW_UNICAST_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(2)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_FW_UNICAST_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(3)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_DEAUTH_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(4)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_REKEYP_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(5)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_EAP_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(6)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_ALL_DATA_ENABLE(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(7)); ++} ++ ++static inline void RTW89_SET_WOW_WAKEUP_CTRL_MAC_ID(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 24)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_R_W(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, BIT(0)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_IDX(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 1)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_WKFM1(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_WKFM2(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 2, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_WKFM3(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 3, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_WKFM4(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 4, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_CRC(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 5, val, GENMASK(15, 0)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_NEGATIVE_PATTERN_MATCH(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 5, val, BIT(22)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_SKIP_MAC_HDR(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 5, val, BIT(23)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_UC(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 5, val, BIT(24)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_MC(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 5, val, BIT(25)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_BC(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 5, val, BIT(26)); ++} ++ ++static inline void RTW89_SET_WOW_CAM_UPD_VALID(void *h2c, u32 val) ++{ ++ le32p_replace_bits((__le32 *)h2c + 5, val, BIT(31)); ++} ++ + enum rtw89_btc_btf_h2c_class { + BTFC_SET = 0x10, + BTFC_GET = 0x11, +@@ -2529,6 +2767,355 @@ static inline void RTW89_SET_FWCMD_TSF32 + le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 16)); + } + ++enum rtw89_fw_mcc_c2h_rpt_cfg { ++ RTW89_FW_MCC_C2H_RPT_OFF = 0, ++ RTW89_FW_MCC_C2H_RPT_FAIL_ONLY = 1, ++ RTW89_FW_MCC_C2H_RPT_ALL = 2, ++}; ++ ++struct rtw89_fw_mcc_add_req { ++ u8 macid; ++ u8 central_ch_seg0; ++ u8 central_ch_seg1; ++ u8 primary_ch; ++ enum rtw89_bandwidth bandwidth: 4; ++ u32 group: 2; ++ u32 c2h_rpt: 2; ++ u32 dis_tx_null: 1; ++ u32 dis_sw_retry: 1; ++ u32 in_curr_ch: 1; ++ u32 sw_retry_count: 3; ++ u32 tx_null_early: 4; ++ u32 btc_in_2g: 1; ++ u32 pta_en: 1; ++ u32 rfk_by_pass: 1; ++ u32 ch_band_type: 2; ++ u32 rsvd0: 9; ++ u32 duration; ++ u8 courtesy_en; ++ u8 courtesy_num; ++ u8 courtesy_target; ++ u8 rsvd1; ++}; ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_MACID(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG0(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_CENTRAL_CH_SEG1(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_PRIMARY_CH(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 24)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_BANDWIDTH(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(3, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(5, 4)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_C2H_RPT(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(7, 6)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_DIS_TX_NULL(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(8)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_DIS_SW_RETRY(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(9)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_IN_CURR_CH(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(10)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_SW_RETRY_COUNT(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(13, 11)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_TX_NULL_EARLY(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(17, 14)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_BTC_IN_2G(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(18)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_PTA_EN(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(19)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_RFK_BY_PASS(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, BIT(20)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_CH_BAND_TYPE(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(22, 21)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_DURATION(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 2, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_COURTESY_EN(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 3, val, BIT(0)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_COURTESY_NUM(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_FWCMD_ADD_MCC_COURTESY_TARGET(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(23, 16)); ++} ++ ++struct rtw89_fw_mcc_start_req { ++ u32 group: 2; ++ u32 btc_in_group: 1; ++ u32 old_group_action: 2; ++ u32 old_group: 2; ++ u32 rsvd0: 9; ++ u32 notify_cnt: 3; ++ u32 rsvd1: 2; ++ u32 notify_rxdbg_en: 1; ++ u32 rsvd2: 2; ++ u32 macid: 8; ++ u32 tsf_low; ++ u32 tsf_high; ++}; ++ ++static inline void RTW89_SET_FWCMD_START_MCC_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_START_MCC_BTC_IN_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, BIT(2)); ++} ++ ++static inline void RTW89_SET_FWCMD_START_MCC_OLD_GROUP_ACTION(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(4, 3)); ++} ++ ++static inline void RTW89_SET_FWCMD_START_MCC_OLD_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(6, 5)); ++} ++ ++static inline void RTW89_SET_FWCMD_START_MCC_NOTIFY_CNT(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(18, 16)); ++} ++ ++static inline void RTW89_SET_FWCMD_START_MCC_NOTIFY_RXDBG_EN(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, BIT(21)); ++} ++ ++static inline void RTW89_SET_FWCMD_START_MCC_MACID(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 24)); ++} ++ ++static inline void RTW89_SET_FWCMD_START_MCC_TSF_LOW(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_START_MCC_TSF_HIGH(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 2, val, GENMASK(31, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_STOP_MCC_MACID(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(7, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_STOP_MCC_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(9, 8)); ++} ++ ++static inline void RTW89_SET_FWCMD_STOP_MCC_PREV_GROUPS(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, BIT(10)); ++} ++ ++static inline void RTW89_SET_FWCMD_DEL_MCC_GROUP_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_DEL_MCC_GROUP_PREV_GROUPS(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, BIT(2)); ++} ++ ++static inline void RTW89_SET_FWCMD_RESET_MCC_GROUP_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0)); ++} ++ ++struct rtw89_fw_mcc_tsf_req { ++ u8 group: 2; ++ u8 rsvd0: 6; ++ u8 macid_x; ++ u8 macid_y; ++ u8 rsvd1; ++}; ++ ++static inline void RTW89_SET_FWCMD_MCC_REQ_TSF_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_X(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_REQ_TSF_MACID_Y(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_MACID_BITMAP_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_MACID_BITMAP_MACID(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP_LENGTH(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_MACID_BITMAP_BITMAP(void *cmd, ++ u8 *bitmap, u8 len) ++{ ++ memcpy((__le32 *)cmd + 1, bitmap, len); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_SYNC_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_SYNC_MACID_SOURCE(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_SYNC_MACID_TARGET(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_SYNC_SYNC_OFFSET(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 24)); ++} ++ ++struct rtw89_fw_mcc_duration { ++ u32 group: 2; ++ u32 btc_in_group: 1; ++ u32 rsvd0: 5; ++ u32 start_macid: 8; ++ u32 macid_x: 8; ++ u32 macid_y: 8; ++ u32 start_tsf_low; ++ u32 start_tsf_high; ++ u32 duration_x; ++ u32 duration_y; ++}; ++ ++static inline void RTW89_SET_FWCMD_MCC_SET_DURATION_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(1, 0)); ++} ++ ++static ++inline void RTW89_SET_FWCMD_MCC_SET_DURATION_BTC_IN_GROUP(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, BIT(2)); ++} ++ ++static ++inline void RTW89_SET_FWCMD_MCC_SET_DURATION_START_MACID(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(15, 8)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_X(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(23, 16)); ++} ++ ++static inline void RTW89_SET_FWCMD_MCC_SET_DURATION_MACID_Y(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 24)); ++} ++ ++static ++inline void RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_LOW(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 1, val, GENMASK(31, 0)); ++} ++ ++static ++inline void RTW89_SET_FWCMD_MCC_SET_DURATION_START_TSF_HIGH(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 2, val, GENMASK(31, 0)); ++} ++ ++static ++inline void RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_X(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 3, val, GENMASK(31, 0)); ++} ++ ++static ++inline void RTW89_SET_FWCMD_MCC_SET_DURATION_DURATION_Y(void *cmd, u32 val) ++{ ++ le32p_replace_bits((__le32 *)cmd + 4, val, GENMASK(31, 0)); ++} ++ + #define RTW89_C2H_HEADER_LEN 8 + + #define RTW89_GET_C2H_CATEGORY(c2h) \ +@@ -2540,6 +3127,20 @@ static inline void RTW89_SET_FWCMD_TSF32 + #define RTW89_GET_C2H_LEN(c2h) \ + le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(13, 0)) + ++struct rtw89_fw_c2h_attr { ++ u8 category; ++ u8 class; ++ u8 func; ++ u16 len; ++}; ++ ++static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb) ++{ ++ static_assert(sizeof(skb->cb) >= sizeof(struct rtw89_fw_c2h_attr)); ++ ++ return (struct rtw89_fw_c2h_attr *)skb->cb; ++} ++ + #define RTW89_GET_C2H_LOG_SRT_PRT(c2h) (char *)((__le32 *)(c2h) + 2) + #define RTW89_GET_C2H_LOG_LEN(len) ((len) - RTW89_C2H_HEADER_LEN) + +@@ -2607,6 +3208,55 @@ static inline void RTW89_SET_FWCMD_TSF32 + #define RTW89_GET_MAC_C2H_SCANOFLD_BAND(c2h) \ + le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(25, 24)) + ++#define RTW89_GET_MAC_C2H_MCC_RCV_ACK_GROUP(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(1, 0)) ++#define RTW89_GET_MAC_C2H_MCC_RCV_ACK_H2C_FUNC(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8)) ++ ++#define RTW89_GET_MAC_C2H_MCC_REQ_ACK_GROUP(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(1, 0)) ++#define RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_RETURN(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 2)) ++#define RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_FUNC(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8)) ++ ++struct rtw89_mac_mcc_tsf_rpt { ++ u32 macid_x; ++ u32 macid_y; ++ u32 tsf_x_low; ++ u32 tsf_x_high; ++ u32 tsf_y_low; ++ u32 tsf_y_high; ++}; ++ ++static_assert(sizeof(struct rtw89_mac_mcc_tsf_rpt) <= RTW89_COMPLETION_BUF_SIZE); ++ ++#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_X(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 0)) ++#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_Y(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8)) ++#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_GROUP(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(17, 16)) ++#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_X(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(31, 0)) ++#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_X(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 0)) ++#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_Y(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h) + 3), GENMASK(31, 0)) ++#define RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_Y(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0)) ++ ++#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_STATUS(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(5, 0)) ++#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_GROUP(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(7, 6)) ++#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_MACID(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h)), GENMASK(15, 8)) ++#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_LOW(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h) + 1), GENMASK(31, 0)) ++#define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h) \ ++ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 0)) ++ + #define RTW89_FW_HDR_SIZE 32 + #define RTW89_FW_SECTION_HDR_SIZE 16 + +@@ -2641,6 +3291,21 @@ struct fwcmd_hdr { + __le32 hdr1; + }; + ++union rtw89_compat_fw_hdr { ++ struct rtw89_mfw_hdr mfw_hdr; ++ u8 fw_hdr[RTW89_FW_HDR_SIZE]; ++}; ++ ++static inline u32 rtw89_compat_fw_hdr_ver_code(const void *fw_buf) ++{ ++ const union rtw89_compat_fw_hdr *compat = (typeof(compat))fw_buf; ++ ++ if (compat->mfw_hdr.sig == RTW89_MFW_SIG) ++ return RTW89_MFW_HDR_VER_CODE(&compat->mfw_hdr); ++ else ++ return RTW89_FW_HDR_VER_CODE(&compat->fw_hdr); ++} ++ + #define RTW89_H2C_RF_PAGE_SIZE 500 + #define RTW89_H2C_RF_PAGE_NUM 3 + struct rtw89_fw_h2c_rf_reg_info { +@@ -2676,6 +3341,14 @@ struct rtw89_fw_h2c_rf_reg_info { + #define H2C_FUNC_LOG_CFG 0x0 + #define H2C_FUNC_MAC_GENERAL_PKT 0x1 + ++/* CLASS 1 - WOW */ ++#define H2C_CL_MAC_WOW 0x1 ++#define H2C_FUNC_KEEP_ALIVE 0x0 ++#define H2C_FUNC_DISCONNECT_DETECT 0x1 ++#define H2C_FUNC_WOW_GLOBAL 0x2 ++#define H2C_FUNC_WAKEUP_CTRL 0x8 ++#define H2C_FUNC_WOW_CAM_UPD 0xC ++ + /* CLASS 2 - PS */ + #define H2C_CL_MAC_PS 0x2 + #define H2C_FUNC_MAC_LPS_PARM 0x0 +@@ -2720,6 +3393,25 @@ struct rtw89_fw_h2c_rf_reg_info { + #define H2C_CL_BA_CAM 0xc + #define H2C_FUNC_MAC_BA_CAM 0x0 + ++/* CLASS 14 - MCC */ ++#define H2C_CL_MCC 0xe ++enum rtw89_mcc_h2c_func { ++ H2C_FUNC_ADD_MCC = 0x0, ++ H2C_FUNC_START_MCC = 0x1, ++ H2C_FUNC_STOP_MCC = 0x2, ++ H2C_FUNC_DEL_MCC_GROUP = 0x3, ++ H2C_FUNC_RESET_MCC_GROUP = 0x4, ++ H2C_FUNC_MCC_REQ_TSF = 0x5, ++ H2C_FUNC_MCC_MACID_BITMAP = 0x6, ++ H2C_FUNC_MCC_SYNC = 0x7, ++ H2C_FUNC_MCC_SET_DURATION = 0x8, ++ ++ NUM_OF_RTW89_MCC_H2C_FUNC, ++}; ++ ++#define RTW89_MCC_WAIT_COND(group, func) \ ++ ((group) * NUM_OF_RTW89_MCC_H2C_FUNC + (func)) ++ + #define H2C_CAT_OUTSRC 0x2 + + #define H2C_CL_OUTSRC_RA 0x1 +@@ -2752,9 +3444,10 @@ struct rtw89_fw_h2c_rf_get_mccch { + + int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev); + int rtw89_fw_recognize(struct rtw89_dev *rtwdev); +-void rtw89_early_fw_feature_recognize(struct device *device, +- const struct rtw89_chip_info *chip, +- u32 *early_feat_map); ++const struct firmware * ++rtw89_early_fw_feature_recognize(struct device *device, ++ const struct rtw89_chip_info *chip, ++ u32 *early_feat_map); + int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type); + int rtw89_load_firmware(struct rtw89_dev *rtwdev); + void rtw89_unload_firmware(struct rtw89_dev *rtwdev); +@@ -2845,6 +3538,38 @@ int rtw89_fw_h2c_p2p_act(struct rtw89_de + u8 act, u8 noa_id); + int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + bool en); ++int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, ++ bool enable); ++int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, bool enable); ++int rtw89_fw_h2c_keep_alive(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, ++ bool enable); ++int rtw89_fw_h2c_disconnect_detect(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, bool enable); ++int rtw89_fw_h2c_wow_global(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, ++ bool enable); ++int rtw89_fw_h2c_wow_wakeup_ctrl(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, bool enable); ++int rtw89_fw_wow_cam_update(struct rtw89_dev *rtwdev, ++ struct rtw89_wow_cam_info *cam_info); ++int rtw89_fw_h2c_add_mcc(struct rtw89_dev *rtwdev, ++ const struct rtw89_fw_mcc_add_req *p); ++int rtw89_fw_h2c_start_mcc(struct rtw89_dev *rtwdev, ++ const struct rtw89_fw_mcc_start_req *p); ++int rtw89_fw_h2c_stop_mcc(struct rtw89_dev *rtwdev, u8 group, u8 macid, ++ bool prev_groups); ++int rtw89_fw_h2c_del_mcc_group(struct rtw89_dev *rtwdev, u8 group, ++ bool prev_groups); ++int rtw89_fw_h2c_reset_mcc_group(struct rtw89_dev *rtwdev, u8 group); ++int rtw89_fw_h2c_mcc_req_tsf(struct rtw89_dev *rtwdev, ++ const struct rtw89_fw_mcc_tsf_req *req, ++ struct rtw89_mac_mcc_tsf_rpt *rpt); ++int rtw89_fw_h2c_mcc_macid_bitamp(struct rtw89_dev *rtwdev, u8 group, u8 macid, ++ u8 *bitmap); ++int rtw89_fw_h2c_mcc_sync(struct rtw89_dev *rtwdev, u8 group, u8 source, ++ u8 target, u8 offset); ++int rtw89_fw_h2c_mcc_set_duration(struct rtw89_dev *rtwdev, ++ const struct rtw89_fw_mcc_duration *p); + + static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) + { +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/Kconfig linux-6.2/drivers/net/wireless/realtek/rtw89/Kconfig +--- linux-6.1/drivers/net/wireless/realtek/rtw89/Kconfig 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/Kconfig 2022-12-24 00:49:25.775376835 +0200 +@@ -19,6 +19,9 @@ config RTW89_PCI + config RTW89_8852A + tristate + ++config RTW89_8852B ++ tristate ++ + config RTW89_8852C + tristate + +@@ -33,6 +36,17 @@ config RTW89_8852AE + + 802.11ax PCIe wireless network (Wi-Fi 6) adapter + ++config RTW89_8852BE ++ tristate "Realtek 8852BE PCI wireless network (Wi-Fi 6) adapter" ++ depends on PCI ++ select RTW89_CORE ++ select RTW89_PCI ++ select RTW89_8852B ++ help ++ Select this option will enable support for 8852BE chipset ++ ++ 802.11ax PCIe wireless network (Wi-Fi 6) adapter ++ + config RTW89_8852CE + tristate "Realtek 8852CE PCI wireless network (Wi-Fi 6E) adapter" + depends on PCI +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/mac80211.c linux-6.2/drivers/net/wireless/realtek/rtw89/mac80211.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/mac80211.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/mac80211.c 2022-12-24 00:49:25.779376835 +0200 +@@ -14,6 +14,7 @@ + #include "sar.h" + #include "ser.h" + #include "util.h" ++#include "wow.h" + + static void rtw89_ops_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, +@@ -124,18 +125,21 @@ static int rtw89_ops_add_interface(struc + RTW89_PORT_NUM); + if (rtwvif->port == RTW89_PORT_NUM) { + ret = -ENOSPC; ++ list_del_init(&rtwvif->list); + goto out; + } + + rtwvif->bcn_hit_cond = 0; + rtwvif->mac_idx = RTW89_MAC_0; + rtwvif->phy_idx = RTW89_PHY_0; ++ rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; + rtwvif->hit_rule = 0; + ether_addr_copy(rtwvif->mac_addr, vif->addr); + + ret = rtw89_mac_add_vif(rtwdev, rtwvif); + if (ret) { + rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); ++ list_del_init(&rtwvif->list); + goto out; + } + +@@ -173,6 +177,9 @@ static int rtw89_ops_change_interface(st + enum nl80211_iftype type, bool p2p) + { + struct rtw89_dev *rtwdev = hw->priv; ++ int ret; ++ ++ set_bit(RTW89_FLAG_CHANGING_INTERFACE, rtwdev->flags); + + rtw89_debug(rtwdev, RTW89_DBG_STATE, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n", + vif->addr, vif->type, type, vif->p2p, p2p); +@@ -182,7 +189,13 @@ static int rtw89_ops_change_interface(st + vif->type = type; + vif->p2p = p2p; + +- return rtw89_ops_add_interface(hw, vif); ++ ret = rtw89_ops_add_interface(hw, vif); ++ if (ret) ++ rtw89_warn(rtwdev, "failed to change interface %d\n", ret); ++ ++ clear_bit(RTW89_FLAG_CHANGING_INTERFACE, rtwdev->flags); ++ ++ return ret; + } + + static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, +@@ -443,6 +456,7 @@ void rtw89_ops_stop_ap(struct ieee80211_ + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + + mutex_lock(&rtwdev->mutex); ++ rtw89_mac_stop_ap(rtwdev, rtwvif); + rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); + rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); + mutex_unlock(&rtwdev->mutex); +@@ -916,6 +930,55 @@ static int rtw89_ops_set_tid_config(stru + return 0; + } + ++#ifdef CONFIG_PM ++static int rtw89_ops_suspend(struct ieee80211_hw *hw, ++ struct cfg80211_wowlan *wowlan) ++{ ++ struct rtw89_dev *rtwdev = hw->priv; ++ int ret; ++ ++ set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); ++ cancel_delayed_work_sync(&rtwdev->track_work); ++ ++ mutex_lock(&rtwdev->mutex); ++ ret = rtw89_wow_suspend(rtwdev, wowlan); ++ mutex_unlock(&rtwdev->mutex); ++ ++ if (ret) { ++ rtw89_warn(rtwdev, "failed to suspend for wow %d\n", ret); ++ clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int rtw89_ops_resume(struct ieee80211_hw *hw) ++{ ++ struct rtw89_dev *rtwdev = hw->priv; ++ int ret; ++ ++ mutex_lock(&rtwdev->mutex); ++ ret = rtw89_wow_resume(rtwdev); ++ if (ret) ++ rtw89_warn(rtwdev, "failed to resume for wow %d\n", ret); ++ mutex_unlock(&rtwdev->mutex); ++ ++ clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); ++ ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work, ++ RTW89_TRACK_WORK_PERIOD); ++ ++ return ret ? 1 : 0; ++} ++ ++static void rtw89_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled) ++{ ++ struct rtw89_dev *rtwdev = hw->priv; ++ ++ device_set_wakeup_enable(rtwdev->dev, enabled); ++} ++#endif ++ + const struct ieee80211_ops rtw89_ops = { + .tx = rtw89_ops_tx, + .wake_tx_queue = rtw89_ops_wake_tx_queue, +@@ -953,5 +1016,10 @@ const struct ieee80211_ops rtw89_ops = { + .set_sar_specs = rtw89_ops_set_sar_specs, + .sta_rc_update = rtw89_ops_sta_rc_update, + .set_tid_config = rtw89_ops_set_tid_config, ++#ifdef CONFIG_PM ++ .suspend = rtw89_ops_suspend, ++ .resume = rtw89_ops_resume, ++ .set_wakeup = rtw89_ops_set_wakeup, ++#endif + }; + EXPORT_SYMBOL(rtw89_ops); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/mac.c linux-6.2/drivers/net/wireless/realtek/rtw89/mac.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/mac.c 2022-12-31 22:58:05.367710726 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/mac.c 2022-12-24 00:49:25.779376835 +0200 +@@ -7,6 +7,7 @@ + #include "debug.h" + #include "fw.h" + #include "mac.h" ++#include "pci.h" + #include "ps.h" + #include "reg.h" + #include "util.h" +@@ -31,6 +32,8 @@ const u32 rtw89_mac_mem_base_addrs[RTW89 + [RTW89_MAC_MEM_TXDATA_FIFO_1] = TXDATA_FIFO_1_BASE_ADDR, + [RTW89_MAC_MEM_CPU_LOCAL] = CPU_LOCAL_BASE_ADDR, + [RTW89_MAC_MEM_BSSID_CAM] = BSSID_CAM_BASE_ADDR, ++ [RTW89_MAC_MEM_TXD_FIFO_0_V1] = TXD_FIFO_0_BASE_ADDR_V1, ++ [RTW89_MAC_MEM_TXD_FIFO_1_V1] = TXD_FIFO_1_BASE_ADDR_V1, + }; + + static void rtw89_mac_mem_write(struct rtw89_dev *rtwdev, u32 offset, +@@ -272,106 +275,163 @@ static void rtw89_mac_dump_l0_to_l1(stru + } + } + +-static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, +- enum mac_ax_err_info err) ++static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev) + { +- u32 dmac_err, cmac_err; ++ const struct rtw89_chip_info *chip = rtwdev->chip; ++ u32 dmac_err; ++ int i, ret; + +- if (err != MAC_AX_ERR_L1_ERR_DMAC && +- err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && +- err != MAC_AX_ERR_L0_ERR_CMAC0 && +- err != MAC_AX_ERR_L0_ERR_CMAC1) ++ ret = rtw89_mac_check_mac_en(rtwdev, 0, RTW89_DMAC_SEL); ++ if (ret) { ++ rtw89_warn(rtwdev, "[DMAC] : DMAC not enabled\n"); + return; ++ } + +- rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); +- rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); +- +- cmac_err = rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR); +- rtw89_info(rtwdev, "R_AX_CMAC_ERR_ISR =0x%08x\n", cmac_err); + dmac_err = rtw89_read32(rtwdev, R_AX_DMAC_ERR_ISR); +- rtw89_info(rtwdev, "R_AX_DMAC_ERR_ISR =0x%08x\n", dmac_err); ++ rtw89_info(rtwdev, "R_AX_DMAC_ERR_ISR=0x%08x\n", dmac_err); ++ rtw89_info(rtwdev, "R_AX_DMAC_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_DMAC_ERR_IMR)); + + if (dmac_err) { +- rtw89_info(rtwdev, "R_AX_WDE_ERR_FLAG_CFG =0x%08x ", +- rtw89_read32(rtwdev, R_AX_WDE_ERR_FLAG_CFG)); +- rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_CFG =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_CFG)); ++ rtw89_info(rtwdev, "R_AX_WDE_ERR_FLAG_CFG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDE_ERR_FLAG_CFG_NUM1)); ++ rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_CFG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_CFG_NUM1)); ++ if (chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_PLE_ERRFLAG_MSG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_ERRFLAG_MSG)); ++ rtw89_info(rtwdev, "R_AX_WDE_ERRFLAG_MSG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_WDE_ERRFLAG_MSG)); ++ rtw89_info(rtwdev, "R_AX_PLE_DBGERR_LOCKEN=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_DBGERR_LOCKEN)); ++ rtw89_info(rtwdev, "R_AX_PLE_DBGERR_STS=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_PLE_DBGERR_STS)); ++ } + } + + if (dmac_err & B_AX_WDRLS_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_WDRLS_ERR_IMR =0x%08x ", ++ rtw89_info(rtwdev, "R_AX_WDRLS_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDRLS_ERR_IMR)); +- rtw89_info(rtwdev, "R_AX_WDRLS_ERR_ISR =0x%08x\n", ++ rtw89_info(rtwdev, "R_AX_WDRLS_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDRLS_ERR_ISR)); ++ if (chip->chip_id == RTL8852C) ++ rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX_V1)); ++ else ++ rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX)); + } + + if (dmac_err & B_AX_WSEC_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR_ISR =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D00 =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D04 =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D10 =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D14 =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D18 =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_CAM_WDATA)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D20 =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D24 =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D28 =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_TRX_PKT_CNT)); +- rtw89_info(rtwdev, "SEC_local_Register 0x9D2C =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_SEC_TRX_BLK_CNT)); ++ if (chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_ERROR_FLAG_IMR)); ++ rtw89_info(rtwdev, "R_AX_SEC_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_ERROR_FLAG)); ++ rtw89_info(rtwdev, "R_AX_SEC_ENG_CTRL=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); ++ rtw89_info(rtwdev, "R_AX_SEC_MPDU_PROC=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); ++ rtw89_info(rtwdev, "R_AX_SEC_CAM_ACCESS=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); ++ rtw89_info(rtwdev, "R_AX_SEC_CAM_RDATA=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); ++ rtw89_info(rtwdev, "R_AX_SEC_DEBUG1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_DEBUG1)); ++ rtw89_info(rtwdev, "R_AX_SEC_TX_DEBUG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); ++ rtw89_info(rtwdev, "R_AX_SEC_RX_DEBUG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); ++ ++ rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, ++ B_AX_DBG_SEL0, 0x8B); ++ rtw89_write32_mask(rtwdev, R_AX_DBG_CTRL, ++ B_AX_DBG_SEL1, 0x8B); ++ rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, ++ B_AX_SEL_0XC0_MASK, 1); ++ for (i = 0; i < 0x10; i++) { ++ rtw89_write32_mask(rtwdev, R_AX_SEC_ENG_CTRL, ++ B_AX_SEC_DBG_PORT_FIELD_MASK, i); ++ rtw89_info(rtwdev, "sel=%x,R_AX_SEC_DEBUG2=0x%08x\n", ++ i, rtw89_read32(rtwdev, R_AX_SEC_DEBUG2)); ++ } ++ } else { ++ rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_DEBUG)); ++ rtw89_info(rtwdev, "R_AX_SEC_ENG_CTRL=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_ENG_CTRL)); ++ rtw89_info(rtwdev, "R_AX_SEC_MPDU_PROC=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_MPDU_PROC)); ++ rtw89_info(rtwdev, "R_AX_SEC_CAM_ACCESS=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_ACCESS)); ++ rtw89_info(rtwdev, "R_AX_SEC_CAM_RDATA=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_RDATA)); ++ rtw89_info(rtwdev, "R_AX_SEC_CAM_WDATA=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_CAM_WDATA)); ++ rtw89_info(rtwdev, "R_AX_SEC_TX_DEBUG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_TX_DEBUG)); ++ rtw89_info(rtwdev, "R_AX_SEC_RX_DEBUG=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_RX_DEBUG)); ++ rtw89_info(rtwdev, "R_AX_SEC_TRX_PKT_CNT=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_TRX_PKT_CNT)); ++ rtw89_info(rtwdev, "R_AX_SEC_TRX_BLK_CNT=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SEC_TRX_BLK_CNT)); ++ } + } + + if (dmac_err & B_AX_MPDU_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_IMR =0x%08x ", ++ rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_IMR)); +- rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_ISR =0x%08x\n", ++ rtw89_info(rtwdev, "R_AX_MPDU_TX_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_TX_ERR_ISR)); +- rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_IMR =0x%08x ", ++ rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_IMR)); +- rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_ISR =0x%08x\n", ++ rtw89_info(rtwdev, "R_AX_MPDU_RX_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_MPDU_RX_ERR_ISR)); + } + + if (dmac_err & B_AX_STA_SCHEDULER_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR =0x%08x ", ++ rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR)); +- rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR= 0x%08x\n", ++ rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR)); + } + + if (dmac_err & B_AX_WDE_DLE_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x ", ++ rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_WDE_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); +- rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x ", ++ rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); +- dump_err_status_dispatcher(rtwdev); + } + + if (dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); +- rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); ++ if (chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_IMR)); ++ rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_ISR)); ++ rtw89_info(rtwdev, "R_AX_TXPKTCTL_B1_ERRFLAG_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_B1_ERRFLAG_IMR)); ++ rtw89_info(rtwdev, "R_AX_TXPKTCTL_B1_ERRFLAG_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_B1_ERRFLAG_ISR)); ++ } else { ++ rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR)); ++ rtw89_info(rtwdev, "R_AX_TXPKTCTL_ERR_IMR_ISR_B1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_TXPKTCTL_ERR_IMR_ISR_B1)); ++ } + } + + if (dmac_err & B_AX_PLE_DLE_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x ", ++ rtw89_info(rtwdev, "R_AX_WDE_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_WDE_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_WDE_ERR_ISR)); +- rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x ", ++ rtw89_info(rtwdev, "R_AX_PLE_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_IMR)); + rtw89_info(rtwdev, "R_AX_PLE_ERR_FLAG_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PLE_ERR_FLAG_ISR)); +@@ -391,86 +451,190 @@ static void rtw89_mac_dump_err_status(st + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_2)); + rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS)); +- rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); +- rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); +- rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); +- dump_err_status_dispatcher(rtwdev); ++ if (chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_RX_CTRL0=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RX_CTRL0)); ++ rtw89_info(rtwdev, "R_AX_RX_CTRL1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RX_CTRL1)); ++ rtw89_info(rtwdev, "R_AX_RX_CTRL2=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RX_CTRL2)); ++ } else { ++ rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0)); ++ rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1)); ++ rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2)); ++ } + } + + if (dmac_err & B_AX_PKTIN_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_PKTIN_ERR_IMR =0x%08x ", +- rtw89_read32(rtwdev, R_AX_PKTIN_ERR_IMR)); +- rtw89_info(rtwdev, "R_AX_PKTIN_ERR_ISR =0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); +- rtw89_info(rtwdev, "R_AX_PKTIN_ERR_IMR =0x%08x ", ++ rtw89_info(rtwdev, "R_AX_PKTIN_ERR_IMR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PKTIN_ERR_IMR)); +- rtw89_info(rtwdev, "R_AX_PKTIN_ERR_ISR =0x%08x\n", ++ rtw89_info(rtwdev, "R_AX_PKTIN_ERR_ISR=0x%08x\n", + rtw89_read32(rtwdev, R_AX_PKTIN_ERR_ISR)); + } + +- if (dmac_err & B_AX_DISPATCH_ERR_FLAG) +- dump_err_status_dispatcher(rtwdev); ++ if (dmac_err & B_AX_DISPATCH_ERR_FLAG) { ++ rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR)); ++ rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR)); ++ rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR)); ++ rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR)); ++ rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR)); ++ rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR)); ++ } ++ ++ if (dmac_err & B_AX_BBRPT_ERR_FLAG) { ++ if (chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_ISR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_CHINFO_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_ISR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_CHINFO_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); ++ } else { ++ rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_CHINFO_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_ISR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_CHINFO_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_CHINFO_ERR_IMR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_IMR)); ++ rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR)); ++ } ++ } + +- if (dmac_err & B_AX_DLE_CPUIO_ERR_FLAG) { +- rtw89_info(rtwdev, "R_AX_CPUIO_ERR_IMR=0x%08x ", +- rtw89_read32(rtwdev, R_AX_CPUIO_ERR_IMR)); +- rtw89_info(rtwdev, "R_AX_CPUIO_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_CPUIO_ERR_ISR)); ++ if (dmac_err & B_AX_HAXIDMA_ERR_FLAG && chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK)); ++ rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_HAXI_IDCT)); + } ++} + +- if (dmac_err & BIT(11)) { +- rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR_ISR)); ++static void rtw89_mac_dump_cmac_err_status(struct rtw89_dev *rtwdev, ++ u8 band) ++{ ++ const struct rtw89_chip_info *chip = rtwdev->chip; ++ u32 offset = 0; ++ u32 cmac_err; ++ int ret; ++ ++ ret = rtw89_mac_check_mac_en(rtwdev, band, RTW89_CMAC_SEL); ++ if (ret) { ++ if (band) ++ rtw89_warn(rtwdev, "[CMAC] : CMAC1 not enabled\n"); ++ else ++ rtw89_warn(rtwdev, "[CMAC] : CMAC0 not enabled\n"); ++ return; + } + ++ if (band) ++ offset = RTW89_MAC_AX_BAND_REG_OFFSET; ++ ++ cmac_err = rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR + offset); ++ rtw89_info(rtwdev, "R_AX_CMAC_ERR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_CMAC_ERR_ISR + offset)); ++ rtw89_info(rtwdev, "R_AX_CMAC_FUNC_EN [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_CMAC_FUNC_EN + offset)); ++ rtw89_info(rtwdev, "R_AX_CK_EN [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_CK_EN + offset)); ++ + if (cmac_err & B_AX_SCHEDULE_TOP_ERR_IND) { +- rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_IMR=0x%08x ", +- rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_IMR)); +- rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_ISR=0x%04x\n", +- rtw89_read16(rtwdev, R_AX_SCHEDULE_ERR_ISR)); ++ rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_IMR + offset)); ++ rtw89_info(rtwdev, "R_AX_SCHEDULE_ERR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_SCHEDULE_ERR_ISR + offset)); + } + + if (cmac_err & B_AX_PTCL_TOP_ERR_IND) { +- rtw89_info(rtwdev, "R_AX_PTCL_IMR0=0x%08x ", +- rtw89_read32(rtwdev, R_AX_PTCL_IMR0)); +- rtw89_info(rtwdev, "R_AX_PTCL_ISR0=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PTCL_ISR0)); ++ rtw89_info(rtwdev, "R_AX_PTCL_IMR0 [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PTCL_IMR0 + offset)); ++ rtw89_info(rtwdev, "R_AX_PTCL_ISR0 [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PTCL_ISR0 + offset)); + } + + if (cmac_err & B_AX_DMA_TOP_ERR_IND) { +- rtw89_info(rtwdev, "R_AX_DLE_CTRL=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_DLE_CTRL)); ++ if (chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_RX_ERR_FLAG [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_RX_ERR_FLAG + offset)); ++ rtw89_info(rtwdev, "R_AX_RX_ERR_FLAG_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_RX_ERR_FLAG_IMR + offset)); ++ } else { ++ rtw89_info(rtwdev, "R_AX_DLE_CTRL [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_DLE_CTRL + offset)); ++ } + } + +- if (cmac_err & B_AX_PHYINTF_ERR_IND) { +- rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_IMR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR)); ++ if (cmac_err & B_AX_DMA_TOP_ERR_IND || cmac_err & B_AX_WMAC_RX_ERR_IND) { ++ if (chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR + offset)); ++ rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR + offset)); ++ } else { ++ rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_IMR + offset)); ++ } + } + + if (cmac_err & B_AX_TXPWR_CTRL_ERR_IND) { +- rtw89_info(rtwdev, "R_AX_TXPWR_IMR=0x%08x ", +- rtw89_read32(rtwdev, R_AX_TXPWR_IMR)); +- rtw89_info(rtwdev, "R_AX_TXPWR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_TXPWR_ISR)); +- } +- +- if (cmac_err & B_AX_WMAC_RX_ERR_IND) { +- rtw89_info(rtwdev, "R_AX_DBGSEL_TRXPTCL=0x%08x ", +- rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL)); +- rtw89_info(rtwdev, "R_AX_PHYINFO_ERR_ISR=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_PHYINFO_ERR_ISR)); ++ rtw89_info(rtwdev, "R_AX_TXPWR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TXPWR_IMR + offset)); ++ rtw89_info(rtwdev, "R_AX_TXPWR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TXPWR_ISR + offset)); + } + + if (cmac_err & B_AX_WMAC_TX_ERR_IND) { +- rtw89_info(rtwdev, "R_AX_TMAC_ERR_IMR_ISR=0x%08x ", +- rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR)); +- rtw89_info(rtwdev, "R_AX_DBGSEL_TRXPTCL=0x%08x\n", +- rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL)); ++ if (chip->chip_id == RTL8852C) { ++ rtw89_info(rtwdev, "R_AX_TRXPTCL_ERROR_INDICA [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TRXPTCL_ERROR_INDICA + offset)); ++ rtw89_info(rtwdev, "R_AX_TRXPTCL_ERROR_INDICA_MASK [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TRXPTCL_ERROR_INDICA_MASK + offset)); ++ } else { ++ rtw89_info(rtwdev, "R_AX_TMAC_ERR_IMR_ISR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_TMAC_ERR_IMR_ISR + offset)); ++ } ++ rtw89_info(rtwdev, "R_AX_DBGSEL_TRXPTCL [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_DBGSEL_TRXPTCL + offset)); + } + ++ rtw89_info(rtwdev, "R_AX_CMAC_ERR_IMR [%d]=0x%08x\n", band, ++ rtw89_read32(rtwdev, R_AX_CMAC_ERR_IMR + offset)); ++} ++ ++static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, ++ enum mac_ax_err_info err) ++{ ++ if (err != MAC_AX_ERR_L1_ERR_DMAC && ++ err != MAC_AX_ERR_L0_PROMOTE_TO_L1 && ++ err != MAC_AX_ERR_L0_ERR_CMAC0 && ++ err != MAC_AX_ERR_L0_ERR_CMAC1) ++ return; ++ ++ rtw89_info(rtwdev, "--->\nerr=0x%x\n", err); ++ rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n", ++ rtw89_read32(rtwdev, R_AX_SER_DBG_INFO)); ++ ++ rtw89_mac_dump_dmac_err_status(rtwdev); ++ rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_0); ++ if (rtwdev->dbcc_en) ++ rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_1); ++ + rtwdev->hci.ops->dump_err_status(rtwdev); + + if (err == MAC_AX_ERR_L0_PROMOTE_TO_L1) +@@ -1304,6 +1468,8 @@ const struct rtw89_mac_size_set rtw89_ma + .ple_qt47 = {525, 0, 32, 20, 1034, 13, 1199, 0, 1053, 62, 160, 1037,}, + /* PCIE 64 */ + .ple_qt58 = {147, 0, 16, 20, 157, 13, 229, 0, 172, 14, 24, 0,}, ++ /* 8852A PCIE WOW */ ++ .ple_qt_52a_wow = {264, 0, 32, 20, 64, 13, 1005, 0, 64, 128, 120,}, + }; + EXPORT_SYMBOL(rtw89_mac_size); + +@@ -1331,6 +1497,60 @@ static const struct rtw89_dle_mem *get_d + return cfg; + } + ++static bool mac_is_txq_empty(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_mac_dle_dfi_qempty qempty; ++ u32 qnum, qtmp, val32, msk32; ++ int i, j, ret; ++ ++ qnum = rtwdev->chip->wde_qempty_acq_num; ++ qempty.dle_type = DLE_CTRL_TYPE_WDE; ++ ++ for (i = 0; i < qnum; i++) { ++ qempty.grpsel = i; ++ ret = dle_dfi_qempty(rtwdev, &qempty); ++ if (ret) { ++ rtw89_warn(rtwdev, "dle dfi acq empty %d\n", ret); ++ return false; ++ } ++ qtmp = qempty.qempty; ++ for (j = 0 ; j < QEMP_ACQ_GRP_MACID_NUM; j++) { ++ val32 = FIELD_GET(QEMP_ACQ_GRP_QSEL_MASK, qtmp); ++ if (val32 != QEMP_ACQ_GRP_QSEL_MASK) ++ return false; ++ qtmp >>= QEMP_ACQ_GRP_QSEL_SH; ++ } ++ } ++ ++ qempty.grpsel = rtwdev->chip->wde_qempty_mgq_sel; ++ ret = dle_dfi_qempty(rtwdev, &qempty); ++ if (ret) { ++ rtw89_warn(rtwdev, "dle dfi mgq empty %d\n", ret); ++ return false; ++ } ++ msk32 = B_CMAC0_MGQ_NORMAL | B_CMAC0_MGQ_NO_PWRSAV | B_CMAC0_CPUMGQ; ++ if ((qempty.qempty & msk32) != msk32) ++ return false; ++ ++ if (rtwdev->dbcc_en) { ++ msk32 |= B_CMAC1_MGQ_NORMAL | B_CMAC1_MGQ_NO_PWRSAV | B_CMAC1_CPUMGQ; ++ if ((qempty.qempty & msk32) != msk32) ++ return false; ++ } ++ ++ msk32 = B_AX_WDE_EMPTY_QTA_DMAC_WLAN_CPU | B_AX_WDE_EMPTY_QTA_DMAC_DATA_CPU | ++ B_AX_PLE_EMPTY_QTA_DMAC_WLAN_CPU | B_AX_PLE_EMPTY_QTA_DMAC_H2C | ++ B_AX_WDE_EMPTY_QUE_OTHERS | B_AX_PLE_EMPTY_QUE_DMAC_MPDU_TX | ++ B_AX_WDE_EMPTY_QTA_DMAC_CPUIO | B_AX_PLE_EMPTY_QTA_DMAC_CPUIO | ++ B_AX_WDE_EMPTY_QUE_DMAC_PKTIN | B_AX_WDE_EMPTY_QTA_DMAC_HIF | ++ B_AX_PLE_EMPTY_QUE_DMAC_SEC_TX | B_AX_WDE_EMPTY_QTA_DMAC_PKTIN | ++ B_AX_PLE_EMPTY_QTA_DMAC_B0_TXPL | B_AX_PLE_EMPTY_QTA_DMAC_B1_TXPL | ++ B_AX_PLE_EMPTY_QTA_DMAC_MPDU_TX; ++ val32 = rtw89_read32(rtwdev, R_AX_DLE_EMPTY0); ++ ++ return (val32 & msk32) == msk32; ++} ++ + static inline u32 dle_used_size(const struct rtw89_dle_size *wde, + const struct rtw89_dle_size *ple) + { +@@ -1474,8 +1694,48 @@ static void ple_quota_cfg(struct rtw89_d + SET_QUOTA(tx_rpt, PLE, 11); + } + ++int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow) ++{ ++ const struct rtw89_ple_quota *min_cfg, *max_cfg; ++ const struct rtw89_dle_mem *cfg; ++ u32 val; ++ ++ if (rtwdev->chip->chip_id == RTL8852C) ++ return 0; ++ ++ if (rtwdev->mac.qta_mode != RTW89_QTA_SCC) { ++ rtw89_err(rtwdev, "[ERR]support SCC mode only\n"); ++ return -EINVAL; ++ } ++ ++ if (wow) ++ cfg = get_dle_mem_cfg(rtwdev, RTW89_QTA_WOW); ++ else ++ cfg = get_dle_mem_cfg(rtwdev, RTW89_QTA_SCC); ++ if (!cfg) { ++ rtw89_err(rtwdev, "[ERR]get_dle_mem_cfg\n"); ++ return -EINVAL; ++ } ++ ++ min_cfg = cfg->ple_min_qt; ++ max_cfg = cfg->ple_max_qt; ++ SET_QUOTA(cma0_dma, PLE, 6); ++ SET_QUOTA(cma1_dma, PLE, 7); ++ ++ return 0; ++} + #undef SET_QUOTA + ++void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool enable) ++{ ++ u32 msk32 = B_AX_UC_MGNT_DEC | B_AX_BMC_MGNT_DEC; ++ ++ if (enable) ++ rtw89_write32_set(rtwdev, R_AX_SEC_ENG_CTRL, msk32); ++ else ++ rtw89_write32_clr(rtwdev, R_AX_SEC_ENG_CTRL, msk32); ++} ++ + static void dle_quota_cfg(struct rtw89_dev *rtwdev, + const struct rtw89_dle_mem *cfg, + u16 ext_wde_min_qt_wcpu) +@@ -1825,10 +2085,10 @@ static int scheduler_init(struct rtw89_d + return 0; + } + +-static int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, +- enum rtw89_machdr_frame_type type, +- enum rtw89_mac_fwd_target fwd_target, +- u8 mac_idx) ++int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, ++ enum rtw89_machdr_frame_type type, ++ enum rtw89_mac_fwd_target fwd_target, ++ u8 mac_idx) + { + u32 reg; + u32 val; +@@ -3112,7 +3372,7 @@ static void rtw89_disable_fw_watchdog(st + rtw89_mac_mem_write(rtwdev, R_AX_WDT_STATUS, val32, RTW89_MAC_MEM_CPU_LOCAL); + } + +-static void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev) ++void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev) + { + clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags); + +@@ -3127,8 +3387,7 @@ static void rtw89_mac_disable_cpu(struct + rtw89_write32_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); + } + +-static int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, +- bool dlfw) ++int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw) + { + u32 val; + int ret; +@@ -3267,11 +3526,6 @@ int rtw89_mac_partial_init(struct rtw89_ + return ret; + } + +- rtw89_mac_disable_cpu(rtwdev); +- ret = rtw89_mac_enable_cpu(rtwdev, 0, true); +- if (ret) +- return ret; +- + ret = rtw89_fw_download(rtwdev, RTW89_FW_NORMAL); + if (ret) + return ret; +@@ -3346,6 +3600,13 @@ int rtw89_mac_set_macid_pause(struct rtw + u8 grp = macid >> 5; + int ret; + ++ /* If this is called by change_interface() in the case of P2P, it could ++ * be power-off, so ignore this operation. ++ */ ++ if (test_bit(RTW89_FLAG_CHANGING_INTERFACE, rtwdev->flags) && ++ !test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) ++ return 0; ++ + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL); + if (ret) + return ret; +@@ -3616,11 +3877,16 @@ static void rtw89_mac_port_cfg_hiq_drop( + } + + static void rtw89_mac_port_cfg_func_en(struct rtw89_dev *rtwdev, +- struct rtw89_vif *rtwvif) ++ struct rtw89_vif *rtwvif, bool enable) + { + const struct rtw89_port_reg *p = &rtw_port_base; + +- rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN); ++ if (enable) ++ rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, ++ B_AX_PORT_FUNC_EN); ++ else ++ rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, ++ B_AX_PORT_FUNC_EN); + } + + static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev, +@@ -3652,6 +3918,49 @@ static void rtw89_mac_port_cfg_tbtt_shif + B_AX_TBTT_SHIFT_OFST_MASK, val); + } + ++static void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, ++ struct rtw89_vif *rtwvif_src, u8 offset, ++ int *n_offset) ++{ ++ u32 val, reg; ++ ++ if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE || rtwvif == rtwvif_src) ++ return; ++ ++ /* adjust offset randomly to avoid beacon conflict */ ++ offset = offset - offset / 4 + get_random_u32() % (offset / 2); ++ val = RTW89_PORT_OFFSET_MS_TO_32US((*n_offset)++, offset); ++ reg = rtw89_mac_reg_by_idx(R_AX_PORT0_TSF_SYNC + rtwvif->port * 4, ++ rtwvif->mac_idx); ++ ++ rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_SRC, rtwvif_src->port); ++ rtw89_write32_mask(rtwdev, reg, B_AX_SYNC_PORT_OFFSET_VAL, val); ++ rtw89_write32_set(rtwdev, reg, B_AX_SYNC_NOW); ++} ++ ++static void rtw89_mac_port_tsf_resync_all(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_vif *src = NULL, *tmp; ++ u8 offset = 100, vif_aps = 0; ++ int n_offset = 1; ++ ++ rtw89_for_each_rtwvif(rtwdev, tmp) { ++ if (!src || tmp->net_type == RTW89_NET_TYPE_INFRA) ++ src = tmp; ++ if (tmp->net_type == RTW89_NET_TYPE_AP_MODE) ++ vif_aps++; ++ } ++ ++ if (vif_aps == 0) ++ return; ++ ++ offset /= (vif_aps + 1); ++ ++ rtw89_for_each_rtwvif(rtwdev, tmp) ++ rtw89_mac_port_tsf_sync(rtwdev, tmp, src, offset, &n_offset); ++} ++ + int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) + { + int ret; +@@ -3671,6 +3980,10 @@ int rtw89_mac_vif_init(struct rtw89_dev + if (ret) + return ret; + ++ ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); ++ if (ret) ++ return ret; ++ + ret = rtw89_cam_init(rtwdev, rtwvif); + if (ret) + return ret; +@@ -3729,7 +4042,8 @@ int rtw89_mac_port_update(struct rtw89_d + rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif); + rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif); + rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif); +- rtw89_mac_port_cfg_func_en(rtwdev, rtwvif); ++ rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, true); ++ rtw89_mac_port_tsf_resync_all(rtwdev); + fsleep(BCN_ERLY_SET_DLY); + rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif); + +@@ -3780,6 +4094,11 @@ void rtw89_mac_set_he_obss_narrow_bw_ru( + rtw89_write32_set(rtwdev, reg, B_AX_RXTRIG_RU26_DIS); + } + ++void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) ++{ ++ rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, false); ++} ++ + int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) + { + int ret; +@@ -3926,6 +4245,164 @@ rtw89_mac_c2h_tsf32_toggle_rpt(struct rt + { + } + ++static void ++rtw89_mac_c2h_mcc_rcv_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) ++{ ++ u8 group = RTW89_GET_MAC_C2H_MCC_RCV_ACK_GROUP(c2h->data); ++ u8 func = RTW89_GET_MAC_C2H_MCC_RCV_ACK_H2C_FUNC(c2h->data); ++ ++ switch (func) { ++ case H2C_FUNC_ADD_MCC: ++ case H2C_FUNC_START_MCC: ++ case H2C_FUNC_STOP_MCC: ++ case H2C_FUNC_DEL_MCC_GROUP: ++ case H2C_FUNC_RESET_MCC_GROUP: ++ case H2C_FUNC_MCC_REQ_TSF: ++ case H2C_FUNC_MCC_MACID_BITMAP: ++ case H2C_FUNC_MCC_SYNC: ++ case H2C_FUNC_MCC_SET_DURATION: ++ break; ++ default: ++ rtw89_debug(rtwdev, RTW89_DBG_FW, ++ "invalid MCC C2H RCV ACK: func %d\n", func); ++ return; ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_FW, ++ "MCC C2H RCV ACK: group %d, func %d\n", group, func); ++} ++ ++static void ++rtw89_mac_c2h_mcc_req_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) ++{ ++ u8 group = RTW89_GET_MAC_C2H_MCC_REQ_ACK_GROUP(c2h->data); ++ u8 func = RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_FUNC(c2h->data); ++ u8 retcode = RTW89_GET_MAC_C2H_MCC_REQ_ACK_H2C_RETURN(c2h->data); ++ struct rtw89_completion_data data = {}; ++ unsigned int cond; ++ bool next = false; ++ ++ switch (func) { ++ case H2C_FUNC_MCC_REQ_TSF: ++ next = true; ++ break; ++ case H2C_FUNC_MCC_MACID_BITMAP: ++ case H2C_FUNC_MCC_SYNC: ++ case H2C_FUNC_MCC_SET_DURATION: ++ break; ++ case H2C_FUNC_ADD_MCC: ++ case H2C_FUNC_START_MCC: ++ case H2C_FUNC_STOP_MCC: ++ case H2C_FUNC_DEL_MCC_GROUP: ++ case H2C_FUNC_RESET_MCC_GROUP: ++ default: ++ rtw89_debug(rtwdev, RTW89_DBG_FW, ++ "invalid MCC C2H REQ ACK: func %d\n", func); ++ return; ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_FW, ++ "MCC C2H REQ ACK: group %d, func %d, return code %d\n", ++ group, func, retcode); ++ ++ if (!retcode && next) ++ return; ++ ++ data.err = !!retcode; ++ cond = RTW89_MCC_WAIT_COND(group, func); ++ rtw89_complete_cond(&rtwdev->mcc.wait, cond, &data); ++} ++ ++static void ++rtw89_mac_c2h_mcc_tsf_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) ++{ ++ u8 group = RTW89_GET_MAC_C2H_MCC_TSF_RPT_GROUP(c2h->data); ++ struct rtw89_completion_data data = {}; ++ struct rtw89_mac_mcc_tsf_rpt *rpt; ++ unsigned int cond; ++ ++ rpt = (struct rtw89_mac_mcc_tsf_rpt *)data.buf; ++ rpt->macid_x = RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_X(c2h->data); ++ rpt->macid_y = RTW89_GET_MAC_C2H_MCC_TSF_RPT_MACID_Y(c2h->data); ++ rpt->tsf_x_low = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_X(c2h->data); ++ rpt->tsf_x_high = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_X(c2h->data); ++ rpt->tsf_y_low = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_LOW_Y(c2h->data); ++ rpt->tsf_y_high = RTW89_GET_MAC_C2H_MCC_TSF_RPT_TSF_HIGH_Y(c2h->data); ++ ++ cond = RTW89_MCC_WAIT_COND(group, H2C_FUNC_MCC_REQ_TSF); ++ rtw89_complete_cond(&rtwdev->mcc.wait, cond, &data); ++} ++ ++static void ++rtw89_mac_c2h_mcc_status_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) ++{ ++ u8 group = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_GROUP(c2h->data); ++ u8 macid = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_MACID(c2h->data); ++ u8 status = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_STATUS(c2h->data); ++ u32 tsf_low = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_LOW(c2h->data); ++ u32 tsf_high = RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h->data); ++ struct rtw89_completion_data data = {}; ++ unsigned int cond; ++ bool rsp = true; ++ bool err; ++ u8 func; ++ ++ switch (status) { ++ case RTW89_MAC_MCC_ADD_ROLE_OK: ++ case RTW89_MAC_MCC_ADD_ROLE_FAIL: ++ func = H2C_FUNC_ADD_MCC; ++ err = status == RTW89_MAC_MCC_ADD_ROLE_FAIL; ++ break; ++ case RTW89_MAC_MCC_START_GROUP_OK: ++ case RTW89_MAC_MCC_START_GROUP_FAIL: ++ func = H2C_FUNC_START_MCC; ++ err = status == RTW89_MAC_MCC_START_GROUP_FAIL; ++ break; ++ case RTW89_MAC_MCC_STOP_GROUP_OK: ++ case RTW89_MAC_MCC_STOP_GROUP_FAIL: ++ func = H2C_FUNC_STOP_MCC; ++ err = status == RTW89_MAC_MCC_STOP_GROUP_FAIL; ++ break; ++ case RTW89_MAC_MCC_DEL_GROUP_OK: ++ case RTW89_MAC_MCC_DEL_GROUP_FAIL: ++ func = H2C_FUNC_DEL_MCC_GROUP; ++ err = status == RTW89_MAC_MCC_DEL_GROUP_FAIL; ++ break; ++ case RTW89_MAC_MCC_RESET_GROUP_OK: ++ case RTW89_MAC_MCC_RESET_GROUP_FAIL: ++ func = H2C_FUNC_RESET_MCC_GROUP; ++ err = status == RTW89_MAC_MCC_RESET_GROUP_FAIL; ++ break; ++ case RTW89_MAC_MCC_SWITCH_CH_OK: ++ case RTW89_MAC_MCC_SWITCH_CH_FAIL: ++ case RTW89_MAC_MCC_TXNULL0_OK: ++ case RTW89_MAC_MCC_TXNULL0_FAIL: ++ case RTW89_MAC_MCC_TXNULL1_OK: ++ case RTW89_MAC_MCC_TXNULL1_FAIL: ++ case RTW89_MAC_MCC_SWITCH_EARLY: ++ case RTW89_MAC_MCC_TBTT: ++ case RTW89_MAC_MCC_DURATION_START: ++ case RTW89_MAC_MCC_DURATION_END: ++ rsp = false; ++ break; ++ default: ++ rtw89_debug(rtwdev, RTW89_DBG_FW, ++ "invalid MCC C2H STS RPT: status %d\n", status); ++ return; ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_FW, ++ "MCC C2H STS RPT: group %d, macid %d, status %d, tsf {%d, %d}\n", ++ group, macid, status, tsf_low, tsf_high); ++ ++ if (!rsp) ++ return; ++ ++ data.err = err; ++ cond = RTW89_MCC_WAIT_COND(group, func); ++ rtw89_complete_cond(&rtwdev->mcc.wait, cond, &data); ++} ++ + static + void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev, + struct sk_buff *c2h, u32 len) = { +@@ -3947,6 +4424,25 @@ void (* const rtw89_mac_c2h_info_handler + [RTW89_MAC_C2H_FUNC_BCN_CNT] = rtw89_mac_c2h_bcn_cnt, + }; + ++static ++void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev, ++ struct sk_buff *c2h, u32 len) = { ++ [RTW89_MAC_C2H_FUNC_MCC_RCV_ACK] = rtw89_mac_c2h_mcc_rcv_ack, ++ [RTW89_MAC_C2H_FUNC_MCC_REQ_ACK] = rtw89_mac_c2h_mcc_req_ack, ++ [RTW89_MAC_C2H_FUNC_MCC_TSF_RPT] = rtw89_mac_c2h_mcc_tsf_rpt, ++ [RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt, ++}; ++ ++bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) ++{ ++ switch (class) { ++ default: ++ return false; ++ case RTW89_MAC_C2H_CLASS_MCC: ++ return true; ++ } ++} ++ + void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, + u32 len, u8 class, u8 func) + { +@@ -3962,6 +4458,10 @@ void rtw89_mac_c2h_handle(struct rtw89_d + if (func < RTW89_MAC_C2H_FUNC_OFLD_MAX) + handler = rtw89_mac_c2h_ofld_handler[func]; + break; ++ case RTW89_MAC_C2H_CLASS_MCC: ++ if (func < NUM_OF_RTW89_MAC_C2H_FUNC_MCC) ++ handler = rtw89_mac_c2h_mcc_handler[func]; ++ break; + case RTW89_MAC_C2H_CLASS_FWDBG: + return; + default: +@@ -4817,6 +5317,7 @@ int rtw89_mac_read_xtal_si(struct rtw89_ + + return 0; + } ++EXPORT_SYMBOL(rtw89_mac_read_xtal_si); + + static + void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) +@@ -4862,3 +5363,24 @@ void rtw89_mac_pkt_drop_vif(struct rtw89 + rtw89_mac_pkt_drop_vif_iter, + rtwvif); + } ++ ++int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, ++ enum rtw89_mac_idx band) ++{ ++ struct rtw89_pkt_drop_params params = {0}; ++ bool empty; ++ int i, ret = 0, try_cnt = 3; ++ ++ params.mac_band = band; ++ params.sel = RTW89_PKT_DROP_SEL_BAND_ONCE; ++ ++ for (i = 0; i < try_cnt; i++) { ++ ret = read_poll_timeout(mac_is_txq_empty, empty, empty, 50, ++ 50000, false, rtwdev); ++ if (ret) ++ rtw89_fw_h2c_pkt_drop(rtwdev, ¶ms); ++ else ++ return 0; ++ } ++ return ret; ++} +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/mac.h linux-6.2/drivers/net/wireless/realtek/rtw89/mac.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/mac.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/mac.h 2022-12-24 00:49:25.779376835 +0200 +@@ -168,6 +168,8 @@ enum rtw89_mac_ax_l0_to_l1_event { + MAC_AX_L0_TO_L1_EVENT_MAX = 15, + }; + ++#define RTW89_PORT_OFFSET_MS_TO_32US(n, shift_ms) ((n) * (shift_ms) * 1000 / 32) ++ + enum rtw89_mac_dbg_port_sel { + /* CMAC 0 related */ + RTW89_DBG_PORT_SEL_PTCL_C0 = 0, +@@ -211,6 +213,51 @@ enum rtw89_mac_dbg_port_sel { + RTW89_DBG_PORT_SEL_PLE_QUEMGN_QLNKTBL, + RTW89_DBG_PORT_SEL_PLE_QUEMGN_QEMPTY, + RTW89_DBG_PORT_SEL_PKTINFO, ++ /* DISPATCHER related */ ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX0, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX1, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX2, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX3, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX4, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX5, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX6, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX7, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX8, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TX9, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TXA, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TXB, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TXC, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TXD, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TXE, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_TXF, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX0, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX1, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX3, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX4, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX5, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX6, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX7, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX8, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TX9, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TXA, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TXB, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_TXC, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_RX0, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_RX1, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_RX2, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_RX3, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_RX4, ++ RTW89_DBG_PORT_SEL_DSPT_HDT_RX5, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_0, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_1, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P0_2, ++ RTW89_DBG_PORT_SEL_DSPT_CDT_RX_P1, ++ RTW89_DBG_PORT_SEL_DSPT_STF_CTRL, ++ RTW89_DBG_PORT_SEL_DSPT_ADDR_CTRL, ++ RTW89_DBG_PORT_SEL_DSPT_WDE_INTF, ++ RTW89_DBG_PORT_SEL_DSPT_PLE_INTF, ++ RTW89_DBG_PORT_SEL_DSPT_FLOW_CTRL, + /* PCIE related */ + RTW89_DBG_PORT_SEL_PCIE_TXDMA, + RTW89_DBG_PORT_SEL_PCIE_RXDMA, +@@ -245,6 +292,8 @@ enum rtw89_mac_dbg_port_sel { + #define BCN_IE_CAM1_BASE_ADDR 0x188A0000 + #define TXD_FIFO_0_BASE_ADDR 0x18856200 + #define TXD_FIFO_1_BASE_ADDR 0x188A1080 ++#define TXD_FIFO_0_BASE_ADDR_V1 0x18856400 /* for 8852C */ ++#define TXD_FIFO_1_BASE_ADDR_V1 0x188A1080 /* for 8852C */ + #define TXDATA_FIFO_0_BASE_ADDR 0x18856000 + #define TXDATA_FIFO_1_BASE_ADDR 0x188A1000 + #define CPU_LOCAL_BASE_ADDR 0x18003000 +@@ -271,6 +320,8 @@ enum rtw89_mac_mem_sel { + RTW89_MAC_MEM_TXDATA_FIFO_1, + RTW89_MAC_MEM_CPU_LOCAL, + RTW89_MAC_MEM_BSSID_CAM, ++ RTW89_MAC_MEM_TXD_FIFO_0_V1, ++ RTW89_MAC_MEM_TXD_FIFO_1_V1, + + /* keep last */ + RTW89_MAC_MEM_NUM, +@@ -319,6 +370,15 @@ enum rtw89_mac_c2h_info_func { + RTW89_MAC_C2H_FUNC_INFO_MAX, + }; + ++enum rtw89_mac_c2h_mcc_func { ++ RTW89_MAC_C2H_FUNC_MCC_RCV_ACK = 0, ++ RTW89_MAC_C2H_FUNC_MCC_REQ_ACK = 1, ++ RTW89_MAC_C2H_FUNC_MCC_TSF_RPT = 2, ++ RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT = 3, ++ ++ NUM_OF_RTW89_MAC_C2H_FUNC_MCC, ++}; ++ + enum rtw89_mac_c2h_class { + RTW89_MAC_C2H_CLASS_INFO, + RTW89_MAC_C2H_CLASS_OFLD, +@@ -329,6 +389,31 @@ enum rtw89_mac_c2h_class { + RTW89_MAC_C2H_CLASS_MAX, + }; + ++enum rtw89_mac_mcc_status { ++ RTW89_MAC_MCC_ADD_ROLE_OK = 0, ++ RTW89_MAC_MCC_START_GROUP_OK = 1, ++ RTW89_MAC_MCC_STOP_GROUP_OK = 2, ++ RTW89_MAC_MCC_DEL_GROUP_OK = 3, ++ RTW89_MAC_MCC_RESET_GROUP_OK = 4, ++ RTW89_MAC_MCC_SWITCH_CH_OK = 5, ++ RTW89_MAC_MCC_TXNULL0_OK = 6, ++ RTW89_MAC_MCC_TXNULL1_OK = 7, ++ ++ RTW89_MAC_MCC_SWITCH_EARLY = 10, ++ RTW89_MAC_MCC_TBTT = 11, ++ RTW89_MAC_MCC_DURATION_START = 12, ++ RTW89_MAC_MCC_DURATION_END = 13, ++ ++ RTW89_MAC_MCC_ADD_ROLE_FAIL = 20, ++ RTW89_MAC_MCC_START_GROUP_FAIL = 21, ++ RTW89_MAC_MCC_STOP_GROUP_FAIL = 22, ++ RTW89_MAC_MCC_DEL_GROUP_FAIL = 23, ++ RTW89_MAC_MCC_RESET_GROUP_FAIL = 24, ++ RTW89_MAC_MCC_SWITCH_CH_FAIL = 25, ++ RTW89_MAC_MCC_TXNULL0_FAIL = 26, ++ RTW89_MAC_MCC_TXNULL1_FAIL = 27, ++}; ++ + struct rtw89_mac_ax_coex { + #define RTW89_MAC_AX_COEX_RTK_MODE 0 + #define RTW89_MAC_AX_COEX_CSR_MODE 1 +@@ -391,6 +476,7 @@ enum rtw89_mac_bf_rrsc_rate { + #define ACCESS_CMAC(_addr) \ + ({typeof(_addr) __addr = (_addr); \ + __addr >= R_AX_CMAC_REG_START && __addr <= R_AX_CMAC_REG_END; }) ++#define RTW89_MAC_AX_BAND_REG_OFFSET 0x2000 + + #define PTCL_IDLE_POLL_CNT 10000 + #define SW_CVR_DUR_US 8 +@@ -416,6 +502,17 @@ enum rtw89_mac_bf_rrsc_rate { + #define S_AX_PLE_PAGE_SEL_128 1 + #define S_AX_PLE_PAGE_SEL_256 2 + ++#define B_CMAC0_MGQ_NORMAL BIT(2) ++#define B_CMAC0_MGQ_NO_PWRSAV BIT(3) ++#define B_CMAC0_CPUMGQ BIT(4) ++#define B_CMAC1_MGQ_NORMAL BIT(10) ++#define B_CMAC1_MGQ_NO_PWRSAV BIT(11) ++#define B_CMAC1_CPUMGQ BIT(12) ++ ++#define QEMP_ACQ_GRP_MACID_NUM 8 ++#define QEMP_ACQ_GRP_QSEL_SH 4 ++#define QEMP_ACQ_GRP_QSEL_MASK 0xF ++ + #define SDIO_LOCAL_BASE_ADDR 0x80000000 + + #define PWR_CMD_WRITE 0 +@@ -715,6 +812,7 @@ struct rtw89_mac_size_set { + const struct rtw89_ple_quota ple_qt46; + const struct rtw89_ple_quota ple_qt47; + const struct rtw89_ple_quota ple_qt58; ++ const struct rtw89_ple_quota ple_qt_52a_wow; + }; + + extern const struct rtw89_mac_size_set rtw89_mac_size; +@@ -810,7 +908,10 @@ int rtw89_mac_add_vif(struct rtw89_dev * + int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); + void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif); ++void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); + int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); ++void rtw89_mac_disable_cpu(struct rtw89_dev *rtwdev); ++int rtw89_mac_enable_cpu(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw); + int rtw89_mac_enable_bb_rf(struct rtw89_dev *rtwdev); + int rtw89_mac_disable_bb_rf(struct rtw89_dev *rtwdev); + +@@ -830,6 +931,7 @@ static inline int rtw89_chip_disable_bb_ + + u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev); + int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err); ++bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func); + void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, + u32 len, u8 class, u8 func); + int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev); +@@ -962,6 +1064,16 @@ static inline void rtw89_mac_ctrl_hci_dm + B_AX_HCI_TXDMA_EN | B_AX_HCI_RXDMA_EN); + } + ++static inline bool rtw89_mac_get_power_state(struct rtw89_dev *rtwdev) ++{ ++ u32 val; ++ ++ val = rtw89_read32_mask(rtwdev, R_AX_IC_PWR_STATE, ++ B_AX_WLMAC_PWR_STE_MASK); ++ ++ return !!val; ++} ++ + int rtw89_mac_set_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool resume, u32 tx_time); + int rtw89_mac_get_tx_time(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, +@@ -1010,6 +1122,7 @@ enum rtw89_mac_xtal_si_offset { + #define XTAL_SI_PON_EI BIT(1) + #define XTAL_SI_PON_WEI BIT(0) + XTAL_SI_SRAM_CTRL = 0xA1, ++#define XTAL_SI_SRAM_DIS BIT(1) + #define FULL_BIT_MASK GENMASK(7, 0) + }; + +@@ -1019,5 +1132,12 @@ void rtw89_mac_pkt_drop_vif(struct rtw89 + u16 rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd); + int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev, + struct rtw89_cpuio_ctrl *ctrl_para, bool wd); ++int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev, ++ enum rtw89_machdr_frame_type type, ++ enum rtw89_mac_fwd_target fwd_target, u8 mac_idx); ++int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow); ++int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev, ++ enum rtw89_mac_idx band); ++void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow); + + #endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/Makefile linux-6.2/drivers/net/wireless/realtek/rtw89/Makefile +--- linux-6.1/drivers/net/wireless/realtek/rtw89/Makefile 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/Makefile 2022-12-24 00:49:25.775376835 +0200 +@@ -15,6 +15,8 @@ rtw89_core-y += core.o \ + chan.o \ + ser.o + ++rtw89_core-$(CONFIG_PM) += wow.o ++ + obj-$(CONFIG_RTW89_8852A) += rtw89_8852a.o + rtw89_8852a-objs := rtw8852a.o \ + rtw8852a_table.o \ +@@ -24,6 +26,15 @@ rtw89_8852a-objs := rtw8852a.o \ + obj-$(CONFIG_RTW89_8852AE) += rtw89_8852ae.o + rtw89_8852ae-objs := rtw8852ae.o + ++obj-$(CONFIG_RTW89_8852B) += rtw89_8852b.o ++rtw89_8852b-objs := rtw8852b.o \ ++ rtw8852b_table.o \ ++ rtw8852b_rfk.o \ ++ rtw8852b_rfk_table.o ++ ++obj-$(CONFIG_RTW89_8852BE) += rtw89_8852be.o ++rtw89_8852be-objs := rtw8852be.o ++ + obj-$(CONFIG_RTW89_8852C) += rtw89_8852c.o + rtw89_8852c-objs := rtw8852c.o \ + rtw8852c_table.o \ +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/pci.c linux-6.2/drivers/net/wireless/realtek/rtw89/pci.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/pci.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/pci.c 2022-12-24 00:49:25.780376835 +0200 +@@ -186,6 +186,17 @@ static void rtw89_pci_ctrl_txdma_ch_pcie + } + } + ++static void rtw89_pci_ctrl_txdma_fw_ch_pcie(struct rtw89_dev *rtwdev, bool enable) ++{ ++ const struct rtw89_pci_info *info = rtwdev->pci_info; ++ const struct rtw89_reg_def *dma_stop1 = &info->dma_stop1; ++ ++ if (enable) ++ rtw89_write32_clr(rtwdev, dma_stop1->addr, B_AX_STOP_CH12); ++ else ++ rtw89_write32_set(rtwdev, dma_stop1->addr, B_AX_STOP_CH12); ++} ++ + static bool + rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls, + struct sk_buff *new, +@@ -256,7 +267,7 @@ static u32 rtw89_pci_rxbd_deliver_skbs(s + + rtw89_core_query_rxdesc(rtwdev, desc_info, skb->data, rxinfo_size); + +- new = dev_alloc_skb(desc_info->pkt_size); ++ new = rtw89_alloc_skb_for_rx(rtwdev, desc_info->pkt_size); + if (!new) + goto err_sync_device; + +@@ -960,8 +971,10 @@ static u32 __rtw89_pci_check_and_reclaim + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; + struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; ++ const struct rtw89_chip_info *chip = rtwdev->chip; + u32 bd_cnt, wd_cnt, min_cnt = 0; + struct rtw89_pci_rx_ring *rx_ring; ++ enum rtw89_debug_mask debug_mask; + u32 cnt; + + rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; +@@ -985,10 +998,20 @@ static u32 __rtw89_pci_check_and_reclaim + bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring); + wd_cnt = wd_ring->curr_num; + min_cnt = min(bd_cnt, wd_cnt); +- if (min_cnt == 0) +- rtw89_debug(rtwdev, rtwpci->low_power ? RTW89_DBG_TXRX : RTW89_DBG_UNEXP, ++ if (min_cnt == 0) { ++ /* This message can be frequently shown in low power mode or ++ * high traffic with 8852B, and we have recognized it as normal ++ * behavior, so print with mask RTW89_DBG_TXRX in these situations. ++ */ ++ if (rtwpci->low_power || chip->chip_id == RTL8852B) ++ debug_mask = RTW89_DBG_TXRX; ++ else ++ debug_mask = RTW89_DBG_UNEXP; ++ ++ rtw89_debug(rtwdev, debug_mask, + "still no tx resource after reclaim: wd_cnt=%d bd_cnt=%d\n", + wd_cnt, bd_cnt); ++ } + + out_unlock: + spin_unlock_bh(&rtwpci->trx_lock); +@@ -2513,7 +2536,7 @@ static int rtw89_pci_ops_mac_pre_init(st + + /* disable all channels except to FW CMD channel to download firmware */ + rtw89_pci_ctrl_txdma_ch_pcie(rtwdev, false); +- rtw89_write32_clr(rtwdev, info->dma_stop1.addr, B_AX_STOP_CH12); ++ rtw89_pci_ctrl_txdma_fw_ch_pcie(rtwdev, true); + + /* start DMA activities */ + rtw89_pci_ctrl_dma_all(rtwdev, true); +@@ -3771,6 +3794,16 @@ static const struct rtw89_hci_ops rtw89_ + + .recovery_start = rtw89_pci_ops_recovery_start, + .recovery_complete = rtw89_pci_ops_recovery_complete, ++ ++ .ctrl_txdma_ch = rtw89_pci_ctrl_txdma_ch_pcie, ++ .ctrl_txdma_fw_ch = rtw89_pci_ctrl_txdma_fw_ch_pcie, ++ .ctrl_trxhci = rtw89_pci_ctrl_dma_trx, ++ .poll_txdma_ch = rtw89_poll_txdma_ch_idle_pcie, ++ .clr_idx_all = rtw89_pci_clr_idx_all, ++ .clear = rtw89_pci_clear_resource, ++ .disable_intr = rtw89_pci_disable_intr_lock, ++ .enable_intr = rtw89_pci_enable_intr_lock, ++ .rst_bdram = rtw89_pci_rst_bdram_pcie, + }; + + int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/pci.h linux-6.2/drivers/net/wireless/realtek/rtw89/pci.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/pci.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/pci.h 2022-12-24 00:49:25.780376835 +0200 +@@ -202,6 +202,18 @@ + #define B_AX_RXP1DMA_INT BIT(1) + #define B_AX_RXDMA_INT BIT(0) + ++#define R_AX_HAXI_IDCT_MSK 0x10B8 ++#define B_AX_TXBD_LEN0_ERR_IDCT_MSK BIT(3) ++#define B_AX_TXBD_4KBOUND_ERR_IDCT_MSK BIT(2) ++#define B_AX_RXMDA_STUCK_IDCT_MSK BIT(1) ++#define B_AX_TXMDA_STUCK_IDCT_MSK BIT(0) ++ ++#define R_AX_HAXI_IDCT 0x10BC ++#define B_AX_TXBD_LEN0_ERR_IDCT BIT(3) ++#define B_AX_TXBD_4KBOUND_ERR_IDCT BIT(2) ++#define B_AX_RXMDA_STUCK_IDCT BIT(1) ++#define B_AX_TXMDA_STUCK_IDCT BIT(0) ++ + #define R_AX_HAXI_HIMR10 0x11E0 + #define B_AX_TXDMA_CH11_INT_EN_V1 BIT(1) + #define B_AX_TXDMA_CH10_INT_EN_V1 BIT(0) +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/phy.c linux-6.2/drivers/net/wireless/realtek/rtw89/phy.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/phy.c 2022-12-31 22:58:05.367710726 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/phy.c 2022-12-24 00:49:25.781376835 +0200 +@@ -2,6 +2,7 @@ + /* Copyright(c) 2019-2020 Realtek Corporation + */ + ++#include "coex.h" + #include "debug.h" + #include "fw.h" + #include "mac.h" +@@ -9,7 +10,7 @@ + #include "ps.h" + #include "reg.h" + #include "sar.h" +-#include "coex.h" ++#include "util.h" + + static u16 get_max_amsdu_len(struct rtw89_dev *rtwdev, + const struct rtw89_ra_report *report) +@@ -801,6 +802,11 @@ bool rtw89_phy_write_rf_v1(struct rtw89_ + } + EXPORT_SYMBOL(rtw89_phy_write_rf_v1); + ++static bool rtw89_chip_rf_v1(struct rtw89_dev *rtwdev) ++{ ++ return rtwdev->chip->ops->write_rf == rtw89_phy_write_rf_v1; ++} ++ + static void rtw89_phy_bb_reset(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) + { +@@ -1036,6 +1042,7 @@ static void rtw89_phy_config_bb_gain(str + { + const struct rtw89_chip_info *chip = rtwdev->chip; + union rtw89_phy_bb_gain_arg arg = { .addr = reg->addr }; ++ struct rtw89_efuse *efuse = &rtwdev->efuse; + + if (arg.gain_band >= RTW89_BB_GAIN_BAND_NR) + return; +@@ -1061,6 +1068,11 @@ static void rtw89_phy_config_bb_gain(str + case 3: + rtw89_phy_cfg_bb_gain_op1db(rtwdev, arg, reg->data); + break; ++ case 4: ++ /* This cfg_type is only used by rfe_type >= 50 with eFEM */ ++ if (efuse->rfe_type < 50) ++ break; ++ fallthrough; + default: + rtw89_warn(rtwdev, + "bb gain {0x%x:0x%x} with unknown cfg type: %d\n", +@@ -1117,6 +1129,24 @@ out: + return ret; + } + ++static void rtw89_phy_config_rf_reg_noio(struct rtw89_dev *rtwdev, ++ const struct rtw89_reg2_def *reg, ++ enum rtw89_rf_path rf_path, ++ void *extra_data) ++{ ++ u32 addr = reg->addr; ++ ++ if (addr == 0xfe || addr == 0xfd || addr == 0xfc || addr == 0xfb || ++ addr == 0xfa || addr == 0xf9) ++ return; ++ ++ if (rtw89_chip_rf_v1(rtwdev) && addr < 0x100) ++ return; ++ ++ rtw89_phy_cofig_rf_reg_store(rtwdev, reg, rf_path, ++ (struct rtw89_fw_h2c_rf_reg_info *)extra_data); ++} ++ + static void rtw89_phy_config_rf_reg(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, +@@ -1329,7 +1359,7 @@ static u32 rtw89_phy_nctl_poll(struct rt + return rtw89_phy_read32(rtwdev, 0x8080); + } + +-void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev) ++void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio) + { + void (*config)(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, void *data); +@@ -1345,7 +1375,11 @@ void rtw89_phy_init_rf_reg(struct rtw89_ + for (path = RF_PATH_A; path < chip->rf_path_num; path++) { + rf_table = chip->rf_table[path]; + rf_reg_info->rf_path = rf_table->rf_path; +- config = rf_table->config ? rf_table->config : rtw89_phy_config_rf_reg; ++ if (noio) ++ config = rtw89_phy_config_rf_reg_noio; ++ else ++ config = rf_table->config ? rf_table->config : ++ rtw89_phy_config_rf_reg; + rtw89_phy_init_reg(rtwdev, rf_table, config, (void *)rf_reg_info); + if (rtw89_phy_config_rf_reg_fw(rtwdev, rf_reg_info)) + rtw89_warn(rtwdev, "rf path %d reg h2c config failed\n", +@@ -1362,13 +1396,15 @@ static void rtw89_phy_init_rf_nctl(struc + int ret; + + /* IQK/DPK clock & reset */ +- rtw89_phy_write32_set(rtwdev, 0x0c60, 0x3); +- rtw89_phy_write32_set(rtwdev, 0x0c6c, 0x1); +- rtw89_phy_write32_set(rtwdev, 0x58ac, 0x8000000); +- rtw89_phy_write32_set(rtwdev, 0x78ac, 0x8000000); ++ rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x3); ++ rtw89_phy_write32_set(rtwdev, R_GNT_BT_WGT_EN, 0x1); ++ rtw89_phy_write32_set(rtwdev, R_P0_PATH_RST, 0x8000000); ++ rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000); ++ if (chip->chip_id == RTL8852B) ++ rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x2); + + /* check 0x8080 */ +- rtw89_phy_write32(rtwdev, 0x8000, 0x8); ++ rtw89_phy_write32(rtwdev, R_NCTL_CFG, 0x8); + + ret = read_poll_timeout(rtw89_phy_nctl_poll, val, val == 0x4, 10, + 1000, false, rtwdev); +@@ -1419,6 +1455,15 @@ void rtw89_phy_write32_idx(struct rtw89_ + } + EXPORT_SYMBOL(rtw89_phy_write32_idx); + ++u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, ++ enum rtw89_phy_idx phy_idx) ++{ ++ if (rtwdev->dbcc_en && phy_idx == RTW89_PHY_1) ++ addr += rtw89_phy0_phy1_offset(rtwdev, addr); ++ return rtw89_phy_read32_mask(rtwdev, addr, mask); ++} ++EXPORT_SYMBOL(rtw89_phy_read32_idx); ++ + void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask, + u32 val) + { +@@ -1443,23 +1488,21 @@ void rtw89_phy_write_reg3_tbl(struct rtw + } + EXPORT_SYMBOL(rtw89_phy_write_reg3_tbl); + +-const u8 rtw89_rs_idx_max[] = { ++static const u8 rtw89_rs_idx_max[] = { + [RTW89_RS_CCK] = RTW89_RATE_CCK_MAX, + [RTW89_RS_OFDM] = RTW89_RATE_OFDM_MAX, + [RTW89_RS_MCS] = RTW89_RATE_MCS_MAX, + [RTW89_RS_HEDCM] = RTW89_RATE_HEDCM_MAX, + [RTW89_RS_OFFSET] = RTW89_RATE_OFFSET_MAX, + }; +-EXPORT_SYMBOL(rtw89_rs_idx_max); + +-const u8 rtw89_rs_nss_max[] = { ++static const u8 rtw89_rs_nss_max[] = { + [RTW89_RS_CCK] = 1, + [RTW89_RS_OFDM] = 1, + [RTW89_RS_MCS] = RTW89_NSS_MAX, + [RTW89_RS_HEDCM] = RTW89_NSS_HEDCM_MAX, + [RTW89_RS_OFFSET] = 1, + }; +-EXPORT_SYMBOL(rtw89_rs_nss_max); + + static const u8 _byr_of_rs[] = { + [RTW89_RS_CCK] = offsetof(struct rtw89_txpwr_byrate, cck), +@@ -1501,6 +1544,7 @@ EXPORT_SYMBOL(rtw89_phy_load_txpwr_byrat + (txpwr_rf) >> (__c->txpwr_factor_rf - __c->txpwr_factor_mac); \ + }) + ++static + s8 rtw89_phy_read_txpwr_byrate(struct rtw89_dev *rtwdev, u8 band, + const struct rtw89_rate_desc *rate_desc) + { +@@ -1523,7 +1567,6 @@ s8 rtw89_phy_read_txpwr_byrate(struct rt + + return _phy_txpwr_rf_to_mac(rtwdev, byr[idx]); + } +-EXPORT_SYMBOL(rtw89_phy_read_txpwr_byrate); + + static u8 rtw89_channel_6g_to_idx(struct rtw89_dev *rtwdev, u8 channel_6g) + { +@@ -1783,6 +1826,7 @@ static void rtw89_phy_fill_txpwr_limit_1 + lmt->mcs_40m_2p5[i] = min_t(s8, val_2p5_n[i], val_2p5_p[i]); + } + ++static + void rtw89_phy_fill_txpwr_limit(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + struct rtw89_txpwr_limit *lmt, +@@ -1813,7 +1857,6 @@ void rtw89_phy_fill_txpwr_limit(struct r + break; + } + } +-EXPORT_SYMBOL(rtw89_phy_fill_txpwr_limit); + + static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, + u8 ru, u8 ntx, u8 ch) +@@ -1962,6 +2005,7 @@ rtw89_phy_fill_txpwr_limit_ru_160m(struc + } + } + ++static + void rtw89_phy_fill_txpwr_limit_ru(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + struct rtw89_txpwr_limit_ru *lmt_ru, +@@ -1992,7 +2036,161 @@ void rtw89_phy_fill_txpwr_limit_ru(struc + break; + } + } +-EXPORT_SYMBOL(rtw89_phy_fill_txpwr_limit_ru); ++ ++void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ static const u8 rs[] = { ++ RTW89_RS_CCK, ++ RTW89_RS_OFDM, ++ RTW89_RS_MCS, ++ RTW89_RS_HEDCM, ++ }; ++ struct rtw89_rate_desc cur; ++ u8 band = chan->band_type; ++ u8 ch = chan->channel; ++ u32 addr, val; ++ s8 v[4] = {}; ++ u8 i; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, ++ "[TXPWR] set txpwr byrate with ch=%d\n", ch); ++ ++ BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_CCK] % 4); ++ BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_OFDM] % 4); ++ BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_MCS] % 4); ++ BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_HEDCM] % 4); ++ ++ addr = R_AX_PWR_BY_RATE; ++ for (cur.nss = 0; cur.nss <= RTW89_NSS_2; cur.nss++) { ++ for (i = 0; i < ARRAY_SIZE(rs); i++) { ++ if (cur.nss >= rtw89_rs_nss_max[rs[i]]) ++ continue; ++ ++ cur.rs = rs[i]; ++ for (cur.idx = 0; cur.idx < rtw89_rs_idx_max[rs[i]]; ++ cur.idx++) { ++ v[cur.idx % 4] = ++ rtw89_phy_read_txpwr_byrate(rtwdev, ++ band, ++ &cur); ++ ++ if ((cur.idx + 1) % 4) ++ continue; ++ ++ val = FIELD_PREP(GENMASK(7, 0), v[0]) | ++ FIELD_PREP(GENMASK(15, 8), v[1]) | ++ FIELD_PREP(GENMASK(23, 16), v[2]) | ++ FIELD_PREP(GENMASK(31, 24), v[3]); ++ ++ rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, ++ val); ++ addr += 4; ++ } ++ } ++ } ++} ++EXPORT_SYMBOL(rtw89_phy_set_txpwr_byrate); ++ ++void rtw89_phy_set_txpwr_offset(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ struct rtw89_rate_desc desc = { ++ .nss = RTW89_NSS_1, ++ .rs = RTW89_RS_OFFSET, ++ }; ++ u8 band = chan->band_type; ++ s8 v[RTW89_RATE_OFFSET_MAX] = {}; ++ u32 val; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr offset\n"); ++ ++ for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_MAX; desc.idx++) ++ v[desc.idx] = rtw89_phy_read_txpwr_byrate(rtwdev, band, &desc); ++ ++ BUILD_BUG_ON(RTW89_RATE_OFFSET_MAX != 5); ++ val = FIELD_PREP(GENMASK(3, 0), v[0]) | ++ FIELD_PREP(GENMASK(7, 4), v[1]) | ++ FIELD_PREP(GENMASK(11, 8), v[2]) | ++ FIELD_PREP(GENMASK(15, 12), v[3]) | ++ FIELD_PREP(GENMASK(19, 16), v[4]); ++ ++ rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_OFST_CTRL, ++ GENMASK(19, 0), val); ++} ++EXPORT_SYMBOL(rtw89_phy_set_txpwr_offset); ++ ++void rtw89_phy_set_txpwr_limit(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ struct rtw89_txpwr_limit lmt; ++ u8 ch = chan->channel; ++ u8 bw = chan->band_width; ++ const s8 *ptr; ++ u32 addr, val; ++ u8 i, j; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, ++ "[TXPWR] set txpwr limit with ch=%d bw=%d\n", ch, bw); ++ ++ BUILD_BUG_ON(sizeof(struct rtw89_txpwr_limit) != ++ RTW89_TXPWR_LMT_PAGE_SIZE); ++ ++ addr = R_AX_PWR_LMT; ++ for (i = 0; i < RTW89_NTX_NUM; i++) { ++ rtw89_phy_fill_txpwr_limit(rtwdev, chan, &lmt, i); ++ ++ ptr = (s8 *)&lmt; ++ for (j = 0; j < RTW89_TXPWR_LMT_PAGE_SIZE; ++ j += 4, addr += 4, ptr += 4) { ++ val = FIELD_PREP(GENMASK(7, 0), ptr[0]) | ++ FIELD_PREP(GENMASK(15, 8), ptr[1]) | ++ FIELD_PREP(GENMASK(23, 16), ptr[2]) | ++ FIELD_PREP(GENMASK(31, 24), ptr[3]); ++ ++ rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val); ++ } ++ } ++} ++EXPORT_SYMBOL(rtw89_phy_set_txpwr_limit); ++ ++void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ struct rtw89_txpwr_limit_ru lmt_ru; ++ u8 ch = chan->channel; ++ u8 bw = chan->band_width; ++ const s8 *ptr; ++ u32 addr, val; ++ u8 i, j; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, ++ "[TXPWR] set txpwr limit ru with ch=%d bw=%d\n", ch, bw); ++ ++ BUILD_BUG_ON(sizeof(struct rtw89_txpwr_limit_ru) != ++ RTW89_TXPWR_LMT_RU_PAGE_SIZE); ++ ++ addr = R_AX_PWR_RU_LMT; ++ for (i = 0; i < RTW89_NTX_NUM; i++) { ++ rtw89_phy_fill_txpwr_limit_ru(rtwdev, chan, &lmt_ru, i); ++ ++ ptr = (s8 *)&lmt_ru; ++ for (j = 0; j < RTW89_TXPWR_LMT_RU_PAGE_SIZE; ++ j += 4, addr += 4, ptr += 4) { ++ val = FIELD_PREP(GENMASK(7, 0), ptr[0]) | ++ FIELD_PREP(GENMASK(15, 8), ptr[1]) | ++ FIELD_PREP(GENMASK(23, 16), ptr[2]) | ++ FIELD_PREP(GENMASK(31, 24), ptr[3]); ++ ++ rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val); ++ } ++ } ++} ++EXPORT_SYMBOL(rtw89_phy_set_txpwr_limit_ru); + + struct rtw89_phy_iter_ra_data { + struct rtw89_dev *rtwdev; +@@ -2106,6 +2304,10 @@ void rtw89_phy_c2h_handle(struct rtw89_d + if (func < RTW89_PHY_C2H_FUNC_RA_MAX) + handler = rtw89_phy_c2h_ra_handler[func]; + break; ++ case RTW89_PHY_C2H_CLASS_DM: ++ if (func == RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY) ++ return; ++ fallthrough; + default: + rtw89_info(rtwdev, "c2h class %d not support\n", class); + return; +@@ -2593,6 +2795,129 @@ void rtw89_phy_cfo_parse(struct rtw89_de + cfo->packet_count++; + } + ++void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) ++{ ++ const struct rtw89_chip_info *chip = rtwdev->chip; ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info; ++ ++ if (!chip->support_ul_tb_ctrl) ++ return; ++ ++ rtwvif->def_tri_idx = ++ rtw89_phy_read32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG); ++ ++ if (chip->chip_id == RTL8852B && rtwdev->hal.cv > CHIP_CBV) ++ rtwvif->dyn_tb_bedge_en = false; ++ else if (chan->band_type >= RTW89_BAND_5G && ++ chan->band_width >= RTW89_CHANNEL_WIDTH_40) ++ rtwvif->dyn_tb_bedge_en = true; ++ else ++ rtwvif->dyn_tb_bedge_en = false; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_UL_TB, ++ "[ULTB] def_if_bandedge=%d, def_tri_idx=%d\n", ++ ul_tb_info->def_if_bandedge, rtwvif->def_tri_idx); ++ rtw89_debug(rtwdev, RTW89_DBG_UL_TB, ++ "[ULTB] dyn_tb_begde_en=%d, dyn_tb_tri_en=%d\n", ++ rtwvif->dyn_tb_bedge_en, ul_tb_info->dyn_tb_tri_en); ++} ++ ++struct rtw89_phy_ul_tb_check_data { ++ bool valid; ++ bool high_tf_client; ++ bool low_tf_client; ++ bool dyn_tb_bedge_en; ++ u8 def_tri_idx; ++}; ++ ++static ++void rtw89_phy_ul_tb_ctrl_check(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, ++ struct rtw89_phy_ul_tb_check_data *ul_tb_data) ++{ ++ struct rtw89_traffic_stats *stats = &rtwdev->stats; ++ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); ++ ++ if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION) ++ return; ++ ++ if (!vif->cfg.assoc) ++ return; ++ ++ if (stats->rx_tf_periodic > UL_TB_TF_CNT_L2H_TH) ++ ul_tb_data->high_tf_client = true; ++ else if (stats->rx_tf_periodic < UL_TB_TF_CNT_H2L_TH) ++ ul_tb_data->low_tf_client = true; ++ ++ ul_tb_data->valid = true; ++ ul_tb_data->def_tri_idx = rtwvif->def_tri_idx; ++ ul_tb_data->dyn_tb_bedge_en = rtwvif->dyn_tb_bedge_en; ++} ++ ++void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev) ++{ ++ const struct rtw89_chip_info *chip = rtwdev->chip; ++ struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info; ++ struct rtw89_phy_ul_tb_check_data ul_tb_data = {}; ++ struct rtw89_vif *rtwvif; ++ ++ if (!chip->support_ul_tb_ctrl) ++ return; ++ ++ if (rtwdev->total_sta_assoc != 1) ++ return; ++ ++ rtw89_for_each_rtwvif(rtwdev, rtwvif) ++ rtw89_phy_ul_tb_ctrl_check(rtwdev, rtwvif, &ul_tb_data); ++ ++ if (!ul_tb_data.valid) ++ return; ++ ++ if (ul_tb_data.dyn_tb_bedge_en) { ++ if (ul_tb_data.high_tf_client) { ++ rtw89_phy_write32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN, 0); ++ rtw89_debug(rtwdev, RTW89_DBG_UL_TB, ++ "[ULTB] Turn off if_bandedge\n"); ++ } else if (ul_tb_data.low_tf_client) { ++ rtw89_phy_write32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN, ++ ul_tb_info->def_if_bandedge); ++ rtw89_debug(rtwdev, RTW89_DBG_UL_TB, ++ "[ULTB] Set to default if_bandedge = %d\n", ++ ul_tb_info->def_if_bandedge); ++ } ++ } ++ ++ if (ul_tb_info->dyn_tb_tri_en) { ++ if (ul_tb_data.high_tf_client) { ++ rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT, ++ B_TXSHAPE_TRIANGULAR_CFG, 0); ++ rtw89_debug(rtwdev, RTW89_DBG_UL_TB, ++ "[ULTB] Turn off Tx triangle\n"); ++ } else if (ul_tb_data.low_tf_client) { ++ rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT, ++ B_TXSHAPE_TRIANGULAR_CFG, ++ ul_tb_data.def_tri_idx); ++ rtw89_debug(rtwdev, RTW89_DBG_UL_TB, ++ "[ULTB] Set to default tx_shap_idx = %d\n", ++ ul_tb_data.def_tri_idx); ++ } ++ } ++} ++ ++static void rtw89_phy_ul_tb_info_init(struct rtw89_dev *rtwdev) ++{ ++ const struct rtw89_chip_info *chip = rtwdev->chip; ++ struct rtw89_phy_ul_tb_info *ul_tb_info = &rtwdev->ul_tb_info; ++ ++ if (!chip->support_ul_tb_ctrl) ++ return; ++ ++ ul_tb_info->dyn_tb_tri_en = true; ++ ul_tb_info->def_if_bandedge = ++ rtw89_phy_read32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN); ++} ++ + static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev) + { + struct rtw89_phy_stat *phystat = &rtwdev->phystat; +@@ -3779,6 +4104,7 @@ void rtw89_phy_dm_init(struct rtw89_dev + rtw89_physts_parsing_init(rtwdev); + rtw89_phy_dig_init(rtwdev); + rtw89_phy_cfo_init(rtwdev); ++ rtw89_phy_ul_tb_info_init(rtwdev); + + rtw89_phy_init_rf_nctl(rtwdev); + rtw89_chip_rfk_init(rtwdev); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/phy.h linux-6.2/drivers/net/wireless/realtek/rtw89/phy.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/phy.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/phy.h 2022-12-24 00:49:25.781376835 +0200 +@@ -64,6 +64,9 @@ + #define MAX_CFO_TOLERANCE 30 + #define CFO_TF_CNT_TH 300 + ++#define UL_TB_TF_CNT_L2H_TH 100 ++#define UL_TB_TF_CNT_H2L_TH 70 ++ + #define CCX_MAX_PERIOD 2097 + #define CCX_MAX_PERIOD_UNIT 32 + #define MS_TO_4US_RATIO 250 +@@ -114,6 +117,15 @@ enum rtw89_phy_c2h_ra_func { + RTW89_PHY_C2H_FUNC_RA_MAX, + }; + ++enum rtw89_phy_c2h_dm_func { ++ RTW89_PHY_C2H_DM_FUNC_FW_TEST, ++ RTW89_PHY_C2H_DM_FUNC_FW_TRIG_TX_RPT, ++ RTW89_PHY_C2H_DM_FUNC_SIGB, ++ RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY, ++ RTW89_PHY_C2H_DM_FUNC_MCC_DIG, ++ RTW89_PHY_C2H_DM_FUNC_NUM, ++}; ++ + enum rtw89_phy_c2h_class { + RTW89_PHY_C2H_CLASS_RUA, + RTW89_PHY_C2H_CLASS_RA, +@@ -317,9 +329,6 @@ struct rtw89_nbi_reg_def { + struct rtw89_reg_def notch2_en; + }; + +-extern const u8 rtw89_rs_idx_max[RTW89_RS_MAX]; +-extern const u8 rtw89_rs_nss_max[RTW89_RS_MAX]; +- + static inline void rtw89_phy_write8(struct rtw89_dev *rtwdev, + u32 addr, u8 data) + { +@@ -377,6 +386,50 @@ static inline u32 rtw89_phy_read32_mask( + return rtw89_read32_mask(rtwdev, addr | RTW89_PHY_ADDR_OFFSET, mask); + } + ++static inline ++enum rtw89_gain_offset rtw89_subband_to_gain_offset_band_of_ofdm(enum rtw89_subband subband) ++{ ++ switch (subband) { ++ default: ++ case RTW89_CH_2G: ++ return RTW89_GAIN_OFFSET_2G_OFDM; ++ case RTW89_CH_5G_BAND_1: ++ return RTW89_GAIN_OFFSET_5G_LOW; ++ case RTW89_CH_5G_BAND_3: ++ return RTW89_GAIN_OFFSET_5G_MID; ++ case RTW89_CH_5G_BAND_4: ++ return RTW89_GAIN_OFFSET_5G_HIGH; ++ } ++} ++ ++static inline ++enum rtw89_phy_bb_gain_band rtw89_subband_to_bb_gain_band(enum rtw89_subband subband) ++{ ++ switch (subband) { ++ default: ++ case RTW89_CH_2G: ++ return RTW89_BB_GAIN_BAND_2G; ++ case RTW89_CH_5G_BAND_1: ++ return RTW89_BB_GAIN_BAND_5G_L; ++ case RTW89_CH_5G_BAND_3: ++ return RTW89_BB_GAIN_BAND_5G_M; ++ case RTW89_CH_5G_BAND_4: ++ return RTW89_BB_GAIN_BAND_5G_H; ++ case RTW89_CH_6G_BAND_IDX0: ++ case RTW89_CH_6G_BAND_IDX1: ++ return RTW89_BB_GAIN_BAND_6G_L; ++ case RTW89_CH_6G_BAND_IDX2: ++ case RTW89_CH_6G_BAND_IDX3: ++ return RTW89_BB_GAIN_BAND_6G_M; ++ case RTW89_CH_6G_BAND_IDX4: ++ case RTW89_CH_6G_BAND_IDX5: ++ return RTW89_BB_GAIN_BAND_6G_H; ++ case RTW89_CH_6G_BAND_IDX6: ++ case RTW89_CH_6G_BAND_IDX7: ++ return RTW89_BB_GAIN_BAND_6G_UH; ++ } ++} ++ + enum rtw89_rfk_flag { + RTW89_RFK_F_WRF = 0, + RTW89_RFK_F_WM = 1, +@@ -450,7 +503,7 @@ bool rtw89_phy_write_rf(struct rtw89_dev + bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, + u32 addr, u32 mask, u32 data); + void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev); +-void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev); ++void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio); + void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, +@@ -458,20 +511,24 @@ void rtw89_phy_config_rf_reg_v1(struct r + void rtw89_phy_dm_init(struct rtw89_dev *rtwdev); + void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, + u32 data, enum rtw89_phy_idx phy_idx); ++u32 rtw89_phy_read32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, ++ enum rtw89_phy_idx phy_idx); + void rtw89_phy_load_txpwr_byrate(struct rtw89_dev *rtwdev, + const struct rtw89_txpwr_table *tbl); +-s8 rtw89_phy_read_txpwr_byrate(struct rtw89_dev *rtwdev, u8 band, +- const struct rtw89_rate_desc *rate_desc); +-void rtw89_phy_fill_txpwr_limit(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- struct rtw89_txpwr_limit *lmt, +- u8 ntx); +-void rtw89_phy_fill_txpwr_limit_ru(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- struct rtw89_txpwr_limit_ru *lmt_ru, +- u8 ntx); + s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, + u8 bw, u8 ntx, u8 rs, u8 bf, u8 ch); ++void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx); ++void rtw89_phy_set_txpwr_offset(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx); ++void rtw89_phy_set_txpwr_limit(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx); ++void rtw89_phy_set_txpwr_limit_ru(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx); + void rtw89_phy_ra_assoc(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta); + void rtw89_phy_ra_update(struct rtw89_dev *rtwdev); + void rtw89_phy_ra_updata_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, +@@ -496,5 +553,7 @@ void rtw89_phy_set_bss_color(struct rtw8 + void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx, + enum rtw89_tssi_bandedge_cfg bandedge_cfg); ++void rtw89_phy_ul_tb_assoc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); ++void rtw89_phy_ul_tb_ctrl_track(struct rtw89_dev *rtwdev); + + #endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/ps.c linux-6.2/drivers/net/wireless/realtek/rtw89/ps.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/ps.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/ps.c 2022-12-24 00:49:25.781376835 +0200 +@@ -59,7 +59,7 @@ static void rtw89_ps_power_mode_change(s + rtw89_mac_power_mode_change(rtwdev, enter); + } + +-static void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) ++void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) + { + if (rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) + return; +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/ps.h linux-6.2/drivers/net/wireless/realtek/rtw89/ps.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/ps.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/ps.h 2022-12-24 00:49:25.781376835 +0200 +@@ -8,6 +8,7 @@ + void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); + void rtw89_leave_lps(struct rtw89_dev *rtwdev); + void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); ++void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); + void rtw89_leave_ps_mode(struct rtw89_dev *rtwdev); + void rtw89_enter_ips(struct rtw89_dev *rtwdev); + void rtw89_leave_ips(struct rtw89_dev *rtwdev); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/reg.h linux-6.2/drivers/net/wireless/realtek/rtw89/reg.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/reg.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/reg.h 2022-12-24 00:49:25.781376835 +0200 +@@ -34,6 +34,9 @@ + #define R_AX_SYS_CLK_CTRL 0x0008 + #define B_AX_CPU_CLK_EN BIT(14) + ++#define R_AX_SYS_SWR_CTRL1 0x0010 ++#define B_AX_SYM_CTRL_SPS_PWMFREQ BIT(10) ++ + #define R_AX_SYS_ADIE_PAD_PWR_CTRL 0x0018 + #define B_AX_SYM_PADPDN_WL_PTA_1P3 BIT(6) + #define B_AX_SYM_PADPDN_WL_RFC_1P3 BIT(5) +@@ -42,6 +45,9 @@ + #define B_AX_R_DIS_PRST BIT(6) + #define B_AX_WLOCK_1C_BIT6 BIT(5) + ++#define R_AX_AFE_LDO_CTRL 0x0020 ++#define B_AX_AON_OFF_PC_EN BIT(23) ++ + #define R_AX_EFUSE_CTRL_1 0x0038 + #define B_AX_EF_PGPD_MASK GENMASK(30, 28) + #define B_AX_EF_RDT BIT(27) +@@ -118,6 +124,9 @@ + #define B_AX_R_AX_BG_LPF BIT(2) + #define B_AX_R_AX_BG GENMASK(1, 0) + ++#define R_AX_HCI_LDO_CTRL 0x007A ++#define B_AX_R_AX_VADJ_MASK GENMASK(3, 0) ++ + #define R_AX_PLATFORM_ENABLE 0x0088 + #define B_AX_AXIDMA_EN BIT(3) + #define B_AX_WCPU_EN BIT(1) +@@ -125,6 +134,7 @@ + + #define R_AX_WLLPS_CTRL 0x0090 + #define B_AX_DIS_WLBT_LPSEN_LOPC BIT(1) ++#define SW_LPS_OPTION 0x0001A0B2 + + #define R_AX_SCOREBOARD 0x00AC + #define B_AX_TOGGLE BIT(31) +@@ -229,6 +239,13 @@ + + #define R_AX_GPIO0_7_FUNC_SEL 0x02D0 + ++#define R_AX_EECS_EESK_FUNC_SEL 0x02D8 ++#define B_AX_PINMUX_EESK_FUNC_SEL_MASK GENMASK(7, 4) ++ ++#define R_AX_LED1_FUNC_SEL 0x02DC ++#define B_AX_PINMUX_EESK_FUNC_SEL_V1_MASK GENMASK(27, 24) ++#define PINMUX_EESK_FUNC_SEL_BT_LOG 0x1 ++ + #define R_AX_GPIO0_15_EECS_EESK_LED1_PULL_LOW_EN 0x02E4 + #define B_AX_LED1_PULL_LOW_EN BIT(18) + #define B_AX_EESK_PULL_LOW_EN BIT(17) +@@ -249,6 +266,10 @@ + #define B_AX_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2) + #define B_AX_PCIE_HCISYS_PWR_STE_MASK GENMASK(1, 0) + ++#define R_AX_SPS_DIG_OFF_CTRL0 0x0400 ++#define B_AX_C3_L1_MASK GENMASK(5, 4) ++#define B_AX_C1_L1_MASK GENMASK(1, 0) ++ + #define R_AX_AFE_OFF_CTRL1 0x0444 + #define B_AX_S1_LDO_VSEL_F_MASK GENMASK(25, 24) + #define B_AX_S1_LDO2PWRCUT_F BIT(23) +@@ -305,8 +326,7 @@ + + #define R_AX_PCIE_DBG_CTRL 0x11C0 + #define B_AX_DBG_DUMMY_MASK GENMASK(23, 16) +-#define B_AX_DBG_SEL_MASK GENMASK(15, 13) +-#define B_AX_PCIE_DBG_SEL BIT(12) ++#define B_AX_PCIE_DBG_SEL_MASK GENMASK(15, 13) + #define B_AX_MRD_TIMEOUT_EN BIT(10) + #define B_AX_ASFF_FULL_NO_STK BIT(1) + #define B_AX_EN_STUCK_DBG BIT(0) +@@ -445,6 +465,7 @@ + #define B_AX_DISPATCHER_EN BIT(18) + #define B_AX_BBRPT_EN BIT(17) + #define B_AX_MAC_SEC_EN BIT(16) ++#define B_AX_DMACREG_GCKEN BIT(15) + #define B_AX_MAC_UN_EN BIT(15) + #define B_AX_H_AXIDMA_EN BIT(14) + +@@ -523,6 +544,19 @@ + #define B_AX_WDE_EMPTY_QUE_CMAC0_MBH BIT(1) + #define B_AX_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0) + ++#define R_AX_DLE_EMPTY1 0x8434 ++#define B_AX_PLE_EMPTY_QTA_DMAC_WDRLS BIT(20) ++#define B_AX_PLE_EMPTY_QTA_CMAC1_DMA_BBRPT BIT(19) ++#define B_AX_PLE_EMPTY_QTA_CMAC1_DMA_RX BIT(18) ++#define B_AX_PLE_EMPTY_QTA_CMAC0_DMA_RX BIT(17) ++#define B_AX_PLE_EMPTY_QTA_DMAC_C2H BIT(16) ++#define B_AX_PLE_EMPTY_QUE_DMAC_PLRLS BIT(5) ++#define B_AX_PLE_EMPTY_QUE_DMAC_CPUIO BIT(4) ++#define B_AX_PLE_EMPTY_QUE_DMAC_SEC_RX BIT(3) ++#define B_AX_PLE_EMPTY_QUE_DMAC_MPDU_RX BIT(2) ++#define B_AX_PLE_EMPTY_QUE_DMAC_HDP BIT(1) ++#define B_AX_WDE_EMPTY_QUE_DMAC_WDRLS BIT(0) ++ + #define R_AX_DMAC_ERR_IMR 0x8520 + #define B_AX_DLE_CPUIO_ERR_INT_EN BIT(10) + #define B_AX_APB_BRIDGE_ERR_INT_EN BIT(9) +@@ -539,6 +573,10 @@ + #define DMAC_ERR_IMR_DIS 0 + + #define R_AX_DMAC_ERR_ISR 0x8524 ++#define B_AX_HAXIDMA_ERR_FLAG BIT(14) ++#define B_AX_PAXIDMA_ERR_FLAG BIT(13) ++#define B_AX_HCI_BUF_ERR_FLAG BIT(12) ++#define B_AX_BBRPT_ERR_FLAG BIT(11) + #define B_AX_DLE_CPUIO_ERR_FLAG BIT(10) + #define B_AX_APB_BRIDGE_ERR_FLAG BIT(9) + #define B_AX_DISPATCH_ERR_FLAG BIT(8) +@@ -917,6 +955,14 @@ + B_AX_STF_OQT_OVERFLOW_ERR_INT_EN | \ + B_AX_STF_OQT_UNDERFLOW_ERR_INT_EN) + ++#define R_AX_DISPATCHER_DBG_PORT 0x8860 ++#define B_AX_DISPATCHER_DBG_SEL_MASK GENMASK(11, 8) ++#define B_AX_DISPATCHER_INTN_SEL_MASK GENMASK(7, 4) ++#define B_AX_DISPATCHER_CH_SEL_MASK GENMASK(3, 0) ++ ++#define R_AX_RX_FUNCTION_STOP 0x8920 ++#define B_AX_HDR_RX_STOP BIT(0) ++ + #define R_AX_HCI_FC_CTRL 0x8A00 + #define B_AX_HCI_FC_CH12_FULL_COND_MASK GENMASK(11, 10) + #define B_AX_HCI_FC_WP_CH811_FULL_COND_MASK GENMASK(9, 8) +@@ -998,7 +1044,13 @@ + #define R_AX_WDE_ERRFLAG_MSG 0x8C30 + #define B_AX_WDE_ERR_FLAG_MSG_MASK GENMASK(31, 0) + +-#define R_AX_WDE_ERR_FLAG_CFG 0x8C34 ++#define R_AX_WDE_ERR_FLAG_CFG_NUM1 0x8C34 ++#define B_AX_WDE_ERR_FLAG_NUM1_VLD BIT(31) ++#define B_AX_WDE_ERR_FLAG_NUM1_MSTIDX_MASK GENMASK(27, 24) ++#define B_AX_WDE_ERR_FLAG_NUM1_ISRIDX_MASK GENMASK(20, 16) ++#define B_AX_WDE_DATCHN_FRZTMR_MODE BIT(2) ++#define B_AX_WDE_QUEMGN_FRZTMR_MODE BIT(1) ++#define B_AX_WDE_BUFMGN_FRZTMR_MODE BIT(0) + + #define R_AX_WDE_ERR_IMR 0x8C38 + #define B_AX_WDE_DATCHN_RRDY_ERR_INT_EN BIT(27) +@@ -1182,7 +1234,59 @@ + #define B_AX_PLE_START_BOUND_MASK GENMASK(13, 8) + #define B_AX_PLE_PAGE_SEL_MASK GENMASK(1, 0) + #define B_AX_PLE_FREE_PAGE_NUM_MASK GENMASK(28, 16) +-#define R_AX_PLE_ERR_FLAG_CFG 0x9034 ++ ++#define R_AX_PLE_DBGERR_LOCKEN 0x9020 ++#define B_AX_PLE_LOCKEN_DLEPIF07 BIT(7) ++#define B_AX_PLE_LOCKEN_DLEPIF06 BIT(6) ++#define B_AX_PLE_LOCKEN_DLEPIF05 BIT(5) ++#define B_AX_PLE_LOCKEN_DLEPIF04 BIT(4) ++#define B_AX_PLE_LOCKEN_DLEPIF03 BIT(3) ++#define B_AX_PLE_LOCKEN_DLEPIF02 BIT(2) ++#define B_AX_PLE_LOCKEN_DLEPIF01 BIT(1) ++#define B_AX_PLE_LOCKEN_DLEPIF00 BIT(0) ++ ++#define R_AX_PLE_DBGERR_STS 0x9024 ++#define B_AX_PLE_LOCKON_DLEPIF07 BIT(7) ++#define B_AX_PLE_LOCKON_DLEPIF06 BIT(6) ++#define B_AX_PLE_LOCKON_DLEPIF05 BIT(5) ++#define B_AX_PLE_LOCKON_DLEPIF04 BIT(4) ++#define B_AX_PLE_LOCKON_DLEPIF03 BIT(3) ++#define B_AX_PLE_LOCKON_DLEPIF02 BIT(2) ++#define B_AX_PLE_LOCKON_DLEPIF01 BIT(1) ++#define B_AX_PLE_LOCKON_DLEPIF00 BIT(0) ++ ++#define R_AX_PLE_ERR_FLAG_CFG_NUM1 0x9034 ++#define B_AX_PLE_ERR_FLAG_NUM1_VLD BIT(31) ++#define B_AX_PLE_ERR_FLAG_NUM1_MSTIDX_MASK GENMASK(27, 24) ++#define B_AX_PLE_ERR_FLAG_NUM1_ISRIDX_MASK GENMASK(20, 16) ++#define B_AX_PLE_DATCHN_FRZTMR_MODE BIT(2) ++#define B_AX_PLE_QUEMGN_FRZTMR_MODE BIT(1) ++#define B_AX_PLE_BUFMGN_FRZTMR_MODE BIT(0) ++ ++#define R_AX_PLE_ERRFLAG_MSG 0x9030 ++#define B_AX_PLE_ERR_FLAG_MSG_MASK GENMASK(31, 0) ++#define B_AX_PLE_DATCHN_CAMREQ_ERR_INT_EN BIT(29) ++#define B_AX_PLE_DATCHN_ADRERR_ERR_INT_EN BIT(28) ++#define B_AX_PLE_BUFMGN_FRZTO_ERR_INT_EN_V1 BIT(9) ++#define B_AX_PLE_GETNPG_PGOFST_ERR_INT_EN_V1 BIT(8) ++#define B_AX_PLE_GETNPG_STRPG_ERR_INT_EN_V1 BIT(7) ++#define B_AX_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN_V1 BIT(6) ++#define B_AX_PLE_BUFRTN_SIZE_ERR_INT_EN_V1 BIT(5) ++#define B_AX_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN_V1 BIT(4) ++#define B_AX_PLE_BUFREQ_UNAVAL_ERR_INT_EN_V1 BIT(3) ++#define B_AX_PLE_BUFREQ_SIZELMT_INT_EN BIT(2) ++#define B_AX_PLE_BUFREQ_SIZE0_INT_EN BIT(1) ++#define B_AX_PLE_DATCHN_CAMREQ_ERR BIT(29) ++#define B_AX_PLE_DATCHN_ADRERR_ERR BIT(28) ++#define B_AX_PLE_BUFMGN_FRZTO_ERR_V1 BIT(9) ++#define B_AX_PLE_GETNPG_PGOFST_ERR_V1 BIT(8) ++#define B_AX_PLE_GETNPG_STRPG_ERR_V1 BIT(7) ++#define B_AX_PLE_BUFREQ_SRCHTAILPG_ERR_V1 BIT(6) ++#define B_AX_PLE_BUFRTN_SIZE_ERR_V1 BIT(5) ++#define B_AX_PLE_BUFRTN_INVLD_PKTID_ERR_V1 BIT(4) ++#define B_AX_PLE_BUFREQ_UNAVAL_ERR_V1 BIT(3) ++#define B_AX_PLE_BUFREQ_SIZELMT_ERR BIT(2) ++#define B_AX_PLE_BUFREQ_SIZE0_ERR BIT(1) + + #define R_AX_PLE_ERR_IMR 0x9038 + #define B_AX_PLE_DATCHN_RRDY_ERR_INT_EN BIT(27) +@@ -1393,6 +1497,19 @@ + #define B_AX_BBRPT_COM_NULL_PLPKTID_ERR BIT(16) + #define B_AX_BBRPT_COM_NULL_PLPKTID_ERR_INT_EN BIT(0) + ++#define R_AX_BBRPT_COM_ERR_ISR 0x960C ++#define B_AX_BBRPT_COM_NULL_PLPKTID_ERR_INT_V1 BIT(0) ++ ++#define R_AX_BBRPT_CHINFO_ERR_ISR 0x962C ++#define B_AX_BBPRT_CHIF_TO_ERR_V1 BIT(7) ++#define B_AX_BBPRT_CHIF_NULL_ERR_V1 BIT(6) ++#define B_AX_BBPRT_CHIF_LEFT2_ERR_V1 BIT(5) ++#define B_AX_BBPRT_CHIF_LEFT1_ERR_V1 BIT(4) ++#define B_AX_BBPRT_CHIF_HDRL_ERR_V1 BIT(3) ++#define B_AX_BBPRT_CHIF_BOVF_ERR_V1 BIT(2) ++#define B_AX_BBPRT_CHIF_OVF_ERR_V1 BIT(1) ++#define B_AX_BBPRT_CHIF_BB_TO_ERR_V1 BIT(0) ++ + #define R_AX_BBRPT_CHINFO_ERR_IMR 0x9628 + #define B_AX_BBPRT_CHIF_TO_ERR_INT_EN BIT(7) + #define B_AX_BBPRT_CHIF_NULL_ERR_INT_EN BIT(6) +@@ -1444,6 +1561,9 @@ + #define B_AX_BBRPT_DFS_TO_ERR BIT(16) + #define B_AX_BBRPT_DFS_TO_ERR_INT_EN BIT(0) + ++#define R_AX_BBRPT_DFS_ERR_ISR 0x963C ++#define B_AX_BBRPT_DFS_TO_ERR_V1 BIT(0) ++ + #define R_AX_LA_ERRFLAG 0x966C + #define B_AX_LA_ISR_DATA_LOSS_ERR BIT(16) + #define B_AX_LA_IMR_DATA_LOSS_ERR BIT(0) +@@ -1535,6 +1655,8 @@ + #define R_AX_ACTION_FWD0 0x9C04 + #define TRXCFG_MPDU_PROC_ACT_FRWD 0x02A95A95 + ++#define R_AX_ACTION_FWD1 0x9C08 ++ + #define R_AX_TF_FWD 0x9C14 + #define TRXCFG_MPDU_PROC_TF_FRWD 0x0000AA55 + +@@ -1546,6 +1668,9 @@ + #define R_AX_CUT_AMSDU_CTRL 0x9C40 + #define TRXCFG_MPDU_PROC_CUT_CTRL 0x010E05F0 + ++#define R_AX_WOW_CTRL 0x9C50 ++#define B_AX_WOW_WOWEN BIT(1) ++ + #define R_AX_MPDU_RX_ERR_ISR 0x9CF0 + #define R_AX_MPDU_RX_ERR_IMR 0x9CF4 + #define B_AX_RPT_ERR_INT_EN BIT(3) +@@ -1554,6 +1679,7 @@ + #define B_AX_MPDU_RX_IMR_SET_V1 B_AX_RPT_ERR_INT_EN + + #define R_AX_SEC_ENG_CTRL 0x9D00 ++#define B_AX_SEC_DBG_PORT_FIELD_MASK GENMASK(19, 16) + #define B_AX_TX_PARTIAL_MODE BIT(11) + #define B_AX_CLK_EN_CGCMP BIT(10) + #define B_AX_CLK_EN_WAPI BIT(9) +@@ -1583,12 +1709,21 @@ + #define R_AX_SEC_TX_DEBUG 0x9D20 + #define R_AX_SEC_RX_DEBUG 0x9D24 + #define R_AX_SEC_TRX_PKT_CNT 0x9D28 ++ ++#define R_AX_SEC_DEBUG2 0x9D28 ++#define B_AX_DBG_READ_SH 2 ++#define B_AX_DBG_READ_MSK 0x3fffffff ++ + #define R_AX_SEC_TRX_BLK_CNT 0x9D2C + + #define R_AX_SEC_ERROR_FLAG_IMR 0x9D2C + #define B_AX_RX_HANG_IMR BIT(1) + #define B_AX_TX_HANG_IMR BIT(0) + ++#define R_AX_SEC_ERROR_FLAG 0x9D30 ++#define B_AX_RX_HANG_ERROR_V1 BIT(1) ++#define B_AX_TX_HANG_ERROR_V1 BIT(0) ++ + #define R_AX_SS_CTRL 0x9E10 + #define B_AX_SS_INIT_DONE_1 BIT(31) + #define B_AX_SS_WARM_INIT_FLG BIT(29) +@@ -1723,6 +1858,28 @@ + B_AX_B0_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_AX_B0_IMR_ERR_PRELD_ENTNUMCFG) + ++#define R_AX_TXPKTCTL_B0_ERRFLAG_ISR 0x9F7C ++#define B_AX_B0_ISR_ERR_PRELD_EVT3 BIT(23) ++#define B_AX_B0_ISR_ERR_PRELD_EVT2 BIT(22) ++#define B_AX_B0_ISR_ERR_PRELD_ENTNUMCFG BIT(21) ++#define B_AX_B0_ISR_ERR_PRELD_RLSPKTSZERR BIT(20) ++#define B_AX_B0_ISR_ERR_MPDUIF_ERR1 BIT(19) ++#define B_AX_B0_ISR_ERR_MPDUIF_DATAERR BIT(18) ++#define B_AX_B0_ISR_ERR_MPDUINFO_ERR1 BIT(17) ++#define B_AX_B0_ISR_ERR_MPDUINFO_RECFG BIT(16) ++#define B_AX_B0_ISR_ERR_CMDPSR_TBLSZ BIT(11) ++#define B_AX_B0_ISR_ERR_CMDPSR_FRZTO BIT(10) ++#define B_AX_B0_ISR_ERR_CMDPSR_CMDTYPE BIT(9) ++#define B_AX_B0_ISR_ERR_CMDPSR_1STCMDERR BIT(8) ++#define B_AX_B0_ISR_ERR_USRCTL_EVT7 BIT(7) ++#define B_AX_B0_ISR_ERR_USRCTL_EVT6 BIT(6) ++#define B_AX_B0_ISR_ERR_USRCTL_EVT5 BIT(5) ++#define B_AX_B0_ISR_ERR_USRCTL_EVT4 BIT(4) ++#define B_AX_B0_ISR_ERR_USRCTL_RLSBMPLEN BIT(3) ++#define B_AX_B0_ISR_ERR_USRCTL_RDNRLSCMD BIT(2) ++#define B_AX_B0_ISR_ERR_USRCTL_NOINIT BIT(1) ++#define B_AX_B0_ISR_ERR_USRCTL_REINIT BIT(0) ++ + #define R_AX_TXPKTCTL_B1_PRELD_CFG0 0x9F88 + #define B_AX_B1_PRELD_FEN BIT(31) + #define B_AX_B1_PRELD_USEMAXSZ_MASK GENMASK(25, 16) +@@ -1770,6 +1927,28 @@ + B_AX_B1_IMR_ERR_PRELD_RLSPKTSZERR | \ + B_AX_B1_IMR_ERR_PRELD_ENTNUMCFG) + ++#define R_AX_TXPKTCTL_B1_ERRFLAG_ISR 0x9FBC ++#define B_AX_B1_ISR_ERR_PRELD_EVT3 BIT(23) ++#define B_AX_B1_ISR_ERR_PRELD_EVT2 BIT(22) ++#define B_AX_B1_ISR_ERR_PRELD_ENTNUMCFG BIT(21) ++#define B_AX_B1_ISR_ERR_PRELD_RLSPKTSZERR BIT(20) ++#define B_AX_B1_ISR_ERR_MPDUIF_ERR1 BIT(19) ++#define B_AX_B1_ISR_ERR_MPDUIF_DATAERR BIT(18) ++#define B_AX_B1_ISR_ERR_MPDUINFO_ERR1 BIT(17) ++#define B_AX_B1_ISR_ERR_MPDUINFO_RECFG BIT(16) ++#define B_AX_B1_ISR_ERR_CMDPSR_TBLSZ BIT(11) ++#define B_AX_B1_ISR_ERR_CMDPSR_FRZTO BIT(10) ++#define B_AX_B1_ISR_ERR_CMDPSR_CMDTYPE BIT(9) ++#define B_AX_B1_ISR_ERR_CMDPSR_1STCMDERR BIT(8) ++#define B_AX_B1_ISR_ERR_USRCTL_EVT7 BIT(7) ++#define B_AX_B1_ISR_ERR_USRCTL_EVT6 BIT(6) ++#define B_AX_B1_ISR_ERR_USRCTL_EVT5 BIT(5) ++#define B_AX_B1_ISR_ERR_USRCTL_EVT4 BIT(4) ++#define B_AX_B1_ISR_ERR_USRCTL_RLSBMPLEN BIT(3) ++#define B_AX_B1_ISR_ERR_USRCTL_RDNRLSCMD BIT(2) ++#define B_AX_B1_ISR_ERR_USRCTL_NOINIT BIT(1) ++#define B_AX_B1_ISR_ERR_USRCTL_REINIT BIT(0) ++ + #define R_AX_AFE_CTRL1 0x0024 + + #define B_AX_R_SYM_WLCMAC1_P4_PC_EN BIT(4) +@@ -1869,6 +2048,23 @@ + #define B_AX_PTCL_TOP_ERR_IND BIT(1) + #define B_AX_SCHEDULE_TOP_ERR_IND BIT(0) + ++#define R_AX_PORT0_TSF_SYNC 0xC2A0 ++#define R_AX_PORT0_TSF_SYNC_C1 0xE2A0 ++#define R_AX_PORT1_TSF_SYNC 0xC2A4 ++#define R_AX_PORT1_TSF_SYNC_C1 0xE2A4 ++#define R_AX_PORT2_TSF_SYNC 0xC2A8 ++#define R_AX_PORT2_TSF_SYNC_C1 0xE2A8 ++#define R_AX_PORT3_TSF_SYNC 0xC2AC ++#define R_AX_PORT3_TSF_SYNC_C1 0xE2AC ++#define R_AX_PORT4_TSF_SYNC 0xC2B0 ++#define R_AX_PORT4_TSF_SYNC_C1 0xE2B0 ++#define B_AX_SYNC_NOW BIT(30) ++#define B_AX_SYNC_ONCE BIT(29) ++#define B_AX_SYNC_AUTO BIT(28) ++#define B_AX_SYNC_PORT_SRC GENMASK(26, 24) ++#define B_AX_SYNC_PORT_OFFSET_SIGN BIT(18) ++#define B_AX_SYNC_PORT_OFFSET_VAL GENMASK(17, 0) ++ + #define R_AX_MACID_SLEEP_0 0xC2C0 + #define R_AX_MACID_SLEEP_0_C1 0xE2C0 + #define B_AX_MACID31_0_SLEEP_SH 0 +@@ -2338,6 +2534,41 @@ + #define B_AX_DLE_IMR_SET (B_AX_RXSTS_FSM_HANG_ERROR_IMR | \ + B_AX_RXDATA_FSM_HANG_ERROR_IMR) + ++#define R_AX_RX_ERR_FLAG 0xC800 ++#define R_AX_RX_ERR_FLAG_C1 0xE800 ++#define B_AX_RX_GET_NO_PAGE_ERR BIT(31) ++#define B_AX_RX_GET_NULL_PKT_ERR BIT(30) ++#define B_AX_RX_RU0_FSM_HANG_ERR BIT(29) ++#define B_AX_RX_RU1_FSM_HANG_ERR BIT(28) ++#define B_AX_RX_RU2_FSM_HANG_ERR BIT(27) ++#define B_AX_RX_RU3_FSM_HANG_ERR BIT(26) ++#define B_AX_RX_RU4_FSM_HANG_ERR BIT(25) ++#define B_AX_RX_RU5_FSM_HANG_ERR BIT(24) ++#define B_AX_RX_RU6_FSM_HANG_ERR BIT(23) ++#define B_AX_RX_RU7_FSM_HANG_ERR BIT(22) ++#define B_AX_RX_RXSTS_FSM_HANG_ERR BIT(21) ++#define B_AX_RX_CSI_FSM_HANG_ERR BIT(20) ++#define B_AX_RX_TXRPT_FSM_HANG_ERR BIT(19) ++#define B_AX_RX_F2PCMD_FSM_HANG_ERR BIT(18) ++#define B_AX_RX_RU0_ZERO_LEN_ERR BIT(17) ++#define B_AX_RX_RU1_ZERO_LEN_ERR BIT(16) ++#define B_AX_RX_RU2_ZERO_LEN_ERR BIT(15) ++#define B_AX_RX_RU3_ZERO_LEN_ERR BIT(14) ++#define B_AX_RX_RU4_ZERO_LEN_ERR BIT(13) ++#define B_AX_RX_RU5_ZERO_LEN_ERR BIT(12) ++#define B_AX_RX_RU6_ZERO_LEN_ERR BIT(11) ++#define B_AX_RX_RU7_ZERO_LEN_ERR BIT(10) ++#define B_AX_RX_RXSTS_ZERO_LEN_ERR BIT(9) ++#define B_AX_RX_CSI_ZERO_LEN_ERR BIT(8) ++#define B_AX_PLE_DATA_OPT_FSM_HANG BIT(7) ++#define B_AX_PLE_RXDATA_REQ_BUF_FSM_HANG BIT(6) ++#define B_AX_PLE_TXRPT_REQ_BUF_FSM_HANG BIT(5) ++#define B_AX_PLE_WD_OPT_FSM_HANG BIT(4) ++#define B_AX_PLE_ENQ_FSM_HANG BIT(3) ++#define B_AX_RXDATA_ENQUE_ORDER_ERR BIT(2) ++#define B_AX_RXSTS_ENQUE_ORDER_ERR BIT(1) ++#define B_AX_RX_CSI_PKT_NUM_ERR BIT(0) ++ + #define R_AX_RXDMA_CTRL_0 0xC804 + #define R_AX_RXDMA_CTRL_0_C1 0xE804 + #define B_AX_RXDMA_DBGOUT_EN BIT(31) +@@ -2360,6 +2591,49 @@ + B_AX_RU2_PTR_FULL_MODE | B_AX_RU3_PTR_FULL_MODE | \ + B_AX_CSI_PTR_FULL_MODE | B_AX_RXSTS_PTR_FULL_MODE) + ++#define R_AX_RX_CTRL0 0xC808 ++#define R_AX_RX_CTRL0_C1 0xE808 ++#define B_AX_DLE_CLOCK_FORCE_V1 BIT(31) ++#define B_AX_TXDMA_CLOCK_FORCE_V1 BIT(30) ++#define B_AX_RXDMA_CLOCK_FORCE_V1 BIT(29) ++#define B_AX_RXDMA_DEFAULT_PAGE_V1_MASK GENMASK(28, 24) ++#define B_AX_RXDMA_CSI_TGT_QUEID_MASK GENMASK(23, 18) ++#define B_AX_RXDMA_CSI_TGT_PRID_MASK GENMASK(17, 15) ++#define B_AX_RXDMA_DIS_CSI_RELEASE_V1 BIT(14) ++#define B_AX_CSI_PTR_FULL_MODE_V1 BIT(13) ++#define B_AX_RXDATA_PTR_FULL_MODE BIT(12) ++#define B_AX_RXSTS_PTR_FULL_MODE_V1 BIT(11) ++#define B_AX_TXRPT_FULL_RSV_DEPTH_V1_MASK GENMASK(10, 8) ++#define B_AX_RXDATA_FULL_RSV_DEPTH_MASK GENMASK(7, 5) ++#define B_AX_RXSTS_FULL_RSV_DEPTH_V1_MASK GENMASK(4, 2) ++#define B_AX_ORDER_FIFO_MASK GENMASK(1, 0) ++ ++#define R_AX_RX_CTRL1 0xC80C ++#define R_AX_RX_CTRL1_C1 0xE80C ++#define B_AX_RXDMA_TXRPT_QUEUE_ID_SW_EN BIT(31) ++#define B_AX_RXDMA_TXRPT_QUEUE_ID_SW_V1_MASK GENMASK(30, 25) ++#define B_AX_RXDMA_F2PCMD_QUEUE_ID_SW_EN BIT(24) ++#define B_AX_RXDMA_F2PCMD_QUEUE_ID_SW_V1_MASK GENMASK(23, 18) ++#define B_AX_RXDMA_TXRPT_QUEUE_ID_TGT_SW_EN BIT(17) ++#define B_AX_RXDMA_TXRPT_QUEUE_ID_TGT_SW_1_MASK GENMASK(16, 11) ++#define B_AX_RXDMA_F2PCMD_QUEUE_ID_TGT_SW_EN BIT(10) ++#define B_AX_RXDMA_F2PCMD_QUEUE_ID_TGT_SW_1_MASK GENMASK(9, 4) ++#define B_AX_ORDER_FIFO_OUT BIT(3) ++#define B_AX_ORDER_FIFO_EMPTY BIT(2) ++#define B_AX_DBG_SEL_MASK GENMASK(1, 0) ++ ++#define R_AX_RX_CTRL2 0xC810 ++#define R_AX_RX_CTRL2_C1 0xE810 ++#define B_AX_DLE_WDE_STATE_V1_MASK GENMASK(31, 30) ++#define B_AX_DLE_PLE_STATE_V1_MASK GENMASK(29, 28) ++#define B_AX_DLE_REQ_BUF_STATE_MASK GENMASK(27, 26) ++#define B_AX_DLE_ENQ_STATE_V1 BIT(25) ++#define B_AX_RX_DBG_SEL_MASK GENMASK(24, 19) ++#define B_AX_MACRX_CS_MASK GENMASK(18, 14) ++#define B_AX_RXSTS_CS_MASK GENMASK(13, 9) ++#define B_AX_ERR_INDICATOR BIT(5) ++#define B_AX_TXRPT_CS_MASK GENMASK(4, 0) ++ + #define R_AX_RXDMA_PKT_INFO_0 0xC814 + #define R_AX_RXDMA_PKT_INFO_1 0xC818 + #define R_AX_RXDMA_PKT_INFO_2 0xC81C +@@ -2667,6 +2941,18 @@ + B_AX_TMAC_MIMO_CTRL | \ + B_AX_RMAC_FTM) + ++#define R_AX_TRXPTCL_ERROR_INDICA 0xCCC0 ++#define R_AX_TRXPTCL_ERROR_INDICA_C1 0xECC0 ++#define B_AX_FTM_ERROR_FLAG_CLR BIT(8) ++#define B_AX_CSI_ERROR_FLAG_CLR BIT(7) ++#define B_AX_MIMOCTRL_ERROR_FLAG_CLR BIT(6) ++#define B_AX_RXTB_ERROR_FLAG_CLR BIT(5) ++#define B_AX_HWSIGB_GEN_ERROR_FLAG_CLR BIT(4) ++#define B_AX_TXPLCP_ERROR_FLAG_CLR BIT(3) ++#define B_AX_RESP_ERROR_FLAG_CLR BIT(2) ++#define B_AX_TXCTL_ERROR_FLAG_CLR BIT(1) ++#define B_AX_MACTX_ERROR_FLAG_CLR BIT(0) ++ + #define R_AX_WMAC_TX_TF_INFO_0 0xCCD0 + #define R_AX_WMAC_TX_TF_INFO_0_C1 0xECD0 + #define B_AX_WMAC_TX_TF_INFO_SEL_MASK GENMASK(2, 0) +@@ -2991,6 +3277,7 @@ + + #define R_AX_PWR_RATE_CTRL 0xD200 + #define R_AX_PWR_RATE_CTRL_C1 0xF200 ++#define B_AX_PWR_REF GENMASK(27, 10) + #define B_AX_FORCE_PWR_BY_RATE_EN BIT(9) + #define B_AX_FORCE_PWR_BY_RATE_VALUE_MASK GENMASK(8, 0) + +@@ -3128,6 +3415,7 @@ + #define BTC_BREAK_PARAM 0xf0ffffff + + #define R_BTC_BT_COEX_MSK_TABLE 0xDA30 ++#define B_BTC_PRI_MASK_RXCCK_V1 BIT(28) + #define B_BTC_PRI_MASK_TX_RESP_V1 BIT(3) + + #define R_AX_BT_COEX_CFG_2 0xDA34 +@@ -3271,8 +3559,10 @@ + #define RR_MOD_IQK GENMASK(19, 4) + #define RR_MOD_DPK GENMASK(19, 5) + #define RR_MOD_MASK GENMASK(19, 16) ++#define RR_MOD_RGM GENMASK(13, 4) + #define RR_MOD_V_DOWN 0x0 + #define RR_MOD_V_STANDBY 0x1 ++#define RR_TXAGC 0x10001 + #define RR_MOD_V_TX 0x2 + #define RR_MOD_V_RX 0x3 + #define RR_MOD_V_TXIQK 0x4 +@@ -3308,6 +3598,10 @@ + #define CFGCH_BAND1_2G 0 + #define CFGCH_BAND1_5G 1 + #define CFGCH_BAND1_6G 3 ++#define RR_CFGCH_POW_LCK BIT(15) ++#define RR_CFGCH_TRX_AH BIT(14) ++#define RR_CFGCH_BCN BIT(13) ++#define RR_CFGCH_BW2 BIT(12) + #define RR_CFGCH_BAND0 GENMASK(9, 8) + #define CFGCH_BAND0_2G 0 + #define CFGCH_BAND0_5G 1 +@@ -3340,6 +3634,7 @@ + #define RR_RXK_PLLEN BIT(5) + #define RR_LUTWA 0x33 + #define RR_LUTWA_MASK GENMASK(9, 0) ++#define RR_LUTWA_M1 GENMASK(7, 0) + #define RR_LUTWA_M2 GENMASK(4, 0) + #define RR_LUTWD1 0x3e + #define RR_LUTWD0 0x3f +@@ -3359,6 +3654,8 @@ + #define RR_TXGA_TRK_EN BIT(7) + #define RR_TXGA_LOK_EXT GENMASK(4, 0) + #define RR_TXGA_LOK_EN BIT(0) ++#define RR_TXGA_V1 0x10055 ++#define RR_TXGA_V1_TRK_EN BIT(7) + #define RR_GAINTX 0x56 + #define RR_GAINTX_ALL GENMASK(15, 0) + #define RR_GAINTX_PAD GENMASK(9, 5) +@@ -3387,6 +3684,8 @@ + #define RR_TXA2_LDO GENMASK(19, 16) + #define RR_TRXIQ 0x66 + #define RR_RSV6 0x6d ++#define RR_TXVBUF 0x7c ++#define RR_TXVBUF_DACEN BIT(5) + #define RR_TXPOW 0x7f + #define RR_TXPOW_TXA BIT(8) + #define RR_TXPOW_TXAS BIT(7) +@@ -3397,6 +3696,7 @@ + #define RR_RXBB_VOBUF GENMASK(15, 12) + #define RR_RXBB_C2G GENMASK(16, 10) + #define RR_RXBB_C1G GENMASK(9, 8) ++#define RR_RXBB_FATT GENMASK(7, 0) + #define RR_RXBB_ATTR GENMASK(7, 4) + #define RR_RXBB_ATTC GENMASK(2, 0) + #define RR_RXG 0x84 +@@ -3407,10 +3707,14 @@ + #define RR_RXAE_IQKMOD GENMASK(3, 0) + #define RR_RXA 0x8a + #define RR_RXA_DPK GENMASK(9, 8) ++#define RR_RXA_LNA 0x8b + #define RR_RXA2 0x8c ++#define RR_RAA2_SWATT GENMASK(15, 9) + #define RR_RXA2_C1 GENMASK(12, 10) + #define RR_RXA2_C2 GENMASK(9, 3) ++#define RR_RXA2_CC2 GENMASK(8, 7) + #define RR_RXA2_IATT GENMASK(7, 4) ++#define RR_RXA2_HATT GENMASK(6, 0) + #define RR_RXA2_ATT GENMASK(3, 0) + #define RR_RXIQGEN 0x8d + #define RR_RXIQGEN_ATTL GENMASK(12, 8) +@@ -3422,6 +3726,7 @@ + #define RR_RXBB2_IDAC GENMASK(11, 9) + #define RR_RXBB2_EBW GENMASK(6, 5) + #define RR_XALNA2 0x90 ++#define RR_XALNA2_SW2 GENMASK(9, 8) + #define RR_XALNA2_SW GENMASK(1, 0) + #define RR_DCK 0x92 + #define RR_DCK_DONE GENMASK(7, 5) +@@ -3439,18 +3744,36 @@ + #define RR_IQGEN_BIAS GENMASK(11, 8) + #define RR_TXIQK 0x98 + #define RR_TXIQK_ATT2 GENMASK(15, 12) ++#define RR_TXIQK_ATT1 GENMASK(6, 0) + #define RR_TIA 0x9e + #define RR_TIA_N6 BIT(8) + #define RR_MIXER 0x9f + #define RR_MIXER_GN GENMASK(4, 3) ++#define RR_POW 0xa0 ++#define RR_POW_SYN GENMASK(3, 2) + #define RR_LOGEN 0xa3 + #define RR_LOGEN_RPT GENMASK(19, 16) ++#define RR_SX 0xaf ++#define RR_LDO 0xb1 ++#define RR_LDO_SEL GENMASK(8, 6) ++#define RR_VCO 0xb2 ++#define RR_LPF 0xb7 ++#define RR_LPF_BUSY BIT(8) + #define RR_XTALX2 0xb8 + #define RR_MALSEL 0xbe ++#define RR_SYNFB 0xc5 ++#define RR_SYNFB_LK BIT(15) ++#define RR_LCKST 0xcf ++#define RR_LCKST_BIN BIT(0) + #define RR_LCK_TRG 0xd3 + #define RR_LCK_TRGSEL BIT(8) ++#define RR_MMD 0xd5 ++#define RR_MMD_RST_EN BIT(8) ++#define RR_MMD_RST_SYN BIT(6) + #define RR_IQKPLL 0xdc + #define RR_IQKPLL_MOD GENMASK(9, 8) ++#define RR_SYNLUT 0xdd ++#define RR_SYNLUT_MOD BIT(4) + #define RR_RCKD 0xde + #define RR_RCKD_POW GENMASK(19, 13) + #define RR_RCKD_BW BIT(2) +@@ -3479,11 +3802,14 @@ + #define B_ANAPAR_ADCCLK BIT(30) + #define B_ANAPAR_FLTRST BIT(22) + #define B_ANAPAR_CRXBB GENMASK(18, 16) ++#define B_ANAPAR_EN BIT(16) + #define B_ANAPAR_14 GENMASK(15, 0) + #define R_RFE_E_A2 0x0334 + #define R_RFE_O_SEL_A2 0x0338 + #define R_RFE_SEL0_A2 0x033C + #define R_RFE_SEL32_A2 0x0340 ++#define R_CIRST 0x035c ++#define B_CIRST_SYN GENMASK(11, 10) + #define R_SWSI_DATA_V1 0x0370 + #define B_SWSI_DATA_VAL_V1 GENMASK(19, 0) + #define B_SWSI_DATA_ADDR_V1 GENMASK(27, 20) +@@ -3619,6 +3945,10 @@ + #define R_P0_RFMODE 0x12AC + #define B_P0_RFMODE_ORI_TXRX_FTM_TX GENMASK(31, 4) + #define B_P0_RFMODE_MUX GENMASK(11, 4) ++#define R_P0_RFMODE_ORI_RX 0x12AC ++#define B_P0_RFMODE_ORI_RX_ALL GENMASK(23, 12) ++#define R_P0_RFMODE_FTM_RX 0x12B0 ++#define B_P0_RFMODE_FTM_RX GENMASK(11, 0) + #define R_P0_NRBW 0x12B8 + #define B_P0_NRBW_DBG BIT(30) + #define R_S0_RXDC 0x12D4 +@@ -3671,6 +4001,9 @@ + #define B_TXAGC_TP GENMASK(2, 0) + #define R_TSSI_THER 0x1C10 + #define B_TSSI_THER GENMASK(29, 24) ++#define R_TSSI_CWRPT 0x1C18 ++#define B_TSSI_CWRPT_RDY BIT(16) ++#define B_TSSI_CWRPT GENMASK(8, 0) + #define R_TXAGC_BTP 0x1CA0 + #define B_TXAGC_BTP GENMASK(31, 24) + #define R_TXAGC_BB 0x1C60 +@@ -3712,6 +4045,8 @@ + #define B_RXCCA_DIS_V1 BIT(0) + #define R_RXSC 0x237C + #define B_RXSC_EN BIT(0) ++#define R_RX_RPL_OFST 0x23AC ++#define B_RX_RPL_OFST_CCK_MASK GENMASK(6, 0) + #define R_RXSCOBC 0x23B0 + #define B_RXSCOBC_TH GENMASK(18, 0) + #define R_RXSCOCCK 0x23B4 +@@ -3725,9 +4060,18 @@ + #define B_P1_EN_SOUND_WO_NDP BIT(1) + #define R_S1_HW_SI_DIS 0x3200 + #define B_S1_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) ++#define R_P1_RXCK 0x32A0 ++#define B_P1_RXCK_BW3 BIT(30) ++#define B_P1_TXCK_ALL GENMASK(19, 12) ++#define B_P1_RXCK_ON BIT(19) ++#define B_P1_RXCK_VAL GENMASK(18, 16) + #define R_P1_RFMODE 0x32AC + #define B_P1_RFMODE_ORI_TXRX_FTM_TX GENMASK(31, 4) + #define B_P1_RFMODE_MUX GENMASK(11, 4) ++#define R_P1_RFMODE_ORI_RX 0x32AC ++#define B_P1_RFMODE_ORI_RX_ALL GENMASK(23, 12) ++#define R_P1_RFMODE_FTM_RX 0x32B0 ++#define B_P1_RFMODE_FTM_RX GENMASK(11, 0) + #define R_P1_DBGMOD 0x32B8 + #define B_P1_DBGMOD_ON BIT(30) + #define R_S1_RXDC 0x32D4 +@@ -3761,7 +4105,10 @@ + #define R_T2F_GI_COMB 0x4424 + #define B_T2F_GI_COMB_EN BIT(2) + #define R_BT_DYN_DC_EST_EN 0x441C ++#define R_BT_DYN_DC_EST_EN_V1 0x4420 + #define B_BT_DYN_DC_EST_EN_MSK BIT(31) ++#define R_ASSIGN_SBD_OPT_V1 0x4440 ++#define B_ASSIGN_SBD_OPT_EN_V1 BIT(31) + #define R_ASSIGN_SBD_OPT 0x4450 + #define B_ASSIGN_SBD_OPT_EN BIT(24) + #define R_DCFO_COMP_S0 0x448C +@@ -3770,8 +4117,12 @@ + #define B_DCFO_WEIGHT_MSK GENMASK(27, 24) + #define R_DCFO_OPT 0x4494 + #define B_DCFO_OPT_EN BIT(29) ++#define B_TXSHAPE_TRIANGULAR_CFG GENMASK(25, 24) + #define R_BANDEDGE 0x4498 + #define B_BANDEDGE_EN BIT(30) ++#define R_DPD_BF 0x44a0 ++#define B_DPD_BF_OFDM GENMASK(16, 12) ++#define B_DPD_BF_SCA GENMASK(6, 0) + #define R_TXPATH_SEL 0x458C + #define B_TXPATH_SEL_MSK GENMASK(31, 28) + #define R_TXPWR 0x4594 +@@ -3902,6 +4253,8 @@ + #define R_P1_NBIIDX 0x4770 + #define B_P1_NBIIDX_VAL GENMASK(11, 0) + #define B_P1_NBIIDX_NOTCH_EN BIT(12) ++#define R_PKT_CTRL 0x47D4 ++#define B_PKT_POP_EN BIT(8) + #define R_SEG0R_PD 0x481C + #define R_SEG0R_PD_V1 0x4860 + #define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1 BIT(30) +@@ -3910,20 +4263,42 @@ + #define R_2P4G_BAND 0x4970 + #define B_2P4G_BAND_SEL BIT(1) + #define R_FC0_BW 0x4974 +-#define B_FC0_BW_INV GENMASK(6, 0) ++#define R_FC0_BW_V1 0x49C0 + #define B_FC0_BW_SET GENMASK(31, 30) + #define B_ANT_RX_BT_SEG0 GENMASK(25, 22) + #define B_ANT_RX_1RCCA_SEG1 GENMASK(21, 18) + #define B_ANT_RX_1RCCA_SEG0 GENMASK(17, 14) ++#define B_FC0_BW_INV GENMASK(6, 0) + #define R_CHBW_MOD 0x4978 ++#define R_CHBW_MOD_V1 0x49C4 + #define B_BT_SHARE BIT(14) + #define B_CHBW_MOD_SBW GENMASK(13, 12) + #define B_CHBW_MOD_PRICH GENMASK(11, 8) + #define B_ANT_RX_SEG0 GENMASK(3, 0) ++#define R_P0_RPL1 0x49B0 ++#define B_P0_RPL1_41_MASK GENMASK(31, 24) ++#define B_P0_RPL1_40_MASK GENMASK(23, 16) ++#define B_P0_RPL1_20_MASK GENMASK(15, 8) ++#define B_P0_RPL1_MASK (B_P0_RPL1_41_MASK | B_P0_RPL1_40_MASK | B_P0_RPL1_20_MASK) ++#define B_P0_RPL1_SHIFT 8 ++#define B_P0_RPL1_BIAS_MASK GENMASK(7, 0) ++#define R_P0_RPL2 0x49B4 ++#define B_P0_RTL2_8A_MASK GENMASK(31, 24) ++#define B_P0_RTL2_81_MASK GENMASK(23, 16) ++#define B_P0_RTL2_80_MASK GENMASK(15, 8) ++#define B_P0_RTL2_42_MASK GENMASK(7, 0) ++#define R_P0_RPL3 0x49B8 ++#define B_P0_RTL3_89_MASK GENMASK(31, 24) ++#define B_P0_RTL3_84_MASK GENMASK(23, 16) ++#define B_P0_RTL3_83_MASK GENMASK(15, 8) ++#define B_P0_RTL3_82_MASK GENMASK(7, 0) + #define R_PD_BOOST_EN 0x49E8 + #define B_PD_BOOST_EN BIT(7) + #define R_P1_BACKOFF_IBADC_V1 0x49F0 + #define B_P1_BACKOFF_IBADC_V1 GENMASK(31, 26) ++#define R_P1_RPL1 0x4A00 ++#define R_P1_RPL2 0x4A04 ++#define R_P1_RPL3 0x4A08 + #define R_BK_FC0_INV_V1 0x4A1C + #define B_BK_FC0_INV_MSK_V1 GENMASK(18, 0) + #define R_CCK_FC0_INV_V1 0x4A20 +@@ -3934,8 +4309,10 @@ + #define B_P1_AGC_EN BIT(31) + #define R_PATH1_TIA_INIT_V1 0x4AA8 + #define B_PATH1_TIA_INIT_IDX_MSK_V1 BIT(9) ++#define R_P0_AGC_RSVD 0x4ACC + #define R_PATH0_RXBB_V1 0x4AD4 + #define B_PATH0_RXBB_MSK_V1 GENMASK(31, 0) ++#define R_P1_AGC_RSVD 0x4AD8 + #define R_PATH1_RXBB_V1 0x4AE0 + #define B_PATH1_RXBB_MSK_V1 GENMASK(31, 0) + #define R_PATH0_BT_BACKOFF_V1 0x4AE4 +@@ -3951,6 +4328,7 @@ + #define B_PATH0_NOTCH2_EN BIT(12) + #define B_PATH0_NOTCH2_VAL GENMASK(11, 0) + #define R_PATH0_5MDET 0x4C4C ++#define R_PATH0_5MDET_V1 0x46F8 + #define B_PATH0_5MDET_EN BIT(12) + #define B_PATH0_5MDET_SB2 BIT(8) + #define B_PATH0_5MDET_SB0 BIT(6) +@@ -3964,6 +4342,7 @@ + #define B_PATH1_NOTCH2_EN BIT(12) + #define B_PATH1_NOTCH2_VAL GENMASK(11, 0) + #define R_PATH1_5MDET 0x4D10 ++#define R_PATH1_5MDET_V1 0x47B8 + #define B_PATH1_5MDET_EN BIT(12) + #define B_PATH1_5MDET_SB2 BIT(8) + #define B_PATH1_5MDET_SB0 BIT(6) +@@ -3992,6 +4371,20 @@ + #define B_CFO_COMP_VALID_BIT BIT(29) + #define B_CFO_COMP_WEIGHT_MSK GENMASK(27, 24) + #define B_CFO_COMP_VAL_MSK GENMASK(11, 0) ++#define R_TSSI_PA_K1 0x5600 ++#define R_TSSI_PA_K2 0x5604 ++#define R_P0_TSSI_ALIM1 0x5630 ++#define B_P0_TSSI_ALIM1 GENMASK(29, 0) ++#define B_P0_TSSI_ALIM11 GENMASK(29, 20) ++#define B_P0_TSSI_ALIM12 GENMASK(19, 10) ++#define B_P0_TSSI_ALIM13 GENMASK(9, 0) ++#define R_P0_TSSI_ALIM3 0x5634 ++#define B_P0_TSSI_ALIM31 GENMASK(9, 0) ++#define R_TSSI_PA_K5 0x5638 ++#define R_P0_TSSI_ALIM2 0x563c ++#define B_P0_TSSI_ALIM2 GENMASK(29, 0) ++#define R_P0_TSSI_ALIM4 0x5640 ++#define R_TSSI_PA_K8 0x5644 + #define R_UPD_CLK 0x5670 + #define B_DAC_VAL BIT(31) + #define B_ACK_VAL GENMASK(30, 29) +@@ -4003,6 +4396,11 @@ + #define B_TXPWRB_VAL GENMASK(27, 19) + #define R_DPD_OFT_EN 0x5800 + #define B_DPD_OFT_EN BIT(28) ++#define B_DPD_TSSI_CW GENMASK(26, 18) ++#define B_DPD_PWR_CW GENMASK(17, 9) ++#define B_DPD_REF GENMASK(8, 0) ++#define R_P0_TSSIC 0x5814 ++#define B_P0_TSSIC_BYPASS BIT(11) + #define R_DPD_OFT_ADDR 0x5804 + #define B_DPD_OFT_ADDR GENMASK(31, 27) + #define R_TXPWRB_H 0x580c +@@ -4011,13 +4409,18 @@ + #define B_P0_TMETER GENMASK(15, 10) + #define B_P0_TMETER_DIS BIT(16) + #define B_P0_TMETER_TRK BIT(24) ++#define R_P1_TSSIC 0x7814 ++#define B_P1_TSSIC_BYPASS BIT(11) + #define R_P0_TSSI_TRK 0x5818 + #define B_P0_TSSI_TRK_EN BIT(30) ++#define B_P0_TSSI_RFC GENMASK(28, 27) + #define B_P0_TSSI_OFT_EN BIT(28) + #define B_P0_TSSI_OFT GENMASK(7, 0) + #define R_P0_TSSI_AVG 0x5820 ++#define B_P0_TSSI_EN BIT(31) + #define B_P0_TSSI_AVG GENMASK(15, 12) + #define R_P0_RFCTM 0x5864 ++#define B_P0_RFCTM_EN BIT(29) + #define B_P0_RFCTM_VAL GENMASK(25, 20) + #define R_P0_RFCTM_RDY BIT(26) + #define R_P0_TRSW 0x5868 +@@ -4030,13 +4433,16 @@ + #define B_P0_RFM_TX_OPT BIT(6) + #define B_P0_RFM_BT_EN BIT(5) + #define B_P0_RFM_OUT GENMASK(4, 0) ++#define R_P0_PATH_RST 0x58AC + #define R_P0_TXDPD 0x58D4 + #define B_P0_TXDPD GENMASK(31, 28) + #define R_P0_TXPW_RSTB 0x58DC + #define B_P0_TXPW_RSTB_MANON BIT(30) + #define B_P0_TXPW_RSTB_TSSI BIT(31) + #define R_P0_TSSI_MV_AVG 0x58E4 ++#define B_P0_TSSI_MV_MIX GENMASK(19, 11) + #define B_P0_TSSI_MV_AVG GENMASK(13, 11) ++#define B_P0_TSSI_MV_CLR BIT(14) + #define R_TXGAIN_SCALE 0x58F0 + #define B_TXGAIN_SCALE_EN BIT(19) + #define B_TXGAIN_SCALE_OFT GENMASK(31, 24) +@@ -4061,24 +4467,41 @@ + #define B_S0_DACKQ8_K GENMASK(15, 8) + #define R_RPL_BIAS_COMP1 0x6DF0 + #define B_RPL_BIAS_COMP1_MASK GENMASK(7, 0) ++#define R_P1_TSSI_ALIM1 0x7630 ++#define B_P1_TSSI_ALIM1 GENMASK(29, 0) ++#define B_P1_TSSI_ALIM11 GENMASK(29, 20) ++#define B_P1_TSSI_ALIM12 GENMASK(19, 10) ++#define B_P1_TSSI_ALIM13 GENMASK(9, 0) ++#define R_P1_TSSI_ALIM3 0x7634 ++#define B_P1_TSSI_ALIM31 GENMASK(9, 0) ++#define R_P1_TSSI_ALIM2 0x763c ++#define B_P1_TSSI_ALIM2 GENMASK(29, 0) ++#define R_P1_TSSIC 0x7814 ++#define B_P1_TSSIC_BYPASS BIT(11) + #define R_P1_TMETER 0x7810 + #define B_P1_TMETER GENMASK(15, 10) + #define B_P1_TMETER_DIS BIT(16) + #define B_P1_TMETER_TRK BIT(24) + #define R_P1_TSSI_TRK 0x7818 + #define B_P1_TSSI_TRK_EN BIT(30) ++#define B_P1_TSSI_RFC GENMASK(28, 27) + #define B_P1_TSSI_OFT_EN BIT(28) + #define B_P1_TSSI_OFT GENMASK(7, 0) + #define R_P1_TSSI_AVG 0x7820 ++#define B_P1_TSSI_EN BIT(31) + #define B_P1_TSSI_AVG GENMASK(15, 12) + #define R_P1_RFCTM 0x7864 + #define R_P1_RFCTM_RDY BIT(26) + #define B_P1_RFCTM_VAL GENMASK(25, 20) ++#define B_P1_RFCTM_DEL GENMASK(19, 11) ++#define R_P1_PATH_RST 0x78AC + #define R_P1_TXPW_RSTB 0x78DC + #define B_P1_TXPW_RSTB_MANON BIT(30) + #define B_P1_TXPW_RSTB_TSSI BIT(31) + #define R_P1_TSSI_MV_AVG 0x78E4 ++#define B_P1_TSSI_MV_MIX GENMASK(19, 11) + #define B_P1_TSSI_MV_AVG GENMASK(13, 11) ++#define B_P1_TSSI_MV_CLR BIT(14) + #define R_TSSI_THOF 0x7C00 + #define R_S1_DACKI 0x7E00 + #define B_S1_DACKI_AR GENMASK(31, 28) +@@ -4148,6 +4571,7 @@ + #define B_KPATH_CFG_ED GENMASK(21, 20) + #define R_KIP_RPT1 0x80D4 + #define B_KIP_RPT1_SEL GENMASK(21, 16) ++#define B_KIP_RPT1_SEL_V1 GENMASK(19, 16) + #define R_SRAM_IQRX 0x80D8 + #define R_GAPK 0x80E0 + #define B_GAPK_ADR BIT(0) +@@ -4169,12 +4593,14 @@ + #define B_PRT_COM_GL GENMASK(7, 4) + #define B_PRT_COM_CORI GENMASK(7, 0) + #define B_PRT_COM_RXBB GENMASK(5, 0) ++#define B_PRT_COM_RXBB_V1 GENMASK(4, 0) + #define B_PRT_COM_DONE BIT(0) + #define R_COEF_SEL 0x8104 + #define B_COEF_SEL_IQC BIT(0) + #define B_COEF_SEL_MDPD BIT(8) + #define R_CFIR_SYS 0x8120 + #define R_IQK_RES 0x8124 ++#define B_IQK_RES_K BIT(28) + #define B_IQK_RES_TXCFIR GENMASK(11, 8) + #define B_IQK_RES_RXCFIR GENMASK(3, 0) + #define R_TXIQC 0x8138 +@@ -4206,13 +4632,18 @@ + #define B_DPD_LBK BIT(7) + #define R_DPD_CH0 0x81AC + #define R_DPD_BND 0x81B4 ++#define B_DPD_BND_1 GENMASK(24, 16) ++#define B_DPD_BND_0 GENMASK(8, 0) + #define R_DPD_CH0A 0x81BC + #define B_DPD_MEN GENMASK(31, 28) + #define B_DPD_ORDER GENMASK(26, 24) ++#define B_DPD_ORDER_V1 GENMASK(26, 25) ++#define B_DPD_CFG GENMASK(22, 0) + #define B_DPD_SEL GENMASK(13, 8) + #define R_TXAGC_RFK 0x81C4 + #define B_TXAGC_RFK_CH0 GENMASK(5, 0) + #define R_DPD_COM 0x81C8 ++#define B_DPD_COM_OF BIT(15) + #define R_KIP_IQP 0x81CC + #define B_KIP_IQP_SW GENMASK(13, 12) + #define B_KIP_IQP_IQSW GENMASK(5, 0) +@@ -4231,6 +4662,9 @@ + #define B_RPT_PER_TSSI GENMASK(28, 16) + #define B_RPT_PER_OF GENMASK(15, 8) + #define B_RPT_PER_TH GENMASK(5, 0) ++#define R_IQRSN 0x8220 ++#define B_IQRSN_K1 BIT(28) ++#define B_IQRSN_K2 BIT(16) + #define R_RXCFIR_P0C0 0x8D40 + #define R_RXCFIR_P0C1 0x8D84 + #define R_RXCFIR_P0C2 0x8DC8 +@@ -4288,6 +4722,8 @@ + #define B_DACK_S0P3_OK BIT(2) + #define R_DACK_DADCK01 0xC084 + #define B_DACK_DADCK01 GENMASK(31, 24) ++#define R_DRCK_FH 0xC094 ++#define B_DRCK_LAT BIT(9) + #define R_DRCK 0xC0C4 + #define B_DRCK_IDLE BIT(9) + #define B_DRCK_EN BIT(6) +@@ -4295,15 +4731,29 @@ + #define R_DRCK_RES 0xC0C8 + #define B_DRCK_RES GENMASK(19, 15) + #define B_DRCK_POL BIT(3) ++#define R_DRCK_V1 0xC0CC ++#define B_DRCK_V1_SEL BIT(9) ++#define B_DRCK_V1_KICK BIT(6) ++#define B_DRCK_V1_CV GENMASK(4, 0) ++#define R_DRCK_RS 0xC0D0 ++#define B_DRCK_RS_LPS GENMASK(19, 15) ++#define B_DRCK_RS_DONE BIT(3) + #define R_PATH0_SAMPL_DLY_T_V1 0xC0D4 + #define B_PATH0_SAMPL_DLY_T_MSK_V1 GENMASK(27, 26) + #define R_P0_CFCH_BW0 0xC0D4 + #define B_P0_CFCH_BW0 GENMASK(27, 26) + #define R_P0_CFCH_BW1 0xC0D8 ++#define B_P0_CFCH_EX BIT(13) + #define B_P0_CFCH_BW1 GENMASK(8, 5) ++#define R_ADDCK0D 0xC0F0 ++#define B_ADDCK0D_VAL2 GENMASK(31, 26) ++#define B_ADDCK0D_VAL GENMASK(25, 16) + #define R_ADDCK0 0xC0F4 ++#define B_ADDCK0_TRG BIT(11) + #define B_ADDCK0 GENMASK(9, 8) ++#define B_ADDCK0_MAN GENMASK(5, 4) + #define B_ADDCK0_EN BIT(4) ++#define B_ADDCK0_VAL GENMASK(3, 0) + #define B_ADDCK0_RST BIT(2) + #define R_ADDCK0_RL 0xC0F8 + #define B_ADDCK0_RLS GENMASK(29, 28) +@@ -4343,9 +4793,15 @@ + #define R_PATH0_BW_SEL_V1 0xC0D8 + #define B_PATH0_BW_SEL_MSK_V1 GENMASK(8, 5) + #define R_PATH1_BW_SEL_V1 0xC1D8 ++#define B_PATH1_BW_SEL_EX BIT(13) + #define B_PATH1_BW_SEL_MSK_V1 GENMASK(8, 5) ++#define R_ADDCK1D 0xC1F0 ++#define B_ADDCK1D_VAL2 GENMASK(31, 26) ++#define B_ADDCK1D_VAL GENMASK(25, 16) + #define R_ADDCK1 0xC1F4 ++#define B_ADDCK1_TRG BIT(11) + #define B_ADDCK1 GENMASK(9, 8) ++#define B_ADDCK1_MAN GENMASK(5, 4) + #define B_ADDCK1_EN BIT(4) + #define B_ADDCK1_RST BIT(2) + #define R_ADDCK1_RL 0xC1F8 +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852a.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852a.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852a.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852a.c 2022-12-24 00:49:25.782376835 +0200 +@@ -48,6 +48,10 @@ static const struct rtw89_dle_mem rtw885 + &rtw89_mac_size.ple_size0, &rtw89_mac_size.wde_qt0, + &rtw89_mac_size.wde_qt0, &rtw89_mac_size.ple_qt4, + &rtw89_mac_size.ple_qt5}, ++ [RTW89_QTA_WOW] = {RTW89_QTA_WOW, &rtw89_mac_size.wde_size0, ++ &rtw89_mac_size.ple_size0, &rtw89_mac_size.wde_qt0, ++ &rtw89_mac_size.wde_qt0, &rtw89_mac_size.ple_qt4, ++ &rtw89_mac_size.ple_qt_52a_wow}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size4, + &rtw89_mac_size.ple_size4, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, +@@ -1410,151 +1414,14 @@ static void rtw8852a_set_txpwr_ref(struc + phy_idx); + } + +-static void rtw8852a_set_txpwr_byrate(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- enum rtw89_phy_idx phy_idx) +-{ +- u8 band = chan->band_type; +- u8 ch = chan->channel; +- static const u8 rs[] = { +- RTW89_RS_CCK, +- RTW89_RS_OFDM, +- RTW89_RS_MCS, +- RTW89_RS_HEDCM, +- }; +- s8 tmp; +- u8 i, j; +- u32 val, shf, addr = R_AX_PWR_BY_RATE; +- struct rtw89_rate_desc cur; +- +- rtw89_debug(rtwdev, RTW89_DBG_TXPWR, +- "[TXPWR] set txpwr byrate with ch=%d\n", ch); +- +- for (cur.nss = 0; cur.nss <= RTW89_NSS_2; cur.nss++) { +- for (i = 0; i < ARRAY_SIZE(rs); i++) { +- if (cur.nss >= rtw89_rs_nss_max[rs[i]]) +- continue; +- +- val = 0; +- cur.rs = rs[i]; +- +- for (j = 0; j < rtw89_rs_idx_max[rs[i]]; j++) { +- cur.idx = j; +- shf = (j % 4) * 8; +- tmp = rtw89_phy_read_txpwr_byrate(rtwdev, band, +- &cur); +- val |= (tmp << shf); +- +- if ((j + 1) % 4) +- continue; +- +- rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val); +- val = 0; +- addr += 4; +- } +- } +- } +-} +- +-static void rtw8852a_set_txpwr_offset(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- enum rtw89_phy_idx phy_idx) +-{ +- u8 band = chan->band_type; +- struct rtw89_rate_desc desc = { +- .nss = RTW89_NSS_1, +- .rs = RTW89_RS_OFFSET, +- }; +- u32 val = 0; +- s8 v; +- +- rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr offset\n"); +- +- for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_MAX; desc.idx++) { +- v = rtw89_phy_read_txpwr_byrate(rtwdev, band, &desc); +- val |= ((v & 0xf) << (4 * desc.idx)); +- } +- +- rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_OFST_CTRL, +- GENMASK(19, 0), val); +-} +- +-static void rtw8852a_set_txpwr_limit(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- enum rtw89_phy_idx phy_idx) +-{ +-#define __MAC_TXPWR_LMT_PAGE_SIZE 40 +- u8 ch = chan->channel; +- u8 bw = chan->band_width; +- struct rtw89_txpwr_limit lmt[NTX_NUM_8852A]; +- u32 addr, val; +- const s8 *ptr; +- u8 i, j; +- +- rtw89_debug(rtwdev, RTW89_DBG_TXPWR, +- "[TXPWR] set txpwr limit with ch=%d bw=%d\n", ch, bw); +- +- for (i = 0; i < NTX_NUM_8852A; i++) { +- rtw89_phy_fill_txpwr_limit(rtwdev, chan, &lmt[i], i); +- +- for (j = 0; j < __MAC_TXPWR_LMT_PAGE_SIZE; j += 4) { +- addr = R_AX_PWR_LMT + j + __MAC_TXPWR_LMT_PAGE_SIZE * i; +- ptr = (s8 *)&lmt[i] + j; +- +- val = FIELD_PREP(GENMASK(7, 0), ptr[0]) | +- FIELD_PREP(GENMASK(15, 8), ptr[1]) | +- FIELD_PREP(GENMASK(23, 16), ptr[2]) | +- FIELD_PREP(GENMASK(31, 24), ptr[3]); +- +- rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val); +- } +- } +-#undef __MAC_TXPWR_LMT_PAGE_SIZE +-} +- +-static void rtw8852a_set_txpwr_limit_ru(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- enum rtw89_phy_idx phy_idx) +-{ +-#define __MAC_TXPWR_LMT_RU_PAGE_SIZE 24 +- u8 ch = chan->channel; +- u8 bw = chan->band_width; +- struct rtw89_txpwr_limit_ru lmt_ru[NTX_NUM_8852A]; +- u32 addr, val; +- const s8 *ptr; +- u8 i, j; +- +- rtw89_debug(rtwdev, RTW89_DBG_TXPWR, +- "[TXPWR] set txpwr limit ru with ch=%d bw=%d\n", ch, bw); +- +- for (i = 0; i < NTX_NUM_8852A; i++) { +- rtw89_phy_fill_txpwr_limit_ru(rtwdev, chan, &lmt_ru[i], i); +- +- for (j = 0; j < __MAC_TXPWR_LMT_RU_PAGE_SIZE; j += 4) { +- addr = R_AX_PWR_RU_LMT + j + +- __MAC_TXPWR_LMT_RU_PAGE_SIZE * i; +- ptr = (s8 *)&lmt_ru[i] + j; +- +- val = FIELD_PREP(GENMASK(7, 0), ptr[0]) | +- FIELD_PREP(GENMASK(15, 8), ptr[1]) | +- FIELD_PREP(GENMASK(23, 16), ptr[2]) | +- FIELD_PREP(GENMASK(31, 24), ptr[3]); +- +- rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val); +- } +- } +- +-#undef __MAC_TXPWR_LMT_RU_PAGE_SIZE +-} +- + static void rtw8852a_set_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) + { +- rtw8852a_set_txpwr_byrate(rtwdev, chan, phy_idx); +- rtw8852a_set_txpwr_offset(rtwdev, chan, phy_idx); +- rtw8852a_set_txpwr_limit(rtwdev, chan, phy_idx); +- rtw8852a_set_txpwr_limit_ru(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx); + } + + static void rtw8852a_set_txpwr_ctrl(struct rtw89_dev *rtwdev, +@@ -2008,19 +1875,6 @@ static struct rtw89_btc_fbtc_mreg rtw89_ + }; + + static +-void rtw8852a_btc_bt_aci_imp(struct rtw89_dev *rtwdev) +-{ +- struct rtw89_btc *btc = &rtwdev->btc; +- struct rtw89_btc_dm *dm = &btc->dm; +- struct rtw89_btc_bt_info *bt = &btc->cx.bt; +- struct rtw89_btc_bt_link_info *b = &bt->link_info; +- +- /* fix LNA2 = level-5 for BT ACI issue at BTG */ +- if (btc->dm.wl_btg_rx && b->profile_cnt.now != 0) +- dm->trx_para_level = 1; +-} +- +-static + void rtw8852a_btc_update_bt_cnt(struct rtw89_dev *rtwdev) + { + struct rtw89_btc *btc = &rtwdev->btc; +@@ -2136,6 +1990,15 @@ static void rtw8852a_query_ppdu(struct r + rtw8852a_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); + } + ++#ifdef CONFIG_PM ++static const struct wiphy_wowlan_support rtw_wowlan_stub_8852a = { ++ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, ++ .n_patterns = RTW89_MAX_PATTERN_NUM, ++ .pattern_max_len = RTW89_MAX_PATTERN_SIZE, ++ .pattern_min_len = 1, ++}; ++#endif ++ + static const struct rtw89_chip_ops rtw8852a_chip_ops = { + .enable_bb_rf = rtw89_mac_enable_bb_rf, + .disable_bb_rf = rtw89_mac_disable_bb_rf, +@@ -2178,7 +2041,6 @@ static const struct rtw89_chip_ops rtw88 + .btc_set_wl_pri = rtw8852a_btc_set_wl_pri, + .btc_set_wl_txpwr_ctrl = rtw8852a_btc_set_wl_txpwr_ctrl, + .btc_get_bt_rssi = rtw8852a_btc_get_bt_rssi, +- .btc_bt_aci_imp = rtw8852a_btc_bt_aci_imp, + .btc_update_bt_cnt = rtw8852a_btc_update_bt_cnt, + .btc_wl_s1_standby = rtw8852a_btc_wl_s1_standby, + .btc_set_wl_rx_gain = rtw8852a_btc_set_wl_rx_gain, +@@ -2196,6 +2058,8 @@ const struct rtw89_chip_info rtw8852a_ch + .rsvd_ple_ofst = 0x6f800, + .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, + .dle_mem = rtw8852a_dle_mem_pcie, ++ .wde_qempty_acq_num = 16, ++ .wde_qempty_mgq_sel = 16, + .rf_base_addr = {0xc000, 0xd000}, + .pwr_on_seq = pwr_on_seq_8852a, + .pwr_off_seq = pwr_off_seq_8852a, +@@ -2218,6 +2082,7 @@ const struct rtw89_chip_info rtw8852a_ch + .support_bands = BIT(NL80211_BAND_2GHZ) | + BIT(NL80211_BAND_5GHZ), + .support_bw160 = false, ++ .support_ul_tb_ctrl = false, + .hw_sec_hdr = false, + .rf_path_num = 2, + .tx_nss = 2, +@@ -2279,11 +2144,15 @@ const struct rtw89_chip_info rtw8852a_ch + .c2h_ctrl_reg = R_AX_C2HREG_CTRL, + .c2h_regs = rtw8852a_c2h_regs, + .page_regs = &rtw8852a_page_regs, ++ .cfo_src_fd = false, + .dcfo_comp = &rtw8852a_dcfo_comp, + .dcfo_comp_sft = 3, + .imr_info = &rtw8852a_imr_info, + .rrsr_cfgs = &rtw8852a_rrsr_cfgs, + .dma_ch_mask = 0, ++#ifdef CONFIG_PM ++ .wowlan_stub = &rtw_wowlan_stub_8852a, ++#endif + }; + EXPORT_SYMBOL(rtw8852a_chip_info); + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852a.h linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852a.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852a.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852a.h 2022-12-24 00:49:25.782376835 +0200 +@@ -8,7 +8,6 @@ + #include "core.h" + + #define RF_PATH_NUM_8852A 2 +-#define NTX_NUM_8852A 2 + + enum rtw8852a_pmac_mode { + NONE_TEST, +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b.c 2022-12-24 00:49:25.782376835 +0200 +@@ -2,9 +2,46 @@ + /* Copyright(c) 2019-2022 Realtek Corporation + */ + +-#include "core.h" ++#include "coex.h" ++#include "fw.h" + #include "mac.h" ++#include "phy.h" + #include "reg.h" ++#include "rtw8852b.h" ++#include "rtw8852b_rfk.h" ++#include "rtw8852b_table.h" ++#include "txrx.h" ++ ++static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_pcie[] = { ++ {5, 343, grp_0}, /* ACH 0 */ ++ {5, 343, grp_0}, /* ACH 1 */ ++ {5, 343, grp_0}, /* ACH 2 */ ++ {5, 343, grp_0}, /* ACH 3 */ ++ {0, 0, grp_0}, /* ACH 4 */ ++ {0, 0, grp_0}, /* ACH 5 */ ++ {0, 0, grp_0}, /* ACH 6 */ ++ {0, 0, grp_0}, /* ACH 7 */ ++ {4, 344, grp_0}, /* B0MGQ */ ++ {4, 344, grp_0}, /* B0HIQ */ ++ {0, 0, grp_0}, /* B1MGQ */ ++ {0, 0, grp_0}, /* B1HIQ */ ++ {40, 0, 0} /* FWCMDQ */ ++}; ++ ++static const struct rtw89_hfc_pub_cfg rtw8852b_hfc_pubcfg_pcie = { ++ 448, /* Group 0 */ ++ 0, /* Group 1 */ ++ 448, /* Public Max */ ++ 0 /* WP threshold */ ++}; ++ ++static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_pcie[] = { ++ [RTW89_QTA_SCC] = {rtw8852b_hfc_chcfg_pcie, &rtw8852b_hfc_pubcfg_pcie, ++ &rtw89_mac_size.hfc_preccfg_pcie, RTW89_HCIFC_POH}, ++ [RTW89_QTA_DLFW] = {NULL, NULL, &rtw89_mac_size.hfc_preccfg_pcie, ++ RTW89_HCIFC_POH}, ++ [RTW89_QTA_INVALID] = {NULL}, ++}; + + static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size6, +@@ -19,6 +56,2275 @@ static const struct rtw89_dle_mem rtw885 + NULL}, + }; + ++static const struct rtw89_reg3_def rtw8852b_pmac_ht20_mcs7_tbl[] = { ++ {0x4580, 0x0000ffff, 0x0}, ++ {0x4580, 0xffff0000, 0x0}, ++ {0x4584, 0x0000ffff, 0x0}, ++ {0x4584, 0xffff0000, 0x0}, ++ {0x4580, 0x0000ffff, 0x1}, ++ {0x4578, 0x00ffffff, 0x2018b}, ++ {0x4570, 0x03ffffff, 0x7}, ++ {0x4574, 0x03ffffff, 0x32407}, ++ {0x45b8, 0x00000010, 0x0}, ++ {0x45b8, 0x00000100, 0x0}, ++ {0x45b8, 0x00000080, 0x0}, ++ {0x45b8, 0x00000008, 0x0}, ++ {0x45a0, 0x0000ff00, 0x0}, ++ {0x45a0, 0xff000000, 0x1}, ++ {0x45a4, 0x0000ff00, 0x2}, ++ {0x45a4, 0xff000000, 0x3}, ++ {0x45b8, 0x00000020, 0x0}, ++ {0x4568, 0xe0000000, 0x0}, ++ {0x45b8, 0x00000002, 0x1}, ++ {0x456c, 0xe0000000, 0x0}, ++ {0x45b4, 0x00006000, 0x0}, ++ {0x45b4, 0x00001800, 0x1}, ++ {0x45b8, 0x00000040, 0x0}, ++ {0x45b8, 0x00000004, 0x0}, ++ {0x45b8, 0x00000200, 0x0}, ++ {0x4598, 0xf8000000, 0x0}, ++ {0x45b8, 0x00100000, 0x0}, ++ {0x45a8, 0x00000fc0, 0x0}, ++ {0x45b8, 0x00200000, 0x0}, ++ {0x45b0, 0x00000038, 0x0}, ++ {0x45b0, 0x000001c0, 0x0}, ++ {0x45a0, 0x000000ff, 0x0}, ++ {0x45b8, 0x00400000, 0x0}, ++ {0x4590, 0x000007ff, 0x0}, ++ {0x45b0, 0x00000e00, 0x0}, ++ {0x45ac, 0x0000001f, 0x0}, ++ {0x45b8, 0x00800000, 0x0}, ++ {0x45a8, 0x0003f000, 0x0}, ++ {0x45b8, 0x01000000, 0x0}, ++ {0x45b0, 0x00007000, 0x0}, ++ {0x45b0, 0x00038000, 0x0}, ++ {0x45a0, 0x00ff0000, 0x0}, ++ {0x45b8, 0x02000000, 0x0}, ++ {0x4590, 0x003ff800, 0x0}, ++ {0x45b0, 0x001c0000, 0x0}, ++ {0x45ac, 0x000003e0, 0x0}, ++ {0x45b8, 0x04000000, 0x0}, ++ {0x45a8, 0x00fc0000, 0x0}, ++ {0x45b8, 0x08000000, 0x0}, ++ {0x45b0, 0x00e00000, 0x0}, ++ {0x45b0, 0x07000000, 0x0}, ++ {0x45a4, 0x000000ff, 0x0}, ++ {0x45b8, 0x10000000, 0x0}, ++ {0x4594, 0x000007ff, 0x0}, ++ {0x45b0, 0x38000000, 0x0}, ++ {0x45ac, 0x00007c00, 0x0}, ++ {0x45b8, 0x20000000, 0x0}, ++ {0x45a8, 0x3f000000, 0x0}, ++ {0x45b8, 0x40000000, 0x0}, ++ {0x45b4, 0x00000007, 0x0}, ++ {0x45b4, 0x00000038, 0x0}, ++ {0x45a4, 0x00ff0000, 0x0}, ++ {0x45b8, 0x80000000, 0x0}, ++ {0x4594, 0x003ff800, 0x0}, ++ {0x45b4, 0x000001c0, 0x0}, ++ {0x4598, 0xf8000000, 0x0}, ++ {0x45b8, 0x00100000, 0x0}, ++ {0x45a8, 0x00000fc0, 0x7}, ++ {0x45b8, 0x00200000, 0x0}, ++ {0x45b0, 0x00000038, 0x0}, ++ {0x45b0, 0x000001c0, 0x0}, ++ {0x45a0, 0x000000ff, 0x0}, ++ {0x45b4, 0x06000000, 0x0}, ++ {0x45b0, 0x00000007, 0x0}, ++ {0x45b8, 0x00080000, 0x0}, ++ {0x45a8, 0x0000003f, 0x0}, ++ {0x457c, 0xffe00000, 0x1}, ++ {0x4530, 0xffffffff, 0x0}, ++ {0x4588, 0x00003fff, 0x0}, ++ {0x4598, 0x000001ff, 0x0}, ++ {0x4534, 0xffffffff, 0x0}, ++ {0x4538, 0xffffffff, 0x0}, ++ {0x453c, 0xffffffff, 0x0}, ++ {0x4588, 0x0fffc000, 0x0}, ++ {0x4598, 0x0003fe00, 0x0}, ++ {0x4540, 0xffffffff, 0x0}, ++ {0x4544, 0xffffffff, 0x0}, ++ {0x4548, 0xffffffff, 0x0}, ++ {0x458c, 0x00003fff, 0x0}, ++ {0x4598, 0x07fc0000, 0x0}, ++ {0x454c, 0xffffffff, 0x0}, ++ {0x4550, 0xffffffff, 0x0}, ++ {0x4554, 0xffffffff, 0x0}, ++ {0x458c, 0x0fffc000, 0x0}, ++ {0x459c, 0x000001ff, 0x0}, ++ {0x4558, 0xffffffff, 0x0}, ++ {0x455c, 0xffffffff, 0x0}, ++ {0x4530, 0xffffffff, 0x4e790001}, ++ {0x4588, 0x00003fff, 0x0}, ++ {0x4598, 0x000001ff, 0x1}, ++ {0x4534, 0xffffffff, 0x0}, ++ {0x4538, 0xffffffff, 0x4b}, ++ {0x45ac, 0x38000000, 0x7}, ++ {0x4588, 0xf0000000, 0x0}, ++ {0x459c, 0x7e000000, 0x0}, ++ {0x45b8, 0x00040000, 0x0}, ++ {0x45b8, 0x00020000, 0x0}, ++ {0x4590, 0xffc00000, 0x0}, ++ {0x45b8, 0x00004000, 0x0}, ++ {0x4578, 0xff000000, 0x0}, ++ {0x45b8, 0x00000400, 0x0}, ++ {0x45b8, 0x00000800, 0x0}, ++ {0x45b8, 0x00001000, 0x0}, ++ {0x45b8, 0x00002000, 0x0}, ++ {0x45b4, 0x00018000, 0x0}, ++ {0x45ac, 0x07800000, 0x0}, ++ {0x45b4, 0x00000600, 0x2}, ++ {0x459c, 0x0001fe00, 0x80}, ++ {0x45ac, 0x00078000, 0x3}, ++ {0x459c, 0x01fe0000, 0x1}, ++}; ++ ++static const struct rtw89_reg3_def rtw8852b_btc_preagc_en_defs[] = { ++ {0x46D0, GENMASK(1, 0), 0x3}, ++ {0x4790, GENMASK(1, 0), 0x3}, ++ {0x4AD4, GENMASK(31, 0), 0xf}, ++ {0x4AE0, GENMASK(31, 0), 0xf}, ++ {0x4688, GENMASK(31, 24), 0x80}, ++ {0x476C, GENMASK(31, 24), 0x80}, ++ {0x4694, GENMASK(7, 0), 0x80}, ++ {0x4694, GENMASK(15, 8), 0x80}, ++ {0x4778, GENMASK(7, 0), 0x80}, ++ {0x4778, GENMASK(15, 8), 0x80}, ++ {0x4AE4, GENMASK(23, 0), 0x780D1E}, ++ {0x4AEC, GENMASK(23, 0), 0x780D1E}, ++ {0x469C, GENMASK(31, 26), 0x34}, ++ {0x49F0, GENMASK(31, 26), 0x34}, ++}; ++ ++static DECLARE_PHY_REG3_TBL(rtw8852b_btc_preagc_en_defs); ++ ++static const struct rtw89_reg3_def rtw8852b_btc_preagc_dis_defs[] = { ++ {0x46D0, GENMASK(1, 0), 0x0}, ++ {0x4790, GENMASK(1, 0), 0x0}, ++ {0x4AD4, GENMASK(31, 0), 0x60}, ++ {0x4AE0, GENMASK(31, 0), 0x60}, ++ {0x4688, GENMASK(31, 24), 0x1a}, ++ {0x476C, GENMASK(31, 24), 0x1a}, ++ {0x4694, GENMASK(7, 0), 0x2a}, ++ {0x4694, GENMASK(15, 8), 0x2a}, ++ {0x4778, GENMASK(7, 0), 0x2a}, ++ {0x4778, GENMASK(15, 8), 0x2a}, ++ {0x4AE4, GENMASK(23, 0), 0x79E99E}, ++ {0x4AEC, GENMASK(23, 0), 0x79E99E}, ++ {0x469C, GENMASK(31, 26), 0x26}, ++ {0x49F0, GENMASK(31, 26), 0x26}, ++}; ++ ++static DECLARE_PHY_REG3_TBL(rtw8852b_btc_preagc_dis_defs); ++ ++static const u32 rtw8852b_h2c_regs[RTW89_H2CREG_MAX] = { ++ R_AX_H2CREG_DATA0, R_AX_H2CREG_DATA1, R_AX_H2CREG_DATA2, ++ R_AX_H2CREG_DATA3 ++}; ++ ++static const u32 rtw8852b_c2h_regs[RTW89_C2HREG_MAX] = { ++ R_AX_C2HREG_DATA0, R_AX_C2HREG_DATA1, R_AX_C2HREG_DATA2, ++ R_AX_C2HREG_DATA3 ++}; ++ ++static const struct rtw89_page_regs rtw8852b_page_regs = { ++ .hci_fc_ctrl = R_AX_HCI_FC_CTRL, ++ .ch_page_ctrl = R_AX_CH_PAGE_CTRL, ++ .ach_page_ctrl = R_AX_ACH0_PAGE_CTRL, ++ .ach_page_info = R_AX_ACH0_PAGE_INFO, ++ .pub_page_info3 = R_AX_PUB_PAGE_INFO3, ++ .pub_page_ctrl1 = R_AX_PUB_PAGE_CTRL1, ++ .pub_page_ctrl2 = R_AX_PUB_PAGE_CTRL2, ++ .pub_page_info1 = R_AX_PUB_PAGE_INFO1, ++ .pub_page_info2 = R_AX_PUB_PAGE_INFO2, ++ .wp_page_ctrl1 = R_AX_WP_PAGE_CTRL1, ++ .wp_page_ctrl2 = R_AX_WP_PAGE_CTRL2, ++ .wp_page_info1 = R_AX_WP_PAGE_INFO1, ++}; ++ ++static const struct rtw89_reg_def rtw8852b_dcfo_comp = { ++ R_DCFO_COMP_S0, B_DCFO_COMP_S0_MSK ++}; ++ ++static const struct rtw89_imr_info rtw8852b_imr_info = { ++ .wdrls_imr_set = B_AX_WDRLS_IMR_SET, ++ .wsec_imr_reg = R_AX_SEC_DEBUG, ++ .wsec_imr_set = B_AX_IMR_ERROR, ++ .mpdu_tx_imr_set = 0, ++ .mpdu_rx_imr_set = 0, ++ .sta_sch_imr_set = B_AX_STA_SCHEDULER_IMR_SET, ++ .txpktctl_imr_b0_reg = R_AX_TXPKTCTL_ERR_IMR_ISR, ++ .txpktctl_imr_b0_clr = B_AX_TXPKTCTL_IMR_B0_CLR, ++ .txpktctl_imr_b0_set = B_AX_TXPKTCTL_IMR_B0_SET, ++ .txpktctl_imr_b1_reg = R_AX_TXPKTCTL_ERR_IMR_ISR_B1, ++ .txpktctl_imr_b1_clr = B_AX_TXPKTCTL_IMR_B1_CLR, ++ .txpktctl_imr_b1_set = B_AX_TXPKTCTL_IMR_B1_SET, ++ .wde_imr_clr = B_AX_WDE_IMR_CLR, ++ .wde_imr_set = B_AX_WDE_IMR_SET, ++ .ple_imr_clr = B_AX_PLE_IMR_CLR, ++ .ple_imr_set = B_AX_PLE_IMR_SET, ++ .host_disp_imr_clr = B_AX_HOST_DISP_IMR_CLR, ++ .host_disp_imr_set = B_AX_HOST_DISP_IMR_SET, ++ .cpu_disp_imr_clr = B_AX_CPU_DISP_IMR_CLR, ++ .cpu_disp_imr_set = B_AX_CPU_DISP_IMR_SET, ++ .other_disp_imr_clr = B_AX_OTHER_DISP_IMR_CLR, ++ .other_disp_imr_set = 0, ++ .bbrpt_com_err_imr_reg = R_AX_BBRPT_COM_ERR_IMR_ISR, ++ .bbrpt_chinfo_err_imr_reg = R_AX_BBRPT_CHINFO_ERR_IMR_ISR, ++ .bbrpt_err_imr_set = 0, ++ .bbrpt_dfs_err_imr_reg = R_AX_BBRPT_DFS_ERR_IMR_ISR, ++ .ptcl_imr_clr = B_AX_PTCL_IMR_CLR_ALL, ++ .ptcl_imr_set = B_AX_PTCL_IMR_SET, ++ .cdma_imr_0_reg = R_AX_DLE_CTRL, ++ .cdma_imr_0_clr = B_AX_DLE_IMR_CLR, ++ .cdma_imr_0_set = B_AX_DLE_IMR_SET, ++ .cdma_imr_1_reg = 0, ++ .cdma_imr_1_clr = 0, ++ .cdma_imr_1_set = 0, ++ .phy_intf_imr_reg = R_AX_PHYINFO_ERR_IMR, ++ .phy_intf_imr_clr = 0, ++ .phy_intf_imr_set = 0, ++ .rmac_imr_reg = R_AX_RMAC_ERR_ISR, ++ .rmac_imr_clr = B_AX_RMAC_IMR_CLR, ++ .rmac_imr_set = B_AX_RMAC_IMR_SET, ++ .tmac_imr_reg = R_AX_TMAC_ERR_IMR_ISR, ++ .tmac_imr_clr = B_AX_TMAC_IMR_CLR, ++ .tmac_imr_set = B_AX_TMAC_IMR_SET, ++}; ++ ++static const struct rtw89_rrsr_cfgs rtw8852b_rrsr_cfgs = { ++ .ref_rate = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_REF_RATE_SEL, 0}, ++ .rsc = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_RSC_MASK, 2}, ++}; ++ ++static const struct rtw89_dig_regs rtw8852b_dig_regs = { ++ .seg0_pd_reg = R_SEG0R_PD_V1, ++ .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK, ++ .pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1, ++ .p0_lna_init = {R_PATH0_LNA_INIT_V1, B_PATH0_LNA_INIT_IDX_MSK}, ++ .p1_lna_init = {R_PATH1_LNA_INIT_V1, B_PATH1_LNA_INIT_IDX_MSK}, ++ .p0_tia_init = {R_PATH0_TIA_INIT_V1, B_PATH0_TIA_INIT_IDX_MSK_V1}, ++ .p1_tia_init = {R_PATH1_TIA_INIT_V1, B_PATH1_TIA_INIT_IDX_MSK_V1}, ++ .p0_rxb_init = {R_PATH0_RXB_INIT_V1, B_PATH0_RXB_INIT_IDX_MSK_V1}, ++ .p1_rxb_init = {R_PATH1_RXB_INIT_V1, B_PATH1_RXB_INIT_IDX_MSK_V1}, ++ .p0_p20_pagcugc_en = {R_PATH0_P20_FOLLOW_BY_PAGCUGC_V2, ++ B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK}, ++ .p0_s20_pagcugc_en = {R_PATH0_S20_FOLLOW_BY_PAGCUGC_V2, ++ B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, ++ .p1_p20_pagcugc_en = {R_PATH1_P20_FOLLOW_BY_PAGCUGC_V2, ++ B_PATH1_P20_FOLLOW_BY_PAGCUGC_EN_MSK}, ++ .p1_s20_pagcugc_en = {R_PATH1_S20_FOLLOW_BY_PAGCUGC_V2, ++ B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, ++}; ++ ++static const struct rtw89_btc_rf_trx_para rtw89_btc_8852b_rf_ul[] = { ++ {255, 0, 0, 7}, /* 0 -> original */ ++ {255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */ ++ {255, 0, 0, 7}, /* 2 ->reserved for shared-antenna */ ++ {255, 0, 0, 7}, /* 3- >reserved for shared-antenna */ ++ {255, 0, 0, 7}, /* 4 ->reserved for shared-antenna */ ++ {255, 0, 0, 7}, /* the below id is for non-shared-antenna free-run */ ++ {6, 1, 0, 7}, ++ {13, 1, 0, 7}, ++ {13, 1, 0, 7} ++}; ++ ++static const struct rtw89_btc_rf_trx_para rtw89_btc_8852b_rf_dl[] = { ++ {255, 0, 0, 7}, /* 0 -> original */ ++ {255, 2, 0, 7}, /* 1 -> reserved for shared-antenna */ ++ {255, 0, 0, 7}, /* 2 ->reserved for shared-antenna */ ++ {255, 0, 0, 7}, /* 3- >reserved for shared-antenna */ ++ {255, 0, 0, 7}, /* 4 ->reserved for shared-antenna */ ++ {255, 0, 0, 7}, /* the below id is for non-shared-antenna free-run */ ++ {255, 1, 0, 7}, ++ {255, 1, 0, 7}, ++ {255, 1, 0, 7} ++}; ++ ++static const struct rtw89_btc_fbtc_mreg rtw89_btc_8852b_mon_reg[] = { ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda24), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda28), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda2c), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda30), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda4c), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda10), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda20), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda34), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xcef4), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0x8424), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xd200), ++ RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xd220), ++ RTW89_DEF_FBTC_MREG(REG_BB, 4, 0x980), ++ RTW89_DEF_FBTC_MREG(REG_BT_MODEM, 4, 0x178), ++}; ++ ++static const u8 rtw89_btc_8852b_wl_rssi_thres[BTC_WL_RSSI_THMAX] = {70, 60, 50, 40}; ++static const u8 rtw89_btc_8852b_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30, 20}; ++ ++static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) ++{ ++ u32 val32; ++ u32 ret; ++ ++ rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_AFSM_WLSUS_EN | ++ B_AX_AFSM_PCIE_SUS_EN); ++ rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_DIS_WLBT_PDNSUSEN_SOPC); ++ rtw89_write32_set(rtwdev, R_AX_WLLPS_CTRL, B_AX_DIS_WLBT_LPSEN_LOPC); ++ rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APDM_HPDN); ++ rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); ++ ++ ret = read_poll_timeout(rtw89_read32, val32, val32 & B_AX_RDY_SYSPWR, ++ 1000, 20000, false, rtwdev, R_AX_SYS_PW_CTRL); ++ if (ret) ++ return ret; ++ ++ rtw89_write32_set(rtwdev, R_AX_AFE_LDO_CTRL, B_AX_AON_OFF_PC_EN); ++ ret = read_poll_timeout(rtw89_read32, val32, val32 & B_AX_AON_OFF_PC_EN, ++ 1000, 20000, false, rtwdev, R_AX_AFE_LDO_CTRL); ++ if (ret) ++ return ret; ++ ++ rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, B_AX_C1_L1_MASK, 0x1); ++ rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_OFF_CTRL0, B_AX_C3_L1_MASK, 0x3); ++ rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_EN_WLON); ++ rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFN_ONMAC); ++ ++ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_AX_APFN_ONMAC), ++ 1000, 20000, false, rtwdev, R_AX_SYS_PW_CTRL); ++ if (ret) ++ return ret; ++ ++ rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); ++ rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); ++ rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); ++ rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); ++ ++ rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); ++ rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); ++ ++ rtw89_write32_set(rtwdev, R_AX_SYS_ADIE_PAD_PWR_CTRL, B_AX_SYM_PADPDN_WL_PTA_1P3); ++ ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, ++ XTAL_SI_GND_SHDN_WL, XTAL_SI_GND_SHDN_WL); ++ if (ret) ++ return ret; ++ ++ rtw89_write32_set(rtwdev, R_AX_SYS_ADIE_PAD_PWR_CTRL, B_AX_SYM_PADPDN_WL_RFC_1P3); ++ ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, ++ XTAL_SI_SHDN_WL, XTAL_SI_SHDN_WL); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_OFF_WEI, ++ XTAL_SI_OFF_WEI); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_OFF_EI, ++ XTAL_SI_OFF_EI); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_RFC2RF); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_PON_WEI, ++ XTAL_SI_PON_WEI); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_PON_EI, ++ XTAL_SI_PON_EI); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_SRAM2RFC); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_SRAM_CTRL, 0, XTAL_SI_SRAM_DIS); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_XMD_2, 0, XTAL_SI_LDO_LPS); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_XMD_4, 0, XTAL_SI_LPS_CAP); ++ if (ret) ++ return ret; ++ ++ rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); ++ rtw89_write32_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE); ++ rtw89_write32_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15); ++ ++ fsleep(1000); ++ ++ rtw89_write32_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14); ++ rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); ++ ++ if (!rtwdev->efuse.valid || rtwdev->efuse.power_k_valid) ++ goto func_en; ++ ++ rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_VOL_L1_MASK, 0x9); ++ rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_VREFPFM_L_MASK, 0xA); ++ ++ if (rtwdev->hal.cv == CHIP_CBV) { ++ rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); ++ rtw89_write16_mask(rtwdev, R_AX_HCI_LDO_CTRL, B_AX_R_AX_VADJ_MASK, 0xA); ++ rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); ++ } ++ ++func_en: ++ rtw89_write32_set(rtwdev, R_AX_DMAC_FUNC_EN, ++ B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_MPDU_PROC_EN | ++ B_AX_WD_RLS_EN | B_AX_DLE_WDE_EN | B_AX_TXPKT_CTRL_EN | ++ B_AX_STA_SCH_EN | B_AX_DLE_PLE_EN | B_AX_PKT_BUF_EN | ++ B_AX_DMAC_TBL_EN | B_AX_PKT_IN_EN | B_AX_DLE_CPUIO_EN | ++ B_AX_DISPATCHER_EN | B_AX_BBRPT_EN | B_AX_MAC_SEC_EN | ++ B_AX_DMACREG_GCKEN); ++ rtw89_write32_set(rtwdev, R_AX_CMAC_FUNC_EN, ++ B_AX_CMAC_EN | B_AX_CMAC_TXEN | B_AX_CMAC_RXEN | ++ B_AX_FORCE_CMACREG_GCKEN | B_AX_PHYINTF_EN | B_AX_CMAC_DMA_EN | ++ B_AX_PTCLTOP_EN | B_AX_SCHEDULER_EN | B_AX_TMAC_EN | ++ B_AX_RMAC_EN); ++ ++ rtw89_write32_mask(rtwdev, R_AX_EECS_EESK_FUNC_SEL, B_AX_PINMUX_EESK_FUNC_SEL_MASK, ++ PINMUX_EESK_FUNC_SEL_BT_LOG); ++ ++ return 0; ++} ++ ++static int rtw8852b_pwr_off_func(struct rtw89_dev *rtwdev) ++{ ++ u32 val32; ++ u32 ret; ++ ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF, ++ XTAL_SI_RFC2RF); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_OFF_EI); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_OFF_WEI); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0, XTAL_SI_RF00); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0, XTAL_SI_RF10); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_SRAM2RFC, ++ XTAL_SI_SRAM2RFC); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_PON_EI); ++ if (ret) ++ return ret; ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_PON_WEI); ++ if (ret) ++ return ret; ++ ++ rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_EN_WLON); ++ rtw89_write8_clr(rtwdev, R_AX_SYS_FUNC_EN, B_AX_FEN_BB_GLB_RSTN | B_AX_FEN_BBRSTB); ++ rtw89_write32_clr(rtwdev, R_AX_SYS_ADIE_PAD_PWR_CTRL, B_AX_SYM_PADPDN_WL_RFC_1P3); ++ ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_SHDN_WL); ++ if (ret) ++ return ret; ++ ++ rtw89_write32_clr(rtwdev, R_AX_SYS_ADIE_PAD_PWR_CTRL, B_AX_SYM_PADPDN_WL_PTA_1P3); ++ ++ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_GND_SHDN_WL); ++ if (ret) ++ return ret; ++ ++ rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_OFFMAC); ++ ++ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_AX_APFM_OFFMAC), ++ 1000, 20000, false, rtwdev, R_AX_SYS_PW_CTRL); ++ if (ret) ++ return ret; ++ ++ rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); ++ rtw89_write32_set(rtwdev, R_AX_SYS_SWR_CTRL1, B_AX_SYM_CTRL_SPS_PWMFREQ); ++ rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_REG_ZCDC_H_MASK, 0x3); ++ rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); ++ ++ return 0; ++} ++ ++static void rtw8852be_efuse_parsing(struct rtw89_efuse *efuse, ++ struct rtw8852b_efuse *map) ++{ ++ ether_addr_copy(efuse->addr, map->e.mac_addr); ++ efuse->rfe_type = map->rfe_type; ++ efuse->xtal_cap = map->xtal_k; ++} ++ ++static void rtw8852b_efuse_parsing_tssi(struct rtw89_dev *rtwdev, ++ struct rtw8852b_efuse *map) ++{ ++ struct rtw89_tssi_info *tssi = &rtwdev->tssi; ++ struct rtw8852b_tssi_offset *ofst[] = {&map->path_a_tssi, &map->path_b_tssi}; ++ u8 i, j; ++ ++ tssi->thermal[RF_PATH_A] = map->path_a_therm; ++ tssi->thermal[RF_PATH_B] = map->path_b_therm; ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) { ++ memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi, ++ sizeof(ofst[i]->cck_tssi)); ++ ++ for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++) ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n", ++ i, j, tssi->tssi_cck[i][j]); ++ ++ memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi, ++ sizeof(ofst[i]->bw40_tssi)); ++ memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM, ++ ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g)); ++ ++ for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++) ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n", ++ i, j, tssi->tssi_mcs[i][j]); ++ } ++} ++ ++static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low) ++{ ++ if (high) ++ *high = sign_extend32(FIELD_GET(GENMASK(7, 4), data), 3); ++ if (low) ++ *low = sign_extend32(FIELD_GET(GENMASK(3, 0), data), 3); ++ ++ return data != 0xff; ++} ++ ++static void rtw8852b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, ++ struct rtw8852b_efuse *map) ++{ ++ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; ++ bool valid = false; ++ ++ valid |= _decode_efuse_gain(map->rx_gain_2g_cck, ++ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK], ++ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_CCK]); ++ valid |= _decode_efuse_gain(map->rx_gain_2g_ofdm, ++ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM], ++ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_OFDM]); ++ valid |= _decode_efuse_gain(map->rx_gain_5g_low, ++ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW], ++ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_LOW]); ++ valid |= _decode_efuse_gain(map->rx_gain_5g_mid, ++ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID], ++ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_MID]); ++ valid |= _decode_efuse_gain(map->rx_gain_5g_high, ++ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH], ++ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH]); ++ ++ gain->offset_valid = valid; ++} ++ ++static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) ++{ ++ struct rtw89_efuse *efuse = &rtwdev->efuse; ++ struct rtw8852b_efuse *map; ++ ++ map = (struct rtw8852b_efuse *)log_map; ++ ++ efuse->country_code[0] = map->country_code[0]; ++ efuse->country_code[1] = map->country_code[1]; ++ rtw8852b_efuse_parsing_tssi(rtwdev, map); ++ rtw8852b_efuse_parsing_gain_offset(rtwdev, map); ++ ++ switch (rtwdev->hci.type) { ++ case RTW89_HCI_TYPE_PCIE: ++ rtw8852be_efuse_parsing(efuse, map); ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); ++ ++ return 0; ++} ++ ++static void rtw8852b_phycap_parsing_power_cal(struct rtw89_dev *rtwdev, u8 *phycap_map) ++{ ++#define PWR_K_CHK_OFFSET 0x5E9 ++#define PWR_K_CHK_VALUE 0xAA ++ u32 offset = PWR_K_CHK_OFFSET - rtwdev->chip->phycap_addr; ++ ++ if (phycap_map[offset] == PWR_K_CHK_VALUE) ++ rtwdev->efuse.power_k_valid = true; ++} ++ ++static void rtw8852b_phycap_parsing_tssi(struct rtw89_dev *rtwdev, u8 *phycap_map) ++{ ++ struct rtw89_tssi_info *tssi = &rtwdev->tssi; ++ static const u32 tssi_trim_addr[RF_PATH_NUM_8852B] = {0x5D6, 0x5AB}; ++ u32 addr = rtwdev->chip->phycap_addr; ++ bool pg = false; ++ u32 ofst; ++ u8 i, j; ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) { ++ for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) { ++ /* addrs are in decreasing order */ ++ ofst = tssi_trim_addr[i] - addr - j; ++ tssi->tssi_trim[i][j] = phycap_map[ofst]; ++ ++ if (phycap_map[ofst] != 0xff) ++ pg = true; ++ } ++ } ++ ++ if (!pg) { ++ memset(tssi->tssi_trim, 0, sizeof(tssi->tssi_trim)); ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM] no PG, set all trim info to 0\n"); ++ } ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) ++ for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] path=%d idx=%d trim=0x%x addr=0x%x\n", ++ i, j, tssi->tssi_trim[i][j], ++ tssi_trim_addr[i] - j); ++} ++ ++static void rtw8852b_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev, ++ u8 *phycap_map) ++{ ++ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; ++ static const u32 thm_trim_addr[RF_PATH_NUM_8852B] = {0x5DF, 0x5DC}; ++ u32 addr = rtwdev->chip->phycap_addr; ++ u8 i; ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) { ++ info->thermal_trim[i] = phycap_map[thm_trim_addr[i] - addr]; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[THERMAL][TRIM] path=%d thermal_trim=0x%x\n", ++ i, info->thermal_trim[i]); ++ ++ if (info->thermal_trim[i] != 0xff) ++ info->pg_thermal_trim = true; ++ } ++} ++ ++static void rtw8852b_thermal_trim(struct rtw89_dev *rtwdev) ++{ ++#define __thm_setting(raw) \ ++({ \ ++ u8 __v = (raw); \ ++ ((__v & 0x1) << 3) | ((__v & 0x1f) >> 1); \ ++}) ++ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; ++ u8 i, val; ++ ++ if (!info->pg_thermal_trim) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[THERMAL][TRIM] no PG, do nothing\n"); ++ ++ return; ++ } ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) { ++ val = __thm_setting(info->thermal_trim[i]); ++ rtw89_write_rf(rtwdev, i, RR_TM2, RR_TM2_OFF, val); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[THERMAL][TRIM] path=%d thermal_setting=0x%x\n", ++ i, val); ++ } ++#undef __thm_setting ++} ++ ++static void rtw8852b_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, ++ u8 *phycap_map) ++{ ++ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; ++ static const u32 pabias_trim_addr[RF_PATH_NUM_8852B] = {0x5DE, 0x5DB}; ++ u32 addr = rtwdev->chip->phycap_addr; ++ u8 i; ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) { ++ info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr]; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n", ++ i, info->pa_bias_trim[i]); ++ ++ if (info->pa_bias_trim[i] != 0xff) ++ info->pg_pa_bias_trim = true; ++ } ++} ++ ++static void rtw8852b_pa_bias_trim(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; ++ u8 pabias_2g, pabias_5g; ++ u8 i; ++ ++ if (!info->pg_pa_bias_trim) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[PA_BIAS][TRIM] no PG, do nothing\n"); ++ ++ return; ++ } ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) { ++ pabias_2g = FIELD_GET(GENMASK(3, 0), info->pa_bias_trim[i]); ++ pabias_5g = FIELD_GET(GENMASK(7, 4), info->pa_bias_trim[i]); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n", ++ i, pabias_2g, pabias_5g); ++ ++ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG, pabias_2g); ++ rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA, pabias_5g); ++ } ++} ++ ++static void rtw8852b_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phycap_map) ++{ ++ static const u32 comp_addrs[][RTW89_SUBBAND_2GHZ_5GHZ_NR] = { ++ {0x5BB, 0x5BA, 0, 0x5B9, 0x5B8}, ++ {0x590, 0x58F, 0, 0x58E, 0x58D}, ++ }; ++ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; ++ u32 phycap_addr = rtwdev->chip->phycap_addr; ++ bool valid = false; ++ int path, i; ++ u8 data; ++ ++ for (path = 0; path < 2; path++) ++ for (i = 0; i < RTW89_SUBBAND_2GHZ_5GHZ_NR; i++) { ++ if (comp_addrs[path][i] == 0) ++ continue; ++ ++ data = phycap_map[comp_addrs[path][i] - phycap_addr]; ++ valid |= _decode_efuse_gain(data, NULL, ++ &gain->comp[path][i]); ++ } ++ ++ gain->comp_valid = valid; ++} ++ ++static int rtw8852b_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) ++{ ++ rtw8852b_phycap_parsing_power_cal(rtwdev, phycap_map); ++ rtw8852b_phycap_parsing_tssi(rtwdev, phycap_map); ++ rtw8852b_phycap_parsing_thermal_trim(rtwdev, phycap_map); ++ rtw8852b_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); ++ rtw8852b_phycap_parsing_gain_comp(rtwdev, phycap_map); ++ ++ return 0; ++} ++ ++static void rtw8852b_power_trim(struct rtw89_dev *rtwdev) ++{ ++ rtw8852b_thermal_trim(rtwdev); ++ rtw8852b_pa_bias_trim(rtwdev); ++} ++ ++static void rtw8852b_set_channel_mac(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ u8 mac_idx) ++{ ++ u32 rf_mod = rtw89_mac_reg_by_idx(R_AX_WMAC_RFMOD, mac_idx); ++ u32 sub_carr = rtw89_mac_reg_by_idx(R_AX_TX_SUB_CARRIER_VALUE, mac_idx); ++ u32 chk_rate = rtw89_mac_reg_by_idx(R_AX_TXRATE_CHK, mac_idx); ++ u8 txsc20 = 0, txsc40 = 0; ++ ++ switch (chan->band_width) { ++ case RTW89_CHANNEL_WIDTH_80: ++ txsc40 = rtw89_phy_get_txsc(rtwdev, chan, RTW89_CHANNEL_WIDTH_40); ++ fallthrough; ++ case RTW89_CHANNEL_WIDTH_40: ++ txsc20 = rtw89_phy_get_txsc(rtwdev, chan, RTW89_CHANNEL_WIDTH_20); ++ break; ++ default: ++ break; ++ } ++ ++ switch (chan->band_width) { ++ case RTW89_CHANNEL_WIDTH_80: ++ rtw89_write8_mask(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK, BIT(1)); ++ rtw89_write32(rtwdev, sub_carr, txsc20 | (txsc40 << 4)); ++ break; ++ case RTW89_CHANNEL_WIDTH_40: ++ rtw89_write8_mask(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK, BIT(0)); ++ rtw89_write32(rtwdev, sub_carr, txsc20); ++ break; ++ case RTW89_CHANNEL_WIDTH_20: ++ rtw89_write8_clr(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK); ++ rtw89_write32(rtwdev, sub_carr, 0); ++ break; ++ default: ++ break; ++ } ++ ++ if (chan->channel > 14) { ++ rtw89_write8_clr(rtwdev, chk_rate, B_AX_BAND_MODE); ++ rtw89_write8_set(rtwdev, chk_rate, ++ B_AX_CHECK_CCK_EN | B_AX_RTS_LIMIT_IN_OFDM6); ++ } else { ++ rtw89_write8_set(rtwdev, chk_rate, B_AX_BAND_MODE); ++ rtw89_write8_clr(rtwdev, chk_rate, ++ B_AX_CHECK_CCK_EN | B_AX_RTS_LIMIT_IN_OFDM6); ++ } ++} ++ ++static const u32 rtw8852b_sco_barker_threshold[14] = { ++ 0x1cfea, 0x1d0e1, 0x1d1d7, 0x1d2cd, 0x1d3c3, 0x1d4b9, 0x1d5b0, 0x1d6a6, ++ 0x1d79c, 0x1d892, 0x1d988, 0x1da7f, 0x1db75, 0x1ddc4 ++}; ++ ++static const u32 rtw8852b_sco_cck_threshold[14] = { ++ 0x27de3, 0x27f35, 0x28088, 0x281da, 0x2832d, 0x2847f, 0x285d2, 0x28724, ++ 0x28877, 0x289c9, 0x28b1c, 0x28c6e, 0x28dc1, 0x290ed ++}; ++ ++static void rtw8852b_ctrl_sco_cck(struct rtw89_dev *rtwdev, u8 primary_ch) ++{ ++ u8 ch_element = primary_ch - 1; ++ ++ rtw89_phy_write32_mask(rtwdev, R_RXSCOBC, B_RXSCOBC_TH, ++ rtw8852b_sco_barker_threshold[ch_element]); ++ rtw89_phy_write32_mask(rtwdev, R_RXSCOCCK, B_RXSCOCCK_TH, ++ rtw8852b_sco_cck_threshold[ch_element]); ++} ++ ++static u8 rtw8852b_sco_mapping(u8 central_ch) ++{ ++ if (central_ch == 1) ++ return 109; ++ else if (central_ch >= 2 && central_ch <= 6) ++ return 108; ++ else if (central_ch >= 7 && central_ch <= 10) ++ return 107; ++ else if (central_ch >= 11 && central_ch <= 14) ++ return 106; ++ else if (central_ch == 36 || central_ch == 38) ++ return 51; ++ else if (central_ch >= 40 && central_ch <= 58) ++ return 50; ++ else if (central_ch >= 60 && central_ch <= 64) ++ return 49; ++ else if (central_ch == 100 || central_ch == 102) ++ return 48; ++ else if (central_ch >= 104 && central_ch <= 126) ++ return 47; ++ else if (central_ch >= 128 && central_ch <= 151) ++ return 46; ++ else if (central_ch >= 153 && central_ch <= 177) ++ return 45; ++ else ++ return 0; ++} ++ ++struct rtw8852b_bb_gain { ++ u32 gain_g[BB_PATH_NUM_8852B]; ++ u32 gain_a[BB_PATH_NUM_8852B]; ++ u32 gain_mask; ++}; ++ ++static const struct rtw8852b_bb_gain bb_gain_lna[LNA_GAIN_NUM] = { ++ { .gain_g = {0x4678, 0x475C}, .gain_a = {0x45DC, 0x4740}, ++ .gain_mask = 0x00ff0000 }, ++ { .gain_g = {0x4678, 0x475C}, .gain_a = {0x45DC, 0x4740}, ++ .gain_mask = 0xff000000 }, ++ { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, ++ .gain_mask = 0x000000ff }, ++ { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, ++ .gain_mask = 0x0000ff00 }, ++ { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, ++ .gain_mask = 0x00ff0000 }, ++ { .gain_g = {0x467C, 0x4760}, .gain_a = {0x4660, 0x4744}, ++ .gain_mask = 0xff000000 }, ++ { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, ++ .gain_mask = 0x000000ff }, ++}; ++ ++static const struct rtw8852b_bb_gain bb_gain_tia[TIA_GAIN_NUM] = { ++ { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, ++ .gain_mask = 0x00ff0000 }, ++ { .gain_g = {0x4680, 0x4764}, .gain_a = {0x4664, 0x4748}, ++ .gain_mask = 0xff000000 }, ++}; ++ ++static void rtw8852b_set_gain_error(struct rtw89_dev *rtwdev, ++ enum rtw89_subband subband, ++ enum rtw89_rf_path path) ++{ ++ const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; ++ u8 gain_band = rtw89_subband_to_bb_gain_band(subband); ++ s32 val; ++ u32 reg; ++ u32 mask; ++ int i; ++ ++ for (i = 0; i < LNA_GAIN_NUM; i++) { ++ if (subband == RTW89_CH_2G) ++ reg = bb_gain_lna[i].gain_g[path]; ++ else ++ reg = bb_gain_lna[i].gain_a[path]; ++ ++ mask = bb_gain_lna[i].gain_mask; ++ val = gain->lna_gain[gain_band][path][i]; ++ rtw89_phy_write32_mask(rtwdev, reg, mask, val); ++ } ++ ++ for (i = 0; i < TIA_GAIN_NUM; i++) { ++ if (subband == RTW89_CH_2G) ++ reg = bb_gain_tia[i].gain_g[path]; ++ else ++ reg = bb_gain_tia[i].gain_a[path]; ++ ++ mask = bb_gain_tia[i].gain_mask; ++ val = gain->tia_gain[gain_band][path][i]; ++ rtw89_phy_write32_mask(rtwdev, reg, mask, val); ++ } ++} ++ ++static void rtw8852b_set_gain_offset(struct rtw89_dev *rtwdev, ++ enum rtw89_subband subband, ++ enum rtw89_phy_idx phy_idx) ++{ ++ static const u32 gain_err_addr[2] = {R_P0_AGC_RSVD, R_P1_AGC_RSVD}; ++ static const u32 rssi_ofst_addr[2] = {R_PATH0_G_TIA1_LNA6_OP1DB_V1, ++ R_PATH1_G_TIA1_LNA6_OP1DB_V1}; ++ struct rtw89_hal *hal = &rtwdev->hal; ++ struct rtw89_phy_efuse_gain *efuse_gain = &rtwdev->efuse_gain; ++ enum rtw89_gain_offset gain_ofdm_band; ++ s32 offset_a, offset_b; ++ s32 offset_ofdm, offset_cck; ++ s32 tmp; ++ u8 path; ++ ++ if (!efuse_gain->comp_valid) ++ goto next; ++ ++ for (path = RF_PATH_A; path < BB_PATH_NUM_8852B; path++) { ++ tmp = efuse_gain->comp[path][subband]; ++ tmp = clamp_t(s32, tmp << 2, S8_MIN, S8_MAX); ++ rtw89_phy_write32_mask(rtwdev, gain_err_addr[path], MASKBYTE0, tmp); ++ } ++ ++next: ++ if (!efuse_gain->offset_valid) ++ return; ++ ++ gain_ofdm_band = rtw89_subband_to_gain_offset_band_of_ofdm(subband); ++ ++ offset_a = -efuse_gain->offset[RF_PATH_A][gain_ofdm_band]; ++ offset_b = -efuse_gain->offset[RF_PATH_B][gain_ofdm_band]; ++ ++ tmp = -((offset_a << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2)); ++ tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); ++ rtw89_phy_write32_mask(rtwdev, rssi_ofst_addr[RF_PATH_A], B_PATH0_R_G_OFST_MASK, tmp); ++ ++ tmp = -((offset_b << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2)); ++ tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); ++ rtw89_phy_write32_mask(rtwdev, rssi_ofst_addr[RF_PATH_B], B_PATH0_R_G_OFST_MASK, tmp); ++ ++ if (hal->antenna_rx == RF_B) { ++ offset_ofdm = -efuse_gain->offset[RF_PATH_B][gain_ofdm_band]; ++ offset_cck = -efuse_gain->offset[RF_PATH_B][0]; ++ } else { ++ offset_ofdm = -efuse_gain->offset[RF_PATH_A][gain_ofdm_band]; ++ offset_cck = -efuse_gain->offset[RF_PATH_A][0]; ++ } ++ ++ tmp = (offset_ofdm << 4) + efuse_gain->offset_base[RTW89_PHY_0]; ++ tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); ++ rtw89_phy_write32_idx(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK, tmp, phy_idx); ++ ++ tmp = (offset_ofdm << 4) + efuse_gain->rssi_base[RTW89_PHY_0]; ++ tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); ++ rtw89_phy_write32_idx(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK, tmp, phy_idx); ++ ++ if (subband == RTW89_CH_2G) { ++ tmp = (offset_cck << 3) + (efuse_gain->offset_base[RTW89_PHY_0] >> 1); ++ tmp = clamp_t(s32, tmp, S8_MIN >> 1, S8_MAX >> 1); ++ rtw89_phy_write32_mask(rtwdev, R_RX_RPL_OFST, ++ B_RX_RPL_OFST_CCK_MASK, tmp); ++ } ++} ++ ++static ++void rtw8852b_set_rxsc_rpl_comp(struct rtw89_dev *rtwdev, enum rtw89_subband subband) ++{ ++ const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; ++ u8 band = rtw89_subband_to_bb_gain_band(subband); ++ u32 val; ++ ++ val = FIELD_PREP(B_P0_RPL1_20_MASK, (gain->rpl_ofst_20[band][RF_PATH_A] + ++ gain->rpl_ofst_20[band][RF_PATH_B]) / 2) | ++ FIELD_PREP(B_P0_RPL1_40_MASK, (gain->rpl_ofst_40[band][RF_PATH_A][0] + ++ gain->rpl_ofst_40[band][RF_PATH_B][0]) / 2) | ++ FIELD_PREP(B_P0_RPL1_41_MASK, (gain->rpl_ofst_40[band][RF_PATH_A][1] + ++ gain->rpl_ofst_40[band][RF_PATH_B][1]) / 2); ++ val >>= B_P0_RPL1_SHIFT; ++ rtw89_phy_write32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_MASK, val); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_MASK, val); ++ ++ val = FIELD_PREP(B_P0_RTL2_42_MASK, (gain->rpl_ofst_40[band][RF_PATH_A][2] + ++ gain->rpl_ofst_40[band][RF_PATH_B][2]) / 2) | ++ FIELD_PREP(B_P0_RTL2_80_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][0] + ++ gain->rpl_ofst_80[band][RF_PATH_B][0]) / 2) | ++ FIELD_PREP(B_P0_RTL2_81_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][1] + ++ gain->rpl_ofst_80[band][RF_PATH_B][1]) / 2) | ++ FIELD_PREP(B_P0_RTL2_8A_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][10] + ++ gain->rpl_ofst_80[band][RF_PATH_B][10]) / 2); ++ rtw89_phy_write32(rtwdev, R_P0_RPL2, val); ++ rtw89_phy_write32(rtwdev, R_P1_RPL2, val); ++ ++ val = FIELD_PREP(B_P0_RTL3_82_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][2] + ++ gain->rpl_ofst_80[band][RF_PATH_B][2]) / 2) | ++ FIELD_PREP(B_P0_RTL3_83_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][3] + ++ gain->rpl_ofst_80[band][RF_PATH_B][3]) / 2) | ++ FIELD_PREP(B_P0_RTL3_84_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][4] + ++ gain->rpl_ofst_80[band][RF_PATH_B][4]) / 2) | ++ FIELD_PREP(B_P0_RTL3_89_MASK, (gain->rpl_ofst_80[band][RF_PATH_A][9] + ++ gain->rpl_ofst_80[band][RF_PATH_B][9]) / 2); ++ rtw89_phy_write32(rtwdev, R_P0_RPL3, val); ++ rtw89_phy_write32(rtwdev, R_P1_RPL3, val); ++} ++ ++static void rtw8852b_ctrl_ch(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ u8 central_ch = chan->channel; ++ u8 subband = chan->subband_type; ++ u8 sco_comp; ++ bool is_2g = central_ch <= 14; ++ ++ /* Path A */ ++ if (is_2g) ++ rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, ++ B_PATH0_BAND_SEL_MSK_V1, 1, phy_idx); ++ else ++ rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, ++ B_PATH0_BAND_SEL_MSK_V1, 0, phy_idx); ++ ++ /* Path B */ ++ if (is_2g) ++ rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, ++ B_PATH1_BAND_SEL_MSK_V1, 1, phy_idx); ++ else ++ rtw89_phy_write32_idx(rtwdev, R_PATH1_BAND_SEL_V1, ++ B_PATH1_BAND_SEL_MSK_V1, 0, phy_idx); ++ ++ /* SCO compensate FC setting */ ++ sco_comp = rtw8852b_sco_mapping(central_ch); ++ rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_INV, sco_comp, phy_idx); ++ ++ if (chan->band_type == RTW89_BAND_6G) ++ return; ++ ++ /* CCK parameters */ ++ if (central_ch == 14) { ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR0, B_TXFIR_C01, 0x3b13ff); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR2, B_TXFIR_C23, 0x1c42de); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR4, B_TXFIR_C45, 0xfdb0ad); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR6, B_TXFIR_C67, 0xf60f6e); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR8, B_TXFIR_C89, 0xfd8f92); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIRA, B_TXFIR_CAB, 0x2d011); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIRC, B_TXFIR_CCD, 0x1c02c); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIRE, B_TXFIR_CEF, 0xfff00a); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR0, B_TXFIR_C01, 0x3d23ff); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR2, B_TXFIR_C23, 0x29b354); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR4, B_TXFIR_C45, 0xfc1c8); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR6, B_TXFIR_C67, 0xfdb053); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIR8, B_TXFIR_C89, 0xf86f9a); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIRA, B_TXFIR_CAB, 0xfaef92); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIRC, B_TXFIR_CCD, 0xfe5fcc); ++ rtw89_phy_write32_mask(rtwdev, R_TXFIRE, B_TXFIR_CEF, 0xffdff5); ++ } ++ ++ rtw8852b_set_gain_error(rtwdev, subband, RF_PATH_A); ++ rtw8852b_set_gain_error(rtwdev, subband, RF_PATH_B); ++ rtw8852b_set_gain_offset(rtwdev, subband, phy_idx); ++ rtw8852b_set_rxsc_rpl_comp(rtwdev, subband); ++} ++ ++static void rtw8852b_bw_setting(struct rtw89_dev *rtwdev, u8 bw, u8 path) ++{ ++ static const u32 adc_sel[2] = {0xC0EC, 0xC1EC}; ++ static const u32 wbadc_sel[2] = {0xC0E4, 0xC1E4}; ++ ++ switch (bw) { ++ case RTW89_CHANNEL_WIDTH_5: ++ rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x1); ++ rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x0); ++ break; ++ case RTW89_CHANNEL_WIDTH_10: ++ rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x2); ++ rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x1); ++ break; ++ case RTW89_CHANNEL_WIDTH_20: ++ rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); ++ rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); ++ break; ++ case RTW89_CHANNEL_WIDTH_40: ++ rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); ++ rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); ++ break; ++ case RTW89_CHANNEL_WIDTH_80: ++ rtw89_phy_write32_mask(rtwdev, adc_sel[path], 0x6000, 0x0); ++ rtw89_phy_write32_mask(rtwdev, wbadc_sel[path], 0x30, 0x2); ++ break; ++ default: ++ rtw89_warn(rtwdev, "Fail to set ADC\n"); ++ } ++} ++ ++static void rtw8852b_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, ++ enum rtw89_phy_idx phy_idx) ++{ ++ u32 rx_path_0; ++ ++ switch (bw) { ++ case RTW89_CHANNEL_WIDTH_5: ++ rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x1, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); ++ ++ /*Set RF mode at 3 */ ++ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, ++ B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, ++ B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); ++ break; ++ case RTW89_CHANNEL_WIDTH_10: ++ rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x2, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); ++ ++ /*Set RF mode at 3 */ ++ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, ++ B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, ++ B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); ++ break; ++ case RTW89_CHANNEL_WIDTH_20: ++ rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); ++ ++ /*Set RF mode at 3 */ ++ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, ++ B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, ++ B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); ++ break; ++ case RTW89_CHANNEL_WIDTH_40: ++ rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x1, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, ++ pri_ch, phy_idx); ++ ++ /*Set RF mode at 3 */ ++ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, ++ B_P0_RFMODE_ORI_RX_ALL, 0x333, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, ++ B_P1_RFMODE_ORI_RX_ALL, 0x333, phy_idx); ++ /*CCK primary channel */ ++ if (pri_ch == RTW89_SC_20_UPPER) ++ rtw89_phy_write32_mask(rtwdev, R_RXSC, B_RXSC_EN, 1); ++ else ++ rtw89_phy_write32_mask(rtwdev, R_RXSC, B_RXSC_EN, 0); ++ ++ break; ++ case RTW89_CHANNEL_WIDTH_80: ++ rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x2, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, ++ pri_ch, phy_idx); ++ ++ /*Set RF mode at A */ ++ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, ++ B_P0_RFMODE_ORI_RX_ALL, 0xaaa, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, ++ B_P1_RFMODE_ORI_RX_ALL, 0xaaa, phy_idx); ++ break; ++ default: ++ rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri ch:%d)\n", bw, ++ pri_ch); ++ } ++ ++ rtw8852b_bw_setting(rtwdev, bw, RF_PATH_A); ++ rtw8852b_bw_setting(rtwdev, bw, RF_PATH_B); ++ ++ rx_path_0 = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, ++ phy_idx); ++ if (rx_path_0 == 0x1) ++ rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_ORI_RX, ++ B_P1_RFMODE_ORI_RX_ALL, 0x111, phy_idx); ++ else if (rx_path_0 == 0x2) ++ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_ORI_RX, ++ B_P0_RFMODE_ORI_RX_ALL, 0x111, phy_idx); ++} ++ ++static void rtw8852b_ctrl_cck_en(struct rtw89_dev *rtwdev, bool cck_en) ++{ ++ if (cck_en) { ++ rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 1); ++ rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 1); ++ } ++} ++ ++static void rtw8852b_5m_mask(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ u8 pri_ch = chan->primary_channel; ++ bool mask_5m_low; ++ bool mask_5m_en; ++ ++ switch (chan->band_width) { ++ case RTW89_CHANNEL_WIDTH_40: ++ /* Prich=1: Mask 5M High, Prich=2: Mask 5M Low */ ++ mask_5m_en = true; ++ mask_5m_low = pri_ch == 2; ++ break; ++ case RTW89_CHANNEL_WIDTH_80: ++ /* Prich=3: Mask 5M High, Prich=4: Mask 5M Low, Else: Disable */ ++ mask_5m_en = pri_ch == 3 || pri_ch == 4; ++ mask_5m_low = pri_ch == 4; ++ break; ++ default: ++ mask_5m_en = false; ++ break; ++ } ++ ++ if (!mask_5m_en) { ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x0); ++ rtw89_phy_write32_idx(rtwdev, R_ASSIGN_SBD_OPT_V1, ++ B_ASSIGN_SBD_OPT_EN_V1, 0x0, phy_idx); ++ return; ++ } ++ ++ if (mask_5m_low) { ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_TH, 0x4); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB2, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB0, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_TH, 0x4); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB2, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB0, 0x1); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_TH, 0x4); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB2, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB0, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_TH, 0x4); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB2, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_5MDET_V1, B_PATH1_5MDET_SB0, 0x0); ++ } ++ rtw89_phy_write32_idx(rtwdev, R_ASSIGN_SBD_OPT_V1, ++ B_ASSIGN_SBD_OPT_EN_V1, 0x1, phy_idx); ++} ++ ++static void rtw8852b_bb_reset_all(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) ++{ ++ rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_S1_HW_SI_DIS, B_S1_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); ++ fsleep(1); ++ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_S1_HW_SI_DIS, B_S1_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); ++} ++ ++static void rtw8852b_bb_reset_en(struct rtw89_dev *rtwdev, enum rtw89_band band, ++ enum rtw89_phy_idx phy_idx, bool en) ++{ ++ if (en) { ++ rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, ++ B_S0_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_S1_HW_SI_DIS, ++ B_S1_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); ++ if (band == RTW89_BAND_2G) ++ rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x0); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x1); ++ rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, ++ B_S0_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); ++ rtw89_phy_write32_idx(rtwdev, R_S1_HW_SI_DIS, ++ B_S1_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); ++ fsleep(1); ++ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, phy_idx); ++ } ++} ++ ++static void rtw8852b_bb_reset(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy_idx) ++{ ++ rtw89_phy_write32_set(rtwdev, R_P0_TXPW_RSTB, B_P0_TXPW_RSTB_MANON); ++ rtw89_phy_write32_set(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_TRK_EN); ++ rtw89_phy_write32_set(rtwdev, R_P1_TXPW_RSTB, B_P1_TXPW_RSTB_MANON); ++ rtw89_phy_write32_set(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_TRK_EN); ++ rtw8852b_bb_reset_all(rtwdev, phy_idx); ++ rtw89_phy_write32_clr(rtwdev, R_P0_TXPW_RSTB, B_P0_TXPW_RSTB_MANON); ++ rtw89_phy_write32_clr(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_TRK_EN); ++ rtw89_phy_write32_clr(rtwdev, R_P1_TXPW_RSTB, B_P1_TXPW_RSTB_MANON); ++ rtw89_phy_write32_clr(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_TRK_EN); ++} ++ ++static void rtw8852b_bb_macid_ctrl_init(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy_idx) ++{ ++ u32 addr; ++ ++ for (addr = R_AX_PWR_MACID_LMT_TABLE0; ++ addr <= R_AX_PWR_MACID_LMT_TABLE127; addr += 4) ++ rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, 0); ++} ++ ++static void rtw8852b_bb_sethw(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; ++ ++ rtw89_phy_write32_clr(rtwdev, R_P0_EN_SOUND_WO_NDP, B_P0_EN_SOUND_WO_NDP); ++ rtw89_phy_write32_clr(rtwdev, R_P1_EN_SOUND_WO_NDP, B_P1_EN_SOUND_WO_NDP); ++ ++ rtw8852b_bb_macid_ctrl_init(rtwdev, RTW89_PHY_0); ++ ++ /* read these registers after loading BB parameters */ ++ gain->offset_base[RTW89_PHY_0] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK); ++ gain->rssi_base[RTW89_PHY_0] = ++ rtw89_phy_read32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK); ++} ++ ++static void rtw8852b_bb_set_pop(struct rtw89_dev *rtwdev) ++{ ++ if (rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR) ++ rtw89_phy_write32_clr(rtwdev, R_PKT_CTRL, B_PKT_POP_EN); ++} ++ ++static void rtw8852b_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ bool cck_en = chan->channel <= 14; ++ u8 pri_ch_idx = chan->pri_ch_idx; ++ ++ if (cck_en) ++ rtw8852b_ctrl_sco_cck(rtwdev, chan->primary_channel); ++ ++ rtw8852b_ctrl_ch(rtwdev, chan, phy_idx); ++ rtw8852b_ctrl_bw(rtwdev, pri_ch_idx, chan->band_width, phy_idx); ++ rtw8852b_ctrl_cck_en(rtwdev, cck_en); ++ if (chan->band_type == RTW89_BAND_5G) { ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, ++ B_PATH0_BT_SHARE_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, ++ B_PATH0_BTG_PATH_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, ++ B_PATH1_BT_SHARE_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, ++ B_PATH1_BTG_PATH_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, ++ B_BT_DYN_DC_EST_EN_MSK, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0); ++ } ++ rtw89_phy_write32_mask(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0, ++ chan->primary_channel); ++ rtw8852b_5m_mask(rtwdev, chan, phy_idx); ++ rtw8852b_bb_set_pop(rtwdev); ++ rtw8852b_bb_reset_all(rtwdev, phy_idx); ++} ++ ++static void rtw8852b_set_channel(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_mac_idx mac_idx, ++ enum rtw89_phy_idx phy_idx) ++{ ++ rtw8852b_set_channel_mac(rtwdev, chan, mac_idx); ++ rtw8852b_set_channel_bb(rtwdev, chan, phy_idx); ++ rtw8852b_set_channel_rf(rtwdev, chan, phy_idx); ++} ++ ++static void rtw8852b_tssi_cont_en(struct rtw89_dev *rtwdev, bool en, ++ enum rtw89_rf_path path) ++{ ++ static const u32 tssi_trk[2] = {R_P0_TSSI_TRK, R_P1_TSSI_TRK}; ++ static const u32 ctrl_bbrst[2] = {R_P0_TXPW_RSTB, R_P1_TXPW_RSTB}; ++ ++ if (en) { ++ rtw89_phy_write32_mask(rtwdev, ctrl_bbrst[path], B_P0_TXPW_RSTB_MANON, 0x0); ++ rtw89_phy_write32_mask(rtwdev, tssi_trk[path], B_P0_TSSI_TRK_EN, 0x0); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, ctrl_bbrst[path], B_P0_TXPW_RSTB_MANON, 0x1); ++ rtw89_phy_write32_mask(rtwdev, tssi_trk[path], B_P0_TSSI_TRK_EN, 0x1); ++ } ++} ++ ++static void rtw8852b_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, ++ u8 phy_idx) ++{ ++ if (!rtwdev->dbcc_en) { ++ rtw8852b_tssi_cont_en(rtwdev, en, RF_PATH_A); ++ rtw8852b_tssi_cont_en(rtwdev, en, RF_PATH_B); ++ } else { ++ if (phy_idx == RTW89_PHY_0) ++ rtw8852b_tssi_cont_en(rtwdev, en, RF_PATH_A); ++ else ++ rtw8852b_tssi_cont_en(rtwdev, en, RF_PATH_B); ++ } ++} ++ ++static void rtw8852b_adc_en(struct rtw89_dev *rtwdev, bool en) ++{ ++ if (en) ++ rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RST, 0x0); ++ else ++ rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RST, 0xf); ++} ++ ++static void rtw8852b_set_channel_help(struct rtw89_dev *rtwdev, bool enter, ++ struct rtw89_channel_help_params *p, ++ const struct rtw89_chan *chan, ++ enum rtw89_mac_idx mac_idx, ++ enum rtw89_phy_idx phy_idx) ++{ ++ if (enter) { ++ rtw89_chip_stop_sch_tx(rtwdev, RTW89_MAC_0, &p->tx_en, RTW89_SCH_TX_SEL_ALL); ++ rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); ++ rtw8852b_tssi_cont_en_phyidx(rtwdev, false, RTW89_PHY_0); ++ rtw8852b_adc_en(rtwdev, false); ++ fsleep(40); ++ rtw8852b_bb_reset_en(rtwdev, chan->band_type, phy_idx, false); ++ } else { ++ rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); ++ rtw8852b_adc_en(rtwdev, true); ++ rtw8852b_tssi_cont_en_phyidx(rtwdev, true, RTW89_PHY_0); ++ rtw8852b_bb_reset_en(rtwdev, chan->band_type, phy_idx, true); ++ rtw89_chip_resume_sch_tx(rtwdev, RTW89_MAC_0, p->tx_en); ++ } ++} ++ ++static void rtw8852b_rfk_init(struct rtw89_dev *rtwdev) ++{ ++ rtwdev->is_tssi_mode[RF_PATH_A] = false; ++ rtwdev->is_tssi_mode[RF_PATH_B] = false; ++ ++ rtw8852b_dpk_init(rtwdev); ++ rtw8852b_rck(rtwdev); ++ rtw8852b_dack(rtwdev); ++ rtw8852b_rx_dck(rtwdev, RTW89_PHY_0); ++} ++ ++static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev) ++{ ++ enum rtw89_phy_idx phy_idx = RTW89_PHY_0; ++ ++ rtw8852b_rx_dck(rtwdev, phy_idx); ++ rtw8852b_iqk(rtwdev, phy_idx); ++ rtw8852b_tssi(rtwdev, phy_idx, true); ++ rtw8852b_dpk(rtwdev, phy_idx); ++} ++ ++static void rtw8852b_rfk_band_changed(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy_idx) ++{ ++ rtw8852b_tssi_scan(rtwdev, phy_idx); ++} ++ ++static void rtw8852b_rfk_scan(struct rtw89_dev *rtwdev, bool start) ++{ ++ rtw8852b_wifi_scan_notify(rtwdev, start, RTW89_PHY_0); ++} ++ ++static void rtw8852b_rfk_track(struct rtw89_dev *rtwdev) ++{ ++ rtw8852b_dpk_track(rtwdev); ++} ++ ++static u32 rtw8852b_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy_idx, s16 ref) ++{ ++ const u16 tssi_16dbm_cw = 0x12c; ++ const u8 base_cw_0db = 0x27; ++ const s8 ofst_int = 0; ++ s16 pwr_s10_3; ++ s16 rf_pwr_cw; ++ u16 bb_pwr_cw; ++ u32 pwr_cw; ++ u32 tssi_ofst_cw; ++ ++ pwr_s10_3 = (ref << 1) + (s16)(ofst_int) + (s16)(base_cw_0db << 3); ++ bb_pwr_cw = FIELD_GET(GENMASK(2, 0), pwr_s10_3); ++ rf_pwr_cw = FIELD_GET(GENMASK(8, 3), pwr_s10_3); ++ rf_pwr_cw = clamp_t(s16, rf_pwr_cw, 15, 63); ++ pwr_cw = (rf_pwr_cw << 3) | bb_pwr_cw; ++ ++ tssi_ofst_cw = (u32)((s16)tssi_16dbm_cw + (ref << 1) - (16 << 3)); ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, ++ "[TXPWR] tssi_ofst_cw=%d rf_cw=0x%x bb_cw=0x%x\n", ++ tssi_ofst_cw, rf_pwr_cw, bb_pwr_cw); ++ ++ return FIELD_PREP(B_DPD_TSSI_CW, tssi_ofst_cw) | ++ FIELD_PREP(B_DPD_PWR_CW, pwr_cw) | ++ FIELD_PREP(B_DPD_REF, ref); ++} ++ ++static void rtw8852b_set_txpwr_ref(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy_idx) ++{ ++ static const u32 addr[RF_PATH_NUM_8852B] = {0x5800, 0x7800}; ++ const u32 mask = B_DPD_TSSI_CW | B_DPD_PWR_CW | B_DPD_REF; ++ const u8 ofst_ofdm = 0x4; ++ const u8 ofst_cck = 0x8; ++ const s16 ref_ofdm = 0; ++ const s16 ref_cck = 0; ++ u32 val; ++ u8 i; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n"); ++ ++ rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_CTRL, ++ B_AX_PWR_REF, 0x0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb ofdm txpwr ref\n"); ++ val = rtw8852b_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_ofdm); ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) ++ rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_ofdm, mask, val, ++ phy_idx); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb cck txpwr ref\n"); ++ val = rtw8852b_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_cck); ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) ++ rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_cck, mask, val, ++ phy_idx); ++} ++ ++static void rtw8852b_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, ++ u8 tx_shape_idx, ++ enum rtw89_phy_idx phy_idx) ++{ ++#define __DFIR_CFG_ADDR(i) (R_TXFIR0 + ((i) << 2)) ++#define __DFIR_CFG_MASK 0xffffffff ++#define __DFIR_CFG_NR 8 ++#define __DECL_DFIR_PARAM(_name, _val...) \ ++ static const u32 param_ ## _name[] = {_val}; \ ++ static_assert(ARRAY_SIZE(param_ ## _name) == __DFIR_CFG_NR) ++ ++ __DECL_DFIR_PARAM(flat, ++ 0x023D23FF, 0x0029B354, 0x000FC1C8, 0x00FDB053, ++ 0x00F86F9A, 0x06FAEF92, 0x00FE5FCC, 0x00FFDFF5); ++ __DECL_DFIR_PARAM(sharp, ++ 0x023D83FF, 0x002C636A, 0x0013F204, 0x00008090, ++ 0x00F87FB0, 0x06F99F83, 0x00FDBFBA, 0x00003FF5); ++ __DECL_DFIR_PARAM(sharp_14, ++ 0x023B13FF, 0x001C42DE, 0x00FDB0AD, 0x00F60F6E, ++ 0x00FD8F92, 0x0602D011, 0x0001C02C, 0x00FFF00A); ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u8 ch = chan->channel; ++ const u32 *param; ++ u32 addr; ++ int i; ++ ++ if (ch > 14) { ++ rtw89_warn(rtwdev, ++ "set tx shape dfir by unknown ch: %d on 2G\n", ch); ++ return; ++ } ++ ++ if (ch == 14) ++ param = param_sharp_14; ++ else ++ param = tx_shape_idx == 0 ? param_flat : param_sharp; ++ ++ for (i = 0; i < __DFIR_CFG_NR; i++) { ++ addr = __DFIR_CFG_ADDR(i); ++ rtw89_debug(rtwdev, RTW89_DBG_TXPWR, ++ "set tx shape dfir: 0x%x: 0x%x\n", addr, param[i]); ++ rtw89_phy_write32_idx(rtwdev, addr, __DFIR_CFG_MASK, param[i], ++ phy_idx); ++ } ++ ++#undef __DECL_DFIR_PARAM ++#undef __DFIR_CFG_NR ++#undef __DFIR_CFG_MASK ++#undef __DECL_CFG_ADDR ++} ++ ++static void rtw8852b_set_tx_shape(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ u8 band = chan->band_type; ++ u8 regd = rtw89_regd_get(rtwdev, band); ++ u8 tx_shape_cck = rtw89_8852b_tx_shape[band][RTW89_RS_CCK][regd]; ++ u8 tx_shape_ofdm = rtw89_8852b_tx_shape[band][RTW89_RS_OFDM][regd]; ++ ++ if (band == RTW89_BAND_2G) ++ rtw8852b_bb_set_tx_shape_dfir(rtwdev, tx_shape_cck, phy_idx); ++ ++ rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG, ++ tx_shape_ofdm); ++} ++ ++static void rtw8852b_set_txpwr(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx); ++ rtw8852b_set_tx_shape(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx); ++} ++ ++static void rtw8852b_set_txpwr_ctrl(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy_idx) ++{ ++ rtw8852b_set_txpwr_ref(rtwdev, phy_idx); ++} ++ ++static ++void rtw8852b_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, ++ s8 pw_ofst, enum rtw89_mac_idx mac_idx) ++{ ++ u32 reg; ++ ++ if (pw_ofst < -16 || pw_ofst > 15) { ++ rtw89_warn(rtwdev, "[ULTB] Err pwr_offset=%d\n", pw_ofst); ++ return; ++ } ++ ++ reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_CTRL, mac_idx); ++ rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN); ++ ++ reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_1T, mac_idx); ++ rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst); ++ ++ pw_ofst = max_t(s8, pw_ofst - 3, -16); ++ reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx); ++ rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst); ++} ++ ++static int ++rtw8852b_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) ++{ ++ int ret; ++ ++ ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL2, 0x07763333); ++ if (ret) ++ return ret; ++ ++ ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_COEXT_CTRL, 0x01ebf000); ++ if (ret) ++ return ret; ++ ++ ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL0, 0x0002f8ff); ++ if (ret) ++ return ret; ++ ++ rtw8852b_set_txpwr_ul_tb_offset(rtwdev, 0, phy_idx == RTW89_PHY_1 ? ++ RTW89_MAC_1 : RTW89_MAC_0); ++ ++ return 0; ++} ++ ++void rtw8852b_bb_set_plcp_tx(struct rtw89_dev *rtwdev) ++{ ++ const struct rtw89_reg3_def *def = rtw8852b_pmac_ht20_mcs7_tbl; ++ u8 i; ++ ++ for (i = 0; i < ARRAY_SIZE(rtw8852b_pmac_ht20_mcs7_tbl); i++, def++) ++ rtw89_phy_write32_mask(rtwdev, def->addr, def->mask, def->data); ++} ++ ++static void rtw8852b_stop_pmac_tx(struct rtw89_dev *rtwdev, ++ struct rtw8852b_bb_pmac_info *tx_info, ++ enum rtw89_phy_idx idx) ++{ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC Stop Tx"); ++ if (tx_info->mode == CONT_TX) ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_CTX_EN, 0, idx); ++ else if (tx_info->mode == PKTS_TX) ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_PTX_EN, 0, idx); ++} ++ ++static void rtw8852b_start_pmac_tx(struct rtw89_dev *rtwdev, ++ struct rtw8852b_bb_pmac_info *tx_info, ++ enum rtw89_phy_idx idx) ++{ ++ enum rtw8852b_pmac_mode mode = tx_info->mode; ++ u32 pkt_cnt = tx_info->tx_cnt; ++ u16 period = tx_info->period; ++ ++ if (mode == CONT_TX && !tx_info->is_cck) { ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_CTX_EN, 1, idx); ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CTx Start"); ++ } else if (mode == PKTS_TX) { ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, B_PMAC_PTX_EN, 1, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_PRD, ++ B_PMAC_TX_PRD_MSK, period, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CNT, B_PMAC_TX_CNT_MSK, ++ pkt_cnt, idx); ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC PTx Start"); ++ } ++ ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CTRL, B_PMAC_TXEN_DIS, 1, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_TX_CTRL, B_PMAC_TXEN_DIS, 0, idx); ++} ++ ++void rtw8852b_bb_set_pmac_tx(struct rtw89_dev *rtwdev, ++ struct rtw8852b_bb_pmac_info *tx_info, ++ enum rtw89_phy_idx idx) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ ++ if (!tx_info->en_pmac_tx) { ++ rtw8852b_stop_pmac_tx(rtwdev, tx_info, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0, idx); ++ if (chan->band_type == RTW89_BAND_2G) ++ rtw89_phy_write32_clr(rtwdev, R_RXCCA, B_RXCCA_DIS); ++ return; ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC Tx Enable"); ++ ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_TXEN, 1, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_RXEN, 1, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_RX_CFG1, B_PMAC_OPT1_MSK, 0x3f, idx); ++ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 1, idx); ++ rtw89_phy_write32_set(rtwdev, R_RXCCA, B_RXCCA_DIS); ++ rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, idx); ++ ++ rtw8852b_start_pmac_tx(rtwdev, tx_info, idx); ++} ++ ++void rtw8852b_bb_set_pmac_pkt_tx(struct rtw89_dev *rtwdev, u8 enable, ++ u16 tx_cnt, u16 period, u16 tx_time, ++ enum rtw89_phy_idx idx) ++{ ++ struct rtw8852b_bb_pmac_info tx_info = {0}; ++ ++ tx_info.en_pmac_tx = enable; ++ tx_info.is_cck = 0; ++ tx_info.mode = PKTS_TX; ++ tx_info.tx_cnt = tx_cnt; ++ tx_info.period = period; ++ tx_info.tx_time = tx_time; ++ ++ rtw8852b_bb_set_pmac_tx(rtwdev, &tx_info, idx); ++} ++ ++void rtw8852b_bb_set_power(struct rtw89_dev *rtwdev, s16 pwr_dbm, ++ enum rtw89_phy_idx idx) ++{ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CFG Tx PWR = %d", pwr_dbm); ++ ++ rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 1, idx); ++ rtw89_phy_write32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, pwr_dbm, idx); ++} ++ ++void rtw8852b_bb_cfg_tx_path(struct rtw89_dev *rtwdev, u8 tx_path) ++{ ++ rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 7, RTW89_PHY_0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "PMAC CFG Tx Path = %d", tx_path); ++ ++ if (tx_path == RF_PATH_A) { ++ rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 1); ++ rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0); ++ } else if (tx_path == RF_PATH_B) { ++ rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 2); ++ rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0); ++ } else if (tx_path == RF_PATH_AB) { ++ rtw89_phy_write32_mask(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, 3); ++ rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 4); ++ } else { ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "Error Tx Path"); ++ } ++} ++ ++void rtw8852b_bb_tx_mode_switch(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx idx, u8 mode) ++{ ++ if (mode != 0) ++ return; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "Tx mode switch"); ++ ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_TXEN, 0, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_RXEN, 0, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_RX_CFG1, B_PMAC_OPT1_MSK, 0, idx); ++ rtw89_phy_write32_idx(rtwdev, R_PMAC_RXMOD, B_PMAC_RXMOD_MSK, 0, idx); ++ rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_DPD_EN, 0, idx); ++ rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0, idx); ++ rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 0, idx); ++} ++ ++void rtw8852b_bb_backup_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, ++ struct rtw8852b_bb_tssi_bak *bak) ++{ ++ s32 tmp; ++ ++ bak->tx_path = rtw89_phy_read32_idx(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, idx); ++ bak->rx_path = rtw89_phy_read32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, idx); ++ bak->p0_rfmode = rtw89_phy_read32_idx(rtwdev, R_P0_RFMODE, MASKDWORD, idx); ++ bak->p0_rfmode_ftm = rtw89_phy_read32_idx(rtwdev, R_P0_RFMODE_FTM_RX, MASKDWORD, idx); ++ bak->p1_rfmode = rtw89_phy_read32_idx(rtwdev, R_P1_RFMODE, MASKDWORD, idx); ++ bak->p1_rfmode_ftm = rtw89_phy_read32_idx(rtwdev, R_P1_RFMODE_FTM_RX, MASKDWORD, idx); ++ tmp = rtw89_phy_read32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, idx); ++ bak->tx_pwr = sign_extend32(tmp, 8); ++} ++ ++void rtw8852b_bb_restore_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, ++ const struct rtw8852b_bb_tssi_bak *bak) ++{ ++ rtw89_phy_write32_idx(rtwdev, R_TXPATH_SEL, B_TXPATH_SEL_MSK, bak->tx_path, idx); ++ if (bak->tx_path == RF_AB) ++ rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0x4); ++ else ++ rtw89_phy_write32_mask(rtwdev, R_TXNSS_MAP, B_TXNSS_MAP_MSK, 0x0); ++ rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, bak->rx_path, idx); ++ rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_PWR_EN, 1, idx); ++ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE, MASKDWORD, bak->p0_rfmode, idx); ++ rtw89_phy_write32_idx(rtwdev, R_P0_RFMODE_FTM_RX, MASKDWORD, bak->p0_rfmode_ftm, idx); ++ rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE, MASKDWORD, bak->p1_rfmode, idx); ++ rtw89_phy_write32_idx(rtwdev, R_P1_RFMODE_FTM_RX, MASKDWORD, bak->p1_rfmode_ftm, idx); ++ rtw89_phy_write32_idx(rtwdev, R_TXPWR, B_TXPWR_MSK, bak->tx_pwr, idx); ++} ++ ++static void rtw8852b_bb_ctrl_btc_preagc(struct rtw89_dev *rtwdev, bool bt_en) ++{ ++ rtw89_phy_write_reg3_tbl(rtwdev, bt_en ? &rtw8852b_btc_preagc_en_defs_tbl : ++ &rtw8852b_btc_preagc_dis_defs_tbl); ++} ++ ++static void rtw8852b_ctrl_btg(struct rtw89_dev *rtwdev, bool btg) ++{ ++ if (btg) { ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, ++ B_PATH0_BT_SHARE_V1, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, ++ B_PATH0_BTG_PATH_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_G_LNA6_OP1DB_V1, ++ B_PATH1_G_LNA6_OP1DB_V1, 0x20); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_G_TIA0_LNA6_OP1DB_V1, ++ B_PATH1_G_TIA0_LNA6_OP1DB_V1, 0x30); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, ++ B_PATH1_BT_SHARE_V1, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, ++ B_PATH1_BTG_PATH_V1, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x2); ++ rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, ++ B_BT_DYN_DC_EST_EN_MSK, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x1); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, ++ B_PATH0_BT_SHARE_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, ++ B_PATH0_BTG_PATH_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_G_LNA6_OP1DB_V1, ++ B_PATH1_G_LNA6_OP1DB_V1, 0x1a); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_G_TIA0_LNA6_OP1DB_V1, ++ B_PATH1_G_TIA0_LNA6_OP1DB_V1, 0x2a); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_BT_SHARE_V1, ++ B_PATH1_BT_SHARE_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_BTG_PATH_V1, ++ B_PATH1_BTG_PATH_V1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0xc); ++ rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, ++ B_BT_DYN_DC_EST_EN_MSK, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0); ++ } ++} ++ ++void rtw8852b_bb_ctrl_rx_path(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path_bit rx_path) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u32 rst_mask0; ++ u32 rst_mask1; ++ ++ if (rx_path == RF_A) { ++ rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 1); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 1); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 1); ++ rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); ++ } else if (rx_path == RF_B) { ++ rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 2); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 2); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 2); ++ rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); ++ } else if (rx_path == RF_AB) { ++ rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 3); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 3); ++ rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 3); ++ rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 1); ++ rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 1); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 1); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 1); ++ } ++ ++ rtw8852b_set_gain_offset(rtwdev, chan->subband_type, RTW89_PHY_0); ++ ++ if (chan->band_type == RTW89_BAND_2G && ++ (rx_path == RF_B || rx_path == RF_AB)) ++ rtw8852b_ctrl_btg(rtwdev, true); ++ else ++ rtw8852b_ctrl_btg(rtwdev, false); ++ ++ rst_mask0 = B_P0_TXPW_RSTB_MANON | B_P0_TXPW_RSTB_TSSI; ++ rst_mask1 = B_P1_TXPW_RSTB_MANON | B_P1_TXPW_RSTB_TSSI; ++ if (rx_path == RF_A) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 1); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 3); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB, rst_mask1, 1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB, rst_mask1, 3); ++ } ++} ++ ++static void rtw8852b_bb_ctrl_rf_mode_rx_path(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path_bit rx_path) ++{ ++ if (rx_path == RF_A) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, ++ B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, ++ B_P0_RFMODE_FTM_RX, 0x333); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, ++ B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1111111); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, ++ B_P1_RFMODE_FTM_RX, 0x111); ++ } else if (rx_path == RF_B) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, ++ B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1111111); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, ++ B_P0_RFMODE_FTM_RX, 0x111); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, ++ B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, ++ B_P1_RFMODE_FTM_RX, 0x333); ++ } else if (rx_path == RF_AB) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE, ++ B_P0_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFMODE_FTM_RX, ++ B_P0_RFMODE_FTM_RX, 0x333); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE, ++ B_P1_RFMODE_ORI_TXRX_FTM_TX, 0x1233312); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFMODE_FTM_RX, ++ B_P1_RFMODE_FTM_RX, 0x333); ++ } ++} ++ ++static void rtw8852b_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_hal *hal = &rtwdev->hal; ++ enum rtw89_rf_path_bit rx_path = hal->antenna_rx ? hal->antenna_rx : RF_AB; ++ ++ rtw8852b_bb_ctrl_rx_path(rtwdev, rx_path); ++ rtw8852b_bb_ctrl_rf_mode_rx_path(rtwdev, rx_path); ++ ++ if (rtwdev->hal.rx_nss == 1) { ++ rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 1); ++ rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 1); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 1); ++ rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 1); ++ } ++ ++ rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0x0, RTW89_PHY_0); ++} ++ ++static u8 rtw8852b_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) ++{ ++ if (rtwdev->is_tssi_mode[rf_path]) { ++ u32 addr = 0x1c10 + (rf_path << 13); ++ ++ return rtw89_phy_read32_mask(rtwdev, addr, 0x3F000000); ++ } ++ ++ rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); ++ rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x0); ++ rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); ++ ++ fsleep(200); ++ ++ return rtw89_read_rf(rtwdev, rf_path, RR_TM, RR_TM_VAL); ++} ++ ++static void rtw8852b_btc_set_rfe(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_btc *btc = &rtwdev->btc; ++ struct rtw89_btc_module *module = &btc->mdinfo; ++ ++ module->rfe_type = rtwdev->efuse.rfe_type; ++ module->cv = rtwdev->hal.cv; ++ module->bt_solo = 0; ++ module->switch_type = BTC_SWITCH_INTERNAL; ++ ++ if (module->rfe_type > 0) ++ module->ant.num = module->rfe_type % 2 ? 2 : 3; ++ else ++ module->ant.num = 2; ++ ++ module->ant.diversity = 0; ++ module->ant.isolation = 10; ++ ++ if (module->ant.num == 3) { ++ module->ant.type = BTC_ANT_DEDICATED; ++ module->bt_pos = BTC_BT_ALONE; ++ } else { ++ module->ant.type = BTC_ANT_SHARED; ++ module->bt_pos = BTC_BT_BTG; ++ } ++} ++ ++static ++void rtw8852b_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val) ++{ ++ rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0x20000); ++ rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, group); ++ rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, val); ++ rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0x0); ++} ++ ++static void rtw8852b_btc_init_cfg(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_btc *btc = &rtwdev->btc; ++ struct rtw89_btc_module *module = &btc->mdinfo; ++ const struct rtw89_chip_info *chip = rtwdev->chip; ++ const struct rtw89_mac_ax_coex coex_params = { ++ .pta_mode = RTW89_MAC_AX_COEX_RTK_MODE, ++ .direction = RTW89_MAC_AX_COEX_INNER, ++ }; ++ ++ /* PTA init */ ++ rtw89_mac_coex_init(rtwdev, &coex_params); ++ ++ /* set WL Tx response = Hi-Pri */ ++ chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true); ++ chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true); ++ ++ /* set rf gnt debug off */ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_WLSEL, RFREG_MASK, 0x0); ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_WLSEL, RFREG_MASK, 0x0); ++ ++ /* set WL Tx thru in TRX mask table if GNT_WL = 0 && BT_S1 = ss group */ ++ if (module->ant.type == BTC_ANT_SHARED) { ++ rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5ff); ++ rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_SS_GROUP, 0x5ff); ++ /* set path-A(S0) Tx/Rx no-mask if GNT_WL=0 && BT_S1=tx group */ ++ rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_TX_GROUP, 0x5ff); ++ rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_TX_GROUP, 0x55f); ++ } else { /* set WL Tx stb if GNT_WL = 0 && BT_S1 = ss group for 3-ant */ ++ rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_SS_GROUP, 0x5df); ++ rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_SS_GROUP, 0x5df); ++ rtw8852b_set_trx_mask(rtwdev, RF_PATH_A, BTC_BT_TX_GROUP, 0x5ff); ++ rtw8852b_set_trx_mask(rtwdev, RF_PATH_B, BTC_BT_TX_GROUP, 0x5ff); ++ } ++ ++ /* set PTA break table */ ++ rtw89_write32(rtwdev, R_BTC_BREAK_TABLE, BTC_BREAK_PARAM); ++ ++ /* enable BT counter 0xda40[16,2] = 2b'11 */ ++ rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN); ++ btc->cx.wl.status.map.init_ok = true; ++} ++ ++static ++void rtw8852b_btc_set_wl_pri(struct rtw89_dev *rtwdev, u8 map, bool state) ++{ ++ u32 bitmap; ++ u32 reg; ++ ++ switch (map) { ++ case BTC_PRI_MASK_TX_RESP: ++ reg = R_BTC_BT_COEX_MSK_TABLE; ++ bitmap = B_BTC_PRI_MASK_TX_RESP_V1; ++ break; ++ case BTC_PRI_MASK_BEACON: ++ reg = R_AX_WL_PRI_MSK; ++ bitmap = B_AX_PTA_WL_PRI_MASK_BCNQ; ++ break; ++ case BTC_PRI_MASK_RX_CCK: ++ reg = R_BTC_BT_COEX_MSK_TABLE; ++ bitmap = B_BTC_PRI_MASK_RXCCK_V1; ++ break; ++ default: ++ return; ++ } ++ ++ if (state) ++ rtw89_write32_set(rtwdev, reg, bitmap); ++ else ++ rtw89_write32_clr(rtwdev, reg, bitmap); ++} ++ ++union rtw8852b_btc_wl_txpwr_ctrl { ++ u32 txpwr_val; ++ struct { ++ union { ++ u16 ctrl_all_time; ++ struct { ++ s16 data:9; ++ u16 rsvd:6; ++ u16 flag:1; ++ } all_time; ++ }; ++ union { ++ u16 ctrl_gnt_bt; ++ struct { ++ s16 data:9; ++ u16 rsvd:7; ++ } gnt_bt; ++ }; ++ }; ++} __packed; ++ ++static void ++rtw8852b_btc_set_wl_txpwr_ctrl(struct rtw89_dev *rtwdev, u32 txpwr_val) ++{ ++ union rtw8852b_btc_wl_txpwr_ctrl arg = { .txpwr_val = txpwr_val }; ++ s32 val; ++ ++#define __write_ctrl(_reg, _msk, _val, _en, _cond) \ ++do { \ ++ u32 _wrt = FIELD_PREP(_msk, _val); \ ++ BUILD_BUG_ON(!!(_msk & _en)); \ ++ if (_cond) \ ++ _wrt |= _en; \ ++ else \ ++ _wrt &= ~_en; \ ++ rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, _reg, \ ++ _msk | _en, _wrt); \ ++} while (0) ++ ++ switch (arg.ctrl_all_time) { ++ case 0xffff: ++ val = 0; ++ break; ++ default: ++ val = arg.all_time.data; ++ break; ++ } ++ ++ __write_ctrl(R_AX_PWR_RATE_CTRL, B_AX_FORCE_PWR_BY_RATE_VALUE_MASK, ++ val, B_AX_FORCE_PWR_BY_RATE_EN, ++ arg.ctrl_all_time != 0xffff); ++ ++ switch (arg.ctrl_gnt_bt) { ++ case 0xffff: ++ val = 0; ++ break; ++ default: ++ val = arg.gnt_bt.data; ++ break; ++ } ++ ++ __write_ctrl(R_AX_PWR_COEXT_CTRL, B_AX_TXAGC_BT_MASK, val, ++ B_AX_TXAGC_BT_EN, arg.ctrl_gnt_bt != 0xffff); ++ ++#undef __write_ctrl ++} ++ ++static ++s8 rtw8852b_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val) ++{ ++ return clamp_t(s8, val, -100, 0) + 100; ++} ++ ++static ++void rtw8852b_btc_update_bt_cnt(struct rtw89_dev *rtwdev) ++{ ++ /* Feature move to firmware */ ++} ++ ++static void rtw8852b_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state) ++{ ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x80000); ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1); ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD1, RFREG_MASK, 0x31); ++ ++ /* set WL standby = Rx for GNT_BT_Tx = 1->0 settle issue */ ++ if (state) ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x579); ++ else ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0, RFREG_MASK, 0x20); ++ ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0); ++} ++ ++static void rtw8852b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) ++{ ++} ++ ++static void rtw8852b_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, ++ struct rtw89_rx_phy_ppdu *phy_ppdu, ++ struct ieee80211_rx_status *status) ++{ ++ u16 chan = phy_ppdu->chan_idx; ++ u8 band; ++ ++ if (chan == 0) ++ return; ++ ++ band = chan <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; ++ status->freq = ieee80211_channel_to_frequency(chan, band); ++ status->band = band; ++} ++ ++static void rtw8852b_query_ppdu(struct rtw89_dev *rtwdev, ++ struct rtw89_rx_phy_ppdu *phy_ppdu, ++ struct ieee80211_rx_status *status) ++{ ++ u8 path; ++ u8 *rx_power = phy_ppdu->rssi; ++ ++ status->signal = RTW89_RSSI_RAW_TO_DBM(max(rx_power[RF_PATH_A], rx_power[RF_PATH_B])); ++ for (path = 0; path < rtwdev->chip->rf_path_num; path++) { ++ status->chains |= BIT(path); ++ status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]); ++ } ++ if (phy_ppdu->valid) ++ rtw8852b_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); ++} ++ + static int rtw8852b_mac_enable_bb_rf(struct rtw89_dev *rtwdev) + { + int ret; +@@ -75,13 +2381,150 @@ static int rtw8852b_mac_disable_bb_rf(st + static const struct rtw89_chip_ops rtw8852b_chip_ops = { + .enable_bb_rf = rtw8852b_mac_enable_bb_rf, + .disable_bb_rf = rtw8852b_mac_disable_bb_rf, ++ .bb_reset = rtw8852b_bb_reset, ++ .bb_sethw = rtw8852b_bb_sethw, ++ .read_rf = rtw89_phy_read_rf_v1, ++ .write_rf = rtw89_phy_write_rf_v1, ++ .set_channel = rtw8852b_set_channel, ++ .set_channel_help = rtw8852b_set_channel_help, ++ .read_efuse = rtw8852b_read_efuse, ++ .read_phycap = rtw8852b_read_phycap, ++ .fem_setup = NULL, ++ .rfk_init = rtw8852b_rfk_init, ++ .rfk_channel = rtw8852b_rfk_channel, ++ .rfk_band_changed = rtw8852b_rfk_band_changed, ++ .rfk_scan = rtw8852b_rfk_scan, ++ .rfk_track = rtw8852b_rfk_track, ++ .power_trim = rtw8852b_power_trim, ++ .set_txpwr = rtw8852b_set_txpwr, ++ .set_txpwr_ctrl = rtw8852b_set_txpwr_ctrl, ++ .init_txpwr_unit = rtw8852b_init_txpwr_unit, ++ .get_thermal = rtw8852b_get_thermal, ++ .ctrl_btg = rtw8852b_ctrl_btg, ++ .query_ppdu = rtw8852b_query_ppdu, ++ .bb_ctrl_btc_preagc = rtw8852b_bb_ctrl_btc_preagc, ++ .cfg_txrx_path = rtw8852b_bb_cfg_txrx_path, ++ .set_txpwr_ul_tb_offset = rtw8852b_set_txpwr_ul_tb_offset, ++ .pwr_on_func = rtw8852b_pwr_on_func, ++ .pwr_off_func = rtw8852b_pwr_off_func, ++ .fill_txdesc = rtw89_core_fill_txdesc, ++ .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, ++ .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, ++ .mac_cfg_gnt = rtw89_mac_cfg_gnt, ++ .stop_sch_tx = rtw89_mac_stop_sch_tx, ++ .resume_sch_tx = rtw89_mac_resume_sch_tx, ++ .h2c_dctl_sec_cam = NULL, ++ ++ .btc_set_rfe = rtw8852b_btc_set_rfe, ++ .btc_init_cfg = rtw8852b_btc_init_cfg, ++ .btc_set_wl_pri = rtw8852b_btc_set_wl_pri, ++ .btc_set_wl_txpwr_ctrl = rtw8852b_btc_set_wl_txpwr_ctrl, ++ .btc_get_bt_rssi = rtw8852b_btc_get_bt_rssi, ++ .btc_update_bt_cnt = rtw8852b_btc_update_bt_cnt, ++ .btc_wl_s1_standby = rtw8852b_btc_wl_s1_standby, ++ .btc_set_wl_rx_gain = rtw8852b_btc_set_wl_rx_gain, ++ .btc_set_policy = rtw89_btc_set_policy, + }; + + const struct rtw89_chip_info rtw8852b_chip_info = { + .chip_id = RTL8852B, ++ .ops = &rtw8852b_chip_ops, ++ .fw_name = "rtw89/rtw8852b_fw.bin", + .fifo_size = 196608, + .dle_scc_rsvd_size = 98304, ++ .max_amsdu_limit = 3500, ++ .dis_2g_40m_ul_ofdma = true, ++ .rsvd_ple_ofst = 0x2f800, ++ .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, + .dle_mem = rtw8852b_dle_mem_pcie, ++ .rf_base_addr = {0xe000, 0xf000}, ++ .pwr_on_seq = NULL, ++ .pwr_off_seq = NULL, ++ .bb_table = &rtw89_8852b_phy_bb_table, ++ .bb_gain_table = &rtw89_8852b_phy_bb_gain_table, ++ .rf_table = {&rtw89_8852b_phy_radioa_table, ++ &rtw89_8852b_phy_radiob_table,}, ++ .nctl_table = &rtw89_8852b_phy_nctl_table, ++ .byr_table = &rtw89_8852b_byr_table, ++ .txpwr_lmt_2g = &rtw89_8852b_txpwr_lmt_2g, ++ .txpwr_lmt_5g = &rtw89_8852b_txpwr_lmt_5g, ++ .txpwr_lmt_ru_2g = &rtw89_8852b_txpwr_lmt_ru_2g, ++ .txpwr_lmt_ru_5g = &rtw89_8852b_txpwr_lmt_ru_5g, ++ .txpwr_factor_rf = 2, ++ .txpwr_factor_mac = 1, ++ .dig_table = NULL, ++ .dig_regs = &rtw8852b_dig_regs, ++ .tssi_dbw_table = NULL, ++ .support_chanctx_num = 0, ++ .support_bands = BIT(NL80211_BAND_2GHZ) | ++ BIT(NL80211_BAND_5GHZ), ++ .support_bw160 = false, ++ .support_ul_tb_ctrl = true, ++ .hw_sec_hdr = false, ++ .rf_path_num = 2, ++ .tx_nss = 2, ++ .rx_nss = 2, ++ .acam_num = 128, ++ .bcam_num = 10, ++ .scam_num = 128, ++ .bacam_num = 2, ++ .bacam_dynamic_num = 4, ++ .bacam_v1 = false, ++ .sec_ctrl_efuse_size = 4, ++ .physical_efuse_size = 1216, ++ .logical_efuse_size = 2048, ++ .limit_efuse_size = 1280, ++ .dav_phy_efuse_size = 96, ++ .dav_log_efuse_size = 16, ++ .phycap_addr = 0x580, ++ .phycap_size = 128, ++ .para_ver = 0, ++ .wlcx_desired = 0x05050000, ++ .btcx_desired = 0x5, ++ .scbd = 0x1, ++ .mailbox = 0x1, ++ .btc_fwinfo_buf = 1024, ++ ++ .fcxbtcrpt_ver = 1, ++ .fcxtdma_ver = 1, ++ .fcxslots_ver = 1, ++ .fcxcysta_ver = 2, ++ .fcxstep_ver = 2, ++ .fcxnullsta_ver = 1, ++ .fcxmreg_ver = 1, ++ .fcxgpiodbg_ver = 1, ++ .fcxbtver_ver = 1, ++ .fcxbtscan_ver = 1, ++ .fcxbtafh_ver = 1, ++ .fcxbtdevinfo_ver = 1, ++ .afh_guard_ch = 6, ++ .wl_rssi_thres = rtw89_btc_8852b_wl_rssi_thres, ++ .bt_rssi_thres = rtw89_btc_8852b_bt_rssi_thres, ++ .rssi_tol = 2, ++ .mon_reg_num = ARRAY_SIZE(rtw89_btc_8852b_mon_reg), ++ .mon_reg = rtw89_btc_8852b_mon_reg, ++ .rf_para_ulink_num = ARRAY_SIZE(rtw89_btc_8852b_rf_ul), ++ .rf_para_ulink = rtw89_btc_8852b_rf_ul, ++ .rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8852b_rf_dl), ++ .rf_para_dlink = rtw89_btc_8852b_rf_dl, ++ .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) | ++ BIT(RTW89_PS_MODE_CLK_GATED) | ++ BIT(RTW89_PS_MODE_PWR_GATED), ++ .low_power_hci_modes = 0, ++ .h2c_cctl_func_id = H2C_FUNC_MAC_CCTLINFO_UD, ++ .hci_func_en_addr = R_AX_HCI_FUNC_EN, ++ .h2c_desc_size = sizeof(struct rtw89_txwd_body), ++ .txwd_body_size = sizeof(struct rtw89_txwd_body), ++ .h2c_ctrl_reg = R_AX_H2CREG_CTRL, ++ .h2c_regs = rtw8852b_h2c_regs, ++ .c2h_ctrl_reg = R_AX_C2HREG_CTRL, ++ .c2h_regs = rtw8852b_c2h_regs, ++ .page_regs = &rtw8852b_page_regs, ++ .cfo_src_fd = true, ++ .dcfo_comp = &rtw8852b_dcfo_comp, ++ .dcfo_comp_sft = 3, ++ .imr_info = &rtw8852b_imr_info, ++ .rrsr_cfgs = &rtw8852b_rrsr_cfgs, + .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | + BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | + BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852be.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852be.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852be.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852be.c 2022-12-24 00:49:25.785376835 +0200 +@@ -7,18 +7,82 @@ + + #include "pci.h" + #include "reg.h" ++#include "rtw8852b.h" + + static const struct rtw89_pci_info rtw8852b_pci_info = { ++ .txbd_trunc_mode = MAC_AX_BD_TRUNC, ++ .rxbd_trunc_mode = MAC_AX_BD_TRUNC, ++ .rxbd_mode = MAC_AX_RXBD_PKT, ++ .tag_mode = MAC_AX_TAG_MULTI, ++ .tx_burst = MAC_AX_TX_BURST_2048B, ++ .rx_burst = MAC_AX_RX_BURST_128B, ++ .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS, ++ .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS, ++ .multi_tag_num = MAC_AX_TAG_NUM_8, ++ .lbc_en = MAC_AX_PCIE_ENABLE, ++ .lbc_tmr = MAC_AX_LBC_TMR_2MS, ++ .autok_en = MAC_AX_PCIE_DISABLE, ++ .io_rcy_en = MAC_AX_PCIE_DISABLE, ++ .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, ++ ++ .init_cfg_reg = R_AX_PCIE_INIT_CFG1, ++ .txhci_en_bit = B_AX_TXHCI_EN, ++ .rxhci_en_bit = B_AX_RXHCI_EN, ++ .rxbd_mode_bit = B_AX_RXBD_MODE, ++ .exp_ctrl_reg = R_AX_PCIE_EXP_CTRL, ++ .max_tag_num_mask = B_AX_MAX_TAG_NUM, ++ .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, ++ .txbd_rwptr_clr2_reg = 0, + .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1}, + .dma_stop2 = {0}, + .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1}, + .dma_busy2_reg = 0, + .dma_busy3_reg = R_AX_PCIE_DMA_BUSY1, + ++ .rpwm_addr = R_AX_PCIE_HRPWM, ++ .cpwm_addr = R_AX_CPWM, + .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | + BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | + BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), ++ .bd_idx_addr_low_power = NULL, ++ .dma_addr_set = &rtw89_pci_ch_dma_addr_set, ++ ++ .ltr_set = rtw89_pci_ltr_set, ++ .fill_txaddr_info = rtw89_pci_fill_txaddr_info, ++ .config_intr_mask = rtw89_pci_config_intr_mask, ++ .enable_intr = rtw89_pci_enable_intr, ++ .disable_intr = rtw89_pci_disable_intr, ++ .recognize_intrs = rtw89_pci_recognize_intrs, ++}; ++ ++static const struct rtw89_driver_info rtw89_8852be_info = { ++ .chip = &rtw8852b_chip_info, ++ .bus = { ++ .pci = &rtw8852b_pci_info, ++ }, ++}; ++ ++static const struct pci_device_id rtw89_8852be_id_table[] = { ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xb852), ++ .driver_data = (kernel_ulong_t)&rtw89_8852be_info, ++ }, ++ { ++ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xb85b), ++ .driver_data = (kernel_ulong_t)&rtw89_8852be_info, ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(pci, rtw89_8852be_id_table); ++ ++static struct pci_driver rtw89_8852be_driver = { ++ .name = "rtw89_8852be", ++ .id_table = rtw89_8852be_id_table, ++ .probe = rtw89_pci_probe, ++ .remove = rtw89_pci_remove, ++ .driver.pm = &rtw89_pm_ops, + }; ++module_pci_driver(rtw89_8852be_driver); + + MODULE_AUTHOR("Realtek Corporation"); + MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852BE driver"); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b.h linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b.h 2022-12-24 00:49:25.782376835 +0200 +@@ -0,0 +1,137 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2019-2022 Realtek Corporation ++ */ ++ ++#ifndef __RTW89_8852B_H__ ++#define __RTW89_8852B_H__ ++ ++#include "core.h" ++ ++#define RF_PATH_NUM_8852B 2 ++#define BB_PATH_NUM_8852B 2 ++ ++enum rtw8852b_pmac_mode { ++ NONE_TEST, ++ PKTS_TX, ++ PKTS_RX, ++ CONT_TX ++}; ++ ++struct rtw8852b_u_efuse { ++ u8 rsvd[0x88]; ++ u8 mac_addr[ETH_ALEN]; ++}; ++ ++struct rtw8852b_e_efuse { ++ u8 mac_addr[ETH_ALEN]; ++}; ++ ++struct rtw8852b_tssi_offset { ++ u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM]; ++ u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM]; ++ u8 rsvd[7]; ++ u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM]; ++} __packed; ++ ++struct rtw8852b_efuse { ++ u8 rsvd[0x210]; ++ struct rtw8852b_tssi_offset path_a_tssi; ++ u8 rsvd1[10]; ++ struct rtw8852b_tssi_offset path_b_tssi; ++ u8 rsvd2[94]; ++ u8 channel_plan; ++ u8 xtal_k; ++ u8 rsvd3; ++ u8 iqk_lck; ++ u8 rsvd4[5]; ++ u8 reg_setting:2; ++ u8 tx_diversity:1; ++ u8 rx_diversity:2; ++ u8 ac_mode:1; ++ u8 module_type:2; ++ u8 rsvd5; ++ u8 shared_ant:1; ++ u8 coex_type:3; ++ u8 ant_iso:1; ++ u8 radio_on_off:1; ++ u8 rsvd6:2; ++ u8 eeprom_version; ++ u8 customer_id; ++ u8 tx_bb_swing_2g; ++ u8 tx_bb_swing_5g; ++ u8 tx_cali_pwr_trk_mode; ++ u8 trx_path_selection; ++ u8 rfe_type; ++ u8 country_code[2]; ++ u8 rsvd7[3]; ++ u8 path_a_therm; ++ u8 path_b_therm; ++ u8 rsvd8[2]; ++ u8 rx_gain_2g_ofdm; ++ u8 rsvd9; ++ u8 rx_gain_2g_cck; ++ u8 rsvd10; ++ u8 rx_gain_5g_low; ++ u8 rsvd11; ++ u8 rx_gain_5g_mid; ++ u8 rsvd12; ++ u8 rx_gain_5g_high; ++ u8 rsvd13[35]; ++ u8 path_a_cck_pwr_idx[6]; ++ u8 path_a_bw40_1tx_pwr_idx[5]; ++ u8 path_a_ofdm_1tx_pwr_idx_diff:4; ++ u8 path_a_bw20_1tx_pwr_idx_diff:4; ++ u8 path_a_bw20_2tx_pwr_idx_diff:4; ++ u8 path_a_bw40_2tx_pwr_idx_diff:4; ++ u8 path_a_cck_2tx_pwr_idx_diff:4; ++ u8 path_a_ofdm_2tx_pwr_idx_diff:4; ++ u8 rsvd14[0xf2]; ++ union { ++ struct rtw8852b_u_efuse u; ++ struct rtw8852b_e_efuse e; ++ }; ++} __packed; ++ ++struct rtw8852b_bb_pmac_info { ++ u8 en_pmac_tx:1; ++ u8 is_cck:1; ++ u8 mode:3; ++ u8 rsvd:3; ++ u16 tx_cnt; ++ u16 period; ++ u16 tx_time; ++ u8 duty_cycle; ++}; ++ ++struct rtw8852b_bb_tssi_bak { ++ u8 tx_path; ++ u8 rx_path; ++ u32 p0_rfmode; ++ u32 p0_rfmode_ftm; ++ u32 p1_rfmode; ++ u32 p1_rfmode_ftm; ++ s16 tx_pwr; /* S9 */ ++}; ++ ++extern const struct rtw89_chip_info rtw8852b_chip_info; ++ ++void rtw8852b_bb_set_plcp_tx(struct rtw89_dev *rtwdev); ++void rtw8852b_bb_set_pmac_tx(struct rtw89_dev *rtwdev, ++ struct rtw8852b_bb_pmac_info *tx_info, ++ enum rtw89_phy_idx idx); ++void rtw8852b_bb_set_pmac_pkt_tx(struct rtw89_dev *rtwdev, u8 enable, ++ u16 tx_cnt, u16 period, u16 tx_time, ++ enum rtw89_phy_idx idx); ++void rtw8852b_bb_set_power(struct rtw89_dev *rtwdev, s16 pwr_dbm, ++ enum rtw89_phy_idx idx); ++void rtw8852b_bb_cfg_tx_path(struct rtw89_dev *rtwdev, u8 tx_path); ++void rtw8852b_bb_ctrl_rx_path(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path_bit rx_path); ++void rtw8852b_bb_tx_mode_switch(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx idx, u8 mode); ++void rtw8852b_bb_backup_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, ++ struct rtw8852b_bb_tssi_bak *bak); ++void rtw8852b_bb_restore_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx idx, ++ const struct rtw8852b_bb_tssi_bak *bak); ++ ++#endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c 2022-12-24 00:49:25.783376835 +0200 +@@ -0,0 +1,4174 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2019-2022 Realtek Corporation ++ */ ++ ++#include "coex.h" ++#include "debug.h" ++#include "mac.h" ++#include "phy.h" ++#include "reg.h" ++#include "rtw8852b.h" ++#include "rtw8852b_rfk.h" ++#include "rtw8852b_rfk_table.h" ++#include "rtw8852b_table.h" ++ ++#define RTW8852B_RXDCK_VER 0x1 ++#define RTW8852B_IQK_VER 0x2a ++#define RTW8852B_IQK_SS 2 ++#define RTW8852B_RXK_GROUP_NR 4 ++#define RTW8852B_TSSI_PATH_NR 2 ++#define RTW8852B_RF_REL_VERSION 34 ++#define RTW8852B_DPK_VER 0x0d ++#define RTW8852B_DPK_RF_PATH 2 ++#define RTW8852B_DPK_KIP_REG_NUM 2 ++ ++#define _TSSI_DE_MASK GENMASK(21, 12) ++#define ADDC_T_AVG 100 ++#define DPK_TXAGC_LOWER 0x2e ++#define DPK_TXAGC_UPPER 0x3f ++#define DPK_TXAGC_INVAL 0xff ++#define RFREG_MASKRXBB 0x003e0 ++#define RFREG_MASKMODE 0xf0000 ++ ++enum rtw8852b_dpk_id { ++ LBK_RXIQK = 0x06, ++ SYNC = 0x10, ++ MDPK_IDL = 0x11, ++ MDPK_MPA = 0x12, ++ GAIN_LOSS = 0x13, ++ GAIN_CAL = 0x14, ++ DPK_RXAGC = 0x15, ++ KIP_PRESET = 0x16, ++ KIP_RESTORE = 0x17, ++ DPK_TXAGC = 0x19, ++ D_KIP_PRESET = 0x28, ++ D_TXAGC = 0x29, ++ D_RXAGC = 0x2a, ++ D_SYNC = 0x2b, ++ D_GAIN_LOSS = 0x2c, ++ D_MDPK_IDL = 0x2d, ++ D_GAIN_NORM = 0x2f, ++ D_KIP_THERMAL = 0x30, ++ D_KIP_RESTORE = 0x31 ++}; ++ ++enum dpk_agc_step { ++ DPK_AGC_STEP_SYNC_DGAIN, ++ DPK_AGC_STEP_GAIN_ADJ, ++ DPK_AGC_STEP_GAIN_LOSS_IDX, ++ DPK_AGC_STEP_GL_GT_CRITERION, ++ DPK_AGC_STEP_GL_LT_CRITERION, ++ DPK_AGC_STEP_SET_TX_GAIN, ++}; ++ ++enum rtw8852b_iqk_type { ++ ID_TXAGC = 0x0, ++ ID_FLOK_COARSE = 0x1, ++ ID_FLOK_FINE = 0x2, ++ ID_TXK = 0x3, ++ ID_RXAGC = 0x4, ++ ID_RXK = 0x5, ++ ID_NBTXK = 0x6, ++ ID_NBRXK = 0x7, ++ ID_FLOK_VBUFFER = 0x8, ++ ID_A_FLOK_COARSE = 0x9, ++ ID_G_FLOK_COARSE = 0xa, ++ ID_A_FLOK_FINE = 0xb, ++ ID_G_FLOK_FINE = 0xc, ++ ID_IQK_RESTORE = 0x10, ++}; ++ ++static const u32 _tssi_trigger[RTW8852B_TSSI_PATH_NR] = {0x5820, 0x7820}; ++static const u32 _tssi_cw_rpt_addr[RTW8852B_TSSI_PATH_NR] = {0x1c18, 0x3c18}; ++static const u32 _tssi_cw_default_addr[RTW8852B_TSSI_PATH_NR][4] = { ++ {0x5634, 0x5630, 0x5630, 0x5630}, ++ {0x7634, 0x7630, 0x7630, 0x7630} }; ++static const u32 _tssi_cw_default_mask[4] = { ++ 0x000003ff, 0x3ff00000, 0x000ffc00, 0x000003ff}; ++static const u32 _tssi_de_cck_long[RF_PATH_NUM_8852B] = {0x5858, 0x7858}; ++static const u32 _tssi_de_cck_short[RF_PATH_NUM_8852B] = {0x5860, 0x7860}; ++static const u32 _tssi_de_mcs_20m[RF_PATH_NUM_8852B] = {0x5838, 0x7838}; ++static const u32 _tssi_de_mcs_40m[RF_PATH_NUM_8852B] = {0x5840, 0x7840}; ++static const u32 _tssi_de_mcs_80m[RF_PATH_NUM_8852B] = {0x5848, 0x7848}; ++static const u32 _tssi_de_mcs_80m_80m[RF_PATH_NUM_8852B] = {0x5850, 0x7850}; ++static const u32 _tssi_de_mcs_5m[RF_PATH_NUM_8852B] = {0x5828, 0x7828}; ++static const u32 _tssi_de_mcs_10m[RF_PATH_NUM_8852B] = {0x5830, 0x7830}; ++static const u32 _a_idxrxgain[RTW8852B_RXK_GROUP_NR] = {0x190, 0x198, 0x350, 0x352}; ++static const u32 _a_idxattc2[RTW8852B_RXK_GROUP_NR] = {0x0f, 0x0f, 0x3f, 0x7f}; ++static const u32 _a_idxattc1[RTW8852B_RXK_GROUP_NR] = {0x3, 0x1, 0x0, 0x0}; ++static const u32 _g_idxrxgain[RTW8852B_RXK_GROUP_NR] = {0x212, 0x21c, 0x350, 0x360}; ++static const u32 _g_idxattc2[RTW8852B_RXK_GROUP_NR] = {0x00, 0x00, 0x28, 0x5f}; ++static const u32 _g_idxattc1[RTW8852B_RXK_GROUP_NR] = {0x3, 0x3, 0x2, 0x1}; ++static const u32 _a_power_range[RTW8852B_RXK_GROUP_NR] = {0x0, 0x0, 0x0, 0x0}; ++static const u32 _a_track_range[RTW8852B_RXK_GROUP_NR] = {0x3, 0x3, 0x6, 0x6}; ++static const u32 _a_gain_bb[RTW8852B_RXK_GROUP_NR] = {0x08, 0x0e, 0x06, 0x0e}; ++static const u32 _a_itqt[RTW8852B_RXK_GROUP_NR] = {0x12, 0x12, 0x12, 0x1b}; ++static const u32 _g_power_range[RTW8852B_RXK_GROUP_NR] = {0x0, 0x0, 0x0, 0x0}; ++static const u32 _g_track_range[RTW8852B_RXK_GROUP_NR] = {0x4, 0x4, 0x6, 0x6}; ++static const u32 _g_gain_bb[RTW8852B_RXK_GROUP_NR] = {0x08, 0x0e, 0x06, 0x0e}; ++static const u32 _g_itqt[RTW8852B_RXK_GROUP_NR] = {0x09, 0x12, 0x1b, 0x24}; ++ ++static const u32 rtw8852b_backup_bb_regs[] = {0x2344, 0x5800, 0x7800}; ++static const u32 rtw8852b_backup_rf_regs[] = { ++ 0xde, 0xdf, 0x8b, 0x90, 0x97, 0x85, 0x1e, 0x0, 0x2, 0x5, 0x10005 ++}; ++ ++#define BACKUP_BB_REGS_NR ARRAY_SIZE(rtw8852b_backup_bb_regs) ++#define BACKUP_RF_REGS_NR ARRAY_SIZE(rtw8852b_backup_rf_regs) ++ ++static const struct rtw89_reg3_def rtw8852b_set_nondbcc_path01[] = { ++ {0x20fc, 0xffff0000, 0x0303}, ++ {0x5864, 0x18000000, 0x3}, ++ {0x7864, 0x18000000, 0x3}, ++ {0x12b8, 0x40000000, 0x1}, ++ {0x32b8, 0x40000000, 0x1}, ++ {0x030c, 0xff000000, 0x13}, ++ {0x032c, 0xffff0000, 0x0041}, ++ {0x12b8, 0x10000000, 0x1}, ++ {0x58c8, 0x01000000, 0x1}, ++ {0x78c8, 0x01000000, 0x1}, ++ {0x5864, 0xc0000000, 0x3}, ++ {0x7864, 0xc0000000, 0x3}, ++ {0x2008, 0x01ffffff, 0x1ffffff}, ++ {0x0c1c, 0x00000004, 0x1}, ++ {0x0700, 0x08000000, 0x1}, ++ {0x0c70, 0x000003ff, 0x3ff}, ++ {0x0c60, 0x00000003, 0x3}, ++ {0x0c6c, 0x00000001, 0x1}, ++ {0x58ac, 0x08000000, 0x1}, ++ {0x78ac, 0x08000000, 0x1}, ++ {0x0c3c, 0x00000200, 0x1}, ++ {0x2344, 0x80000000, 0x1}, ++ {0x4490, 0x80000000, 0x1}, ++ {0x12a0, 0x00007000, 0x7}, ++ {0x12a0, 0x00008000, 0x1}, ++ {0x12a0, 0x00070000, 0x3}, ++ {0x12a0, 0x00080000, 0x1}, ++ {0x32a0, 0x00070000, 0x3}, ++ {0x32a0, 0x00080000, 0x1}, ++ {0x0700, 0x01000000, 0x1}, ++ {0x0700, 0x06000000, 0x2}, ++ {0x20fc, 0xffff0000, 0x3333}, ++}; ++ ++static const struct rtw89_reg3_def rtw8852b_restore_nondbcc_path01[] = { ++ {0x20fc, 0xffff0000, 0x0303}, ++ {0x12b8, 0x40000000, 0x0}, ++ {0x32b8, 0x40000000, 0x0}, ++ {0x5864, 0xc0000000, 0x0}, ++ {0x7864, 0xc0000000, 0x0}, ++ {0x2008, 0x01ffffff, 0x0000000}, ++ {0x0c1c, 0x00000004, 0x0}, ++ {0x0700, 0x08000000, 0x0}, ++ {0x0c70, 0x0000001f, 0x03}, ++ {0x0c70, 0x000003e0, 0x03}, ++ {0x12a0, 0x000ff000, 0x00}, ++ {0x32a0, 0x000ff000, 0x00}, ++ {0x0700, 0x07000000, 0x0}, ++ {0x20fc, 0xffff0000, 0x0000}, ++ {0x58c8, 0x01000000, 0x0}, ++ {0x78c8, 0x01000000, 0x0}, ++ {0x0c3c, 0x00000200, 0x0}, ++ {0x2344, 0x80000000, 0x0}, ++}; ++ ++static void _rfk_backup_bb_reg(struct rtw89_dev *rtwdev, u32 backup_bb_reg_val[]) ++{ ++ u32 i; ++ ++ for (i = 0; i < BACKUP_BB_REGS_NR; i++) { ++ backup_bb_reg_val[i] = ++ rtw89_phy_read32_mask(rtwdev, rtw8852b_backup_bb_regs[i], ++ MASKDWORD); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RFK]backup bb reg : %x, value =%x\n", ++ rtw8852b_backup_bb_regs[i], backup_bb_reg_val[i]); ++ } ++} ++ ++static void _rfk_backup_rf_reg(struct rtw89_dev *rtwdev, u32 backup_rf_reg_val[], ++ u8 rf_path) ++{ ++ u32 i; ++ ++ for (i = 0; i < BACKUP_RF_REGS_NR; i++) { ++ backup_rf_reg_val[i] = ++ rtw89_read_rf(rtwdev, rf_path, ++ rtw8852b_backup_rf_regs[i], RFREG_MASK); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RFK]backup rf S%d reg : %x, value =%x\n", rf_path, ++ rtw8852b_backup_rf_regs[i], backup_rf_reg_val[i]); ++ } ++} ++ ++static void _rfk_restore_bb_reg(struct rtw89_dev *rtwdev, ++ const u32 backup_bb_reg_val[]) ++{ ++ u32 i; ++ ++ for (i = 0; i < BACKUP_BB_REGS_NR; i++) { ++ rtw89_phy_write32_mask(rtwdev, rtw8852b_backup_bb_regs[i], ++ MASKDWORD, backup_bb_reg_val[i]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RFK]restore bb reg : %x, value =%x\n", ++ rtw8852b_backup_bb_regs[i], backup_bb_reg_val[i]); ++ } ++} ++ ++static void _rfk_restore_rf_reg(struct rtw89_dev *rtwdev, ++ const u32 backup_rf_reg_val[], u8 rf_path) ++{ ++ u32 i; ++ ++ for (i = 0; i < BACKUP_RF_REGS_NR; i++) { ++ rtw89_write_rf(rtwdev, rf_path, rtw8852b_backup_rf_regs[i], ++ RFREG_MASK, backup_rf_reg_val[i]); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RFK]restore rf S%d reg: %x, value =%x\n", rf_path, ++ rtw8852b_backup_rf_regs[i], backup_rf_reg_val[i]); ++ } ++} ++ ++static void _rfk_rf_direct_cntrl(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path path, bool is_bybb) ++{ ++ if (is_bybb) ++ rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x1); ++ else ++ rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); ++} ++ ++static void _rfk_drf_direct_cntrl(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path path, bool is_bybb) ++{ ++ if (is_bybb) ++ rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x1); ++ else ++ rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x0); ++} ++ ++static bool _iqk_check_cal(struct rtw89_dev *rtwdev, u8 path) ++{ ++ bool fail = true; ++ u32 val; ++ int ret; ++ ++ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x55, ++ 1, 8200, false, rtwdev, 0xbff8, MASKBYTE0); ++ if (ret) ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]NCTL1 IQK timeout!!!\n"); ++ ++ udelay(200); ++ ++ if (!ret) ++ fail = rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, MASKBYTE0, 0x0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, ret=%d\n", path, ret); ++ val = rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x8008 = 0x%x\n", path, val); ++ ++ return fail; ++} ++ ++static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) ++{ ++ u8 val; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]dbcc_en: %x,PHY%d\n", ++ rtwdev->dbcc_en, phy_idx); ++ ++ if (!rtwdev->dbcc_en) { ++ val = RF_AB; ++ } else { ++ if (phy_idx == RTW89_PHY_0) ++ val = RF_A; ++ else ++ val = RF_B; ++ } ++ return val; ++} ++ ++static void _set_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ rtw89_write_rf(rtwdev, path, RR_DCK1, RR_DCK1_CLR, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x1); ++ mdelay(1); ++} ++ ++static void _rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) ++{ ++ u8 path, dck_tune; ++ u32 rf_reg5; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RX_DCK] ****** RXDCK Start (Ver: 0x%x, CV : 0x%x) ******\n", ++ RTW8852B_RXDCK_VER, rtwdev->hal.cv); ++ ++ for (path = 0; path < RF_PATH_NUM_8852B; path++) { ++ rf_reg5 = rtw89_read_rf(rtwdev, path, RR_RSV1, RFREG_MASK); ++ dck_tune = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_FINE); ++ ++ if (rtwdev->is_tssi_mode[path]) ++ rtw89_phy_write32_mask(rtwdev, ++ R_P0_TSSI_TRK + (path << 13), ++ B_P0_TSSI_TRK_EN, 0x1); ++ ++ rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_FINE, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX); ++ _set_rx_dck(rtwdev, phy, path); ++ rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_FINE, dck_tune); ++ rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5); ++ ++ if (rtwdev->is_tssi_mode[path]) ++ rtw89_phy_write32_mask(rtwdev, ++ R_P0_TSSI_TRK + (path << 13), ++ B_P0_TSSI_TRK_EN, 0x0); ++ } ++} ++ ++static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) ++{ ++ u32 rf_reg5; ++ u32 rck_val; ++ u32 val; ++ int ret; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] ====== S%d RCK ======\n", path); ++ ++ rf_reg5 = rtw89_read_rf(rtwdev, path, RR_RSV1, RFREG_MASK); ++ ++ rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] RF0x00 = 0x%05x\n", ++ rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK)); ++ ++ /* RCK trigger */ ++ rtw89_write_rf(rtwdev, path, RR_RCKC, RFREG_MASK, 0x00240); ++ ++ ret = read_poll_timeout_atomic(rtw89_read_rf, val, val, 2, 30, ++ false, rtwdev, path, RR_RCKS, BIT(3)); ++ ++ rck_val = rtw89_read_rf(rtwdev, path, RR_RCKC, RR_RCKC_CA); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] rck_val = 0x%x, ret = %d\n", ++ rck_val, ret); ++ ++ rtw89_write_rf(rtwdev, path, RR_RCKC, RFREG_MASK, rck_val); ++ rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] RF 0x1b = 0x%x\n", ++ rtw89_read_rf(rtwdev, path, RR_RCKC, RFREG_MASK)); ++} ++ ++static void _afe_init(struct rtw89_dev *rtwdev) ++{ ++ rtw89_write32(rtwdev, R_AX_PHYREG_SET, 0xf); ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_afe_init_defs_tbl); ++} ++ ++static void _drck(struct rtw89_dev *rtwdev) ++{ ++ u32 rck_d; ++ u32 val; ++ int ret; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]Ddie RCK start!!!\n"); ++ rtw89_phy_write32_mask(rtwdev, R_DRCK_V1, B_DRCK_V1_KICK, 0x1); ++ ++ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, 1, 10000, ++ false, rtwdev, R_DRCK_RS, B_DRCK_RS_DONE); ++ if (ret) ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DRCK timeout\n"); ++ ++ rtw89_phy_write32_mask(rtwdev, R_DRCK_V1, B_DRCK_V1_KICK, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_DRCK_FH, B_DRCK_LAT, 0x1); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_DRCK_FH, B_DRCK_LAT, 0x0); ++ rck_d = rtw89_phy_read32_mask(rtwdev, R_DRCK_RS, B_DRCK_RS_LPS); ++ rtw89_phy_write32_mask(rtwdev, R_DRCK_V1, B_DRCK_V1_SEL, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_DRCK_V1, B_DRCK_V1_CV, rck_d); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0xc0cc = 0x%x\n", ++ rtw89_phy_read32_mask(rtwdev, R_DRCK_V1, MASKDWORD)); ++} ++ ++static void _addck_backup(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0, 0x0); ++ dack->addck_d[0][0] = rtw89_phy_read32_mask(rtwdev, R_ADDCKR0, B_ADDCKR0_A0); ++ dack->addck_d[0][1] = rtw89_phy_read32_mask(rtwdev, R_ADDCKR0, B_ADDCKR0_A1); ++ ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1, 0x0); ++ dack->addck_d[1][0] = rtw89_phy_read32_mask(rtwdev, R_ADDCKR1, B_ADDCKR1_A0); ++ dack->addck_d[1][1] = rtw89_phy_read32_mask(rtwdev, R_ADDCKR1, B_ADDCKR1_A1); ++} ++ ++static void _addck_reload(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ ++ /* S0 */ ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK0D_VAL, dack->addck_d[0][0]); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_VAL, dack->addck_d[0][1] >> 6); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK0D_VAL2, dack->addck_d[0][1] & 0x3f); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_MAN, 0x3); ++ ++ /* S1 */ ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK1D, B_ADDCK1D_VAL, dack->addck_d[1][0]); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK0_VAL, dack->addck_d[1][1] >> 6); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK1D, B_ADDCK1D_VAL2, dack->addck_d[1][1] & 0x3f); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1_MAN, 0x3); ++} ++ ++static void _dack_backup_s0(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ u8 i; ++ ++ rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); ++ ++ for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { ++ rtw89_phy_write32_mask(rtwdev, R_DCOF0, B_DCOF0_V, i); ++ dack->msbk_d[0][0][i] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_S0P2, B_DACK_S0M0); ++ rtw89_phy_write32_mask(rtwdev, R_DCOF8, B_DCOF8_V, i); ++ dack->msbk_d[0][1][i] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_S0P3, B_DACK_S0M1); ++ } ++ ++ dack->biask_d[0][0] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS00, B_DACK_BIAS00); ++ dack->biask_d[0][1] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS01, B_DACK_BIAS01); ++ ++ dack->dadck_d[0][0] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK00, B_DACK_DADCK00); ++ dack->dadck_d[0][1] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK01, B_DACK_DADCK01); ++} ++ ++static void _dack_backup_s1(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ u8 i; ++ ++ rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); ++ ++ for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { ++ rtw89_phy_write32_mask(rtwdev, R_DACK10, B_DACK10, i); ++ dack->msbk_d[1][0][i] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK10S, B_DACK10S); ++ rtw89_phy_write32_mask(rtwdev, R_DACK11, B_DACK11, i); ++ dack->msbk_d[1][1][i] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK11S, B_DACK11S); ++ } ++ ++ dack->biask_d[1][0] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS10, B_DACK_BIAS10); ++ dack->biask_d[1][1] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS11, B_DACK_BIAS11); ++ ++ dack->dadck_d[1][0] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK10, B_DACK_DADCK10); ++ dack->dadck_d[1][1] = ++ rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK11, B_DACK_DADCK11); ++} ++ ++static void _check_addc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) ++{ ++ s32 dc_re = 0, dc_im = 0; ++ u32 tmp; ++ u32 i; ++ ++ rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, ++ &rtw8852b_check_addc_defs_a_tbl, ++ &rtw8852b_check_addc_defs_b_tbl); ++ ++ for (i = 0; i < ADDC_T_AVG; i++) { ++ tmp = rtw89_phy_read32_mask(rtwdev, R_DBG32_D, MASKDWORD); ++ dc_re += sign_extend32(FIELD_GET(0xfff000, tmp), 11); ++ dc_im += sign_extend32(FIELD_GET(0xfff, tmp), 11); ++ } ++ ++ dc_re /= ADDC_T_AVG; ++ dc_im /= ADDC_T_AVG; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DACK]S%d,dc_re = 0x%x,dc_im =0x%x\n", path, dc_re, dc_im); ++} ++ ++static void _addck(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ u32 val; ++ int ret; ++ ++ /* S0 */ ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_MAN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, 0x30, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_ADCCLK, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_FLTRST, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_FLTRST, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0xf); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_SAMPL_DLY_T_V1, BIT(1), 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0x3); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]before S0 ADDCK\n"); ++ _check_addc(rtwdev, RF_PATH_A); ++ ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_TRG, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_TRG, 0x0); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0, 0x1); ++ ++ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, 1, 10000, ++ false, rtwdev, R_ADDCKR0, BIT(0)); ++ if (ret) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADDCK timeout\n"); ++ dack->addck_timeout[0] = true; ++ } ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]ADDCK ret = %d\n", ret); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]after S0 ADDCK\n"); ++ _check_addc(rtwdev, RF_PATH_A); ++ ++ rtw89_phy_write32_mask(rtwdev, R_PATH0_SAMPL_DLY_T_V1, BIT(1), 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0xc); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_ADCCLK, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x0); ++ ++ /* S1 */ ++ rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_ADCCLK, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_FLTRST, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_FLTRST, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0xf); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, BIT(1), 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0x3); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]before S1 ADDCK\n"); ++ _check_addc(rtwdev, RF_PATH_B); ++ ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1_TRG, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1_TRG, 0x0); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ADDCK1, B_ADDCK1, 0x1); ++ ++ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, 1, 10000, ++ false, rtwdev, R_ADDCKR1, BIT(0)); ++ if (ret) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADDCK timeout\n"); ++ dack->addck_timeout[1] = true; ++ } ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]ADDCK ret = %d\n", ret); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]after S1 ADDCK\n"); ++ _check_addc(rtwdev, RF_PATH_B); ++ ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_SAMPL_DLY_T_V1, BIT(1), 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15_H, 0xc); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_ADCCLK, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x0); ++} ++ ++static void _check_dadc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) ++{ ++ rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, ++ &rtw8852b_check_dadc_en_defs_a_tbl, ++ &rtw8852b_check_dadc_en_defs_b_tbl); ++ ++ _check_addc(rtwdev, path); ++ ++ rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, ++ &rtw8852b_check_dadc_dis_defs_a_tbl, ++ &rtw8852b_check_dadc_dis_defs_b_tbl); ++} ++ ++static bool _dack_s0_check_done(struct rtw89_dev *rtwdev, bool part1) ++{ ++ if (part1) { ++ if (rtw89_phy_read32_mask(rtwdev, R_DACK_S0P0, B_DACK_S0P0_OK) == 0 || ++ rtw89_phy_read32_mask(rtwdev, R_DACK_S0P1, B_DACK_S0P1_OK) == 0) ++ return false; ++ } else { ++ if (rtw89_phy_read32_mask(rtwdev, R_DACK_S0P2, B_DACK_S0P2_OK) == 0 || ++ rtw89_phy_read32_mask(rtwdev, R_DACK_S0P3, B_DACK_S0P3_OK) == 0) ++ return false; ++ } ++ ++ return true; ++} ++ ++static void _dack_s0(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ bool done; ++ int ret; ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dack_s0_1_defs_tbl); ++ ++ ret = read_poll_timeout_atomic(_dack_s0_check_done, done, done, 1, 10000, ++ false, rtwdev, true); ++ if (ret) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK timeout\n"); ++ dack->msbk_timeout[0] = true; ++ } ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK ret = %d\n", ret); ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dack_s0_2_defs_tbl); ++ ++ ret = read_poll_timeout_atomic(_dack_s0_check_done, done, done, 1, 10000, ++ false, rtwdev, false); ++ if (ret) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 DADCK timeout\n"); ++ dack->dadck_timeout[0] = true; ++ } ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK ret = %d\n", ret); ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dack_s0_3_defs_tbl); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]after S0 DADCK\n"); ++ ++ _dack_backup_s0(rtwdev); ++ rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x0); ++} ++ ++static bool _dack_s1_check_done(struct rtw89_dev *rtwdev, bool part1) ++{ ++ if (part1) { ++ if (rtw89_phy_read32_mask(rtwdev, R_DACK_S1P0, B_DACK_S1P0_OK) == 0 && ++ rtw89_phy_read32_mask(rtwdev, R_DACK_S1P1, B_DACK_S1P1_OK) == 0) ++ return false; ++ } else { ++ if (rtw89_phy_read32_mask(rtwdev, R_DACK10S, B_DACK_S1P2_OK) == 0 && ++ rtw89_phy_read32_mask(rtwdev, R_DACK11S, B_DACK_S1P3_OK) == 0) ++ return false; ++ } ++ ++ return true; ++} ++ ++static void _dack_s1(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ bool done; ++ int ret; ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dack_s1_1_defs_tbl); ++ ++ ret = read_poll_timeout_atomic(_dack_s1_check_done, done, done, 1, 10000, ++ false, rtwdev, true); ++ if (ret) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK timeout\n"); ++ dack->msbk_timeout[1] = true; ++ } ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK ret = %d\n", ret); ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dack_s1_2_defs_tbl); ++ ++ ret = read_poll_timeout_atomic(_dack_s1_check_done, done, done, 1, 10000, ++ false, rtwdev, false); ++ if (ret) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 DADCK timeout\n"); ++ dack->dadck_timeout[1] = true; ++ } ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK ret = %d\n", ret); ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dack_s1_3_defs_tbl); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]after S1 DADCK\n"); ++ ++ _check_dadc(rtwdev, RF_PATH_B); ++ _dack_backup_s1(rtwdev); ++ rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x0); ++} ++ ++static void _dack(struct rtw89_dev *rtwdev) ++{ ++ _dack_s0(rtwdev); ++ _dack_s1(rtwdev); ++} ++ ++static void _dack_dump(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ u8 i; ++ u8 t; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DACK]S0 ADC_DCK ic = 0x%x, qc = 0x%x\n", ++ dack->addck_d[0][0], dack->addck_d[0][1]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DACK]S1 ADC_DCK ic = 0x%x, qc = 0x%x\n", ++ dack->addck_d[1][0], dack->addck_d[1][1]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DACK]S0 DAC_DCK ic = 0x%x, qc = 0x%x\n", ++ dack->dadck_d[0][0], dack->dadck_d[0][1]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DACK]S1 DAC_DCK ic = 0x%x, qc = 0x%x\n", ++ dack->dadck_d[1][0], dack->dadck_d[1][1]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DACK]S0 biask ic = 0x%x, qc = 0x%x\n", ++ dack->biask_d[0][0], dack->biask_d[0][1]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DACK]S1 biask ic = 0x%x, qc = 0x%x\n", ++ dack->biask_d[1][0], dack->biask_d[1][1]); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic:\n"); ++ for (i = 0; i < 0x10; i++) { ++ t = dack->msbk_d[0][0][i]; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc:\n"); ++ for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { ++ t = dack->msbk_d[0][1][i]; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic:\n"); ++ for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { ++ t = dack->msbk_d[1][0][i]; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc:\n"); ++ for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { ++ t = dack->msbk_d[1][1][i]; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); ++ } ++} ++ ++static void _dac_cal(struct rtw89_dev *rtwdev, bool force) ++{ ++ struct rtw89_dack_info *dack = &rtwdev->dack; ++ u32 rf0_0, rf1_0; ++ ++ dack->dack_done = false; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK 0x1\n"); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK start!!!\n"); ++ ++ rf0_0 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_MOD, RFREG_MASK); ++ rf1_0 = rtw89_read_rf(rtwdev, RF_PATH_B, RR_MOD, RFREG_MASK); ++ _afe_init(rtwdev); ++ _drck(rtwdev); ++ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RR_RSV1_RST, 0x0); ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, RR_RSV1_RST, 0x0); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RFREG_MASK, 0x337e1); ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, RFREG_MASK, 0x337e1); ++ _addck(rtwdev); ++ _addck_backup(rtwdev); ++ _addck_reload(rtwdev); ++ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MODOPT, RFREG_MASK, 0x0); ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MODOPT, RFREG_MASK, 0x0); ++ _dack(rtwdev); ++ _dack_dump(rtwdev); ++ dack->dack_done = true; ++ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RFREG_MASK, rf0_0); ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_MOD, RFREG_MASK, rf1_0); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RR_RSV1_RST, 0x1); ++ rtw89_write_rf(rtwdev, RF_PATH_B, RR_RSV1, RR_RSV1_RST, 0x1); ++ dack->dack_cnt++; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK finish!!!\n"); ++} ++ ++static void _iqk_rxk_setting(struct rtw89_dev *rtwdev, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ u32 tmp; ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, 0xc); ++ rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_SEL2G, 0x1); ++ tmp = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); ++ rtw89_write_rf(rtwdev, path, RR_RSV4, RFREG_MASK, tmp); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, 0xc); ++ rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_SEL5G, 0x1); ++ tmp = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); ++ rtw89_write_rf(rtwdev, path, RR_RSV4, RFREG_MASK, tmp); ++ break; ++ default: ++ break; ++ } ++} ++ ++static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, ++ u8 path, u8 ktype) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ u32 iqk_cmd; ++ bool fail; ++ ++ switch (ktype) { ++ case ID_FLOK_COARSE: ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); ++ iqk_cmd = 0x108 | (1 << (4 + path)); ++ break; ++ case ID_FLOK_FINE: ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); ++ iqk_cmd = 0x208 | (1 << (4 + path)); ++ break; ++ case ID_FLOK_VBUFFER: ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); ++ iqk_cmd = 0x308 | (1 << (4 + path)); ++ break; ++ case ID_TXK: ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); ++ iqk_cmd = 0x008 | (1 << (path + 4)) | ++ (((0x8 + iqk_info->iqk_bw[path]) & 0xf) << 8); ++ break; ++ case ID_RXAGC: ++ iqk_cmd = 0x508 | (1 << (4 + path)) | (path << 1); ++ break; ++ case ID_RXK: ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); ++ iqk_cmd = 0x008 | (1 << (path + 4)) | ++ (((0xb + iqk_info->iqk_bw[path]) & 0xf) << 8); ++ break; ++ case ID_NBTXK: ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x011); ++ iqk_cmd = 0x308 | (1 << (4 + path)); ++ break; ++ case ID_NBRXK: ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); ++ iqk_cmd = 0x608 | (1 << (4 + path)); ++ break; ++ default: ++ return false; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, iqk_cmd + 1); ++ udelay(1); ++ fail = _iqk_check_cal(rtwdev, path); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); ++ ++ return fail; ++} ++ ++static bool _rxk_group_sel(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, ++ u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ bool kfail = false; ++ bool fail; ++ u8 gp; ++ ++ for (gp = 0; gp < RTW8852B_RXK_GROUP_NR; gp++) { ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RGM, ++ _g_idxrxgain[gp]); ++ rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_C2G, ++ _g_idxattc2[gp]); ++ rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_C1G, ++ _g_idxattc1[gp]); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RGM, ++ _a_idxrxgain[gp]); ++ rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RXA2_HATT, ++ _a_idxattc2[gp]); ++ rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RXA2_CC2, ++ _a_idxattc1[gp]); ++ break; ++ default: ++ break; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), ++ B_CFIR_LUT_SEL, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), ++ B_CFIR_LUT_SET, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), ++ B_CFIR_LUT_GP_V1, gp); ++ fail = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXK); ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, ++ BIT(16 + gp + path * 4), fail); ++ kfail |= fail; ++ } ++ rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_SEL5G, 0x0); ++ ++ if (kfail) { ++ iqk_info->nb_rxcfir[path] = 0x40000002; ++ rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), ++ B_IQK_RES_RXCFIR, 0x0); ++ iqk_info->is_wb_rxiqk[path] = false; ++ } else { ++ iqk_info->nb_rxcfir[path] = 0x40000000; ++ rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), ++ B_IQK_RES_RXCFIR, 0x5); ++ iqk_info->is_wb_rxiqk[path] = true; ++ } ++ ++ return kfail; ++} ++ ++static bool _iqk_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, ++ u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ const u8 gp = 0x3; ++ bool kfail = false; ++ bool fail; ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RGM, ++ _g_idxrxgain[gp]); ++ rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_C2G, ++ _g_idxattc2[gp]); ++ rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_C1G, ++ _g_idxattc1[gp]); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RGM, ++ _a_idxrxgain[gp]); ++ rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RXA2_HATT, ++ _a_idxattc2[gp]); ++ rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RXA2_CC2, ++ _a_idxattc1[gp]); ++ break; ++ default: ++ break; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_SEL, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_SET, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_GP_V1, gp); ++ rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); ++ udelay(1); ++ ++ fail = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, BIT(16 + gp + path * 4), fail); ++ kfail |= fail; ++ rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_SEL5G, 0x0); ++ ++ if (!kfail) ++ iqk_info->nb_rxcfir[path] = ++ rtw89_phy_read32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD) | 0x2; ++ else ++ iqk_info->nb_rxcfir[path] = 0x40000002; ++ ++ return kfail; ++} ++ ++static void _iqk_rxclk_setting(struct rtw89_dev *rtwdev, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ ++ if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x0f); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x03); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0xa001); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0xa041); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_VAL, 0x2); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ON, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RXCK, B_P1_RXCK_VAL, 0x2); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RXCK, B_P1_RXCK_ON, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_CLK_ADC_ON, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_CLK_ADC_VAL, 0x1); ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x0f); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x03); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0xa001); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0xa041); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_VAL, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ON, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RXCK, B_P1_RXCK_VAL, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RXCK, B_P1_RXCK_ON, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_CLK_ADC_ON, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_UPD_CLK_ADC_VAL, 0x0); ++ } ++} ++ ++static bool _txk_group_sel(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ bool kfail = false; ++ bool fail; ++ u8 gp; ++ ++ for (gp = 0x0; gp < RTW8852B_RXK_GROUP_NR; gp++) { ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, ++ _g_power_range[gp]); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, ++ _g_track_range[gp]); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, ++ _g_gain_bb[gp]); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), ++ MASKDWORD, _g_itqt[gp]); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, ++ _a_power_range[gp]); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, ++ _a_track_range[gp]); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, ++ _a_gain_bb[gp]); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), ++ MASKDWORD, _a_itqt[gp]); ++ break; ++ default: ++ break; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), ++ B_CFIR_LUT_SEL, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), ++ B_CFIR_LUT_SET, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), ++ B_CFIR_LUT_G2, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), ++ B_CFIR_LUT_GP, gp); ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); ++ fail = _iqk_one_shot(rtwdev, phy_idx, path, ID_TXK); ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, ++ BIT(8 + gp + path * 4), fail); ++ kfail |= fail; ++ } ++ ++ if (kfail) { ++ iqk_info->nb_txcfir[path] = 0x40000002; ++ rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), ++ B_IQK_RES_TXCFIR, 0x0); ++ iqk_info->is_wb_txiqk[path] = false; ++ } else { ++ iqk_info->nb_txcfir[path] = 0x40000000; ++ rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), ++ B_IQK_RES_TXCFIR, 0x5); ++ iqk_info->is_wb_txiqk[path] = true; ++ } ++ ++ return kfail; ++} ++ ++static bool _iqk_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ bool kfail; ++ u8 gp = 0x3; ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, ++ _g_power_range[gp]); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, ++ _g_track_range[gp]); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, ++ _g_gain_bb[gp]); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), ++ MASKDWORD, _g_itqt[gp]); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, ++ _a_power_range[gp]); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, ++ _a_track_range[gp]); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, ++ _a_gain_bb[gp]); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), ++ MASKDWORD, _a_itqt[gp]); ++ break; ++ default: ++ break; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_SEL, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_SET, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_G2, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_GP, gp); ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); ++ kfail = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); ++ ++ if (!kfail) ++ iqk_info->nb_txcfir[path] = ++ rtw89_phy_read32_mask(rtwdev, R_TXIQC + (path << 8), ++ MASKDWORD) | 0x2; ++ else ++ iqk_info->nb_txcfir[path] = 0x40000002; ++ ++ return kfail; ++} ++ ++static void _lok_res_table(struct rtw89_dev *rtwdev, u8 path, u8 ibias) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, ibias = %x\n", path, ibias); ++ ++ rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0x2); ++ if (iqk_info->iqk_band[path] == RTW89_BAND_2G) ++ rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, 0x0); ++ else ++ rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, ibias); ++ rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_TXVBUF, RR_TXVBUF_DACEN, 0x1); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x7c = %x\n", path, ++ rtw89_read_rf(rtwdev, path, RR_TXVBUF, RFREG_MASK)); ++} ++ ++static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ bool is_fail1, is_fail2; ++ u32 vbuff_i; ++ u32 vbuff_q; ++ u32 core_i; ++ u32 core_q; ++ u32 tmp; ++ u8 ch; ++ ++ tmp = rtw89_read_rf(rtwdev, path, RR_TXMO, RFREG_MASK); ++ core_i = FIELD_GET(RR_TXMO_COI, tmp); ++ core_q = FIELD_GET(RR_TXMO_COQ, tmp); ++ ch = (iqk_info->iqk_times / 2) % RTW89_IQK_CHS_NR; ++ ++ if (core_i < 0x2 || core_i > 0x1d || core_q < 0x2 || core_q > 0x1d) ++ is_fail1 = true; ++ else ++ is_fail1 = false; ++ ++ iqk_info->lok_idac[ch][path] = tmp; ++ ++ tmp = rtw89_read_rf(rtwdev, path, RR_LOKVB, RFREG_MASK); ++ vbuff_i = FIELD_GET(RR_LOKVB_COI, tmp); ++ vbuff_q = FIELD_GET(RR_LOKVB_COQ, tmp); ++ ++ if (vbuff_i < 0x2 || vbuff_i > 0x3d || vbuff_q < 0x2 || vbuff_q > 0x3d) ++ is_fail2 = true; ++ else ++ is_fail2 = false; ++ ++ iqk_info->lok_vbuf[ch][path] = tmp; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[IQK]S%x, lok_idac[%x][%x] = 0x%x\n", path, ch, path, ++ iqk_info->lok_idac[ch][path]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[IQK]S%x, lok_vbuf[%x][%x] = 0x%x\n", path, ch, path, ++ iqk_info->lok_vbuf[ch][path]); ++ ++ return is_fail1 | is_fail2; ++} ++ ++static bool _iqk_lok(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ bool tmp; ++ ++ rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x021); ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, 0x6); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, 0x4); ++ break; ++ default: ++ break; ++ } ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x0); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x0); ++ break; ++ default: ++ break; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), MASKDWORD, 0x9); ++ tmp = _iqk_one_shot(rtwdev, phy_idx, path, ID_FLOK_COARSE); ++ iqk_info->lok_cor_fail[0][path] = tmp; ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x12); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x12); ++ break; ++ default: ++ break; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), MASKDWORD, 0x24); ++ tmp = _iqk_one_shot(rtwdev, phy_idx, path, ID_FLOK_VBUFFER); ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x0); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x0); ++ break; ++ default: ++ break; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), MASKDWORD, 0x9); ++ rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x021); ++ tmp = _iqk_one_shot(rtwdev, phy_idx, path, ID_FLOK_FINE); ++ iqk_info->lok_fin_fail[0][path] = tmp; ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x12); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0x12); ++ break; ++ default: ++ break; ++ } ++ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), MASKDWORD, 0x24); ++ _iqk_one_shot(rtwdev, phy_idx, path, ID_FLOK_VBUFFER); ++ ++ return _lok_finetune_check(rtwdev, path); ++} ++ ++static void _iqk_txk_setting(struct rtw89_dev *rtwdev, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ ++ switch (iqk_info->iqk_band[path]) { ++ case RTW89_BAND_2G: ++ rtw89_write_rf(rtwdev, path, RR_XALNA2, RR_XALNA2_SW2, 0x00); ++ rtw89_write_rf(rtwdev, path, RR_TXG1, RR_TXG1_ATT2, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_TXG1, RR_TXG1_ATT1, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_TXG2, RR_TXG2_ATT0, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_TXGA, RR_TXGA_LOK_EXT, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_LUTWE, RR_LUTWE_LOK, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_LUTWA, RR_LUTWA_M1, 0x00); ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_IQK, 0x403e); ++ udelay(1); ++ break; ++ case RTW89_BAND_5G: ++ rtw89_write_rf(rtwdev, path, RR_XGLNA2, RR_XGLNA2_SW, 0x00); ++ rtw89_write_rf(rtwdev, path, RR_BIASA, RR_BIASA_A, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_TXGA, RR_TXGA_LOK_EXT, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_LUTWE, RR_LUTWE_LOK, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_LUTWA, RR_LUTWA_M1, 0x80); ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_IQK, 0x403e); ++ udelay(1); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void _iqk_txclk_setting(struct rtw89_dev *rtwdev, u8 path) ++{ ++ rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_DBGMOD, B_P1_DBGMOD_ON, 0x1); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x1f); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x13); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0001); ++ udelay(1); ++ rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0041); ++} ++ ++static void _iqk_info_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ u32 tmp; ++ bool flag; ++ ++ iqk_info->thermal[path] = ++ ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); ++ iqk_info->thermal_rek_en = false; ++ ++ flag = iqk_info->lok_cor_fail[0][path]; ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, B_IQKINF_FCOR << (path * 4), flag); ++ flag = iqk_info->lok_fin_fail[0][path]; ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, B_IQKINF_FFIN << (path * 4), flag); ++ flag = iqk_info->iqk_tx_fail[0][path]; ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, B_IQKINF_FTX << (path * 4), flag); ++ flag = iqk_info->iqk_rx_fail[0][path]; ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, B_IQKINF_F_RX << (path * 4), flag); ++ ++ tmp = rtw89_phy_read32_mask(rtwdev, R_IQK_RES + (path << 8), MASKDWORD); ++ iqk_info->bp_iqkenable[path] = tmp; ++ tmp = rtw89_phy_read32_mask(rtwdev, R_TXIQC + (path << 8), MASKDWORD); ++ iqk_info->bp_txkresult[path] = tmp; ++ tmp = rtw89_phy_read32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD); ++ iqk_info->bp_rxkresult[path] = tmp; ++ ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF2, B_IQKINF2_KCNT, iqk_info->iqk_times); ++ ++ tmp = rtw89_phy_read32_mask(rtwdev, R_IQKINF, B_IQKINF_FAIL << (path * 4)); ++ if (tmp) ++ iqk_info->iqk_fail_cnt++; ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF2, B_IQKINF2_FCNT << (path * 4), ++ iqk_info->iqk_fail_cnt); ++} ++ ++static void _iqk_by_path(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ bool lok_is_fail = false; ++ const int try = 3; ++ u8 ibias = 0x1; ++ u8 i; ++ ++ _iqk_txclk_setting(rtwdev, path); ++ ++ /* LOK */ ++ for (i = 0; i < try; i++) { ++ _lok_res_table(rtwdev, path, ibias++); ++ _iqk_txk_setting(rtwdev, path); ++ lok_is_fail = _iqk_lok(rtwdev, phy_idx, path); ++ if (!lok_is_fail) ++ break; ++ } ++ ++ if (lok_is_fail) ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] LOK (%d) fail\n", path); ++ ++ /* TXK */ ++ if (iqk_info->is_nbiqk) ++ iqk_info->iqk_tx_fail[0][path] = _iqk_nbtxk(rtwdev, phy_idx, path); ++ else ++ iqk_info->iqk_tx_fail[0][path] = _txk_group_sel(rtwdev, phy_idx, path); ++ ++ /* RX */ ++ _iqk_rxclk_setting(rtwdev, path); ++ _iqk_rxk_setting(rtwdev, path); ++ if (iqk_info->is_nbiqk) ++ iqk_info->iqk_rx_fail[0][path] = _iqk_nbrxk(rtwdev, phy_idx, path); ++ else ++ iqk_info->iqk_rx_fail[0][path] = _rxk_group_sel(rtwdev, phy_idx, path); ++ ++ _iqk_info_iqk(rtwdev, phy_idx, path); ++} ++ ++static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 path) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ u32 reg_rf18; ++ u32 reg_35c; ++ u8 idx; ++ u8 get_empty_table = false; ++ ++ for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { ++ if (iqk_info->iqk_mcc_ch[idx][path] == 0) { ++ get_empty_table = true; ++ break; ++ } ++ } ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (1)idx = %x\n", idx); ++ ++ if (!get_empty_table) { ++ idx = iqk_info->iqk_table_idx[path] + 1; ++ if (idx > 1) ++ idx = 0; ++ } ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (2)idx = %x\n", idx); ++ ++ reg_rf18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); ++ reg_35c = rtw89_phy_read32_mask(rtwdev, R_CIRST, B_CIRST_SYN); ++ ++ iqk_info->iqk_band[path] = chan->band_type; ++ iqk_info->iqk_bw[path] = chan->band_width; ++ iqk_info->iqk_ch[path] = chan->channel; ++ iqk_info->iqk_mcc_ch[idx][path] = chan->channel; ++ iqk_info->iqk_table_idx[path] = idx; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x18= 0x%x, idx = %x\n", ++ path, reg_rf18, idx); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x18= 0x%x\n", ++ path, reg_rf18); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]times = 0x%x, ch =%x\n", ++ iqk_info->iqk_times, idx); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]iqk_mcc_ch[%x][%x] = 0x%x\n", ++ idx, path, iqk_info->iqk_mcc_ch[idx][path]); ++ ++ if (reg_35c == 0x01) ++ iqk_info->syn1to2 = 0x1; ++ else ++ iqk_info->syn1to2 = 0x0; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[IQK]S%x, iqk_info->syn1to2= 0x%x\n", path, ++ iqk_info->syn1to2); ++ ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, B_IQKINF_VER, RTW8852B_IQK_VER); ++ /* 2GHz/5GHz/6GHz = 0/1/2 */ ++ rtw89_phy_write32_mask(rtwdev, R_IQKCH, B_IQKCH_BAND << (path * 16), ++ iqk_info->iqk_band[path]); ++ /* 20/40/80 = 0/1/2 */ ++ rtw89_phy_write32_mask(rtwdev, R_IQKCH, B_IQKCH_BW << (path * 16), ++ iqk_info->iqk_bw[path]); ++ rtw89_phy_write32_mask(rtwdev, R_IQKCH, B_IQKCH_CH << (path * 16), ++ iqk_info->iqk_ch[path]); ++} ++ ++static void _iqk_start_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ _iqk_by_path(rtwdev, phy_idx, path); ++} ++ ++static void _iqk_restore(struct rtw89_dev *rtwdev, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ bool fail; ++ ++ rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), MASKDWORD, ++ iqk_info->nb_txcfir[path]); ++ rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, ++ iqk_info->nb_rxcfir[path]); ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, ++ 0x00000e19 + (path << 4)); ++ fail = _iqk_check_cal(rtwdev, path); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "%s result =%x\n", __func__, fail); ++ ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000000); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x80000000); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_SYS, B_IQK_RES_K, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_IQRSN, B_IQRSN_K1, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_IQRSN, B_IQRSN_K2, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_LUTWE, RR_LUTWE_LOK, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_LUTWE, RR_LUTWE_LOK, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, 0x3); ++ rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x1); ++} ++ ++static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ const struct rtw89_reg3_def *def; ++ int size; ++ u8 kpath; ++ int i; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "===> %s\n", __func__); ++ ++ kpath = _kpath(rtwdev, phy_idx); ++ ++ switch (kpath) { ++ case RF_A: ++ case RF_B: ++ return; ++ default: ++ size = ARRAY_SIZE(rtw8852b_restore_nondbcc_path01); ++ def = rtw8852b_restore_nondbcc_path01; ++ break; ++ } ++ ++ for (i = 0; i < size; i++, def++) ++ rtw89_phy_write32_mask(rtwdev, def->addr, def->mask, def->data); ++} ++ ++static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ u8 idx; ++ ++ idx = iqk_info->iqk_table_idx[path]; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (3)idx = %x\n", idx); ++ ++ rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), B_COEF_SEL_IQC, idx); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_G3, idx); ++ ++ rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000080); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x81ff010a); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK](1)S%x, 0x8%x54 = 0x%x\n", path, 1 << path, ++ rtw89_phy_read32_mask(rtwdev, R_CFIR_LUT + (path << 8), MASKDWORD)); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK](1)S%x, 0x8%x04 = 0x%x\n", path, 1 << path, ++ rtw89_phy_read32_mask(rtwdev, R_COEF_SEL + (path << 8), MASKDWORD)); ++} ++ ++static void _iqk_macbb_setting(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ const struct rtw89_reg3_def *def; ++ int size; ++ u8 kpath; ++ int i; ++ ++ kpath = _kpath(rtwdev, phy_idx); ++ ++ switch (kpath) { ++ case RF_A: ++ case RF_B: ++ return; ++ default: ++ size = ARRAY_SIZE(rtw8852b_set_nondbcc_path01); ++ def = rtw8852b_set_nondbcc_path01; ++ break; ++ } ++ ++ for (i = 0; i < size; i++, def++) ++ rtw89_phy_write32_mask(rtwdev, def->addr, def->mask, def->data); ++} ++ ++static void _iqk_init(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ u8 idx, path; ++ ++ rtw89_phy_write32_mask(rtwdev, R_IQKINF, MASKDWORD, 0x0); ++ if (iqk_info->is_iqk_init) ++ return; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); ++ iqk_info->is_iqk_init = true; ++ iqk_info->is_nbiqk = false; ++ iqk_info->iqk_fft_en = false; ++ iqk_info->iqk_sram_en = false; ++ iqk_info->iqk_cfir_en = false; ++ iqk_info->iqk_xym_en = false; ++ iqk_info->thermal_rek_en = false; ++ iqk_info->iqk_times = 0x0; ++ ++ for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { ++ iqk_info->iqk_channel[idx] = 0x0; ++ for (path = 0; path < RTW8852B_IQK_SS; path++) { ++ iqk_info->lok_cor_fail[idx][path] = false; ++ iqk_info->lok_fin_fail[idx][path] = false; ++ iqk_info->iqk_tx_fail[idx][path] = false; ++ iqk_info->iqk_rx_fail[idx][path] = false; ++ iqk_info->iqk_mcc_ch[idx][path] = 0x0; ++ iqk_info->iqk_table_idx[path] = 0x0; ++ } ++ } ++} ++ ++static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) ++{ ++ u32 rf_mode; ++ u8 path; ++ int ret; ++ ++ for (path = 0; path < RF_PATH_MAX; path++) { ++ if (!(kpath & BIT(path))) ++ continue; ++ ++ ret = read_poll_timeout_atomic(rtw89_read_rf, rf_mode, ++ rf_mode != 2, 2, 5000, false, ++ rtwdev, path, RR_MOD, RR_MOD_MASK); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RFK] Wait S%d to Rx mode!! (ret = %d)\n", path, ret); ++ } ++} ++ ++static void _tmac_tx_pause(struct rtw89_dev *rtwdev, enum rtw89_phy_idx band_idx, ++ bool is_pause) ++{ ++ if (!is_pause) ++ return; ++ ++ _wait_rx_mode(rtwdev, _kpath(rtwdev, band_idx)); ++} ++ ++static void _doiqk(struct rtw89_dev *rtwdev, bool force, ++ enum rtw89_phy_idx phy_idx, u8 path) ++{ ++ struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; ++ u32 backup_bb_val[BACKUP_BB_REGS_NR]; ++ u32 backup_rf_val[RTW8852B_IQK_SS][BACKUP_RF_REGS_NR]; ++ u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB); ++ ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[IQK]==========IQK strat!!!!!==========\n"); ++ iqk_info->iqk_times++; ++ iqk_info->kcount = 0; ++ iqk_info->version = RTW8852B_IQK_VER; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]Test Ver 0x%x\n", iqk_info->version); ++ _iqk_get_ch_info(rtwdev, phy_idx, path); ++ ++ _rfk_backup_bb_reg(rtwdev, &backup_bb_val[0]); ++ _rfk_backup_rf_reg(rtwdev, &backup_rf_val[path][0], path); ++ _iqk_macbb_setting(rtwdev, phy_idx, path); ++ _iqk_preset(rtwdev, path); ++ _iqk_start_iqk(rtwdev, phy_idx, path); ++ _iqk_restore(rtwdev, path); ++ _iqk_afebb_restore(rtwdev, phy_idx, path); ++ _rfk_restore_bb_reg(rtwdev, &backup_bb_val[0]); ++ _rfk_restore_rf_reg(rtwdev, &backup_rf_val[path][0], path); ++ ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_STOP); ++} ++ ++static void _iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool force) ++{ ++ u8 kpath = _kpath(rtwdev, phy_idx); ++ ++ switch (kpath) { ++ case RF_A: ++ _doiqk(rtwdev, force, phy_idx, RF_PATH_A); ++ break; ++ case RF_B: ++ _doiqk(rtwdev, force, phy_idx, RF_PATH_B); ++ break; ++ case RF_AB: ++ _doiqk(rtwdev, force, phy_idx, RF_PATH_A); ++ _doiqk(rtwdev, force, phy_idx, RF_PATH_B); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void _dpk_bkup_kip(struct rtw89_dev *rtwdev, const u32 reg[], ++ u32 reg_bkup[][RTW8852B_DPK_KIP_REG_NUM], u8 path) ++{ ++ u8 i; ++ ++ for (i = 0; i < RTW8852B_DPK_KIP_REG_NUM; i++) { ++ reg_bkup[path][i] = ++ rtw89_phy_read32_mask(rtwdev, reg[i] + (path << 8), MASKDWORD); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Backup 0x%x = %x\n", ++ reg[i] + (path << 8), reg_bkup[path][i]); ++ } ++} ++ ++static void _dpk_reload_kip(struct rtw89_dev *rtwdev, const u32 reg[], ++ const u32 reg_bkup[][RTW8852B_DPK_KIP_REG_NUM], u8 path) ++{ ++ u8 i; ++ ++ for (i = 0; i < RTW8852B_DPK_KIP_REG_NUM; i++) { ++ rtw89_phy_write32_mask(rtwdev, reg[i] + (path << 8), MASKDWORD, ++ reg_bkup[path][i]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Reload 0x%x = %x\n", ++ reg[i] + (path << 8), reg_bkup[path][i]); ++ } ++} ++ ++static u8 _dpk_order_convert(struct rtw89_dev *rtwdev) ++{ ++ u8 order; ++ u8 val; ++ ++ order = rtw89_phy_read32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP); ++ val = 0x3 >> order; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] convert MDPD order to 0x%x\n", val); ++ ++ return val; ++} ++ ++static void _dpk_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool off) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ u8 val, kidx = dpk->cur_idx[path]; ++ ++ val = dpk->is_dpk_enable && !off && dpk->bp[path][kidx].path_ok; ++ ++ rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), ++ MASKBYTE3, _dpk_order_convert(rtwdev) << 1 | val); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] DPK %s !!!\n", path, ++ kidx, dpk->is_dpk_enable && !off ? "enable" : "disable"); ++} ++ ++static void _dpk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, enum rtw8852b_dpk_id id) ++{ ++ u16 dpk_cmd; ++ u32 val; ++ int ret; ++ ++ dpk_cmd = (id << 8) | (0x19 + (path << 4)); ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, dpk_cmd); ++ ++ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x55, ++ 1, 20000, false, ++ rtwdev, 0xbff8, MASKBYTE0); ++ if (ret) ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] one-shot over 20ms!!!!\n"); ++ ++ udelay(1); ++ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, MASKDWORD, 0x00030000); ++ ++ ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x8000, ++ 1, 2000, false, ++ rtwdev, 0x80fc, MASKLWORD); ++ if (ret) ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] one-shot over 20ms!!!!\n"); ++ ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, MASKBYTE0, 0x0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] one-shot for %s = 0x%x\n", ++ id == 0x06 ? "LBK_RXIQK" : ++ id == 0x10 ? "SYNC" : ++ id == 0x11 ? "MDPK_IDL" : ++ id == 0x12 ? "MDPK_MPA" : ++ id == 0x13 ? "GAIN_LOSS" : ++ id == 0x14 ? "PWR_CAL" : ++ id == 0x15 ? "DPK_RXAGC" : ++ id == 0x16 ? "KIP_PRESET" : ++ id == 0x17 ? "KIP_RESTORE" : "DPK_TXAGC", ++ dpk_cmd); ++} ++ ++static void _dpk_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_EN_TIA_IDA, 0x3); ++ _set_rx_dck(rtwdev, phy, path); ++} ++ ++static void _dpk_information(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ ++ u8 kidx = dpk->cur_idx[path]; ++ ++ dpk->bp[path][kidx].band = chan->band_type; ++ dpk->bp[path][kidx].ch = chan->channel; ++ dpk->bp[path][kidx].bw = chan->band_width; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] S%d[%d] (PHY%d): TSSI %s/ DBCC %s/ %s/ CH%d/ %s\n", ++ path, dpk->cur_idx[path], phy, ++ rtwdev->is_tssi_mode[path] ? "on" : "off", ++ rtwdev->dbcc_en ? "on" : "off", ++ dpk->bp[path][kidx].band == 0 ? "2G" : ++ dpk->bp[path][kidx].band == 1 ? "5G" : "6G", ++ dpk->bp[path][kidx].ch, ++ dpk->bp[path][kidx].bw == 0 ? "20M" : ++ dpk->bp[path][kidx].bw == 1 ? "40M" : "80M"); ++} ++ ++static void _dpk_bb_afe_setting(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 kpath) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dpk_afe_defs_tbl); ++ ++ if (chan->band_width == RTW89_CHANNEL_WIDTH_80) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_EX, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_BW_SEL_V1, B_PATH1_BW_SEL_EX, 0x1); ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Set BB/AFE for PHY%d (kpath=%d)\n", phy, kpath); ++} ++ ++static void _dpk_bb_afe_restore(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 kpath) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dpk_afe_restore_defs_tbl); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Restore BB/AFE for PHY%d (kpath=%d)\n", phy, kpath); ++ ++ if (chan->band_width == RTW89_CHANNEL_WIDTH_80) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_EX, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_PATH1_BW_SEL_V1, B_PATH1_BW_SEL_EX, 0x0); ++ } ++} ++ ++static void _dpk_tssi_pause(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path path, bool is_pause) ++{ ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK + (path << 13), ++ B_P0_TSSI_TRK_EN, is_pause); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d TSSI %s\n", path, ++ is_pause ? "pause" : "resume"); ++} ++ ++static void _dpk_kip_restore(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path path) ++{ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_dpk_kip_defs_tbl); ++ ++ if (rtwdev->hal.cv > CHIP_CAV) ++ rtw89_phy_write32_mask(rtwdev, R_DPD_COM + (path << 8), B_DPD_COM_OF, 0x1); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d restore KIP\n", path); ++} ++ ++static void _dpk_lbk_rxiqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ u8 cur_rxbb; ++ u32 tmp; ++ ++ cur_rxbb = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASKRXBB); ++ ++ rtw89_phy_write32_mask(rtwdev, R_MDPK_RX_DCK, B_MDPK_RX_DCK_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), B_IQK_RES_RXCFIR, 0x0); ++ ++ tmp = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); ++ rtw89_write_rf(rtwdev, path, RR_RSV4, RFREG_MASK, tmp); ++ rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASKMODE, 0xd); ++ rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_PLLEN, 0x1); ++ ++ if (cur_rxbb >= 0x11) ++ rtw89_write_rf(rtwdev, path, RR_TXIQK, RR_TXIQK_ATT1, 0x13); ++ else if (cur_rxbb <= 0xa) ++ rtw89_write_rf(rtwdev, path, RR_TXIQK, RR_TXIQK_ATT1, 0x00); ++ else ++ rtw89_write_rf(rtwdev, path, RR_TXIQK, RR_TXIQK_ATT1, 0x05); ++ ++ rtw89_write_rf(rtwdev, path, RR_XGLNA2, RR_XGLNA2_SW, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_POW, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80014); ++ udelay(70); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x025); ++ ++ _dpk_one_shot(rtwdev, phy, path, LBK_RXIQK); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d LBK RXIQC = 0x%x\n", path, ++ rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD)); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_RXK, RR_RXK_PLLEN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_MDPK_RX_DCK, B_MDPK_RX_DCK_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_KPATH_CFG, B_KPATH_CFG_ED, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_DI, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASKMODE, 0x5); ++} ++ ++static void _dpk_get_thermal(struct rtw89_dev *rtwdev, u8 kidx, enum rtw89_rf_path path) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ ++ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x0); ++ rtw89_write_rf(rtwdev, path, RR_TM, RR_TM_TRI, 0x1); ++ ++ udelay(200); ++ ++ dpk->bp[path][kidx].ther_dpk = rtw89_read_rf(rtwdev, path, RR_TM, RR_TM_VAL); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] thermal@DPK = 0x%x\n", ++ dpk->bp[path][kidx].ther_dpk); ++} ++ ++static void _dpk_rf_setting(struct rtw89_dev *rtwdev, u8 gain, ++ enum rtw89_rf_path path, u8 kidx) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ ++ if (dpk->bp[path][kidx].band == RTW89_BAND_2G) { ++ rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASK, 0x50220); ++ rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_FATT, 0xf2); ++ rtw89_write_rf(rtwdev, path, RR_LUTDBG, RR_LUTDBG_TIA, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_TIA, RR_TIA_N6, 0x1); ++ } else { ++ rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASK, 0x50220); ++ rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RAA2_SWATT, 0x5); ++ rtw89_write_rf(rtwdev, path, RR_LUTDBG, RR_LUTDBG_TIA, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_TIA, RR_TIA_N6, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_RXA_LNA, RFREG_MASK, 0x920FC); ++ rtw89_write_rf(rtwdev, path, RR_XALNA2, RFREG_MASK, 0x002C0); ++ rtw89_write_rf(rtwdev, path, RR_IQGEN, RFREG_MASK, 0x38800); ++ } ++ ++ rtw89_write_rf(rtwdev, path, RR_RCKD, RR_RCKD_BW, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_BTC, RR_BTC_TXBB, dpk->bp[path][kidx].bw + 1); ++ rtw89_write_rf(rtwdev, path, RR_BTC, RR_BTC_RXBB, 0x0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] ARF 0x0/0x11/0x1a = 0x%x/ 0x%x/ 0x%x\n", ++ rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK), ++ rtw89_read_rf(rtwdev, path, RR_TXIG, RFREG_MASK), ++ rtw89_read_rf(rtwdev, path, RR_BTC, RFREG_MASK)); ++} ++ ++static void _dpk_bypass_rxcfir(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path path, bool is_bypass) ++{ ++ if (is_bypass) { ++ rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), ++ B_RXIQC_BYPASS2, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), ++ B_RXIQC_BYPASS, 0x1); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Bypass RXIQC (0x8%d3c = 0x%x)\n", 1 + path, ++ rtw89_phy_read32_mask(rtwdev, R_RXIQC + (path << 8), ++ MASKDWORD)); ++ } else { ++ rtw89_phy_write32_clr(rtwdev, R_RXIQC + (path << 8), B_RXIQC_BYPASS2); ++ rtw89_phy_write32_clr(rtwdev, R_RXIQC + (path << 8), B_RXIQC_BYPASS); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] restore 0x8%d3c = 0x%x\n", 1 + path, ++ rtw89_phy_read32_mask(rtwdev, R_RXIQC + (path << 8), ++ MASKDWORD)); ++ } ++} ++ ++static ++void _dpk_tpg_sel(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ ++ if (dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_80) ++ rtw89_phy_write32_clr(rtwdev, R_TPG_MOD, B_TPG_MOD_F); ++ else if (dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_40) ++ rtw89_phy_write32_mask(rtwdev, R_TPG_MOD, B_TPG_MOD_F, 0x2); ++ else ++ rtw89_phy_write32_mask(rtwdev, R_TPG_MOD, B_TPG_MOD_F, 0x1); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] TPG_Select for %s\n", ++ dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_80 ? "80M" : ++ dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_40 ? "40M" : "20M"); ++} ++ ++static void _dpk_table_select(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path path, u8 kidx, u8 gain) ++{ ++ u8 val; ++ ++ val = 0x80 + kidx * 0x20 + gain * 0x10; ++ rtw89_phy_write32_mask(rtwdev, R_DPD_CH0 + (path << 8), MASKBYTE3, val); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] table select for Kidx[%d], Gain[%d] (0x%x)\n", kidx, ++ gain, val); ++} ++ ++static bool _dpk_sync_check(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) ++{ ++#define DPK_SYNC_TH_DC_I 200 ++#define DPK_SYNC_TH_DC_Q 200 ++#define DPK_SYNC_TH_CORR 170 ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ u16 dc_i, dc_q; ++ u8 corr_val, corr_idx; ++ ++ rtw89_phy_write32_clr(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL); ++ ++ corr_idx = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_CORI); ++ corr_val = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_CORV); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] S%d Corr_idx / Corr_val = %d / %d\n", ++ path, corr_idx, corr_val); ++ ++ dpk->corr_idx[path][kidx] = corr_idx; ++ dpk->corr_val[path][kidx] = corr_val; ++ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x9); ++ ++ dc_i = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCI); ++ dc_q = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCQ); ++ ++ dc_i = abs(sign_extend32(dc_i, 11)); ++ dc_q = abs(sign_extend32(dc_q, 11)); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d DC I/Q, = %d / %d\n", ++ path, dc_i, dc_q); ++ ++ dpk->dc_i[path][kidx] = dc_i; ++ dpk->dc_q[path][kidx] = dc_q; ++ ++ if (dc_i > DPK_SYNC_TH_DC_I || dc_q > DPK_SYNC_TH_DC_Q || ++ corr_val < DPK_SYNC_TH_CORR) ++ return true; ++ else ++ return false; ++} ++ ++static bool _dpk_sync(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 kidx) ++{ ++ _dpk_one_shot(rtwdev, phy, path, SYNC); ++ ++ return _dpk_sync_check(rtwdev, path, kidx); ++} ++ ++static u16 _dpk_dgain_read(struct rtw89_dev *rtwdev) ++{ ++ u16 dgain; ++ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x0); ++ ++ dgain = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCI); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] DGain = 0x%x\n", dgain); ++ ++ return dgain; ++} ++ ++static s8 _dpk_dgain_mapping(struct rtw89_dev *rtwdev, u16 dgain) ++{ ++ static const u16 bnd[15] = { ++ 0xbf1, 0xaa5, 0x97d, 0x875, 0x789, 0x6b7, 0x5fc, 0x556, ++ 0x4c1, 0x43d, 0x3c7, 0x35e, 0x2ac, 0x262, 0x220 ++ }; ++ s8 offset; ++ ++ if (dgain >= bnd[0]) ++ offset = 0x6; ++ else if (bnd[0] > dgain && dgain >= bnd[1]) ++ offset = 0x6; ++ else if (bnd[1] > dgain && dgain >= bnd[2]) ++ offset = 0x5; ++ else if (bnd[2] > dgain && dgain >= bnd[3]) ++ offset = 0x4; ++ else if (bnd[3] > dgain && dgain >= bnd[4]) ++ offset = 0x3; ++ else if (bnd[4] > dgain && dgain >= bnd[5]) ++ offset = 0x2; ++ else if (bnd[5] > dgain && dgain >= bnd[6]) ++ offset = 0x1; ++ else if (bnd[6] > dgain && dgain >= bnd[7]) ++ offset = 0x0; ++ else if (bnd[7] > dgain && dgain >= bnd[8]) ++ offset = 0xff; ++ else if (bnd[8] > dgain && dgain >= bnd[9]) ++ offset = 0xfe; ++ else if (bnd[9] > dgain && dgain >= bnd[10]) ++ offset = 0xfd; ++ else if (bnd[10] > dgain && dgain >= bnd[11]) ++ offset = 0xfc; ++ else if (bnd[11] > dgain && dgain >= bnd[12]) ++ offset = 0xfb; ++ else if (bnd[12] > dgain && dgain >= bnd[13]) ++ offset = 0xfa; ++ else if (bnd[13] > dgain && dgain >= bnd[14]) ++ offset = 0xf9; ++ else if (bnd[14] > dgain) ++ offset = 0xf8; ++ else ++ offset = 0x0; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] DGain offset = %d\n", offset); ++ ++ return offset; ++} ++ ++static u8 _dpk_gainloss_read(struct rtw89_dev *rtwdev) ++{ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x6); ++ rtw89_phy_write32_mask(rtwdev, R_DPK_CFG2, B_DPK_CFG2_ST, 0x1); ++ ++ return rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_GL); ++} ++ ++static void _dpk_gainloss(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 kidx) ++{ ++ _dpk_table_select(rtwdev, path, kidx, 1); ++ _dpk_one_shot(rtwdev, phy, path, GAIN_LOSS); ++} ++ ++static void _dpk_kip_preset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 kidx) ++{ ++ _dpk_tpg_sel(rtwdev, path, kidx); ++ _dpk_one_shot(rtwdev, phy, path, KIP_PRESET); ++} ++ ++static void _dpk_kip_pwr_clk_on(struct rtw89_dev *rtwdev, ++ enum rtw89_rf_path path) ++{ ++ rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000080); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x807f030a); ++ rtw89_phy_write32_mask(rtwdev, R_CFIR_SYS + (path << 8), MASKDWORD, 0xce000a08); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] KIP Power/CLK on\n"); ++} ++ ++static void _dpk_kip_set_txagc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 txagc) ++{ ++ rtw89_write_rf(rtwdev, path, RR_TXAGC, RFREG_MASK, txagc); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); ++ _dpk_one_shot(rtwdev, phy, path, DPK_TXAGC); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] set TXAGC = 0x%x\n", txagc); ++} ++ ++static void _dpk_kip_set_rxagc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ u32 tmp; ++ ++ tmp = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_MOD, B_KIP_MOD, tmp); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x1); ++ _dpk_one_shot(rtwdev, phy, path, DPK_RXAGC); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL_V1, 0x8); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] set RXBB = 0x%x (RF0x0[9:5] = 0x%x)\n", ++ rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_RXBB_V1), ++ rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASKRXBB)); ++} ++ ++static u8 _dpk_set_offset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, s8 gain_offset) ++{ ++ u8 txagc; ++ ++ txagc = rtw89_read_rf(rtwdev, path, RR_TXAGC, RFREG_MASK); ++ ++ if (txagc - gain_offset < DPK_TXAGC_LOWER) ++ txagc = DPK_TXAGC_LOWER; ++ else if (txagc - gain_offset > DPK_TXAGC_UPPER) ++ txagc = DPK_TXAGC_UPPER; ++ else ++ txagc = txagc - gain_offset; ++ ++ _dpk_kip_set_txagc(rtwdev, phy, path, txagc); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] tmp_txagc (GL=%d) = 0x%x\n", ++ gain_offset, txagc); ++ return txagc; ++} ++ ++static bool _dpk_pas_read(struct rtw89_dev *rtwdev, bool is_check) ++{ ++ u32 val1_i = 0, val1_q = 0, val2_i = 0, val2_q = 0; ++ u8 i; ++ ++ rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, MASKBYTE2, 0x06); ++ rtw89_phy_write32_mask(rtwdev, R_DPK_CFG2, B_DPK_CFG2_ST, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE2, 0x08); ++ ++ if (is_check) { ++ rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, 0x00); ++ val1_i = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKHWORD); ++ val1_i = abs(sign_extend32(val1_i, 11)); ++ val1_q = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKLWORD); ++ val1_q = abs(sign_extend32(val1_q, 11)); ++ ++ rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, 0x1f); ++ val2_i = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKHWORD); ++ val2_i = abs(sign_extend32(val2_i, 11)); ++ val2_q = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKLWORD); ++ val2_q = abs(sign_extend32(val2_q, 11)); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] PAS_delta = 0x%x\n", ++ phy_div(val1_i * val1_i + val1_q * val1_q, ++ val2_i * val2_i + val2_q * val2_q)); ++ } else { ++ for (i = 0; i < 32; i++) { ++ rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, i); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] PAS_Read[%02d]= 0x%08x\n", i, ++ rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKDWORD)); ++ } ++ } ++ ++ if (val1_i * val1_i + val1_q * val1_q >= ++ (val2_i * val2_i + val2_q * val2_q) * 8 / 5) ++ return true; ++ ++ return false; ++} ++ ++static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 kidx, u8 init_txagc, ++ bool loss_only) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u8 step = DPK_AGC_STEP_SYNC_DGAIN; ++ u8 tmp_txagc, tmp_rxbb = 0, tmp_gl_idx = 0; ++ u8 goout = 0, agc_cnt = 0, limited_rxbb = 0; ++ u16 dgain = 0; ++ s8 offset; ++ int limit = 200; ++ ++ tmp_txagc = init_txagc; ++ ++ do { ++ switch (step) { ++ case DPK_AGC_STEP_SYNC_DGAIN: ++ if (_dpk_sync(rtwdev, phy, path, kidx)) { ++ tmp_txagc = 0xff; ++ goout = 1; ++ break; ++ } ++ ++ dgain = _dpk_dgain_read(rtwdev); ++ ++ if (loss_only == 1 || limited_rxbb == 1) ++ step = DPK_AGC_STEP_GAIN_LOSS_IDX; ++ else ++ step = DPK_AGC_STEP_GAIN_ADJ; ++ break; ++ ++ case DPK_AGC_STEP_GAIN_ADJ: ++ tmp_rxbb = rtw89_read_rf(rtwdev, path, RR_MOD, ++ RFREG_MASKRXBB); ++ offset = _dpk_dgain_mapping(rtwdev, dgain); ++ ++ if (tmp_rxbb + offset > 0x1f) { ++ tmp_rxbb = 0x1f; ++ limited_rxbb = 1; ++ } else if (tmp_rxbb + offset < 0) { ++ tmp_rxbb = 0; ++ limited_rxbb = 1; ++ } else { ++ tmp_rxbb = tmp_rxbb + offset; ++ } ++ ++ rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASKRXBB, ++ tmp_rxbb); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Adjust RXBB (%d) = 0x%x\n", offset, tmp_rxbb); ++ if (offset || agc_cnt == 0) { ++ if (chan->band_width < RTW89_CHANNEL_WIDTH_80) ++ _dpk_bypass_rxcfir(rtwdev, path, true); ++ else ++ _dpk_lbk_rxiqk(rtwdev, phy, path); ++ } ++ if (dgain > 1922 || dgain < 342) ++ step = DPK_AGC_STEP_SYNC_DGAIN; ++ else ++ step = DPK_AGC_STEP_GAIN_LOSS_IDX; ++ ++ agc_cnt++; ++ break; ++ ++ case DPK_AGC_STEP_GAIN_LOSS_IDX: ++ _dpk_gainloss(rtwdev, phy, path, kidx); ++ tmp_gl_idx = _dpk_gainloss_read(rtwdev); ++ ++ if ((tmp_gl_idx == 0 && _dpk_pas_read(rtwdev, true)) || ++ tmp_gl_idx >= 7) ++ step = DPK_AGC_STEP_GL_GT_CRITERION; ++ else if (tmp_gl_idx == 0) ++ step = DPK_AGC_STEP_GL_LT_CRITERION; ++ else ++ step = DPK_AGC_STEP_SET_TX_GAIN; ++ break; ++ ++ case DPK_AGC_STEP_GL_GT_CRITERION: ++ if (tmp_txagc == 0x2e) { ++ goout = 1; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Txagc@lower bound!!\n"); ++ } else { ++ tmp_txagc = _dpk_set_offset(rtwdev, phy, path, 0x3); ++ } ++ step = DPK_AGC_STEP_GAIN_LOSS_IDX; ++ agc_cnt++; ++ break; ++ ++ case DPK_AGC_STEP_GL_LT_CRITERION: ++ if (tmp_txagc == 0x3f) { ++ goout = 1; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Txagc@upper bound!!\n"); ++ } else { ++ tmp_txagc = _dpk_set_offset(rtwdev, phy, path, 0xfe); ++ } ++ step = DPK_AGC_STEP_GAIN_LOSS_IDX; ++ agc_cnt++; ++ break; ++ case DPK_AGC_STEP_SET_TX_GAIN: ++ tmp_txagc = _dpk_set_offset(rtwdev, phy, path, tmp_gl_idx); ++ goout = 1; ++ agc_cnt++; ++ break; ++ ++ default: ++ goout = 1; ++ break; ++ } ++ } while (!goout && agc_cnt < 6 && limit-- > 0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Txagc / RXBB for DPK = 0x%x / 0x%x\n", tmp_txagc, ++ tmp_rxbb); ++ ++ return tmp_txagc; ++} ++ ++static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, u8 order) ++{ ++ switch (order) { ++ case 0: ++ rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, order); ++ rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x3); ++ rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_MAN, 0x1); ++ break; ++ case 1: ++ rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, order); ++ rtw89_phy_write32_clr(rtwdev, R_LDL_NORM, B_LDL_NORM_PN); ++ rtw89_phy_write32_clr(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_MAN); ++ break; ++ case 2: ++ rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, order); ++ rtw89_phy_write32_clr(rtwdev, R_LDL_NORM, B_LDL_NORM_PN); ++ rtw89_phy_write32_clr(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_MAN); ++ break; ++ default: ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Wrong MDPD order!!(0x%x)\n", order); ++ break; ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Set MDPD order to 0x%x for IDL\n", order); ++} ++ ++static void _dpk_idl_mpa(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 kidx, u8 gain) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ ++ if (dpk->bp[path][kidx].bw < RTW89_CHANNEL_WIDTH_80 && ++ dpk->bp[path][kidx].band == RTW89_BAND_5G) ++ _dpk_set_mdpd_para(rtwdev, 0x2); ++ else ++ _dpk_set_mdpd_para(rtwdev, 0x0); ++ ++ _dpk_one_shot(rtwdev, phy, path, MDPK_IDL); ++} ++ ++static void _dpk_fill_result(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 kidx, u8 gain, u8 txagc) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ const u16 pwsf = 0x78; ++ u8 gs = dpk->dpk_gs[phy]; ++ ++ rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), ++ B_COEF_SEL_MDPD, kidx); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Fill txagc/ pwsf/ gs = 0x%x/ 0x%x/ 0x%x\n", txagc, ++ pwsf, gs); ++ ++ dpk->bp[path][kidx].txagc_dpk = txagc; ++ rtw89_phy_write32_mask(rtwdev, R_TXAGC_RFK + (path << 8), ++ 0x3F << ((gain << 3) + (kidx << 4)), txagc); ++ ++ dpk->bp[path][kidx].pwsf = pwsf; ++ rtw89_phy_write32_mask(rtwdev, R_DPD_BND + (path << 8) + (kidx << 2), ++ 0x1FF << (gain << 4), pwsf); ++ ++ rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_MDPD, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_MDPD, 0x0); ++ ++ dpk->bp[path][kidx].gs = gs; ++ if (dpk->dpk_gs[phy] == 0x7f) ++ rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), ++ MASKDWORD, 0x007f7f7f); ++ else ++ rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), ++ MASKDWORD, 0x005b5b5b); ++ ++ rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), ++ B_DPD_ORDER_V1, _dpk_order_convert(rtwdev)); ++ rtw89_phy_write32_mask(rtwdev, R_DPD_V1 + (path << 8), MASKDWORD, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_SEL, 0x0); ++} ++ ++static bool _dpk_reload_check(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ bool is_reload = false; ++ u8 idx, cur_band, cur_ch; ++ ++ cur_band = chan->band_type; ++ cur_ch = chan->channel; ++ ++ for (idx = 0; idx < RTW89_DPK_BKUP_NUM; idx++) { ++ if (cur_band != dpk->bp[path][idx].band || ++ cur_ch != dpk->bp[path][idx].ch) ++ continue; ++ ++ rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), ++ B_COEF_SEL_MDPD, idx); ++ dpk->cur_idx[path] = idx; ++ is_reload = true; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] reload S%d[%d] success\n", path, idx); ++ } ++ ++ return is_reload; ++} ++ ++static bool _dpk_main(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u8 gain) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ u8 txagc = 0x38, kidx = dpk->cur_idx[path]; ++ bool is_fail = false; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] ========= S%d[%d] DPK Start =========\n", path, kidx); ++ ++ _rfk_rf_direct_cntrl(rtwdev, path, false); ++ _rfk_drf_direct_cntrl(rtwdev, path, false); ++ ++ _dpk_kip_pwr_clk_on(rtwdev, path); ++ _dpk_kip_set_txagc(rtwdev, phy, path, txagc); ++ _dpk_rf_setting(rtwdev, gain, path, kidx); ++ _dpk_rx_dck(rtwdev, phy, path); ++ ++ _dpk_kip_preset(rtwdev, phy, path, kidx); ++ _dpk_kip_set_rxagc(rtwdev, phy, path); ++ _dpk_table_select(rtwdev, path, kidx, gain); ++ ++ txagc = _dpk_agc(rtwdev, phy, path, kidx, txagc, false); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Adjust txagc = 0x%x\n", txagc); ++ ++ if (txagc == 0xff) { ++ is_fail = true; ++ } else { ++ _dpk_get_thermal(rtwdev, kidx, path); ++ ++ _dpk_idl_mpa(rtwdev, phy, path, kidx, gain); ++ ++ rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX); ++ ++ _dpk_fill_result(rtwdev, phy, path, kidx, gain, txagc); ++ } ++ ++ if (!is_fail) ++ dpk->bp[path][kidx].path_ok = true; ++ else ++ dpk->bp[path][kidx].path_ok = false; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] DPK %s\n", path, kidx, ++ is_fail ? "Check" : "Success"); ++ ++ return is_fail; ++} ++ ++static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, ++ enum rtw89_phy_idx phy, u8 kpath) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ static const u32 kip_reg[] = {0x813c, 0x8124, 0x8120}; ++ u32 kip_bkup[RTW8852B_DPK_RF_PATH][RTW8852B_DPK_KIP_REG_NUM] = {}; ++ u32 backup_rf_val[RTW8852B_DPK_RF_PATH][BACKUP_RF_REGS_NR]; ++ u32 backup_bb_val[BACKUP_BB_REGS_NR]; ++ bool is_fail = true, reloaded[RTW8852B_DPK_RF_PATH] = {}; ++ u8 path; ++ ++ if (dpk->is_dpk_reload_en) { ++ for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) { ++ reloaded[path] = _dpk_reload_check(rtwdev, phy, path); ++ if (!reloaded[path] && dpk->bp[path][0].ch) ++ dpk->cur_idx[path] = !dpk->cur_idx[path]; ++ else ++ _dpk_onoff(rtwdev, path, false); ++ } ++ } else { ++ for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) ++ dpk->cur_idx[path] = 0; ++ } ++ ++ _rfk_backup_bb_reg(rtwdev, &backup_bb_val[0]); ++ ++ for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) { ++ _dpk_bkup_kip(rtwdev, kip_reg, kip_bkup, path); ++ _rfk_backup_rf_reg(rtwdev, &backup_rf_val[path][0], path); ++ _dpk_information(rtwdev, phy, path); ++ if (rtwdev->is_tssi_mode[path]) ++ _dpk_tssi_pause(rtwdev, path, true); ++ } ++ ++ _dpk_bb_afe_setting(rtwdev, phy, path, kpath); ++ ++ for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) { ++ is_fail = _dpk_main(rtwdev, phy, path, 1); ++ _dpk_onoff(rtwdev, path, is_fail); ++ } ++ ++ _dpk_bb_afe_restore(rtwdev, phy, path, kpath); ++ _rfk_restore_bb_reg(rtwdev, &backup_bb_val[0]); ++ ++ for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) { ++ _dpk_kip_restore(rtwdev, path); ++ _dpk_reload_kip(rtwdev, kip_reg, kip_bkup, path); ++ _rfk_restore_rf_reg(rtwdev, &backup_rf_val[path][0], path); ++ if (rtwdev->is_tssi_mode[path]) ++ _dpk_tssi_pause(rtwdev, path, false); ++ } ++} ++ ++static bool _dpk_bypass_check(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ struct rtw89_fem_info *fem = &rtwdev->fem; ++ ++ if (fem->epa_2g && chan->band_type == RTW89_BAND_2G) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Skip DPK due to 2G_ext_PA exist!!\n"); ++ return true; ++ } else if (fem->epa_5g && chan->band_type == RTW89_BAND_5G) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Skip DPK due to 5G_ext_PA exist!!\n"); ++ return true; ++ } else if (fem->epa_6g && chan->band_type == RTW89_BAND_6G) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] Skip DPK due to 6G_ext_PA exist!!\n"); ++ return true; ++ } ++ ++ return false; ++} ++ ++static void _dpk_force_bypass(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) ++{ ++ u8 path, kpath; ++ ++ kpath = _kpath(rtwdev, phy); ++ ++ for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) { ++ if (kpath & BIT(path)) ++ _dpk_onoff(rtwdev, path, true); ++ } ++} ++ ++static void _dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool force) ++{ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[DPK] ****** DPK Start (Ver: 0x%x, Cv: %d, RF_para: %d) ******\n", ++ RTW8852B_DPK_VER, rtwdev->hal.cv, ++ RTW8852B_RF_REL_VERSION); ++ ++ if (_dpk_bypass_check(rtwdev, phy)) ++ _dpk_force_bypass(rtwdev, phy); ++ else ++ _dpk_cal_select(rtwdev, force, phy, RF_AB); ++} ++ ++static void _dpk_track(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ s8 txagc_bb, txagc_bb_tp, ini_diff = 0, txagc_ofst; ++ s8 delta_ther[2] = {}; ++ u8 trk_idx, txagc_rf; ++ u8 path, kidx; ++ u16 pwsf[2]; ++ u8 cur_ther; ++ u32 tmp; ++ ++ for (path = 0; path < RF_PATH_NUM_8852B; path++) { ++ kidx = dpk->cur_idx[path]; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, ++ "[DPK_TRK] ================[S%d[%d] (CH %d)]================\n", ++ path, kidx, dpk->bp[path][kidx].ch); ++ ++ cur_ther = ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, ++ "[DPK_TRK] thermal now = %d\n", cur_ther); ++ ++ if (dpk->bp[path][kidx].ch && cur_ther) ++ delta_ther[path] = dpk->bp[path][kidx].ther_dpk - cur_ther; ++ ++ if (dpk->bp[path][kidx].band == RTW89_BAND_2G) ++ delta_ther[path] = delta_ther[path] * 3 / 2; ++ else ++ delta_ther[path] = delta_ther[path] * 5 / 2; ++ ++ txagc_rf = rtw89_phy_read32_mask(rtwdev, R_TXAGC_BB + (path << 13), ++ 0x0000003f); ++ ++ if (rtwdev->is_tssi_mode[path]) { ++ trk_idx = rtw89_read_rf(rtwdev, path, RR_TXA, RR_TXA_TRK); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, ++ "[DPK_TRK] txagc_RF / track_idx = 0x%x / %d\n", ++ txagc_rf, trk_idx); ++ ++ txagc_bb = ++ rtw89_phy_read32_mask(rtwdev, R_TXAGC_BB + (path << 13), ++ MASKBYTE2); ++ txagc_bb_tp = ++ rtw89_phy_read32_mask(rtwdev, R_TXAGC_TP + (path << 13), ++ B_TXAGC_TP); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, ++ "[DPK_TRK] txagc_bb_tp / txagc_bb = 0x%x / 0x%x\n", ++ txagc_bb_tp, txagc_bb); ++ ++ txagc_ofst = ++ rtw89_phy_read32_mask(rtwdev, R_TXAGC_BB + (path << 13), ++ MASKBYTE3); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, ++ "[DPK_TRK] txagc_offset / delta_ther = %d / %d\n", ++ txagc_ofst, delta_ther[path]); ++ tmp = rtw89_phy_read32_mask(rtwdev, R_DPD_COM + (path << 8), ++ B_DPD_COM_OF); ++ if (tmp == 0x1) { ++ txagc_ofst = 0; ++ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, ++ "[DPK_TRK] HW txagc offset mode\n"); ++ } ++ ++ if (txagc_rf && cur_ther) ++ ini_diff = txagc_ofst + (delta_ther[path]); ++ ++ tmp = rtw89_phy_read32_mask(rtwdev, ++ R_P0_TXDPD + (path << 13), ++ B_P0_TXDPD); ++ if (tmp == 0x0) { ++ pwsf[0] = dpk->bp[path][kidx].pwsf + ++ txagc_bb_tp - txagc_bb + ini_diff; ++ pwsf[1] = dpk->bp[path][kidx].pwsf + ++ txagc_bb_tp - txagc_bb + ini_diff; ++ } else { ++ pwsf[0] = dpk->bp[path][kidx].pwsf + ini_diff; ++ pwsf[1] = dpk->bp[path][kidx].pwsf + ini_diff; ++ } ++ ++ } else { ++ pwsf[0] = (dpk->bp[path][kidx].pwsf + delta_ther[path]) & 0x1ff; ++ pwsf[1] = (dpk->bp[path][kidx].pwsf + delta_ther[path]) & 0x1ff; ++ } ++ ++ tmp = rtw89_phy_read32_mask(rtwdev, R_DPK_TRK, B_DPK_TRK_DIS); ++ if (!tmp && txagc_rf) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, ++ "[DPK_TRK] New pwsf[0] / pwsf[1] = 0x%x / 0x%x\n", ++ pwsf[0], pwsf[1]); ++ ++ rtw89_phy_write32_mask(rtwdev, ++ R_DPD_BND + (path << 8) + (kidx << 2), ++ B_DPD_BND_0, pwsf[0]); ++ rtw89_phy_write32_mask(rtwdev, ++ R_DPD_BND + (path << 8) + (kidx << 2), ++ B_DPD_BND_1, pwsf[1]); ++ } ++ } ++} ++ ++static void _set_dpd_backoff(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) ++{ ++ struct rtw89_dpk_info *dpk = &rtwdev->dpk; ++ u8 tx_scale, ofdm_bkof, path, kpath; ++ ++ kpath = _kpath(rtwdev, phy); ++ ++ ofdm_bkof = rtw89_phy_read32_mask(rtwdev, R_DPD_BF + (phy << 13), B_DPD_BF_OFDM); ++ tx_scale = rtw89_phy_read32_mask(rtwdev, R_DPD_BF + (phy << 13), B_DPD_BF_SCA); ++ ++ if (ofdm_bkof + tx_scale >= 44) { ++ /* move dpd backoff to bb, and set dpd backoff to 0 */ ++ dpk->dpk_gs[phy] = 0x7f; ++ for (path = 0; path < RF_PATH_NUM_8852B; path++) { ++ if (!(kpath & BIT(path))) ++ continue; ++ ++ rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8), ++ B_DPD_CFG, 0x7f7f7f); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RFK] Set S%d DPD backoff to 0dB\n", path); ++ } ++ } else { ++ dpk->dpk_gs[phy] = 0x5b; ++ } ++} ++ ++static void _tssi_rf_setting(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ enum rtw89_band band = chan->band_type; ++ ++ if (band == RTW89_BAND_2G) ++ rtw89_write_rf(rtwdev, path, RR_TXPOW, RR_TXPOW_TXG, 0x1); ++ else ++ rtw89_write_rf(rtwdev, path, RR_TXPOW, RR_TXPOW_TXA, 0x1); ++} ++ ++static void _tssi_set_sys(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ enum rtw89_band band = chan->band_type; ++ ++ rtw89_rfk_parser(rtwdev, &rtw8852b_tssi_sys_defs_tbl); ++ ++ if (path == RF_PATH_A) ++ rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, ++ &rtw8852b_tssi_sys_a_defs_2g_tbl, ++ &rtw8852b_tssi_sys_a_defs_5g_tbl); ++ else ++ rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, ++ &rtw8852b_tssi_sys_b_defs_2g_tbl, ++ &rtw8852b_tssi_sys_b_defs_5g_tbl); ++} ++ ++static void _tssi_ini_txpwr_ctrl_bb(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, ++ &rtw8852b_tssi_init_txpwr_defs_a_tbl, ++ &rtw8852b_tssi_init_txpwr_defs_b_tbl); ++} ++ ++static void _tssi_ini_txpwr_ctrl_bb_he_tb(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, ++ &rtw8852b_tssi_init_txpwr_he_tb_defs_a_tbl, ++ &rtw8852b_tssi_init_txpwr_he_tb_defs_b_tbl); ++} ++ ++static void _tssi_set_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, ++ &rtw8852b_tssi_dck_defs_a_tbl, ++ &rtw8852b_tssi_dck_defs_b_tbl); ++} ++ ++static void _tssi_set_tmeter_tbl(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++#define RTW8852B_TSSI_GET_VAL(ptr, idx) \ ++({ \ ++ s8 *__ptr = (ptr); \ ++ u8 __idx = (idx), __i, __v; \ ++ u32 __val = 0; \ ++ for (__i = 0; __i < 4; __i++) { \ ++ __v = (__ptr[__idx + __i]); \ ++ __val |= (__v << (8 * __i)); \ ++ } \ ++ __val; \ ++}) ++ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u8 ch = chan->channel; ++ u8 subband = chan->subband_type; ++ const s8 *thm_up_a = NULL; ++ const s8 *thm_down_a = NULL; ++ const s8 *thm_up_b = NULL; ++ const s8 *thm_down_b = NULL; ++ u8 thermal = 0xff; ++ s8 thm_ofst[64] = {0}; ++ u32 tmp = 0; ++ u8 i, j; ++ ++ switch (subband) { ++ default: ++ case RTW89_CH_2G: ++ thm_up_a = rtw89_8852b_trk_cfg.delta_swingidx_2ga_p; ++ thm_down_a = rtw89_8852b_trk_cfg.delta_swingidx_2ga_n; ++ thm_up_b = rtw89_8852b_trk_cfg.delta_swingidx_2gb_p; ++ thm_down_b = rtw89_8852b_trk_cfg.delta_swingidx_2gb_n; ++ break; ++ case RTW89_CH_5G_BAND_1: ++ thm_up_a = rtw89_8852b_trk_cfg.delta_swingidx_5ga_p[0]; ++ thm_down_a = rtw89_8852b_trk_cfg.delta_swingidx_5ga_n[0]; ++ thm_up_b = rtw89_8852b_trk_cfg.delta_swingidx_5gb_p[0]; ++ thm_down_b = rtw89_8852b_trk_cfg.delta_swingidx_5gb_n[0]; ++ break; ++ case RTW89_CH_5G_BAND_3: ++ thm_up_a = rtw89_8852b_trk_cfg.delta_swingidx_5ga_p[1]; ++ thm_down_a = rtw89_8852b_trk_cfg.delta_swingidx_5ga_n[1]; ++ thm_up_b = rtw89_8852b_trk_cfg.delta_swingidx_5gb_p[1]; ++ thm_down_b = rtw89_8852b_trk_cfg.delta_swingidx_5gb_n[1]; ++ break; ++ case RTW89_CH_5G_BAND_4: ++ thm_up_a = rtw89_8852b_trk_cfg.delta_swingidx_5ga_p[2]; ++ thm_down_a = rtw89_8852b_trk_cfg.delta_swingidx_5ga_n[2]; ++ thm_up_b = rtw89_8852b_trk_cfg.delta_swingidx_5gb_p[2]; ++ thm_down_b = rtw89_8852b_trk_cfg.delta_swingidx_5gb_n[2]; ++ break; ++ } ++ ++ if (path == RF_PATH_A) { ++ thermal = tssi_info->thermal[RF_PATH_A]; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] ch=%d thermal_pathA=0x%x\n", ch, thermal); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER_DIS, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER_TRK, 0x1); ++ ++ if (thermal == 0xff) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER, 32); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_VAL, 32); ++ ++ for (i = 0; i < 64; i += 4) { ++ rtw89_phy_write32(rtwdev, R_P0_TSSI_BASE + i, 0x0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] write 0x%x val=0x%08x\n", ++ R_P0_TSSI_BASE + i, 0x0); ++ } ++ ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER, thermal); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_VAL, ++ thermal); ++ ++ i = 0; ++ for (j = 0; j < 32; j++) ++ thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? ++ -thm_down_a[i++] : ++ -thm_down_a[DELTA_SWINGIDX_SIZE - 1]; ++ ++ i = 1; ++ for (j = 63; j >= 32; j--) ++ thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? ++ thm_up_a[i++] : ++ thm_up_a[DELTA_SWINGIDX_SIZE - 1]; ++ ++ for (i = 0; i < 64; i += 4) { ++ tmp = RTW8852B_TSSI_GET_VAL(thm_ofst, i); ++ rtw89_phy_write32(rtwdev, R_P0_TSSI_BASE + i, tmp); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] write 0x%x val=0x%08x\n", ++ 0x5c00 + i, tmp); ++ } ++ } ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, R_P0_RFCTM_RDY, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, R_P0_RFCTM_RDY, 0x0); ++ ++ } else { ++ thermal = tssi_info->thermal[RF_PATH_B]; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] ch=%d thermal_pathB=0x%x\n", ch, thermal); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P1_TMETER, B_P1_TMETER_DIS, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TMETER, B_P1_TMETER_TRK, 0x1); ++ ++ if (thermal == 0xff) { ++ rtw89_phy_write32_mask(rtwdev, R_P1_TMETER, B_P1_TMETER, 32); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P1_RFCTM_VAL, 32); ++ ++ for (i = 0; i < 64; i += 4) { ++ rtw89_phy_write32(rtwdev, R_TSSI_THOF + i, 0x0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] write 0x%x val=0x%08x\n", ++ 0x7c00 + i, 0x0); ++ } ++ ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_P1_TMETER, B_P1_TMETER, thermal); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, B_P1_RFCTM_VAL, ++ thermal); ++ ++ i = 0; ++ for (j = 0; j < 32; j++) ++ thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? ++ -thm_down_b[i++] : ++ -thm_down_b[DELTA_SWINGIDX_SIZE - 1]; ++ ++ i = 1; ++ for (j = 63; j >= 32; j--) ++ thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? ++ thm_up_b[i++] : ++ thm_up_b[DELTA_SWINGIDX_SIZE - 1]; ++ ++ for (i = 0; i < 64; i += 4) { ++ tmp = RTW8852B_TSSI_GET_VAL(thm_ofst, i); ++ rtw89_phy_write32(rtwdev, R_TSSI_THOF + i, tmp); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] write 0x%x val=0x%08x\n", ++ 0x7c00 + i, tmp); ++ } ++ } ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, R_P1_RFCTM_RDY, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_RFCTM, R_P1_RFCTM_RDY, 0x0); ++ } ++#undef RTW8852B_TSSI_GET_VAL ++} ++ ++static void _tssi_set_dac_gain_tbl(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, ++ &rtw8852b_tssi_dac_gain_defs_a_tbl, ++ &rtw8852b_tssi_dac_gain_defs_b_tbl); ++} ++ ++static void _tssi_slope_cal_org(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ enum rtw89_band band = chan->band_type; ++ ++ if (path == RF_PATH_A) ++ rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, ++ &rtw8852b_tssi_slope_a_defs_2g_tbl, ++ &rtw8852b_tssi_slope_a_defs_5g_tbl); ++ else ++ rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, ++ &rtw8852b_tssi_slope_b_defs_2g_tbl, ++ &rtw8852b_tssi_slope_b_defs_5g_tbl); ++} ++ ++static void _tssi_alignment_default(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, bool all) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ enum rtw89_band band = chan->band_type; ++ const struct rtw89_rfk_tbl *tbl = NULL; ++ u8 ch = chan->channel; ++ ++ if (path == RF_PATH_A) { ++ if (band == RTW89_BAND_2G) { ++ if (all) ++ tbl = &rtw8852b_tssi_align_a_2g_all_defs_tbl; ++ else ++ tbl = &rtw8852b_tssi_align_a_2g_part_defs_tbl; ++ } else if (ch >= 36 && ch <= 64) { ++ if (all) ++ tbl = &rtw8852b_tssi_align_a_5g1_all_defs_tbl; ++ else ++ tbl = &rtw8852b_tssi_align_a_5g1_part_defs_tbl; ++ } else if (ch >= 100 && ch <= 144) { ++ if (all) ++ tbl = &rtw8852b_tssi_align_a_5g2_all_defs_tbl; ++ else ++ tbl = &rtw8852b_tssi_align_a_5g2_part_defs_tbl; ++ } else if (ch >= 149 && ch <= 177) { ++ if (all) ++ tbl = &rtw8852b_tssi_align_a_5g3_all_defs_tbl; ++ else ++ tbl = &rtw8852b_tssi_align_a_5g3_part_defs_tbl; ++ } ++ } else { ++ if (ch >= 1 && ch <= 14) { ++ if (all) ++ tbl = &rtw8852b_tssi_align_b_2g_all_defs_tbl; ++ else ++ tbl = &rtw8852b_tssi_align_b_2g_part_defs_tbl; ++ } else if (ch >= 36 && ch <= 64) { ++ if (all) ++ tbl = &rtw8852b_tssi_align_b_5g1_all_defs_tbl; ++ else ++ tbl = &rtw8852b_tssi_align_b_5g1_part_defs_tbl; ++ } else if (ch >= 100 && ch <= 144) { ++ if (all) ++ tbl = &rtw8852b_tssi_align_b_5g2_all_defs_tbl; ++ else ++ tbl = &rtw8852b_tssi_align_b_5g2_part_defs_tbl; ++ } else if (ch >= 149 && ch <= 177) { ++ if (all) ++ tbl = &rtw8852b_tssi_align_b_5g3_all_defs_tbl; ++ else ++ tbl = &rtw8852b_tssi_align_b_5g3_part_defs_tbl; ++ } ++ } ++ ++ if (tbl) ++ rtw89_rfk_parser(rtwdev, tbl); ++} ++ ++static void _tssi_set_tssi_slope(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ rtw89_rfk_parser_by_cond(rtwdev, path == RF_PATH_A, ++ &rtw8852b_tssi_slope_defs_a_tbl, ++ &rtw8852b_tssi_slope_defs_b_tbl); ++} ++ ++static void _tssi_set_tssi_track(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ if (path == RF_PATH_A) ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSIC, B_P0_TSSIC_BYPASS, 0x0); ++ else ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSIC, B_P1_TSSIC_BYPASS, 0x0); ++} ++ ++static void _tssi_set_txagc_offset_mv_avg(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "======>%s path=%d\n", __func__, ++ path); ++ ++ if (path == RF_PATH_A) ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TSSI_MV_MIX, 0x010); ++ else ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_RFCTM_DEL, 0x010); ++} ++ ++static void _tssi_enable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) ++{ ++ u8 i; ++ ++ for (i = 0; i < RF_PATH_NUM_8852B; i++) { ++ _tssi_set_tssi_track(rtwdev, phy, i); ++ _tssi_set_txagc_offset_mv_avg(rtwdev, phy, i); ++ ++ if (i == RF_PATH_A) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, ++ B_P0_TSSI_MV_CLR, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, ++ B_P0_TSSI_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, ++ B_P0_TSSI_EN, 0x1); ++ rtw89_write_rf(rtwdev, i, RR_TXGA_V1, ++ RR_TXGA_V1_TRK_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, ++ B_P0_TSSI_RFC, 0x3); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, ++ B_P0_TSSI_OFT, 0xc0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, ++ B_P0_TSSI_OFT_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, ++ B_P0_TSSI_OFT_EN, 0x1); ++ ++ rtwdev->is_tssi_mode[RF_PATH_A] = true; ++ } else { ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, ++ B_P1_TSSI_MV_CLR, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_AVG, ++ B_P1_TSSI_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_AVG, ++ B_P1_TSSI_EN, 0x1); ++ rtw89_write_rf(rtwdev, i, RR_TXGA_V1, ++ RR_TXGA_V1_TRK_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, ++ B_P1_TSSI_RFC, 0x3); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, ++ B_P1_TSSI_OFT, 0xc0); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, ++ B_P1_TSSI_OFT_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, ++ B_P1_TSSI_OFT_EN, 0x1); ++ ++ rtwdev->is_tssi_mode[RF_PATH_B] = true; ++ } ++ } ++} ++ ++static void _tssi_disable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) ++{ ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, B_P0_TSSI_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_RFC, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TSSI_MV_CLR, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_AVG, B_P1_TSSI_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_RFC, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_TSSI_MV_CLR, 0x1); ++ ++ rtwdev->is_tssi_mode[RF_PATH_A] = false; ++ rtwdev->is_tssi_mode[RF_PATH_B] = false; ++} ++ ++static u32 _tssi_get_cck_group(struct rtw89_dev *rtwdev, u8 ch) ++{ ++ switch (ch) { ++ case 1 ... 2: ++ return 0; ++ case 3 ... 5: ++ return 1; ++ case 6 ... 8: ++ return 2; ++ case 9 ... 11: ++ return 3; ++ case 12 ... 13: ++ return 4; ++ case 14: ++ return 5; ++ } ++ ++ return 0; ++} ++ ++#define TSSI_EXTRA_GROUP_BIT (BIT(31)) ++#define TSSI_EXTRA_GROUP(idx) (TSSI_EXTRA_GROUP_BIT | (idx)) ++#define IS_TSSI_EXTRA_GROUP(group) ((group) & TSSI_EXTRA_GROUP_BIT) ++#define TSSI_EXTRA_GET_GROUP_IDX1(group) ((group) & ~TSSI_EXTRA_GROUP_BIT) ++#define TSSI_EXTRA_GET_GROUP_IDX2(group) (TSSI_EXTRA_GET_GROUP_IDX1(group) + 1) ++ ++static u32 _tssi_get_ofdm_group(struct rtw89_dev *rtwdev, u8 ch) ++{ ++ switch (ch) { ++ case 1 ... 2: ++ return 0; ++ case 3 ... 5: ++ return 1; ++ case 6 ... 8: ++ return 2; ++ case 9 ... 11: ++ return 3; ++ case 12 ... 14: ++ return 4; ++ case 36 ... 40: ++ return 5; ++ case 41 ... 43: ++ return TSSI_EXTRA_GROUP(5); ++ case 44 ... 48: ++ return 6; ++ case 49 ... 51: ++ return TSSI_EXTRA_GROUP(6); ++ case 52 ... 56: ++ return 7; ++ case 57 ... 59: ++ return TSSI_EXTRA_GROUP(7); ++ case 60 ... 64: ++ return 8; ++ case 100 ... 104: ++ return 9; ++ case 105 ... 107: ++ return TSSI_EXTRA_GROUP(9); ++ case 108 ... 112: ++ return 10; ++ case 113 ... 115: ++ return TSSI_EXTRA_GROUP(10); ++ case 116 ... 120: ++ return 11; ++ case 121 ... 123: ++ return TSSI_EXTRA_GROUP(11); ++ case 124 ... 128: ++ return 12; ++ case 129 ... 131: ++ return TSSI_EXTRA_GROUP(12); ++ case 132 ... 136: ++ return 13; ++ case 137 ... 139: ++ return TSSI_EXTRA_GROUP(13); ++ case 140 ... 144: ++ return 14; ++ case 149 ... 153: ++ return 15; ++ case 154 ... 156: ++ return TSSI_EXTRA_GROUP(15); ++ case 157 ... 161: ++ return 16; ++ case 162 ... 164: ++ return TSSI_EXTRA_GROUP(16); ++ case 165 ... 169: ++ return 17; ++ case 170 ... 172: ++ return TSSI_EXTRA_GROUP(17); ++ case 173 ... 177: ++ return 18; ++ } ++ ++ return 0; ++} ++ ++static u32 _tssi_get_trim_group(struct rtw89_dev *rtwdev, u8 ch) ++{ ++ switch (ch) { ++ case 1 ... 8: ++ return 0; ++ case 9 ... 14: ++ return 1; ++ case 36 ... 48: ++ return 2; ++ case 52 ... 64: ++ return 3; ++ case 100 ... 112: ++ return 4; ++ case 116 ... 128: ++ return 5; ++ case 132 ... 144: ++ return 6; ++ case 149 ... 177: ++ return 7; ++ } ++ ++ return 0; ++} ++ ++static s8 _tssi_get_ofdm_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u8 ch = chan->channel; ++ u32 gidx, gidx_1st, gidx_2nd; ++ s8 de_1st; ++ s8 de_2nd; ++ s8 val; ++ ++ gidx = _tssi_get_ofdm_group(rtwdev, ch); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM]: path=%d mcs group_idx=0x%x\n", path, gidx); ++ ++ if (IS_TSSI_EXTRA_GROUP(gidx)) { ++ gidx_1st = TSSI_EXTRA_GET_GROUP_IDX1(gidx); ++ gidx_2nd = TSSI_EXTRA_GET_GROUP_IDX2(gidx); ++ de_1st = tssi_info->tssi_mcs[path][gidx_1st]; ++ de_2nd = tssi_info->tssi_mcs[path][gidx_2nd]; ++ val = (de_1st + de_2nd) / 2; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM]: path=%d mcs de=%d 1st=%d 2nd=%d\n", ++ path, val, de_1st, de_2nd); ++ } else { ++ val = tssi_info->tssi_mcs[path][gidx]; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM]: path=%d mcs de=%d\n", path, val); ++ } ++ ++ return val; ++} ++ ++static s8 _tssi_get_ofdm_trim_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u8 ch = chan->channel; ++ u32 tgidx, tgidx_1st, tgidx_2nd; ++ s8 tde_1st; ++ s8 tde_2nd; ++ s8 val; ++ ++ tgidx = _tssi_get_trim_group(rtwdev, ch); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM]: path=%d mcs trim_group_idx=0x%x\n", ++ path, tgidx); ++ ++ if (IS_TSSI_EXTRA_GROUP(tgidx)) { ++ tgidx_1st = TSSI_EXTRA_GET_GROUP_IDX1(tgidx); ++ tgidx_2nd = TSSI_EXTRA_GET_GROUP_IDX2(tgidx); ++ tde_1st = tssi_info->tssi_trim[path][tgidx_1st]; ++ tde_2nd = tssi_info->tssi_trim[path][tgidx_2nd]; ++ val = (tde_1st + tde_2nd) / 2; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM]: path=%d mcs trim_de=%d 1st=%d 2nd=%d\n", ++ path, val, tde_1st, tde_2nd); ++ } else { ++ val = tssi_info->tssi_trim[path][tgidx]; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM]: path=%d mcs trim_de=%d\n", ++ path, val); ++ } ++ ++ return val; ++} ++ ++static void _tssi_set_efuse_to_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) ++{ ++ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u8 ch = chan->channel; ++ u8 gidx; ++ s8 ofdm_de; ++ s8 trim_de; ++ s32 val; ++ u32 i; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "[TSSI][TRIM]: phy=%d ch=%d\n", ++ phy, ch); ++ ++ for (i = RF_PATH_A; i < RF_PATH_NUM_8852B; i++) { ++ gidx = _tssi_get_cck_group(rtwdev, ch); ++ trim_de = _tssi_get_ofdm_trim_de(rtwdev, phy, i); ++ val = tssi_info->tssi_cck[i][gidx] + trim_de; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM]: path=%d cck[%d]=0x%x trim=0x%x\n", ++ i, gidx, tssi_info->tssi_cck[i][gidx], trim_de); ++ ++ rtw89_phy_write32_mask(rtwdev, _tssi_de_cck_long[i], _TSSI_DE_MASK, val); ++ rtw89_phy_write32_mask(rtwdev, _tssi_de_cck_short[i], _TSSI_DE_MASK, val); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] Set TSSI CCK DE 0x%x[21:12]=0x%x\n", ++ _tssi_de_cck_long[i], ++ rtw89_phy_read32_mask(rtwdev, _tssi_de_cck_long[i], ++ _TSSI_DE_MASK)); ++ ++ ofdm_de = _tssi_get_ofdm_de(rtwdev, phy, i); ++ trim_de = _tssi_get_ofdm_trim_de(rtwdev, phy, i); ++ val = ofdm_de + trim_de; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI][TRIM]: path=%d mcs=0x%x trim=0x%x\n", ++ i, ofdm_de, trim_de); ++ ++ rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_20m[i], _TSSI_DE_MASK, val); ++ rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_40m[i], _TSSI_DE_MASK, val); ++ rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_80m[i], _TSSI_DE_MASK, val); ++ rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_80m_80m[i], _TSSI_DE_MASK, val); ++ rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_5m[i], _TSSI_DE_MASK, val); ++ rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_10m[i], _TSSI_DE_MASK, val); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, ++ "[TSSI] Set TSSI MCS DE 0x%x[21:12]=0x%x\n", ++ _tssi_de_mcs_20m[i], ++ rtw89_phy_read32_mask(rtwdev, _tssi_de_mcs_20m[i], ++ _TSSI_DE_MASK)); ++ } ++} ++ ++static void _tssi_alimentk_dump_result(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) ++{ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K]\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n" ++ "0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n", ++ R_TSSI_PA_K1 + (path << 13), ++ rtw89_phy_read32_mask(rtwdev, R_TSSI_PA_K1 + (path << 13), MASKDWORD), ++ R_TSSI_PA_K2 + (path << 13), ++ rtw89_phy_read32_mask(rtwdev, R_TSSI_PA_K2 + (path << 13), MASKDWORD), ++ R_P0_TSSI_ALIM1 + (path << 13), ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD), ++ R_P0_TSSI_ALIM3 + (path << 13), ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD), ++ R_TSSI_PA_K5 + (path << 13), ++ rtw89_phy_read32_mask(rtwdev, R_TSSI_PA_K5 + (path << 13), MASKDWORD), ++ R_P0_TSSI_ALIM2 + (path << 13), ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD), ++ R_P0_TSSI_ALIM4 + (path << 13), ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD), ++ R_TSSI_PA_K8 + (path << 13), ++ rtw89_phy_read32_mask(rtwdev, R_TSSI_PA_K8 + (path << 13), MASKDWORD)); ++} ++ ++static void _tssi_alimentk_done(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, enum rtw89_rf_path path) ++{ ++ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u8 channel = chan->channel; ++ u8 band; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "======>%s phy=%d path=%d\n", __func__, phy, path); ++ ++ if (channel >= 1 && channel <= 14) ++ band = TSSI_ALIMK_2G; ++ else if (channel >= 36 && channel <= 64) ++ band = TSSI_ALIMK_5GL; ++ else if (channel >= 100 && channel <= 144) ++ band = TSSI_ALIMK_5GM; ++ else if (channel >= 149 && channel <= 177) ++ band = TSSI_ALIMK_5GH; ++ else ++ band = TSSI_ALIMK_2G; ++ ++ if (tssi_info->alignment_done[path][band]) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD, ++ tssi_info->alignment_value[path][band][0]); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD, ++ tssi_info->alignment_value[path][band][1]); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD, ++ tssi_info->alignment_value[path][band][2]); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD, ++ tssi_info->alignment_value[path][band][3]); ++ } ++ ++ _tssi_alimentk_dump_result(rtwdev, path); ++} ++ ++static void _tssi_hw_tx(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, u16 cnt, u16 period, s16 pwr_dbm, ++ u8 enable) ++{ ++ enum rtw89_rf_path_bit rx_path; ++ ++ if (path == RF_PATH_A) ++ rx_path = RF_A; ++ else if (path == RF_PATH_B) ++ rx_path = RF_B; ++ else if (path == RF_PATH_AB) ++ rx_path = RF_AB; ++ else ++ rx_path = RF_ABCD; /* don't change path, but still set others */ ++ ++ if (enable) { ++ rtw8852b_bb_set_plcp_tx(rtwdev); ++ rtw8852b_bb_cfg_tx_path(rtwdev, path); ++ rtw8852b_bb_ctrl_rx_path(rtwdev, rx_path); ++ rtw8852b_bb_set_power(rtwdev, pwr_dbm, phy); ++ } ++ ++ rtw8852b_bb_set_pmac_pkt_tx(rtwdev, enable, cnt, period, 20, phy); ++} ++ ++static void _tssi_backup_bb_registers(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, const u32 reg[], ++ u32 reg_backup[], u32 reg_num) ++{ ++ u32 i; ++ ++ for (i = 0; i < reg_num; i++) { ++ reg_backup[i] = rtw89_phy_read32_mask(rtwdev, reg[i], MASKDWORD); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI] Backup BB 0x%x = 0x%x\n", reg[i], ++ reg_backup[i]); ++ } ++} ++ ++static void _tssi_reload_bb_registers(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, const u32 reg[], ++ u32 reg_backup[], u32 reg_num) ++ ++{ ++ u32 i; ++ ++ for (i = 0; i < reg_num; i++) { ++ rtw89_phy_write32_mask(rtwdev, reg[i], MASKDWORD, reg_backup[i]); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI] Reload BB 0x%x = 0x%x\n", reg[i], ++ reg_backup[i]); ++ } ++} ++ ++static u8 _tssi_ch_to_idx(struct rtw89_dev *rtwdev, u8 channel) ++{ ++ u8 channel_index; ++ ++ if (channel >= 1 && channel <= 14) ++ channel_index = channel - 1; ++ else if (channel >= 36 && channel <= 64) ++ channel_index = (channel - 36) / 2 + 14; ++ else if (channel >= 100 && channel <= 144) ++ channel_index = ((channel - 100) / 2) + 15 + 14; ++ else if (channel >= 149 && channel <= 177) ++ channel_index = ((channel - 149) / 2) + 38 + 14; ++ else ++ channel_index = 0; ++ ++ return channel_index; ++} ++ ++static bool _tssi_get_cw_report(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path, const s16 *power, ++ u32 *tssi_cw_rpt) ++{ ++ u32 tx_counter, tx_counter_tmp; ++ const int retry = 100; ++ u32 tmp; ++ int j, k; ++ ++ for (j = 0; j < RTW8852B_TSSI_PATH_NR; j++) { ++ rtw89_phy_write32_mask(rtwdev, _tssi_trigger[path], B_P0_TSSI_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, _tssi_trigger[path], B_P0_TSSI_EN, 0x1); ++ ++ tx_counter = rtw89_phy_read32_mask(rtwdev, R_TX_COUNTER, MASKLWORD); ++ ++ tmp = rtw89_phy_read32_mask(rtwdev, _tssi_trigger[path], MASKDWORD); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] 0x%x = 0x%08x path=%d\n", ++ _tssi_trigger[path], tmp, path); ++ ++ if (j == 0) ++ _tssi_hw_tx(rtwdev, phy, path, 100, 5000, power[j], true); ++ else ++ _tssi_hw_tx(rtwdev, phy, RF_PATH_ABCD, 100, 5000, power[j], true); ++ ++ tx_counter_tmp = rtw89_phy_read32_mask(rtwdev, R_TX_COUNTER, MASKLWORD); ++ tx_counter_tmp -= tx_counter; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] First HWTXcounter=%d path=%d\n", ++ tx_counter_tmp, path); ++ ++ for (k = 0; k < retry; k++) { ++ tmp = rtw89_phy_read32_mask(rtwdev, _tssi_cw_rpt_addr[path], ++ B_TSSI_CWRPT_RDY); ++ if (tmp) ++ break; ++ ++ udelay(30); ++ ++ tx_counter_tmp = ++ rtw89_phy_read32_mask(rtwdev, R_TX_COUNTER, MASKLWORD); ++ tx_counter_tmp -= tx_counter; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] Flow k = %d HWTXcounter=%d path=%d\n", ++ k, tx_counter_tmp, path); ++ } ++ ++ if (k >= retry) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] TSSI finish bit k > %d mp:100ms normal:30us path=%d\n", ++ k, path); ++ ++ _tssi_hw_tx(rtwdev, phy, path, 100, 5000, power[j], false); ++ return false; ++ } ++ ++ tssi_cw_rpt[j] = ++ rtw89_phy_read32_mask(rtwdev, _tssi_cw_rpt_addr[path], B_TSSI_CWRPT); ++ ++ _tssi_hw_tx(rtwdev, phy, path, 100, 5000, power[j], false); ++ ++ tx_counter_tmp = rtw89_phy_read32_mask(rtwdev, R_TX_COUNTER, MASKLWORD); ++ tx_counter_tmp -= tx_counter; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] Final HWTXcounter=%d path=%d\n", ++ tx_counter_tmp, path); ++ } ++ ++ return true; ++} ++ ++static void _tssi_alimentk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_rf_path path) ++{ ++ static const u32 bb_reg[8] = {0x5820, 0x7820, 0x4978, 0x58e4, ++ 0x78e4, 0x49c0, 0x0d18, 0x0d80}; ++ static const s16 power_2g[4] = {48, 20, 4, 4}; ++ static const s16 power_5g[4] = {48, 20, 4, 4}; ++ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ s32 tssi_alim_offset_1, tssi_alim_offset_2, tssi_alim_offset_3; ++ u32 tssi_cw_rpt[RTW8852B_TSSI_PATH_NR] = {0}; ++ u8 channel = chan->channel; ++ u8 ch_idx = _tssi_ch_to_idx(rtwdev, channel); ++ struct rtw8852b_bb_tssi_bak tssi_bak; ++ s32 aliment_diff, tssi_cw_default; ++ u32 start_time, finish_time; ++ u32 bb_reg_backup[8] = {0}; ++ const s16 *power; ++ u8 band; ++ bool ok; ++ u32 tmp; ++ u8 j; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "======> %s channel=%d path=%d\n", __func__, channel, ++ path); ++ ++ if (tssi_info->check_backup_aligmk[path][ch_idx]) { ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD, ++ tssi_info->alignment_backup_by_ch[path][ch_idx][0]); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD, ++ tssi_info->alignment_backup_by_ch[path][ch_idx][1]); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD, ++ tssi_info->alignment_backup_by_ch[path][ch_idx][2]); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD, ++ tssi_info->alignment_backup_by_ch[path][ch_idx][3]); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "======> %s Reload TSSI Alignment !!!\n", __func__); ++ _tssi_alimentk_dump_result(rtwdev, path); ++ return; ++ } ++ ++ start_time = ktime_get_ns(); ++ ++ if (chan->band_type == RTW89_BAND_2G) ++ power = power_2g; ++ else ++ power = power_5g; ++ ++ if (channel >= 1 && channel <= 14) ++ band = TSSI_ALIMK_2G; ++ else if (channel >= 36 && channel <= 64) ++ band = TSSI_ALIMK_5GL; ++ else if (channel >= 100 && channel <= 144) ++ band = TSSI_ALIMK_5GM; ++ else if (channel >= 149 && channel <= 177) ++ band = TSSI_ALIMK_5GH; ++ else ++ band = TSSI_ALIMK_2G; ++ ++ rtw8852b_bb_backup_tssi(rtwdev, phy, &tssi_bak); ++ _tssi_backup_bb_registers(rtwdev, phy, bb_reg, bb_reg_backup, ARRAY_SIZE(bb_reg_backup)); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, B_P0_TSSI_AVG, 0x8); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_AVG, B_P1_TSSI_AVG, 0x8); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TSSI_MV_AVG, 0x2); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_MV_AVG, B_P1_TSSI_MV_AVG, 0x2); ++ ++ ok = _tssi_get_cw_report(rtwdev, phy, path, power, tssi_cw_rpt); ++ if (!ok) ++ goto out; ++ ++ for (j = 0; j < RTW8852B_TSSI_PATH_NR; j++) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] power[%d]=%d tssi_cw_rpt[%d]=%d\n", j, ++ power[j], j, tssi_cw_rpt[j]); ++ } ++ ++ tmp = rtw89_phy_read32_mask(rtwdev, _tssi_cw_default_addr[path][1], ++ _tssi_cw_default_mask[1]); ++ tssi_cw_default = sign_extend32(tmp, 8); ++ tssi_alim_offset_1 = tssi_cw_rpt[0] - ((power[0] - power[1]) * 2) - ++ tssi_cw_rpt[1] + tssi_cw_default; ++ aliment_diff = tssi_alim_offset_1 - tssi_cw_default; ++ ++ tmp = rtw89_phy_read32_mask(rtwdev, _tssi_cw_default_addr[path][2], ++ _tssi_cw_default_mask[2]); ++ tssi_cw_default = sign_extend32(tmp, 8); ++ tssi_alim_offset_2 = tssi_cw_default + aliment_diff; ++ ++ tmp = rtw89_phy_read32_mask(rtwdev, _tssi_cw_default_addr[path][3], ++ _tssi_cw_default_mask[3]); ++ tssi_cw_default = sign_extend32(tmp, 8); ++ tssi_alim_offset_3 = tssi_cw_default + aliment_diff; ++ ++ if (path == RF_PATH_A) { ++ tmp = FIELD_PREP(B_P1_TSSI_ALIM11, tssi_alim_offset_1) | ++ FIELD_PREP(B_P1_TSSI_ALIM12, tssi_alim_offset_2) | ++ FIELD_PREP(B_P1_TSSI_ALIM13, tssi_alim_offset_3); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM1, B_P0_TSSI_ALIM1, tmp); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM2, B_P0_TSSI_ALIM2, tmp); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] tssi_alim_offset = 0x%x 0x%x 0x%x 0x%x\n", ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM3, B_P0_TSSI_ALIM31), ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1, B_P0_TSSI_ALIM11), ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1, B_P0_TSSI_ALIM12), ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1, B_P0_TSSI_ALIM13)); ++ } else { ++ tmp = FIELD_PREP(B_P1_TSSI_ALIM11, tssi_alim_offset_1) | ++ FIELD_PREP(B_P1_TSSI_ALIM12, tssi_alim_offset_2) | ++ FIELD_PREP(B_P1_TSSI_ALIM13, tssi_alim_offset_3); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_ALIM1, B_P1_TSSI_ALIM1, tmp); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_ALIM2, B_P1_TSSI_ALIM2, tmp); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] tssi_alim_offset = 0x%x 0x%x 0x%x 0x%x\n", ++ rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_ALIM3, B_P1_TSSI_ALIM31), ++ rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_ALIM1, B_P1_TSSI_ALIM11), ++ rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_ALIM1, B_P1_TSSI_ALIM12), ++ rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_ALIM1, B_P1_TSSI_ALIM13)); ++ } ++ ++ tssi_info->alignment_done[path][band] = true; ++ tssi_info->alignment_value[path][band][0] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD); ++ tssi_info->alignment_value[path][band][1] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD); ++ tssi_info->alignment_value[path][band][2] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD); ++ tssi_info->alignment_value[path][band][3] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD); ++ ++ tssi_info->check_backup_aligmk[path][ch_idx] = true; ++ tssi_info->alignment_backup_by_ch[path][ch_idx][0] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD); ++ tssi_info->alignment_backup_by_ch[path][ch_idx][1] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD); ++ tssi_info->alignment_backup_by_ch[path][ch_idx][2] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD); ++ tssi_info->alignment_backup_by_ch[path][ch_idx][3] = ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] tssi_info->alignment_value[path=%d][band=%d][0], 0x%x = 0x%08x\n", ++ path, band, R_P0_TSSI_ALIM1 + (path << 13), ++ tssi_info->alignment_value[path][band][0]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] tssi_info->alignment_value[path=%d][band=%d][1], 0x%x = 0x%08x\n", ++ path, band, R_P0_TSSI_ALIM3 + (path << 13), ++ tssi_info->alignment_value[path][band][1]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] tssi_info->alignment_value[path=%d][band=%d][2], 0x%x = 0x%08x\n", ++ path, band, R_P0_TSSI_ALIM2 + (path << 13), ++ tssi_info->alignment_value[path][band][2]); ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] tssi_info->alignment_value[path=%d][band=%d][3], 0x%x = 0x%08x\n", ++ path, band, R_P0_TSSI_ALIM4 + (path << 13), ++ tssi_info->alignment_value[path][band][3]); ++ ++out: ++ _tssi_reload_bb_registers(rtwdev, phy, bb_reg, bb_reg_backup, ARRAY_SIZE(bb_reg_backup)); ++ rtw8852b_bb_restore_tssi(rtwdev, phy, &tssi_bak); ++ rtw8852b_bb_tx_mode_switch(rtwdev, phy, 0); ++ ++ finish_time = ktime_get_ns(); ++ tssi_info->tssi_alimk_time += finish_time - start_time; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[TSSI PA K] %s processing time = %d ms\n", __func__, ++ tssi_info->tssi_alimk_time); ++} ++ ++void rtw8852b_dpk_init(struct rtw89_dev *rtwdev) ++{ ++ _set_dpd_backoff(rtwdev, RTW89_PHY_0); ++} ++ ++void rtw8852b_rck(struct rtw89_dev *rtwdev) ++{ ++ u8 path; ++ ++ for (path = 0; path < RF_PATH_NUM_8852B; path++) ++ _rck(rtwdev, path); ++} ++ ++void rtw8852b_dack(struct rtw89_dev *rtwdev) ++{ ++ u8 phy_map = rtw89_btc_phymap(rtwdev, RTW89_PHY_0, 0); ++ ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_DACK, BTC_WRFK_START); ++ _dac_cal(rtwdev, false); ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_DACK, BTC_WRFK_STOP); ++} ++ ++void rtw8852b_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) ++{ ++ u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); ++ u32 tx_en; ++ ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_START); ++ rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); ++ _wait_rx_mode(rtwdev, _kpath(rtwdev, phy_idx)); ++ ++ _iqk_init(rtwdev); ++ _iqk(rtwdev, phy_idx, false); ++ ++ rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_STOP); ++} ++ ++void rtw8852b_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) ++{ ++ u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); ++ u32 tx_en; ++ ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_START); ++ rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); ++ _wait_rx_mode(rtwdev, _kpath(rtwdev, phy_idx)); ++ ++ _rx_dck(rtwdev, phy_idx); ++ ++ rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_STOP); ++} ++ ++void rtw8852b_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) ++{ ++ u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); ++ u32 tx_en; ++ ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_DPK, BTC_WRFK_START); ++ rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); ++ _wait_rx_mode(rtwdev, _kpath(rtwdev, phy_idx)); ++ ++ rtwdev->dpk.is_dpk_enable = true; ++ rtwdev->dpk.is_dpk_reload_en = false; ++ _dpk(rtwdev, phy_idx, false); ++ ++ rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_DPK, BTC_WRFK_STOP); ++} ++ ++void rtw8852b_dpk_track(struct rtw89_dev *rtwdev) ++{ ++ _dpk_track(rtwdev); ++} ++ ++void rtw8852b_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_en) ++{ ++ u8 phy_map = rtw89_btc_phymap(rtwdev, phy, RF_AB); ++ u32 tx_en; ++ u8 i; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_TSSI, "[TSSI] %s: phy=%d\n", __func__, phy); ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); ++ ++ _tssi_disable(rtwdev, phy); ++ ++ for (i = RF_PATH_A; i < RF_PATH_NUM_8852B; i++) { ++ _tssi_rf_setting(rtwdev, phy, i); ++ _tssi_set_sys(rtwdev, phy, i); ++ _tssi_ini_txpwr_ctrl_bb(rtwdev, phy, i); ++ _tssi_ini_txpwr_ctrl_bb_he_tb(rtwdev, phy, i); ++ _tssi_set_dck(rtwdev, phy, i); ++ _tssi_set_tmeter_tbl(rtwdev, phy, i); ++ _tssi_set_dac_gain_tbl(rtwdev, phy, i); ++ _tssi_slope_cal_org(rtwdev, phy, i); ++ _tssi_alignment_default(rtwdev, phy, i, true); ++ _tssi_set_tssi_slope(rtwdev, phy, i); ++ ++ rtw89_chip_stop_sch_tx(rtwdev, phy, &tx_en, RTW89_SCH_TX_SEL_ALL); ++ _tmac_tx_pause(rtwdev, phy, true); ++ if (hwtx_en) ++ _tssi_alimentk(rtwdev, phy, i); ++ _tmac_tx_pause(rtwdev, phy, false); ++ rtw89_chip_resume_sch_tx(rtwdev, phy, tx_en); ++ } ++ ++ _tssi_enable(rtwdev, phy); ++ _tssi_set_efuse_to_de(rtwdev, phy); ++ ++ rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_STOP); ++} ++ ++void rtw8852b_tssi_scan(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; ++ u8 channel = chan->channel; ++ u8 band; ++ u32 i; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "======>%s phy=%d channel=%d\n", __func__, phy, channel); ++ ++ if (channel >= 1 && channel <= 14) ++ band = TSSI_ALIMK_2G; ++ else if (channel >= 36 && channel <= 64) ++ band = TSSI_ALIMK_5GL; ++ else if (channel >= 100 && channel <= 144) ++ band = TSSI_ALIMK_5GM; ++ else if (channel >= 149 && channel <= 177) ++ band = TSSI_ALIMK_5GH; ++ else ++ band = TSSI_ALIMK_2G; ++ ++ _tssi_disable(rtwdev, phy); ++ ++ for (i = RF_PATH_A; i < RTW8852B_TSSI_PATH_NR; i++) { ++ _tssi_rf_setting(rtwdev, phy, i); ++ _tssi_set_sys(rtwdev, phy, i); ++ _tssi_set_tmeter_tbl(rtwdev, phy, i); ++ ++ if (tssi_info->alignment_done[i][band]) ++ _tssi_alimentk_done(rtwdev, phy, i); ++ else ++ _tssi_alignment_default(rtwdev, phy, i, true); ++ } ++ ++ _tssi_enable(rtwdev, phy); ++ _tssi_set_efuse_to_de(rtwdev, phy); ++} ++ ++static void rtw8852b_tssi_default_txagc(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, bool enable) ++{ ++ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); ++ u8 channel = chan->channel; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "======> %s ch=%d\n", ++ __func__, channel); ++ ++ if (enable) { ++ if (!rtwdev->is_tssi_mode[RF_PATH_A] && !rtwdev->is_tssi_mode[RF_PATH_B]) ++ rtw8852b_tssi(rtwdev, phy, true); ++ return; ++ } ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "======>%s 1 SCAN_END Set 0x5818[7:0]=0x%x 0x7818[7:0]=0x%x\n", ++ __func__, ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT), ++ rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT)); ++ ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT, 0xc0); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT, 0xc0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x1); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT_EN, 0x0); ++ rtw89_phy_write32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT_EN, 0x1); ++ ++ _tssi_alimentk_done(rtwdev, phy, RF_PATH_A); ++ _tssi_alimentk_done(rtwdev, phy, RF_PATH_B); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "======>%s 2 SCAN_END Set 0x5818[7:0]=0x%x 0x7818[7:0]=0x%x\n", ++ __func__, ++ rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT), ++ rtw89_phy_read32_mask(rtwdev, R_P1_TSSI_TRK, B_P1_TSSI_OFT)); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "======> %s SCAN_END\n", __func__); ++} ++ ++void rtw8852b_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, ++ enum rtw89_phy_idx phy_idx) ++{ ++ if (scan_start) ++ rtw8852b_tssi_default_txagc(rtwdev, phy_idx, true); ++ else ++ rtw8852b_tssi_default_txagc(rtwdev, phy_idx, false); ++} ++ ++static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, ++ enum rtw89_bandwidth bw, bool dav) ++{ ++ u32 rf_reg18; ++ u32 reg18_addr = dav ? RR_CFGCH : RR_CFGCH_V1; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]===> %s\n", __func__); ++ ++ rf_reg18 = rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK); ++ if (rf_reg18 == INV_RF_DATA) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RFK]Invalid RF_0x18 for Path-%d\n", path); ++ return; ++ } ++ rf_reg18 &= ~RR_CFGCH_BW; ++ ++ switch (bw) { ++ case RTW89_CHANNEL_WIDTH_5: ++ case RTW89_CHANNEL_WIDTH_10: ++ case RTW89_CHANNEL_WIDTH_20: ++ rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_20M); ++ break; ++ case RTW89_CHANNEL_WIDTH_40: ++ rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_40M); ++ break; ++ case RTW89_CHANNEL_WIDTH_80: ++ rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_80M); ++ break; ++ default: ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]Fail to set CH\n"); ++ } ++ ++ rf_reg18 &= ~(RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH | RR_CFGCH_BCN | ++ RR_CFGCH_BW2) & RFREG_MASK; ++ rf_reg18 |= RR_CFGCH_BW2; ++ rtw89_write_rf(rtwdev, path, reg18_addr, RFREG_MASK, rf_reg18); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK] set %x at path%d, %x =0x%x\n", ++ bw, path, reg18_addr, ++ rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK)); ++} ++ ++static void _ctrl_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_bandwidth bw) ++{ ++ _bw_setting(rtwdev, RF_PATH_A, bw, true); ++ _bw_setting(rtwdev, RF_PATH_B, bw, true); ++ _bw_setting(rtwdev, RF_PATH_A, bw, false); ++ _bw_setting(rtwdev, RF_PATH_B, bw, false); ++} ++ ++static bool _set_s0_arfc18(struct rtw89_dev *rtwdev, u32 val) ++{ ++ u32 bak; ++ u32 tmp; ++ int ret; ++ ++ bak = rtw89_read_rf(rtwdev, RF_PATH_A, RR_LDO, RFREG_MASK); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_LDO, RR_LDO_SEL, 0x1); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK, val); ++ ++ ret = read_poll_timeout_atomic(rtw89_read_rf, tmp, tmp == 0, 1, 1000, ++ false, rtwdev, RF_PATH_A, RR_LPF, RR_LPF_BUSY); ++ if (ret) ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]LCK timeout\n"); ++ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_LDO, RFREG_MASK, bak); ++ ++ return !!ret; ++} ++ ++static void _lck_check(struct rtw89_dev *rtwdev) ++{ ++ u32 tmp; ++ ++ if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]SYN MMD reset\n"); ++ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_EN, 0x1); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_SYN, 0x0); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_SYN, 0x1); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_EN, 0x0); ++ } ++ ++ udelay(10); ++ ++ if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]re-set RF 0x18\n"); ++ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1); ++ tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK); ++ _set_s0_arfc18(rtwdev, tmp); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0); ++ } ++ ++ if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) { ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]SYN off/on\n"); ++ ++ tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_POW, RFREG_MASK); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RFREG_MASK, tmp); ++ tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_SX, RFREG_MASK); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_SX, RFREG_MASK, tmp); ++ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_SYNLUT, RR_SYNLUT_MOD, 0x1); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x0); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x3); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_SYNLUT, RR_SYNLUT_MOD, 0x0); ++ ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1); ++ tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK); ++ _set_s0_arfc18(rtwdev, tmp); ++ rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]0xb2=%x, 0xc5=%x\n", ++ rtw89_read_rf(rtwdev, RF_PATH_A, RR_VCO, RFREG_MASK), ++ rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RFREG_MASK)); ++ } ++} ++ ++static void _set_ch(struct rtw89_dev *rtwdev, u32 val) ++{ ++ bool timeout; ++ ++ timeout = _set_s0_arfc18(rtwdev, val); ++ if (!timeout) ++ _lck_check(rtwdev); ++} ++ ++static void _ch_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, ++ u8 central_ch, bool dav) ++{ ++ u32 reg18_addr = dav ? RR_CFGCH : RR_CFGCH_V1; ++ bool is_2g_ch = central_ch <= 14; ++ u32 rf_reg18; ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]===> %s\n", __func__); ++ ++ rf_reg18 = rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK); ++ rf_reg18 &= ~(RR_CFGCH_BAND1 | RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH | ++ RR_CFGCH_BCN | RR_CFGCH_BAND0 | RR_CFGCH_CH); ++ rf_reg18 |= FIELD_PREP(RR_CFGCH_CH, central_ch); ++ ++ if (!is_2g_ch) ++ rf_reg18 |= FIELD_PREP(RR_CFGCH_BAND1, CFGCH_BAND1_5G) | ++ FIELD_PREP(RR_CFGCH_BAND0, CFGCH_BAND0_5G); ++ ++ rf_reg18 &= ~(RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH | RR_CFGCH_BCN | ++ RR_CFGCH_BW2) & RFREG_MASK; ++ rf_reg18 |= RR_CFGCH_BW2; ++ ++ if (path == RF_PATH_A && dav) ++ _set_ch(rtwdev, rf_reg18); ++ else ++ rtw89_write_rf(rtwdev, path, reg18_addr, RFREG_MASK, rf_reg18); ++ ++ rtw89_write_rf(rtwdev, path, RR_LCKST, RR_LCKST_BIN, 0); ++ rtw89_write_rf(rtwdev, path, RR_LCKST, RR_LCKST_BIN, 1); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, ++ "[RFK]CH: %d for Path-%d, reg0x%x = 0x%x\n", ++ central_ch, path, reg18_addr, ++ rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK)); ++} ++ ++static void _ctrl_ch(struct rtw89_dev *rtwdev, u8 central_ch) ++{ ++ _ch_setting(rtwdev, RF_PATH_A, central_ch, true); ++ _ch_setting(rtwdev, RF_PATH_B, central_ch, true); ++ _ch_setting(rtwdev, RF_PATH_A, central_ch, false); ++ _ch_setting(rtwdev, RF_PATH_B, central_ch, false); ++} ++ ++static void _set_rxbb_bw(struct rtw89_dev *rtwdev, enum rtw89_bandwidth bw, ++ enum rtw89_rf_path path) ++{ ++ rtw89_write_rf(rtwdev, path, RR_LUTWE2, RR_LUTWE2_RTXBW, 0x1); ++ rtw89_write_rf(rtwdev, path, RR_LUTWA, RR_LUTWA_M2, 0x12); ++ ++ if (bw == RTW89_CHANNEL_WIDTH_20) ++ rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x1b); ++ else if (bw == RTW89_CHANNEL_WIDTH_40) ++ rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x13); ++ else if (bw == RTW89_CHANNEL_WIDTH_80) ++ rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0xb); ++ else ++ rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x3); ++ ++ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK] set S%d RXBB BW 0x3F = 0x%x\n", path, ++ rtw89_read_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB)); ++ ++ rtw89_write_rf(rtwdev, path, RR_LUTWE2, RR_LUTWE2_RTXBW, 0x0); ++} ++ ++static void _rxbb_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, ++ enum rtw89_bandwidth bw) ++{ ++ u8 kpath, path; ++ ++ kpath = _kpath(rtwdev, phy); ++ ++ for (path = 0; path < RF_PATH_NUM_8852B; path++) { ++ if (!(kpath & BIT(path))) ++ continue; ++ ++ _set_rxbb_bw(rtwdev, bw, path); ++ } ++} ++ ++static void rtw8852b_ctrl_bw_ch(struct rtw89_dev *rtwdev, ++ enum rtw89_phy_idx phy, u8 central_ch, ++ enum rtw89_band band, enum rtw89_bandwidth bw) ++{ ++ _ctrl_ch(rtwdev, central_ch); ++ _ctrl_bw(rtwdev, phy, bw); ++ _rxbb_bw(rtwdev, phy, bw); ++} ++ ++void rtw8852b_set_channel_rf(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx) ++{ ++ rtw8852b_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type, ++ chan->band_width); ++} +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h 2022-12-24 00:49:25.783376835 +0200 +@@ -0,0 +1,25 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2019-2022 Realtek Corporation ++ */ ++ ++#ifndef __RTW89_8852B_RFK_H__ ++#define __RTW89_8852B_RFK_H__ ++ ++#include "core.h" ++ ++void rtw8852b_rck(struct rtw89_dev *rtwdev); ++void rtw8852b_dack(struct rtw89_dev *rtwdev); ++void rtw8852b_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); ++void rtw8852b_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); ++void rtw8852b_dpk_init(struct rtw89_dev *rtwdev); ++void rtw8852b_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); ++void rtw8852b_dpk_track(struct rtw89_dev *rtwdev); ++void rtw8852b_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_en); ++void rtw8852b_tssi_scan(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); ++void rtw8852b_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, ++ enum rtw89_phy_idx phy_idx); ++void rtw8852b_set_channel_rf(struct rtw89_dev *rtwdev, ++ const struct rtw89_chan *chan, ++ enum rtw89_phy_idx phy_idx); ++ ++#endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.c 2022-12-24 00:49:25.783376835 +0200 +@@ -0,0 +1,794 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2019-2020 Realtek Corporation ++ */ ++ ++#include "rtw8852b_rfk_table.h" ++ ++static const struct rtw89_reg5_def rtw8852b_afe_init_defs[] = { ++ RTW89_DECL_RFK_WM(0xC0D4, 0xffffffff, 0x4486888c), ++ RTW89_DECL_RFK_WM(0xC0D8, 0xffffffff, 0xc6ba10e0), ++ RTW89_DECL_RFK_WM(0xc0dc, 0xffffffff, 0x30c52868), ++ RTW89_DECL_RFK_WM(0xc0e0, 0xffffffff, 0x05008128), ++ RTW89_DECL_RFK_WM(0xc0e4, 0xffffffff, 0x0000272b), ++ RTW89_DECL_RFK_WM(0xC1D4, 0xffffffff, 0x4486888c), ++ RTW89_DECL_RFK_WM(0xC1D8, 0xffffffff, 0xc6ba10e0), ++ RTW89_DECL_RFK_WM(0xc1dc, 0xffffffff, 0x30c52868), ++ RTW89_DECL_RFK_WM(0xc1e0, 0xffffffff, 0x05008128), ++ RTW89_DECL_RFK_WM(0xc1e4, 0xffffffff, 0x0000272b), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_afe_init_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_check_addc_defs_a[] = { ++ RTW89_DECL_RFK_WM(0x20f4, BIT(24), 0x0), ++ RTW89_DECL_RFK_WM(0x20f8, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x20f0, 0xff0000, 0x1), ++ RTW89_DECL_RFK_WM(0x20f0, 0xf00, 0x2), ++ RTW89_DECL_RFK_WM(0x20f0, 0xf, 0x0), ++ RTW89_DECL_RFK_WM(0x20f0, 0xc0, 0x2), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_check_addc_defs_a); ++ ++static const struct rtw89_reg5_def rtw8852b_check_addc_defs_b[] = { ++ RTW89_DECL_RFK_WM(0x20f4, BIT(24), 0x0), ++ RTW89_DECL_RFK_WM(0x20f8, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x20f0, 0xff0000, 0x1), ++ RTW89_DECL_RFK_WM(0x20f0, 0xf00, 0x2), ++ RTW89_DECL_RFK_WM(0x20f0, 0xf, 0x0), ++ RTW89_DECL_RFK_WM(0x20f0, 0xc0, 0x3), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_check_addc_defs_b); ++ ++static const struct rtw89_reg5_def rtw8852b_check_dadc_en_defs_a[] = { ++ RTW89_DECL_RFK_WM(0x032C, BIT(30), 0x0), ++ RTW89_DECL_RFK_WM(0x030C, 0x0f000000, 0xf), ++ RTW89_DECL_RFK_WM(0x030C, 0x0f000000, 0x3), ++ RTW89_DECL_RFK_WM(0x032C, BIT(16), 0x0), ++ RTW89_DECL_RFK_WM(0x12dc, BIT(0), 0x1), ++ RTW89_DECL_RFK_WM(0x12e8, BIT(2), 0x1), ++ RTW89_DECL_RFK_WRF(RF_PATH_A, 0x8f, BIT(13), 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_check_dadc_en_defs_a); ++ ++static const struct rtw89_reg5_def rtw8852b_check_dadc_en_defs_b[] = { ++ RTW89_DECL_RFK_WM(0x032C, BIT(30), 0x0), ++ RTW89_DECL_RFK_WM(0x030C, 0x0f000000, 0xf), ++ RTW89_DECL_RFK_WM(0x030C, 0x0f000000, 0x3), ++ RTW89_DECL_RFK_WM(0x032C, BIT(16), 0x0), ++ RTW89_DECL_RFK_WM(0x32dc, BIT(0), 0x1), ++ RTW89_DECL_RFK_WM(0x32e8, BIT(2), 0x1), ++ RTW89_DECL_RFK_WRF(RF_PATH_B, 0x8f, BIT(13), 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_check_dadc_en_defs_b); ++ ++static const struct rtw89_reg5_def rtw8852b_check_dadc_dis_defs_a[] = { ++ RTW89_DECL_RFK_WM(0x12dc, BIT(0), 0x0), ++ RTW89_DECL_RFK_WM(0x12e8, BIT(2), 0x0), ++ RTW89_DECL_RFK_WRF(RF_PATH_A, 0x8f, BIT(13), 0x0), ++ RTW89_DECL_RFK_WM(0x032C, BIT(16), 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_check_dadc_dis_defs_a); ++ ++static const struct rtw89_reg5_def rtw8852b_check_dadc_dis_defs_b[] = { ++ RTW89_DECL_RFK_WM(0x32dc, BIT(0), 0x0), ++ RTW89_DECL_RFK_WM(0x32e8, BIT(2), 0x0), ++ RTW89_DECL_RFK_WRF(RF_PATH_B, 0x8f, BIT(13), 0x0), ++ RTW89_DECL_RFK_WM(0x032C, BIT(16), 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_check_dadc_dis_defs_b); ++ ++static const struct rtw89_reg5_def rtw8852b_dack_s0_1_defs[] = { ++ RTW89_DECL_RFK_WM(0x12A0, BIT(15), 0x1), ++ RTW89_DECL_RFK_WM(0x12A0, 0x00007000, 0x3), ++ RTW89_DECL_RFK_WM(0x12B8, BIT(30), 0x1), ++ RTW89_DECL_RFK_WM(0x030C, BIT(28), 0x1), ++ RTW89_DECL_RFK_WM(0x032C, 0x80000000, 0x0), ++ RTW89_DECL_RFK_WM(0xC0D8, BIT(16), 0x1), ++ RTW89_DECL_RFK_WM(0xc0dc, 0x0c000000, 0x3), ++ RTW89_DECL_RFK_WM(0xC004, BIT(30), 0x0), ++ RTW89_DECL_RFK_WM(0xc024, BIT(30), 0x0), ++ RTW89_DECL_RFK_WM(0xC004, 0x3ff00000, 0x30), ++ RTW89_DECL_RFK_WM(0xC004, 0xc0000000, 0x0), ++ RTW89_DECL_RFK_WM(0xC004, BIT(17), 0x1), ++ RTW89_DECL_RFK_WM(0xc024, BIT(17), 0x1), ++ RTW89_DECL_RFK_WM(0xc00c, BIT(2), 0x0), ++ RTW89_DECL_RFK_WM(0xc02c, BIT(2), 0x0), ++ RTW89_DECL_RFK_WM(0xC004, BIT(0), 0x1), ++ RTW89_DECL_RFK_WM(0xc024, BIT(0), 0x1), ++ RTW89_DECL_RFK_DELAY(1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dack_s0_1_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_dack_s0_2_defs[] = { ++ RTW89_DECL_RFK_WM(0xc0dc, 0x0c000000, 0x0), ++ RTW89_DECL_RFK_WM(0xc00c, BIT(2), 0x1), ++ RTW89_DECL_RFK_WM(0xc02c, BIT(2), 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dack_s0_2_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_dack_s0_3_defs[] = { ++ RTW89_DECL_RFK_WM(0xC004, BIT(0), 0x0), ++ RTW89_DECL_RFK_WM(0xc024, BIT(0), 0x0), ++ RTW89_DECL_RFK_WM(0xC0D8, BIT(16), 0x0), ++ RTW89_DECL_RFK_WM(0x12A0, BIT(15), 0x0), ++ RTW89_DECL_RFK_WM(0x12A0, 0x00007000, 0x7), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dack_s0_3_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_dack_s1_1_defs[] = { ++ RTW89_DECL_RFK_WM(0x32a0, BIT(15), 0x1), ++ RTW89_DECL_RFK_WM(0x32a0, 0x7000, 0x3), ++ RTW89_DECL_RFK_WM(0x32B8, BIT(30), 0x1), ++ RTW89_DECL_RFK_WM(0x030C, BIT(28), 0x1), ++ RTW89_DECL_RFK_WM(0x032C, 0x80000000, 0x0), ++ RTW89_DECL_RFK_WM(0xC1D8, BIT(16), 0x1), ++ RTW89_DECL_RFK_WM(0xc1dc, 0x0c000000, 0x3), ++ RTW89_DECL_RFK_WM(0xc104, BIT(30), 0x0), ++ RTW89_DECL_RFK_WM(0xc124, BIT(30), 0x0), ++ RTW89_DECL_RFK_WM(0xc104, 0x3ff00000, 0x30), ++ RTW89_DECL_RFK_WM(0xc104, 0xc0000000, 0x0), ++ RTW89_DECL_RFK_WM(0xc104, BIT(17), 0x1), ++ RTW89_DECL_RFK_WM(0xc124, BIT(17), 0x1), ++ RTW89_DECL_RFK_WM(0xc10c, BIT(2), 0x0), ++ RTW89_DECL_RFK_WM(0xc12c, BIT(2), 0x0), ++ RTW89_DECL_RFK_WM(0xc104, BIT(0), 0x1), ++ RTW89_DECL_RFK_WM(0xc124, BIT(0), 0x1), ++ RTW89_DECL_RFK_DELAY(1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dack_s1_1_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_dack_s1_2_defs[] = { ++ RTW89_DECL_RFK_WM(0xc1dc, 0x0c000000, 0x0), ++ RTW89_DECL_RFK_WM(0xc10c, BIT(2), 0x1), ++ RTW89_DECL_RFK_WM(0xc12c, BIT(2), 0x1), ++ RTW89_DECL_RFK_DELAY(1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dack_s1_2_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_dack_s1_3_defs[] = { ++ RTW89_DECL_RFK_WM(0xc104, BIT(0), 0x0), ++ RTW89_DECL_RFK_WM(0xc124, BIT(0), 0x0), ++ RTW89_DECL_RFK_WM(0xC1D8, BIT(16), 0x0), ++ RTW89_DECL_RFK_WM(0x32a0, BIT(15), 0x0), ++ RTW89_DECL_RFK_WM(0x32a0, 0x7000, 0x7), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dack_s1_3_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_dpk_afe_defs[] = { ++ RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0303), ++ RTW89_DECL_RFK_WM(0x12b8, BIT(30), 0x1), ++ RTW89_DECL_RFK_WM(0x32b8, BIT(30), 0x1), ++ RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x13), ++ RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0041), ++ RTW89_DECL_RFK_WM(0x12b8, BIT(28), 0x1), ++ RTW89_DECL_RFK_WM(0x58c8, BIT(24), 0x1), ++ RTW89_DECL_RFK_WM(0x78c8, BIT(24), 0x1), ++ RTW89_DECL_RFK_WM(0x5864, 0xc0000000, 0x3), ++ RTW89_DECL_RFK_WM(0x7864, 0xc0000000, 0x3), ++ RTW89_DECL_RFK_WM(0x2008, 0x01FFFFFF, 0x1ffffff), ++ RTW89_DECL_RFK_WM(0x0c1c, BIT(2), 0x1), ++ RTW89_DECL_RFK_WM(0x0700, BIT(27), 0x1), ++ RTW89_DECL_RFK_WM(0x0c70, 0x000003FF, 0x3ff), ++ RTW89_DECL_RFK_WM(0x0c60, 0x00000003, 0x3), ++ RTW89_DECL_RFK_WM(0x0c6c, BIT(0), 0x1), ++ RTW89_DECL_RFK_WM(0x58ac, BIT(27), 0x1), ++ RTW89_DECL_RFK_WM(0x78ac, BIT(27), 0x1), ++ RTW89_DECL_RFK_WM(0x0c3c, BIT(9), 0x1), ++ RTW89_DECL_RFK_WM(0x2344, BIT(31), 0x1), ++ RTW89_DECL_RFK_WM(0x4490, BIT(31), 0x1), ++ RTW89_DECL_RFK_WM(0x12a0, 0x000ff000, 0xbf), ++ RTW89_DECL_RFK_WM(0x32a0, 0x000f0000, 0xb), ++ RTW89_DECL_RFK_WM(0x0700, 0x07000000, 0x5), ++ RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x3333), ++ RTW89_DECL_RFK_WM(0x580c, BIT(15), 0x1), ++ RTW89_DECL_RFK_WM(0x5800, 0x0000ffff, 0x0000), ++ RTW89_DECL_RFK_WM(0x780c, BIT(15), 0x1), ++ RTW89_DECL_RFK_WM(0x7800, 0x0000ffff, 0x0000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dpk_afe_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_dpk_afe_restore_defs[] = { ++ RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0303), ++ RTW89_DECL_RFK_WM(0x12b8, BIT(30), 0x0), ++ RTW89_DECL_RFK_WM(0x32b8, BIT(30), 0x0), ++ RTW89_DECL_RFK_WM(0x5864, 0xc0000000, 0x0), ++ RTW89_DECL_RFK_WM(0x7864, 0xc0000000, 0x0), ++ RTW89_DECL_RFK_WM(0x2008, 0x01FFFFFF, 0x0), ++ RTW89_DECL_RFK_WM(0x0c1c, BIT(2), 0x0), ++ RTW89_DECL_RFK_WM(0x0700, BIT(27), 0x0), ++ RTW89_DECL_RFK_WM(0x0c70, 0x000003FF, 0x63), ++ RTW89_DECL_RFK_WM(0x12a0, 0x000FF000, 0x00), ++ RTW89_DECL_RFK_WM(0x32a0, 0x000FF000, 0x00), ++ RTW89_DECL_RFK_WM(0x0700, 0x07000000, 0x0), ++ RTW89_DECL_RFK_WM(0x5864, BIT(29), 0x0), ++ RTW89_DECL_RFK_WM(0x7864, BIT(29), 0x0), ++ RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0000), ++ RTW89_DECL_RFK_WM(0x58c8, BIT(24), 0x0), ++ RTW89_DECL_RFK_WM(0x78c8, BIT(24), 0x0), ++ RTW89_DECL_RFK_WM(0x0c3c, BIT(9), 0x0), ++ RTW89_DECL_RFK_WM(0x580c, BIT(15), 0x0), ++ RTW89_DECL_RFK_WM(0x58e4, 0x18000000, 0x1), ++ RTW89_DECL_RFK_WM(0x58e4, 0x18000000, 0x2), ++ RTW89_DECL_RFK_WM(0x780c, BIT(15), 0x0), ++ RTW89_DECL_RFK_WM(0x78e4, 0x18000000, 0x1), ++ RTW89_DECL_RFK_WM(0x78e4, 0x18000000, 0x2), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dpk_afe_restore_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_dpk_kip_defs[] = { ++ RTW89_DECL_RFK_WM(0x8008, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x8088, 0xffffffff, 0x80000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_dpk_kip_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_sys_defs[] = { ++ RTW89_DECL_RFK_WM(0x12a8, 0x0000000f, 0x5), ++ RTW89_DECL_RFK_WM(0x32a8, 0x0000000f, 0x5), ++ RTW89_DECL_RFK_WM(0x12bc, 0x000ffff0, 0x5555), ++ RTW89_DECL_RFK_WM(0x32bc, 0x000ffff0, 0x5555), ++ RTW89_DECL_RFK_WM(0x0300, 0xff000000, 0x16), ++ RTW89_DECL_RFK_WM(0x0304, 0x000000ff, 0x19), ++ RTW89_DECL_RFK_WM(0x0314, 0xffff0000, 0x2041), ++ RTW89_DECL_RFK_WM(0x0318, 0xffffffff, 0x2041), ++ RTW89_DECL_RFK_WM(0x0318, 0xffffffff, 0x20012041), ++ RTW89_DECL_RFK_WM(0x0020, 0x00006000, 0x3), ++ RTW89_DECL_RFK_WM(0x0024, 0x00006000, 0x3), ++ RTW89_DECL_RFK_WM(0x0704, 0xffff0000, 0x601e), ++ RTW89_DECL_RFK_WM(0x2704, 0xffff0000, 0x601e), ++ RTW89_DECL_RFK_WM(0x0700, 0xf0000000, 0x4), ++ RTW89_DECL_RFK_WM(0x2700, 0xf0000000, 0x4), ++ RTW89_DECL_RFK_WM(0x0650, 0x3c000000, 0x0), ++ RTW89_DECL_RFK_WM(0x2650, 0x3c000000, 0x0), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_sys_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_sys_a_defs_2g[] = { ++ RTW89_DECL_RFK_WM(0x120c, 0x000000ff, 0x33), ++ RTW89_DECL_RFK_WM(0x12c0, 0x0ff00000, 0x33), ++ RTW89_DECL_RFK_WM(0x58f8, 0x40000000, 0x1), ++ RTW89_DECL_RFK_WM(0x0304, 0x0000ff00, 0x1e), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_sys_a_defs_2g); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_sys_a_defs_5g[] = { ++ RTW89_DECL_RFK_WM(0x120c, 0x000000ff, 0x44), ++ RTW89_DECL_RFK_WM(0x12c0, 0x0ff00000, 0x44), ++ RTW89_DECL_RFK_WM(0x58f8, 0x40000000, 0x0), ++ RTW89_DECL_RFK_WM(0x0304, 0x0000ff00, 0x1d), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_sys_a_defs_5g); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_sys_b_defs_2g[] = { ++ RTW89_DECL_RFK_WM(0x32c0, 0x0ff00000, 0x33), ++ RTW89_DECL_RFK_WM(0x320c, 0x000000ff, 0x33), ++ RTW89_DECL_RFK_WM(0x78f8, 0x40000000, 0x1), ++ RTW89_DECL_RFK_WM(0x0304, 0x0000ff00, 0x1e), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_sys_b_defs_2g); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_sys_b_defs_5g[] = { ++ RTW89_DECL_RFK_WM(0x32c0, 0x0ff00000, 0x44), ++ RTW89_DECL_RFK_WM(0x320c, 0x000000ff, 0x44), ++ RTW89_DECL_RFK_WM(0x78f8, 0x40000000, 0x0), ++ RTW89_DECL_RFK_WM(0x0304, 0x0000ff00, 0x1d), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_sys_b_defs_5g); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_init_txpwr_defs_a[] = { ++ RTW89_DECL_RFK_WM(0x566c, 0x00001000, 0x0), ++ RTW89_DECL_RFK_WM(0x5800, 0xffffffff, 0x003f807f), ++ RTW89_DECL_RFK_WM(0x580c, 0x0000007f, 0x40), ++ RTW89_DECL_RFK_WM(0x580c, 0x0fffff00, 0x00040), ++ RTW89_DECL_RFK_WM(0x5810, 0xffffffff, 0x59010000), ++ RTW89_DECL_RFK_WM(0x5814, 0x01ffffff, 0x002d000), ++ RTW89_DECL_RFK_WM(0x5814, 0xf8000000, 0x00), ++ RTW89_DECL_RFK_WM(0x5818, 0xffffffff, 0x002c1800), ++ RTW89_DECL_RFK_WM(0x581c, 0x3fffffff, 0x1dc80280), ++ RTW89_DECL_RFK_WM(0x5820, 0xffffffff, 0x00002080), ++ RTW89_DECL_RFK_WM(0x580c, 0x10000000, 0x1), ++ RTW89_DECL_RFK_WM(0x580c, 0x40000000, 0x1), ++ RTW89_DECL_RFK_WM(0x5834, 0x3fffffff, 0x000115f2), ++ RTW89_DECL_RFK_WM(0x5838, 0x7fffffff, 0x0000121), ++ RTW89_DECL_RFK_WM(0x5854, 0x3fffffff, 0x000115f2), ++ RTW89_DECL_RFK_WM(0x5858, 0x7fffffff, 0x0000121), ++ RTW89_DECL_RFK_WM(0x5860, 0x80000000, 0x0), ++ RTW89_DECL_RFK_WM(0x5864, 0x07ffffff, 0x00801ff), ++ RTW89_DECL_RFK_WM(0x5898, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x589c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x58a4, 0x000000ff, 0x16), ++ RTW89_DECL_RFK_WM(0x58b0, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x58b4, 0x7fffffff, 0x0a002000), ++ RTW89_DECL_RFK_WM(0x58b8, 0x7fffffff, 0x00007628), ++ RTW89_DECL_RFK_WM(0x58bc, 0x07ffffff, 0x7a7807f), ++ RTW89_DECL_RFK_WM(0x58c0, 0xfffe0000, 0x003f), ++ RTW89_DECL_RFK_WM(0x58c4, 0xffffffff, 0x0003ffff), ++ RTW89_DECL_RFK_WM(0x58c8, 0x00ffffff, 0x000000), ++ RTW89_DECL_RFK_WM(0x58c8, 0xf0000000, 0x0), ++ RTW89_DECL_RFK_WM(0x58cc, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x58d0, 0x07ffffff, 0x2008101), ++ RTW89_DECL_RFK_WM(0x58d4, 0x000000ff, 0x00), ++ RTW89_DECL_RFK_WM(0x58d4, 0x0003fe00, 0x0ff), ++ RTW89_DECL_RFK_WM(0x58d4, 0x07fc0000, 0x100), ++ RTW89_DECL_RFK_WM(0x58d8, 0xffffffff, 0x8008016c), ++ RTW89_DECL_RFK_WM(0x58dc, 0x0001ffff, 0x0807f), ++ RTW89_DECL_RFK_WM(0x58dc, 0xfff00000, 0x800), ++ RTW89_DECL_RFK_WM(0x58f0, 0x0003ffff, 0x001ff), ++ RTW89_DECL_RFK_WM(0x58f4, 0x000fffff, 0x000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_init_txpwr_defs_a); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_init_txpwr_defs_b[] = { ++ RTW89_DECL_RFK_WM(0x566c, 0x00001000, 0x0), ++ RTW89_DECL_RFK_WM(0x7800, 0xffffffff, 0x003f807f), ++ RTW89_DECL_RFK_WM(0x780c, 0x0000007f, 0x40), ++ RTW89_DECL_RFK_WM(0x780c, 0x0fffff00, 0x00040), ++ RTW89_DECL_RFK_WM(0x7810, 0xffffffff, 0x59010000), ++ RTW89_DECL_RFK_WM(0x7814, 0x01ffffff, 0x002d000), ++ RTW89_DECL_RFK_WM(0x7814, 0xf8000000, 0x00), ++ RTW89_DECL_RFK_WM(0x7818, 0xffffffff, 0x002c1800), ++ RTW89_DECL_RFK_WM(0x781c, 0x3fffffff, 0x1dc80280), ++ RTW89_DECL_RFK_WM(0x7820, 0xffffffff, 0x00002080), ++ RTW89_DECL_RFK_WM(0x780c, 0x10000000, 0x1), ++ RTW89_DECL_RFK_WM(0x780c, 0x40000000, 0x1), ++ RTW89_DECL_RFK_WM(0x7834, 0x3fffffff, 0x000115f2), ++ RTW89_DECL_RFK_WM(0x7838, 0x7fffffff, 0x0000121), ++ RTW89_DECL_RFK_WM(0x7854, 0x3fffffff, 0x000115f2), ++ RTW89_DECL_RFK_WM(0x7858, 0x7fffffff, 0x0000121), ++ RTW89_DECL_RFK_WM(0x7860, 0x80000000, 0x0), ++ RTW89_DECL_RFK_WM(0x7864, 0x07ffffff, 0x00801ff), ++ RTW89_DECL_RFK_WM(0x7898, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x789c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x78a4, 0x000000ff, 0x16), ++ RTW89_DECL_RFK_WM(0x78b0, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x78b4, 0x7fffffff, 0x0a002000), ++ RTW89_DECL_RFK_WM(0x78b8, 0x7fffffff, 0x00007628), ++ RTW89_DECL_RFK_WM(0x78bc, 0x07ffffff, 0x7a7807f), ++ RTW89_DECL_RFK_WM(0x78c0, 0xfffe0000, 0x003f), ++ RTW89_DECL_RFK_WM(0x78c4, 0xffffffff, 0x0003ffff), ++ RTW89_DECL_RFK_WM(0x78c8, 0x00ffffff, 0x000000), ++ RTW89_DECL_RFK_WM(0x78c8, 0xf0000000, 0x0), ++ RTW89_DECL_RFK_WM(0x78cc, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x78d0, 0x07ffffff, 0x2008101), ++ RTW89_DECL_RFK_WM(0x78d4, 0x000000ff, 0x00), ++ RTW89_DECL_RFK_WM(0x78d4, 0x0003fe00, 0x0ff), ++ RTW89_DECL_RFK_WM(0x78d4, 0x07fc0000, 0x100), ++ RTW89_DECL_RFK_WM(0x78d8, 0xffffffff, 0x8008016c), ++ RTW89_DECL_RFK_WM(0x78dc, 0x0001ffff, 0x0807f), ++ RTW89_DECL_RFK_WM(0x78dc, 0xfff00000, 0x800), ++ RTW89_DECL_RFK_WM(0x78f0, 0x0003ffff, 0x001ff), ++ RTW89_DECL_RFK_WM(0x78f4, 0x000fffff, 0x000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_init_txpwr_defs_b); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_init_txpwr_he_tb_defs_a[] = { ++ RTW89_DECL_RFK_WM(0x58a0, 0xffffffff, 0x000000fe), ++ RTW89_DECL_RFK_WM(0x58e4, 0x0000007f, 0x1f), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_init_txpwr_he_tb_defs_a); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_init_txpwr_he_tb_defs_b[] = { ++ RTW89_DECL_RFK_WM(0x78a0, 0xffffffff, 0x000000fe), ++ RTW89_DECL_RFK_WM(0x78e4, 0x0000007f, 0x1f), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_init_txpwr_he_tb_defs_b); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_dck_defs_a[] = { ++ RTW89_DECL_RFK_WM(0x580c, 0x0fff0000, 0x000), ++ RTW89_DECL_RFK_WM(0x5814, 0x003ff000, 0x0ef), ++ RTW89_DECL_RFK_WM(0x5814, 0x18000000, 0x0), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_dck_defs_a); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_dck_defs_b[] = { ++ RTW89_DECL_RFK_WM(0x780c, 0x0fff0000, 0x000), ++ RTW89_DECL_RFK_WM(0x7814, 0x003ff000, 0x0ef), ++ RTW89_DECL_RFK_WM(0x7814, 0x18000000, 0x0), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_dck_defs_b); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_dac_gain_defs_a[] = { ++ RTW89_DECL_RFK_WM(0x58b0, 0x00000400, 0x1), ++ RTW89_DECL_RFK_WM(0x58b0, 0x00000fff, 0x000), ++ RTW89_DECL_RFK_WM(0x58b0, 0x00000800, 0x1), ++ RTW89_DECL_RFK_WM(0x5a00, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a04, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a08, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a0c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a10, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a14, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a18, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a1c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a20, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a24, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a28, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a2c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a30, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a34, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a38, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a3c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a40, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a44, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a48, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a4c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a50, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a54, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a58, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a5c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a60, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a64, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a68, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a6c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a70, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a74, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a78, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a7c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a80, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a84, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a88, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a8c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a90, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a94, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a98, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5a9c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5aa0, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5aa4, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5aa8, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5aac, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5ab0, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5ab4, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5ab8, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5abc, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5ac0, 0xffffffff, 0x00000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_dac_gain_defs_a); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_dac_gain_defs_b[] = { ++ RTW89_DECL_RFK_WM(0x78b0, 0x00000fff, 0x000), ++ RTW89_DECL_RFK_WM(0x78b0, 0x00000800, 0x1), ++ RTW89_DECL_RFK_WM(0x7a00, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a04, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a08, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a0c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a10, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a14, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a18, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a1c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a20, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a24, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a28, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a2c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a30, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a34, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a38, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a3c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a40, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a44, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a48, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a4c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a50, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a54, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a58, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a5c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a60, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a64, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a68, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a6c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a70, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a74, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a78, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a7c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a80, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a84, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a88, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a8c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a90, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a94, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a98, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7a9c, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7aa0, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7aa4, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7aa8, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7aac, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7ab0, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7ab4, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7ab8, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7abc, 0xffffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7ac0, 0xffffffff, 0x00000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_dac_gain_defs_b); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_slope_a_defs_2g[] = { ++ RTW89_DECL_RFK_WM(0x5608, 0x07ffffff, 0x0801008), ++ RTW89_DECL_RFK_WM(0x560c, 0x07ffffff, 0x0201020), ++ RTW89_DECL_RFK_WM(0x5610, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x5614, 0x07ffffff, 0x0804008), ++ RTW89_DECL_RFK_WM(0x5618, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x561c, 0x000001ff, 0x008), ++ RTW89_DECL_RFK_WM(0x561c, 0xffff0000, 0x0808), ++ RTW89_DECL_RFK_WM(0x5620, 0xffffffff, 0x08081e28), ++ RTW89_DECL_RFK_WM(0x5624, 0xffffffff, 0x08080808), ++ RTW89_DECL_RFK_WM(0x5628, 0xffffffff, 0x08081e28), ++ RTW89_DECL_RFK_WM(0x562c, 0x0000ffff, 0x0808), ++ RTW89_DECL_RFK_WM(0x581c, 0x00100000, 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_slope_a_defs_2g); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_slope_a_defs_5g[] = { ++ RTW89_DECL_RFK_WM(0x5608, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x560c, 0x07ffffff, 0x0201020), ++ RTW89_DECL_RFK_WM(0x5610, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x5614, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x5618, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x561c, 0x000001ff, 0x008), ++ RTW89_DECL_RFK_WM(0x561c, 0xffff0000, 0x0808), ++ RTW89_DECL_RFK_WM(0x5620, 0xffffffff, 0x08081e08), ++ RTW89_DECL_RFK_WM(0x5624, 0xffffffff, 0x08080808), ++ RTW89_DECL_RFK_WM(0x5628, 0xffffffff, 0x08080808), ++ RTW89_DECL_RFK_WM(0x562c, 0x0000ffff, 0x0808), ++ RTW89_DECL_RFK_WM(0x581c, 0x00100000, 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_slope_a_defs_5g); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_slope_b_defs_2g[] = { ++ RTW89_DECL_RFK_WM(0x7608, 0x07ffffff, 0x0801008), ++ RTW89_DECL_RFK_WM(0x760c, 0x07ffffff, 0x0201020), ++ RTW89_DECL_RFK_WM(0x7610, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x7614, 0x07ffffff, 0x0804008), ++ RTW89_DECL_RFK_WM(0x7618, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x761c, 0x000001ff, 0x008), ++ RTW89_DECL_RFK_WM(0x761c, 0xffff0000, 0x0808), ++ RTW89_DECL_RFK_WM(0x7620, 0xffffffff, 0x08081e28), ++ RTW89_DECL_RFK_WM(0x7624, 0xffffffff, 0x08080808), ++ RTW89_DECL_RFK_WM(0x7628, 0xffffffff, 0x08081e28), ++ RTW89_DECL_RFK_WM(0x762c, 0x0000ffff, 0x0808), ++ RTW89_DECL_RFK_WM(0x781c, 0x00100000, 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_slope_b_defs_2g); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_slope_b_defs_5g[] = { ++ RTW89_DECL_RFK_WM(0x7608, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x760c, 0x07ffffff, 0x0201020), ++ RTW89_DECL_RFK_WM(0x7610, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x7614, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x7618, 0x07ffffff, 0x0201008), ++ RTW89_DECL_RFK_WM(0x761c, 0x000001ff, 0x008), ++ RTW89_DECL_RFK_WM(0x761c, 0xffff0000, 0x0808), ++ RTW89_DECL_RFK_WM(0x7620, 0xffffffff, 0x08081e08), ++ RTW89_DECL_RFK_WM(0x7624, 0xffffffff, 0x08080808), ++ RTW89_DECL_RFK_WM(0x7628, 0xffffffff, 0x08080808), ++ RTW89_DECL_RFK_WM(0x762c, 0x0000ffff, 0x0808), ++ RTW89_DECL_RFK_WM(0x781c, 0x00100000, 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_slope_b_defs_5g); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_a_2g_all_defs[] = { ++ RTW89_DECL_RFK_WM(0x5604, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x5600, 0x3fffffff, 0x3f2d2721), ++ RTW89_DECL_RFK_WM(0x5604, 0x003fffff, 0x010101), ++ RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x01ef27af), ++ RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000075), ++ RTW89_DECL_RFK_WM(0x5638, 0x000fffff, 0x00000), ++ RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x017f13ae), ++ RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x0000006e), ++ RTW89_DECL_RFK_WM(0x5644, 0x000fffff, 0x00000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_a_2g_all_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_a_2g_part_defs[] = { ++ RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x01ef27af), ++ RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000075), ++ RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x017f13ae), ++ RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x0000006e), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_a_2g_part_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_a_5g1_all_defs[] = { ++ RTW89_DECL_RFK_WM(0x5604, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x5600, 0x3fffffff, 0x3f2d2721), ++ RTW89_DECL_RFK_WM(0x5604, 0x003fffff, 0x010101), ++ RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x016037e7), ++ RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x0000006f), ++ RTW89_DECL_RFK_WM(0x5638, 0x000fffff, 0x00000), ++ RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5644, 0x000fffff, 0x00000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_a_5g1_all_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_a_5g1_part_defs[] = { ++ RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x016037e7), ++ RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x0000006f), ++ RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_a_5g1_part_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_a_5g2_all_defs[] = { ++ RTW89_DECL_RFK_WM(0x5604, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x5600, 0x3fffffff, 0x3f2d2721), ++ RTW89_DECL_RFK_WM(0x5604, 0x003fffff, 0x010101), ++ RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x01f053f1), ++ RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000070), ++ RTW89_DECL_RFK_WM(0x5638, 0x000fffff, 0x00000), ++ RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5644, 0x000fffff, 0x00000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_a_5g2_all_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_a_5g2_part_defs[] = { ++ RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x01f053f1), ++ RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000070), ++ RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_a_5g2_part_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_a_5g3_all_defs[] = { ++ RTW89_DECL_RFK_WM(0x5604, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x5600, 0x3fffffff, 0x3f2d2721), ++ RTW89_DECL_RFK_WM(0x5604, 0x003fffff, 0x010101), ++ RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x01c047ee), ++ RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000070), ++ RTW89_DECL_RFK_WM(0x5638, 0x000fffff, 0x00000), ++ RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5644, 0x000fffff, 0x00000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_a_5g3_all_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_a_5g3_part_defs[] = { ++ RTW89_DECL_RFK_WM(0x5630, 0x3fffffff, 0x01c047ee), ++ RTW89_DECL_RFK_WM(0x5634, 0x3fffffff, 0x00000070), ++ RTW89_DECL_RFK_WM(0x563c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x5640, 0x3fffffff, 0x00000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_a_5g3_part_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_b_2g_all_defs[] = { ++ RTW89_DECL_RFK_WM(0x7604, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x7600, 0x3fffffff, 0x3f2d2721), ++ RTW89_DECL_RFK_WM(0x7604, 0x003fffff, 0x010101), ++ RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x01ff2bb5), ++ RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000078), ++ RTW89_DECL_RFK_WM(0x7638, 0x000fffff, 0x00000), ++ RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x018f2bb0), ++ RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000072), ++ RTW89_DECL_RFK_WM(0x7644, 0x000fffff, 0x00000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_b_2g_all_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_b_2g_part_defs[] = { ++ RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x01ff2bb5), ++ RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000078), ++ RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x018f2bb0), ++ RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000072), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_b_2g_part_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_b_5g1_all_defs[] = { ++ RTW89_DECL_RFK_WM(0x7604, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x7600, 0x3fffffff, 0x3f2d2721), ++ RTW89_DECL_RFK_WM(0x7604, 0x003fffff, 0x010101), ++ RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x009003da), ++ RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000069), ++ RTW89_DECL_RFK_WM(0x7638, 0x000fffff, 0x00000), ++ RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7644, 0x000fffff, 0x00000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_b_5g1_all_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_b_5g1_part_defs[] = { ++ RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x009003da), ++ RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000069), ++ RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_b_5g1_part_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_b_5g2_all_defs[] = { ++ RTW89_DECL_RFK_WM(0x7604, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x7600, 0x3fffffff, 0x3f2d2721), ++ RTW89_DECL_RFK_WM(0x7604, 0x003fffff, 0x010101), ++ RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x013027e6), ++ RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000069), ++ RTW89_DECL_RFK_WM(0x7638, 0x000fffff, 0x00000), ++ RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7644, 0x000fffff, 0x00000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_b_5g2_all_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_b_5g2_part_defs[] = { ++ RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x013027e6), ++ RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000069), ++ RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_b_5g2_part_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_b_5g3_all_defs[] = { ++ RTW89_DECL_RFK_WM(0x7604, 0x80000000, 0x1), ++ RTW89_DECL_RFK_WM(0x7600, 0x3fffffff, 0x3f2d2721), ++ RTW89_DECL_RFK_WM(0x7604, 0x003fffff, 0x010101), ++ RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x009003da), ++ RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000069), ++ RTW89_DECL_RFK_WM(0x7638, 0x000fffff, 0x00000), ++ RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7644, 0x000fffff, 0x00000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_b_5g3_all_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_align_b_5g3_part_defs[] = { ++ RTW89_DECL_RFK_WM(0x7630, 0x3fffffff, 0x009003da), ++ RTW89_DECL_RFK_WM(0x7634, 0x3fffffff, 0x00000069), ++ RTW89_DECL_RFK_WM(0x763c, 0x3fffffff, 0x00000000), ++ RTW89_DECL_RFK_WM(0x7640, 0x3fffffff, 0x00000000), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_align_b_5g3_part_defs); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_slope_defs_a[] = { ++ RTW89_DECL_RFK_WM(0x5814, 0x00000800, 0x1), ++ RTW89_DECL_RFK_WM(0x581c, 0x20000000, 0x1), ++ RTW89_DECL_RFK_WM(0x5814, 0x20000000, 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_slope_defs_a); ++ ++static const struct rtw89_reg5_def rtw8852b_tssi_slope_defs_b[] = { ++ RTW89_DECL_RFK_WM(0x7814, 0x00000800, 0x1), ++ RTW89_DECL_RFK_WM(0x781c, 0x20000000, 0x1), ++ RTW89_DECL_RFK_WM(0x7814, 0x20000000, 0x1), ++}; ++ ++RTW89_DECLARE_RFK_TBL(rtw8852b_tssi_slope_defs_b); +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.h linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk_table.h 2022-12-24 00:49:25.783376835 +0200 +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2019-2020 Realtek Corporation ++ */ ++ ++#ifndef __RTW89_8852B_RFK_TABLE_H__ ++#define __RTW89_8852B_RFK_TABLE_H__ ++ ++#include "phy.h" ++ ++extern const struct rtw89_rfk_tbl rtw8852b_afe_init_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_check_addc_defs_a_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_check_addc_defs_b_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_check_dadc_en_defs_a_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_check_dadc_en_defs_b_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_check_dadc_dis_defs_a_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_check_dadc_dis_defs_b_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dack_s0_1_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dack_s0_2_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dack_s0_3_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dack_s1_1_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dack_s1_2_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dack_s1_3_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dpk_afe_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dpk_afe_restore_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_dpk_kip_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_sys_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_sys_a_defs_2g_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_sys_a_defs_5g_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_sys_b_defs_2g_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_sys_b_defs_5g_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_init_txpwr_defs_a_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_init_txpwr_defs_b_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_init_txpwr_he_tb_defs_a_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_init_txpwr_he_tb_defs_b_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_dck_defs_a_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_dck_defs_b_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_dac_gain_defs_a_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_dac_gain_defs_b_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_slope_a_defs_2g_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_slope_a_defs_5g_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_slope_b_defs_2g_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_slope_b_defs_5g_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_a_2g_all_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_a_2g_part_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_a_5g1_all_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_a_5g1_part_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_a_5g2_all_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_a_5g2_part_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_a_5g3_all_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_a_5g3_part_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_b_2g_all_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_b_2g_part_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_b_5g1_all_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_b_5g1_part_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_b_5g2_all_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_b_5g2_part_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_b_5g3_all_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_align_b_5g3_part_defs_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_slope_defs_a_tbl; ++extern const struct rtw89_rfk_tbl rtw8852b_tssi_slope_defs_b_tbl; ++ ++#endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c 2022-12-24 00:49:25.785376835 +0200 +@@ -0,0 +1,22877 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2019-2020 Realtek Corporation ++ */ ++ ++#include "phy.h" ++#include "reg.h" ++#include "rtw8852b_table.h" ++ ++static const struct rtw89_reg2_def rtw89_8852b_phy_bb_regs[] = { ++ {0x704, 0x601E0100}, ++ {0x4000, 0x00000000}, ++ {0x4004, 0xCA014000}, ++ {0x4008, 0xC751D4F0}, ++ {0x400C, 0x44511475}, ++ {0x4010, 0x00000000}, ++ {0x4014, 0x00000000}, ++ {0x4018, 0x4F4C084B}, ++ {0x401C, 0x084A4E52}, ++ {0x4020, 0x4D504E4B}, ++ {0x4024, 0x4F4C0849}, ++ {0x4028, 0x08484C50}, ++ {0x402C, 0x4C50504C}, ++ {0x4030, 0x5454084A}, ++ {0x4034, 0x084B5654}, ++ {0x4038, 0x6A6C605A}, ++ {0x403C, 0x4C4C084C}, ++ {0x4040, 0x084B4E4D}, ++ {0x4044, 0x4E4C4B4B}, ++ {0x4048, 0x4B4B084A}, ++ {0x404C, 0x084A4E4C}, ++ {0x4050, 0x514F4C4A}, ++ {0x4054, 0x524E084A}, ++ {0x4058, 0x084A5154}, ++ {0x405C, 0x53555554}, ++ {0x4060, 0x45450845}, ++ {0x4064, 0x08454144}, ++ {0x4068, 0x40434445}, ++ {0x406C, 0x44450845}, ++ {0x4070, 0x08444043}, ++ {0x4074, 0x42434444}, ++ {0x4078, 0x46450844}, ++ {0x407C, 0x08444843}, ++ {0x4080, 0x4B4E4A47}, ++ {0x4084, 0x4F4C084B}, ++ {0x4088, 0x084A4E52}, ++ {0x408C, 0x4D504E4B}, ++ {0x4090, 0x4F4C0849}, ++ {0x4094, 0x08484C50}, ++ {0x4098, 0x4C50504C}, ++ {0x409C, 0x5454084A}, ++ {0x40A0, 0x084B5654}, ++ {0x40A4, 0x6A6C605A}, ++ {0x40A8, 0x4C4C084C}, ++ {0x40AC, 0x084B4E4D}, ++ {0x40B0, 0x4E4C4B4B}, ++ {0x40B4, 0x4B4B084A}, ++ {0x40B8, 0x084A4E4C}, ++ {0x40BC, 0x514F4C4A}, ++ {0x40C0, 0x524E084A}, ++ {0x40C4, 0x084A5154}, ++ {0x40C8, 0x53555554}, ++ {0x40CC, 0x45450845}, ++ {0x40D0, 0x08454144}, ++ {0x40D4, 0x40434445}, ++ {0x40D8, 0x44450845}, ++ {0x40DC, 0x08444043}, ++ {0x40E0, 0x42434444}, ++ {0x40E4, 0x46450844}, ++ {0x40E8, 0x08444843}, ++ {0x40EC, 0x4B4E4A47}, ++ {0x40F0, 0x00000000}, ++ {0x40F4, 0x00000006}, ++ {0x40F8, 0x00000000}, ++ {0x40FC, 0x8C30C30C}, ++ {0x4100, 0x4C30C30C}, ++ {0x4104, 0x0C30C30C}, ++ {0x4108, 0x0C30C30C}, ++ {0x410C, 0x0C30C30C}, ++ {0x4110, 0x0C30C30C}, ++ {0x4114, 0x28A28A28}, ++ {0x4118, 0x28A28A28}, ++ {0x411C, 0x28A28A28}, ++ {0x4120, 0x28A28A28}, ++ {0x4124, 0x28A28A28}, ++ {0x4128, 0x28A28A28}, ++ {0x412C, 0x06666666}, ++ {0x4130, 0x33333333}, ++ {0x4134, 0x33333333}, ++ {0x4138, 0x33333333}, ++ {0x413C, 0x00000031}, ++ {0x4140, 0x5100600A}, ++ {0x4144, 0x18363113}, ++ {0x4148, 0x1D976DDC}, ++ {0x414C, 0x1C072DD7}, ++ {0x4150, 0x1127CDF4}, ++ {0x4154, 0x1E37BDF1}, ++ {0x4158, 0x1FB7F1D6}, ++ {0x415C, 0x1EA7DDF9}, ++ {0x4160, 0x1FE445DD}, ++ {0x4164, 0x1F97F1FE}, ++ {0x4168, 0x1FF781ED}, ++ {0x416C, 0x1FA7F5FE}, ++ {0x4170, 0x1E07B913}, ++ {0x4174, 0x1FD7FDFF}, ++ {0x4178, 0x1E17B9FA}, ++ {0x417C, 0x19A66914}, ++ {0x4180, 0x10F65598}, ++ {0x4184, 0x14A5A111}, ++ {0x4188, 0x1D3765DB}, ++ {0x418C, 0x17C685CA}, ++ {0x4190, 0x1107C5F3}, ++ {0x4194, 0x1B5785EB}, ++ {0x4198, 0x1F97ED8F}, ++ {0x419C, 0x1BC7A5F3}, ++ {0x41A0, 0x1FE43595}, ++ {0x41A4, 0x1EB7D9FC}, ++ {0x41A8, 0x1FE65DBE}, ++ {0x41AC, 0x1EC7D9FC}, ++ {0x41B0, 0x1976FCFF}, ++ {0x41B4, 0x1F77F5FF}, ++ {0x41B8, 0x1976FDEC}, ++ {0x41BC, 0x198664EF}, ++ {0x41C0, 0x11062D93}, ++ {0x41C4, 0x10C4E910}, ++ {0x41C8, 0x1CA759DB}, ++ {0x41CC, 0x1335A9B5}, ++ {0x41D0, 0x1097B9F3}, ++ {0x41D4, 0x17B72DE1}, ++ {0x41D8, 0x1F67ED42}, ++ {0x41DC, 0x18074DE9}, ++ {0x41E0, 0x1FD40547}, ++ {0x41E4, 0x1D57ADF9}, ++ {0x41E8, 0x1FE52182}, ++ {0x41EC, 0x1D67B1F9}, ++ {0x41F0, 0x14860CE1}, ++ {0x41F4, 0x1EC7E9FE}, ++ {0x41F8, 0x14860DD6}, ++ {0x41FC, 0x195664C7}, ++ {0x4200, 0x0005E58A}, ++ {0x4204, 0x00000000}, ++ {0x4208, 0x00000000}, ++ {0x420C, 0x7A000000}, ++ {0x4210, 0x0F9F3D7A}, ++ {0x4214, 0x0040817C}, ++ {0x4218, 0x00E10204}, ++ {0x421C, 0x227D94CD}, ++ {0x4220, 0x08028A28}, ++ {0x4224, 0x00000210}, ++ {0x4228, 0x04688000}, ++ {0x4A48, 0x00000002}, ++ {0x422C, 0x0060B002}, ++ {0x4230, 0x9A8249A8}, ++ {0x4234, 0x26A1469E}, ++ {0x4238, 0x2099A824}, ++ {0x423C, 0x2359461C}, ++ {0x4240, 0x1631A675}, ++ {0x4244, 0x2C6B1D63}, ++ {0x4248, 0x0000000E}, ++ {0x424C, 0x00000001}, ++ {0x4250, 0x00000001}, ++ {0x4254, 0x00000000}, ++ {0x4258, 0x00000000}, ++ {0x425C, 0x00000000}, ++ {0x4260, 0x0020000C}, ++ {0x4264, 0x00000000}, ++ {0x4268, 0x00000000}, ++ {0x426C, 0x0418317C}, ++ {0x4270, 0x2B33135C}, ++ {0x4274, 0x00000002}, ++ {0x4278, 0x00000000}, ++ {0x427C, 0x00000000}, ++ {0x4280, 0x00000000}, ++ {0x4284, 0x00000000}, ++ {0x4288, 0x00000000}, ++ {0x428C, 0x00000000}, ++ {0x4290, 0x00000000}, ++ {0x4294, 0x00000000}, ++ {0x4298, 0x00000000}, ++ {0x429C, 0x84026000}, ++ {0x42A0, 0x0051AC20}, ++ {0x4A24, 0x0010C040}, ++ {0x42A4, 0x02024008}, ++ {0x42A8, 0x00000000}, ++ {0x42AC, 0x00000000}, ++ {0x42B0, 0x22CE803C}, ++ {0x42B4, 0x32000000}, ++ {0x42B8, 0x996FD67D}, ++ {0x42BC, 0xBD67D67D}, ++ {0x42C0, 0x7D67D65B}, ++ {0x42C4, 0x28029F59}, ++ {0x42C8, 0x00280280}, ++ {0x42CC, 0x00000000}, ++ {0x42D0, 0x00000000}, ++ {0x42D4, 0x00000003}, ++ {0x42D8, 0x00000001}, ++ {0x42DC, 0x61861800}, ++ {0x42E0, 0x830C30C3}, ++ {0x42E4, 0xC30C30C3}, ++ {0x42E8, 0x830C30C3}, ++ {0x42EC, 0x451450C3}, ++ {0x42F0, 0x05145145}, ++ {0x42F4, 0x05145145}, ++ {0x42F8, 0x05145145}, ++ {0x42FC, 0x0F0C3145}, ++ {0x4300, 0x030C30CF}, ++ {0x4304, 0x030C30C3}, ++ {0x4308, 0x030CF3C3}, ++ {0x430C, 0x030C30C3}, ++ {0x4310, 0x0F3CF3C3}, ++ {0x4314, 0x0F3CF3CF}, ++ {0x4318, 0x0F3CF3CF}, ++ {0x431C, 0x0F3CF3CF}, ++ {0x4320, 0x0F3CF3CF}, ++ {0x4324, 0x030C10C3}, ++ {0x4328, 0x051430C3}, ++ {0x432C, 0x051490CB}, ++ {0x4330, 0x030CD151}, ++ {0x4334, 0x050C50C7}, ++ {0x4338, 0x051492CB}, ++ {0x433C, 0x05145145}, ++ {0x4340, 0x05145145}, ++ {0x4344, 0x05145145}, ++ {0x4348, 0x05145145}, ++ {0x434C, 0x090CD3CF}, ++ {0x4350, 0x071491C5}, ++ {0x4354, 0x073CF143}, ++ {0x4358, 0x071431C3}, ++ {0x435C, 0x0F3CF1C5}, ++ {0x4360, 0x0F3CF3CF}, ++ {0x4364, 0x0F3CF3CF}, ++ {0x4368, 0x0F3CF3CF}, ++ {0x436C, 0x0F3CF3CF}, ++ {0x4370, 0x090C91CF}, ++ {0x4374, 0x11243143}, ++ {0x4378, 0x9777A777}, ++ {0x437C, 0xBB7BAC95}, ++ {0x4380, 0xB667B889}, ++ {0x4384, 0x7B9B8899}, ++ {0x4388, 0x7A5567C8}, ++ {0x438C, 0x2278CCCC}, ++ {0x4390, 0x7C222222}, ++ {0x4394, 0x0000069B}, ++ {0x4398, 0x001CCCCC}, ++ {0x4AAC, 0xCCCCC88C}, ++ {0x4AB0, 0x0000AACC}, ++ {0x439C, 0x00000000}, ++ {0x43A0, 0x00000008}, ++ {0x43A4, 0x00000000}, ++ {0x43A8, 0x00000000}, ++ {0x43AC, 0x00000000}, ++ {0x43B0, 0x10000000}, ++ {0x43B4, 0x00401001}, ++ {0x43B8, 0x00061003}, ++ {0x43BC, 0x000024D8}, ++ {0x43C0, 0x00000000}, ++ {0x43C4, 0x10000020}, ++ {0x43C8, 0x20000200}, ++ {0x43CC, 0x00000000}, ++ {0x43D0, 0x04000000}, ++ {0x43D4, 0x44000100}, ++ {0x43D8, 0x60804060}, ++ {0x43DC, 0x44204210}, ++ {0x43E0, 0x82108082}, ++ {0x43E4, 0x82108402}, ++ {0x43E8, 0xC8082108}, ++ {0x43EC, 0xC8202084}, ++ {0x43F0, 0x44208208}, ++ {0x43F4, 0x84108204}, ++ {0x43F8, 0xD0108104}, ++ {0x43FC, 0xF8210108}, ++ {0x4400, 0x6431E930}, ++ {0x4404, 0x02309468}, ++ {0x4408, 0x10C61C22}, ++ {0x440C, 0x02109469}, ++ {0x4410, 0x10C61C22}, ++ {0x4414, 0x00041049}, ++ {0x4A4C, 0x00060581}, ++ {0x4418, 0x00000000}, ++ {0x441C, 0x00000000}, ++ {0x4420, 0x6C000000}, ++ {0x4424, 0xB0200020}, ++ {0x4428, 0x00001FF0}, ++ {0x442C, 0x00000000}, ++ {0x4430, 0x00000000}, ++ {0x4434, 0x00000000}, ++ {0x4438, 0x00000000}, ++ {0x443C, 0x190642D0}, ++ {0x4440, 0xA80668A0}, ++ {0x4444, 0x60900820}, ++ {0x4448, 0x9F28518C}, ++ {0x444C, 0x32488A62}, ++ {0x4450, 0x9C6E36DC}, ++ {0x4454, 0x0000F52B}, ++ {0x4458, 0x00000000}, ++ {0x445C, 0x4801442E}, ++ {0x4460, 0x0051A0B8}, ++ {0x4464, 0x00000000}, ++ {0x4468, 0x00000000}, ++ {0x446C, 0x00000000}, ++ {0x4470, 0x00000000}, ++ {0x4474, 0x00000000}, ++ {0x4478, 0x00000000}, ++ {0x447C, 0x00000000}, ++ {0x4480, 0x2A0A6040}, ++ {0x4484, 0x0A0A6829}, ++ {0x4488, 0x00000004}, ++ {0x448C, 0x00000000}, ++ {0x4490, 0x80000000}, ++ {0x4494, 0x10000000}, ++ {0x4498, 0xE0000000}, ++ {0x4AB4, 0x00000000}, ++ {0x449C, 0x0000001E}, ++ {0x44A0, 0x02B2C3A6}, ++ {0x44A4, 0x00000400}, ++ {0x44A8, 0x00000001}, ++ {0x44AC, 0x000190C0}, ++ {0x44B0, 0x00000000}, ++ {0x44B4, 0x00000000}, ++ {0x44B8, 0x00000000}, ++ {0x44BC, 0x00000000}, ++ {0x44C0, 0x00000000}, ++ {0x44C4, 0x00000000}, ++ {0x44C8, 0x00000000}, ++ {0x44CC, 0x00000000}, ++ {0x44D0, 0x00000000}, ++ {0x44D4, 0x00000000}, ++ {0x44D8, 0x00000000}, ++ {0x44DC, 0x00000000}, ++ {0x44E0, 0x00000000}, ++ {0x44E4, 0x00000000}, ++ {0x44E8, 0x00000000}, ++ {0x44EC, 0x00000000}, ++ {0x44F0, 0x00000000}, ++ {0x44F4, 0x00000000}, ++ {0x44F8, 0x00000000}, ++ {0x44FC, 0x00000000}, ++ {0x4500, 0x00000000}, ++ {0x4504, 0x00000000}, ++ {0x4508, 0x00000000}, ++ {0x450C, 0x00000000}, ++ {0x4510, 0x00000000}, ++ {0x4514, 0x00000000}, ++ {0x4518, 0x00000000}, ++ {0x451C, 0x00000000}, ++ {0x4520, 0x00000000}, ++ {0x4524, 0x00000000}, ++ {0x4528, 0x00000000}, ++ {0x452C, 0x00000000}, ++ {0x4530, 0x4E830171}, ++ {0x4534, 0x00000870}, ++ {0x4538, 0x000000FF}, ++ {0x453C, 0x00000000}, ++ {0x4540, 0x00000000}, ++ {0x4544, 0x00000000}, ++ {0x4548, 0x00000000}, ++ {0x454C, 0x00000000}, ++ {0x4550, 0x00000000}, ++ {0x4554, 0x00000000}, ++ {0x4558, 0x00000000}, ++ {0x455C, 0x00000000}, ++ {0x4560, 0x40000000}, ++ {0x4564, 0x40000000}, ++ {0x4568, 0x00000000}, ++ {0x456C, 0x20000000}, ++ {0x4570, 0x04F040BB}, ++ {0x4574, 0x000E53FF}, ++ {0x4578, 0x000205CB}, ++ {0x457C, 0x00200000}, ++ {0x4580, 0x00000040}, ++ {0x4584, 0x00000000}, ++ {0x4588, 0x00000017}, ++ {0x458C, 0x30000000}, ++ {0x4590, 0x00000000}, ++ {0x4594, 0x00000000}, ++ {0x4598, 0x00000001}, ++ {0x459C, 0x0003FE00}, ++ {0x45A0, 0x00000086}, ++ {0x45A4, 0x00000000}, ++ {0x45A8, 0xC00001C0}, ++ {0x45AC, 0x78038000}, ++ {0x45B0, 0x8000004A}, ++ {0x45B4, 0x04094800}, ++ {0x45B8, 0x00280002}, ++ {0x45BC, 0x06748790}, ++ {0x45C0, 0x80000000}, ++ {0x45C4, 0x00000000}, ++ {0x45C8, 0x00000000}, ++ {0x45CC, 0x00558670}, ++ {0x45D0, 0x002883F0}, ++ {0x45D4, 0x00090120}, ++ {0x45D8, 0x00000000}, ++ {0x45E0, 0xA3A6D3C4}, ++ {0x45E4, 0xAB27B126}, ++ {0x45E8, 0x00006778}, ++ {0x45F4, 0x000001B5}, ++ {0x45EC, 0x11110F0A}, ++ {0x45F0, 0x00000003}, ++ {0x4A0C, 0x0000000A}, ++ {0x45F8, 0x0058BC3F}, ++ {0x45FC, 0x00000003}, ++ {0x462C, 0x00000020}, ++ {0x4600, 0x000003D9}, ++ {0x45F0, 0x00000004}, ++ {0x4604, 0x002B1CB0}, ++ {0x4A50, 0xC0000000}, ++ {0x4A54, 0x00001000}, ++ {0x4A58, 0x00000000}, ++ {0x4A18, 0x00000024}, ++ {0x4608, 0x00000001}, ++ {0x460C, 0x00000000}, ++ {0x4A10, 0x00000001}, ++ {0x4610, 0x00000001}, ++ {0x4614, 0x16E5298F}, ++ {0x4618, 0x18C6294A}, ++ {0x461C, 0x0E06318A}, ++ {0x4620, 0x0E539CE5}, ++ {0x4624, 0x00019287}, ++ {0x4A14, 0x000000BF}, ++ {0x4628, 0x00000001}, ++ {0x4630, 0x000001AA}, ++ {0x4A18, 0x00001900}, ++ {0x4A1C, 0x000002A6}, ++ {0x4634, 0x000000A3}, ++ {0x4A20, 0x00000086}, ++ {0x4638, 0x01986456}, ++ {0x49F8, 0x00000000}, ++ {0x463C, 0x00000000}, ++ {0x4640, 0x00000000}, ++ {0x4644, 0x00C8CC00}, ++ {0x4648, 0xC400B6B6}, ++ {0x464C, 0xDC400FC0}, ++ {0x4A8C, 0x00000110}, ++ {0x4650, 0x08882550}, ++ {0x4654, 0x08CC2660}, ++ {0x4658, 0x09102660}, ++ {0x465C, 0x00000154}, ++ {0x45DC, 0xC39E38E8}, ++ {0x4660, 0x452607E6}, ++ {0x4664, 0x6750DC65}, ++ {0x4668, 0xF3F0F1ED}, ++ {0x466C, 0x30141506}, ++ {0x4670, 0x2C2B2B2B}, ++ {0x4674, 0x2C2C2C2C}, ++ {0x4678, 0xDDB738E8}, ++ {0x467C, 0x543618FB}, ++ {0x4680, 0x4F31DC6F}, ++ {0x4684, 0xFBEBDA00}, ++ {0x4688, 0x1A10FF04}, ++ {0x468C, 0x282A3000}, ++ {0x4690, 0x2A29292A}, ++ {0x4694, 0x04FA2A2A}, ++ {0x4698, 0xEE0F04D1}, ++ {0x469C, 0x99E91436}, ++ {0x46A0, 0x0701E79E}, ++ {0x46A4, 0x08D77CFF}, ++ {0x46A8, 0x2212FF14}, ++ {0x46AC, 0x60322437}, ++ {0x46B0, 0x63666666}, ++ {0x46B4, 0x35374425}, ++ {0x46B8, 0x35883042}, ++ {0x46BC, 0x5177C252}, ++ {0x4720, 0x7FFFFD63}, ++ {0x4724, 0xB58D11FF}, ++ {0x4728, 0x07FFFFFF}, ++ {0x472C, 0x0E7893B6}, ++ {0x4730, 0xE0391201}, ++ {0x4734, 0x00000020}, ++ {0x4738, 0x8325C500}, ++ {0x473C, 0x00000B7F}, ++ {0x46C0, 0x00000000}, ++ {0x46C4, 0x00000000}, ++ {0x46C8, 0x00000219}, ++ {0x46CC, 0x00000000}, ++ {0x46D0, 0x00000000}, ++ {0x46D4, 0x00000001}, ++ {0x46D8, 0x00000001}, ++ {0x46DC, 0x00000000}, ++ {0x46E0, 0x00000000}, ++ {0x46E4, 0x00000151}, ++ {0x46E8, 0x00000498}, ++ {0x46EC, 0x00000498}, ++ {0x46F0, 0x00000000}, ++ {0x46F4, 0x00000000}, ++ {0x46F8, 0x00001146}, ++ {0x46FC, 0x00000000}, ++ {0x4700, 0x00000000}, ++ {0x4704, 0x00C8CC00}, ++ {0x4708, 0xC400B6B6}, ++ {0x470C, 0xDC400FC0}, ++ {0x4A90, 0x00000110}, ++ {0x4710, 0x08882550}, ++ {0x4714, 0x08CC2660}, ++ {0x4718, 0x09102660}, ++ {0x471C, 0x00000154}, ++ {0x4740, 0xC69F38E8}, ++ {0x4744, 0x462709E9}, ++ {0x4748, 0x6750DC67}, ++ {0x474C, 0xF3F0F1ED}, ++ {0x4750, 0x30141506}, ++ {0x4754, 0x2C2B2B2B}, ++ {0x4758, 0x2C2C2C2C}, ++ {0x475C, 0xE0B738E8}, ++ {0x4760, 0x52381BFE}, ++ {0x4764, 0x5031DC6C}, ++ {0x4768, 0xFBEBDA00}, ++ {0x476C, 0x1A10FF04}, ++ {0x4770, 0x282A3000}, ++ {0x4774, 0x2A29292A}, ++ {0x4778, 0x04FA2A2A}, ++ {0x477C, 0xEE0F04D1}, ++ {0x49F0, 0x99E91436}, ++ {0x49F4, 0x0701E79E}, ++ {0x49FC, 0x08D77CFF}, ++ {0x4A5C, 0x2212FF14}, ++ {0x4A60, 0x60322437}, ++ {0x4A64, 0x63666666}, ++ {0x4A68, 0x35374425}, ++ {0x4A6C, 0x35883042}, ++ {0x4A70, 0x5177C252}, ++ {0x4A74, 0x7FFFFD63}, ++ {0x4A78, 0xB58D11FF}, ++ {0x4A7C, 0x07FFFFFF}, ++ {0x4A80, 0x0E7893B6}, ++ {0x4A9C, 0xE0391201}, ++ {0x4AA0, 0x00000020}, ++ {0x4AA4, 0x8325C500}, ++ {0x4AA8, 0x00000B7F}, ++ {0x4780, 0x00000000}, ++ {0x4784, 0x00000000}, ++ {0x4788, 0x00000219}, ++ {0x478C, 0x00000000}, ++ {0x4790, 0x00000000}, ++ {0x4794, 0x00000001}, ++ {0x4798, 0x00000001}, ++ {0x479C, 0x00000000}, ++ {0x47A0, 0x00000000}, ++ {0x47A4, 0x00000151}, ++ {0x47A8, 0x00000498}, ++ {0x47AC, 0x00000498}, ++ {0x47B0, 0x00000000}, ++ {0x47B4, 0x00000000}, ++ {0x47B8, 0x00001146}, ++ {0x47BC, 0x00000002}, ++ {0x47C0, 0x00000002}, ++ {0x47C4, 0x00000000}, ++ {0x47C8, 0xA32103FE}, ++ {0x47CC, 0xB20A5328}, ++ {0x47D0, 0xC686314F}, ++ {0x47D4, 0x000005D7}, ++ {0x47D8, 0x009B902A}, ++ {0x47DC, 0x009B902A}, ++ {0x47E0, 0x98682C18}, ++ {0x47E4, 0x6308C4C1}, ++ {0x47E8, 0x6248C631}, ++ {0x47EC, 0x922A8253}, ++ {0x47F0, 0x00000005}, ++ {0x47F4, 0x00001759}, ++ {0x47F8, 0x4BB02000}, ++ {0x47FC, 0x831408BE}, ++ {0x4A84, 0x000000E9}, ++ {0x4800, 0x9ABBCACB}, ++ {0x4804, 0x56767578}, ++ {0x4808, 0xBCCBBB13}, ++ {0x480C, 0x7889989B}, ++ {0x4810, 0xBBB0F455}, ++ {0x4814, 0x777BBBBB}, ++ {0x4818, 0x15277777}, ++ {0x481C, 0x27039CE9}, ++ {0x4820, 0x42424432}, ++ {0x4824, 0x36058342}, ++ {0x4828, 0x00000006}, ++ {0x482C, 0x00000005}, ++ {0x4830, 0x00000005}, ++ {0x4834, 0xC7013016}, ++ {0x4838, 0x84413016}, ++ {0x483C, 0x84413016}, ++ {0x4840, 0x8C413016}, ++ {0x4844, 0x8C40B028}, ++ {0x4848, 0x3140B028}, ++ {0x484C, 0x2940B028}, ++ {0x4850, 0x8440B028}, ++ {0x4854, 0x2318C610}, ++ {0x4858, 0x45344753}, ++ {0x485C, 0x236A6A88}, ++ {0x4860, 0xAC8DF814}, ++ {0x4864, 0x08877ACB}, ++ {0x4868, 0x000107AA}, ++ {0x4A94, 0x00000000}, ++ {0x486C, 0xBCEB4A14}, ++ {0x4870, 0x000A3A4A}, ++ {0x4874, 0xBCEB4A14}, ++ {0x4878, 0x000A3A4A}, ++ {0x487C, 0xBCBDBD85}, ++ {0x4880, 0x0CABB99A}, ++ {0x4884, 0x38384242}, ++ {0x4888, 0x0086102E}, ++ {0x488C, 0xCA24C82A}, ++ {0x4890, 0x00008A62}, ++ {0x4894, 0x00000008}, ++ {0x4898, 0x009B902A}, ++ {0x489C, 0x009B902A}, ++ {0x48A0, 0x98682C18}, ++ {0x48A4, 0x6308C4C1}, ++ {0x48A8, 0x6248C631}, ++ {0x48AC, 0x922A8253}, ++ {0x48B0, 0x00000005}, ++ {0x48B4, 0x00001759}, ++ {0x48B8, 0x4BA02000}, ++ {0x48BC, 0x831408BE}, ++ {0x4A88, 0x000000E9}, ++ {0x48C0, 0x9898A8BB}, ++ {0x48C4, 0x54535368}, ++ {0x48C8, 0x99999B13}, ++ {0x48CC, 0x55555899}, ++ {0x48D0, 0xBBB07453}, ++ {0x48D4, 0x777BBBBB}, ++ {0x48D8, 0x15277777}, ++ {0x48DC, 0x27039CE9}, ++ {0x48E0, 0x31413432}, ++ {0x48E4, 0x36058342}, ++ {0x48E8, 0x00000006}, ++ {0x48EC, 0x00000005}, ++ {0x48F0, 0x00000005}, ++ {0x48F4, 0xC7013016}, ++ {0x48F8, 0x84413016}, ++ {0x48FC, 0x84413016}, ++ {0x4900, 0x8C413016}, ++ {0x4904, 0x8C40B028}, ++ {0x4908, 0x3140B028}, ++ {0x490C, 0x2940B028}, ++ {0x4910, 0x8440B028}, ++ {0x4914, 0x2318C610}, ++ {0x4918, 0x45334753}, ++ {0x491C, 0x236A6A88}, ++ {0x4920, 0xAC8DF814}, ++ {0x4924, 0x08877ACB}, ++ {0x4928, 0x000007AA}, ++ {0x4A98, 0x00000000}, ++ {0x492C, 0xBCEB4A14}, ++ {0x4930, 0x000A3A4A}, ++ {0x4934, 0xBCEB4A14}, ++ {0x4938, 0x000A3A4A}, ++ {0x493C, 0x9A8A8A85}, ++ {0x4940, 0x0CA3B99A}, ++ {0x4944, 0x38384242}, ++ {0x4948, 0x8086102E}, ++ {0x494C, 0xCA24C82A}, ++ {0x4950, 0x00008A62}, ++ {0x4954, 0x00000008}, ++ {0x4958, 0x80040000}, ++ {0x495C, 0x80040000}, ++ {0x4960, 0xFE800000}, ++ {0x4964, 0x834C0000}, ++ {0x4968, 0x00000000}, ++ {0x496C, 0x00000000}, ++ {0x4970, 0x00000000}, ++ {0x4974, 0x00000000}, ++ {0x4978, 0x00000000}, ++ {0x497C, 0x00000000}, ++ {0x4980, 0x40000000}, ++ {0x4984, 0x00000000}, ++ {0x4988, 0x00000000}, ++ {0x498C, 0x00000000}, ++ {0x4990, 0x00000000}, ++ {0x4994, 0x04065800}, ++ {0x4998, 0x02004080}, ++ {0x499C, 0x0E1E3E05}, ++ {0x49A0, 0x0A163068}, ++ {0x49A4, 0x00206040}, ++ {0x49A8, 0x02020202}, ++ {0x49AC, 0x00002020}, ++ {0x49B0, 0xF8F8F418}, ++ {0x49B4, 0xF8E8F8F8}, ++ {0x49B8, 0xF80808E8}, ++ {0x4A00, 0xF8F8FA00}, ++ {0x4A04, 0xFAFAFAF8}, ++ {0x4A08, 0xFAFAFAFA}, ++ {0x4A28, 0xFAFAFAFA}, ++ {0x4A2C, 0xFAFAFAFA}, ++ {0x4A30, 0xFAFAFAFA}, ++ {0x4A34, 0xFAFAFAFA}, ++ {0x4A38, 0xFAFAFAFA}, ++ {0x4A3C, 0xFAFAFAFA}, ++ {0x4A40, 0xFAFAFAFA}, ++ {0x4A44, 0x0000FAFA}, ++ {0x49BC, 0x00000000}, ++ {0x49C0, 0x800CD62D}, ++ {0x49C4, 0x00000103}, ++ {0x49C8, 0x00000000}, ++ {0x49CC, 0x00000000}, ++ {0x49D0, 0x00000000}, ++ {0x49D4, 0x00000000}, ++ {0x49D8, 0x00000000}, ++ {0x49DC, 0x00000000}, ++ {0x49E0, 0x00000000}, ++ {0x49E4, 0x00000000}, ++ {0x49E8, 0x00000000}, ++ {0x49EC, 0x00000000}, ++ {0x994, 0x00000010}, ++ {0x904, 0x00000005}, ++ {0xC3C, 0x2840E1BF}, ++ {0xC40, 0x00000000}, ++ {0xC44, 0x00000007}, ++ {0xC48, 0x410E4000}, ++ {0xC54, 0x1EE14368}, ++ {0xC58, 0x41000000}, ++ {0x730, 0x00000002}, ++ {0xC60, 0x017FFFF2}, ++ {0xC64, 0x0010A130}, ++ {0xC68, 0x10000050}, ++ {0xC6C, 0x10001021}, ++ {0x708, 0x00000000}, ++ {0x884, 0x0043F01D}, ++ {0x704, 0x601E0100}, ++ {0x710, 0xEF810000}, ++ {0x704, 0x601E0100}, ++ {0xD40, 0xF64FA0F7}, ++ {0xD44, 0x0400063F}, ++ {0xD48, 0x0003FF7F}, ++ {0xD4C, 0x00000000}, ++ {0xD50, 0xF64FA0F7}, ++ {0xD54, 0x04100437}, ++ {0xD58, 0x0000FF7F}, ++ {0xD5C, 0x00000000}, ++ {0xD60, 0x00000000}, ++ {0xD64, 0x00000000}, ++ {0xD70, 0x00000015}, ++ {0xD90, 0x000003FF}, ++ {0xD94, 0x00000000}, ++ {0xD98, 0x0000003F}, ++ {0xD9C, 0x00000000}, ++ {0xDA0, 0x000003FE}, ++ {0xDA4, 0x00000000}, ++ {0xDA8, 0x0000003F}, ++ {0xDAC, 0x00000000}, ++ {0xD00, 0x77777777}, ++ {0xD04, 0xBBBBBBBB}, ++ {0xD08, 0xBBBBBBBB}, ++ {0xD0C, 0x00000070}, ++ {0xD10, 0x20110900}, ++ {0xD10, 0x20110FFF}, ++ {0xD78, 0x00000001}, ++ {0xD7C, 0x001D050E}, ++ {0xD84, 0x00004207}, ++ {0xD18, 0x50209900}, ++ {0xD80, 0x00804100}, ++ {0x718, 0x1333233F}, ++ {0x604, 0x041E1E1E}, ++ {0x714, 0x00010000}, ++ {0x586C, 0x000000F0}, ++ {0x586C, 0x000000E0}, ++ {0x586C, 0x000000D0}, ++ {0x586C, 0x000000C0}, ++ {0x586C, 0x000000B0}, ++ {0x586C, 0x000000A0}, ++ {0x586C, 0x00000090}, ++ {0x586C, 0x00000080}, ++ {0x586C, 0x00000070}, ++ {0x586C, 0x00000060}, ++ {0x586C, 0x00000050}, ++ {0x586C, 0x00000040}, ++ {0x586C, 0x00000030}, ++ {0x586C, 0x00000020}, ++ {0x586C, 0x00000010}, ++ {0x586C, 0x00000000}, ++ {0x786C, 0x000000F0}, ++ {0x786C, 0x000000E0}, ++ {0x786C, 0x000000D0}, ++ {0x786C, 0x000000C0}, ++ {0x786C, 0x000000B0}, ++ {0x786C, 0x000000A0}, ++ {0x786C, 0x00000090}, ++ {0x786C, 0x00000080}, ++ {0x786C, 0x00000070}, ++ {0x786C, 0x00000060}, ++ {0x786C, 0x00000050}, ++ {0x786C, 0x00000040}, ++ {0x786C, 0x00000030}, ++ {0x786C, 0x00000020}, ++ {0x786C, 0x00000010}, ++ {0x786C, 0x00000000}, ++ {0xC0D4, 0x4486888C}, ++ {0xC0D8, 0xC6BA10E1}, ++ {0xC0DC, 0x30C52868}, ++ {0xC0E0, 0x05008128}, ++ {0xC0E4, 0x0000A72B}, ++ {0xC1D4, 0x4486888C}, ++ {0xC1D8, 0xC6BA10E1}, ++ {0xC1DC, 0x30C52868}, ++ {0xC1E0, 0x05008128}, ++ {0xC1E4, 0x0000A72B}, ++ {0xC0EC, 0x00000000}, ++ {0xC0E4, 0x0000272B}, ++ {0xC1EC, 0x00000000}, ++ {0xC1E4, 0x0000272B}, ++ {0x334, 0xFFFFFFFF}, ++ {0x33C, 0x55000000}, ++ {0x340, 0x00005555}, ++ {0x724, 0x00111200}, ++ {0x5868, 0xA9550000}, ++ {0x5870, 0x33221100}, ++ {0x5874, 0x77665544}, ++ {0x5878, 0xBBAA9988}, ++ {0x587C, 0xFFEEDDCC}, ++ {0x5880, 0x76543210}, ++ {0x5884, 0xFEDCBA98}, ++ {0x5888, 0x00000000}, ++ {0x588C, 0x00000000}, ++ {0x5894, 0x00000008}, ++ {0x7868, 0xA9550000}, ++ {0x7870, 0x33221100}, ++ {0x7874, 0x77665544}, ++ {0x7878, 0xBBAA9988}, ++ {0x787C, 0xFFEEDDCC}, ++ {0x7880, 0x76543210}, ++ {0x7884, 0xFEDCBA98}, ++ {0x7888, 0x00000000}, ++ {0x788C, 0x00000000}, ++ {0x7894, 0x00000008}, ++ {0x650, 0x00200888}, ++ {0x710, 0xF3810000}, ++ {0x020, 0x0000F381}, ++ {0x024, 0x0000F381}, ++ {0x000, 0xC580801E}, ++ {0xC70, 0x00000400}, ++ {0x980, 0x10002250}, ++ {0x988, 0x3C3C4107}, ++ {0x994, 0x00000010}, ++ {0x2994, 0x00000010}, ++ {0x000, 0x0580801F}, ++ {0x240C, 0x00000000}, ++ {0x640, 0x140A141E}, ++ {0x640, 0x1414141E}, ++ {0x640, 0x1414141E}, ++ {0x644, 0x3414283C}, ++ {0x644, 0x3425283C}, ++ {0x644, 0x3426283C}, ++ {0x2640, 0x140A141E}, ++ {0x2640, 0x1414141E}, ++ {0x2640, 0x1414141E}, ++ {0x2644, 0x3414283C}, ++ {0x2644, 0x3425283C}, ++ {0x2644, 0x3425183C}, ++ {0x2300, 0x02748790}, ++ {0x2304, 0x00558670}, ++ {0x2308, 0x002883F0}, ++ {0x230C, 0x00090120}, ++ {0x2310, 0x00000000}, ++ {0x2314, 0x06000000}, ++ {0x2318, 0x00000000}, ++ {0x231C, 0x00000000}, ++ {0x2320, 0x03020100}, ++ {0x2324, 0x07060504}, ++ {0x2328, 0x0B0A0908}, ++ {0x232C, 0x0F0E0D0C}, ++ {0x2330, 0x13121110}, ++ {0x2334, 0x17161514}, ++ {0x2338, 0x0C700022}, ++ {0x233C, 0x0A0529D0}, ++ {0x2340, 0x000529D0}, ++ {0x2344, 0x0006318A}, ++ {0x2348, 0xB7E6318A}, ++ {0x234C, 0x80039C00}, ++ {0x2350, 0x80039C00}, ++ {0x2354, 0x0005298F}, ++ {0x2358, 0x0015296E}, ++ {0x235C, 0x0C07FC31}, ++ {0x2360, 0x0219AAAE}, ++ {0x2364, 0xE4F624C3}, ++ {0x2368, 0x53626F15}, ++ {0x236C, 0x48000000}, ++ {0x2370, 0x48000000}, ++ {0x2374, 0x07540000}, ++ {0x2378, 0x202401B9}, ++ {0x237C, 0x00F7000E}, ++ {0x2380, 0x0F0A1111}, ++ {0x2384, 0x30D9000F}, ++ {0x2388, 0x0200EA02}, ++ {0x238C, 0x003CB061}, ++ {0x2390, 0x69C00000}, ++ {0x2394, 0x00000000}, ++ {0x2398, 0x000000F0}, ++ {0x239C, 0x0001FFFF}, ++ {0x23A0, 0x00C80064}, ++ {0x23A4, 0x0190012C}, ++ {0x23A8, 0x001917BE}, ++ {0x23AC, 0x0B30880C}, ++ {0x23B0, 0x9281CE00}, ++ {0x23B4, 0x7F027C00}, ++ {0x704, 0x601E0102}, ++ {0x704, 0x601E0102}, ++ {0x5864, 0x080801FF}, ++ {0x7864, 0x080801FF}, ++ {0xC60, 0x017FFFF3}, ++ {0x58AC, 0x08000000}, ++ {0x78AC, 0x08000000}, ++ {0x8088, 0x007F0000}, ++ {0x81A4, 0x003F3A00}, ++ {0x81B4, 0x0100007F}, ++ {0x81C0, 0x0060010B}, ++ {0x81A0, 0x00000010}, ++ {0x8138, 0x00000002}, ++ {0x82A4, 0x003F3A00}, ++ {0x82B4, 0x0100007F}, ++ {0x82C0, 0x0060010B}, ++ {0x82A0, 0x00000010}, ++ {0x81A0, 0x00000010}, ++ {0x8238, 0x00000002}, ++ {0x8088, 0x00000000}, ++ {0x8020, 0x00000000}, ++ {0x8120, 0x00000000}, ++ {0x8220, 0x00000000}, ++ {0x8124, 0x00000F0F}, ++ {0x8224, 0x00000F0F}, ++ {0x5864, 0x180801FF}, ++ {0x7864, 0x180801FF}, ++ {0xC60, 0x017FFFF3}, ++ {0xC70, 0x00000600}, ++ {0xC70, 0x00000660}, ++ {0x58AC, 0x08000000}, ++ {0x78AC, 0x08000000}, ++ {0x8120, 0x10000000}, ++ {0x8120, 0x10030000}, ++ {0x8124, 0x00000F0F}, ++ {0x8124, 0x00000F0F}, ++ {0x8224, 0x00000F0F}, ++ {0x8224, 0x00000F0F}, ++ {0x8220, 0x10000000}, ++ {0x8220, 0x10030000}, ++ {0x704, 0x601E0100}, ++ {0x5864, 0x100801FF}, ++ {0x7864, 0x100801FF}, ++ {0x5864, 0x180801FF}, ++ {0x7864, 0x180801FF}, ++ {0x58D4, 0x7401FE00}, ++ {0x78D4, 0x7401FE00}, ++ {0x58F0, 0x400401FF}, ++ {0x78F0, 0x400401FF}, ++ {0x58F0, 0x400401FF}, ++ {0x78F0, 0x400401FF}, ++ {0x704, 0x601E0102}, ++ {0xC7C, 0x0020BFE0}, ++ {0x58C0, 0x00FE0000}, ++ {0x58FC, 0x00000000}, ++ {0x566C, 0x00000005}, ++ {0x566C, 0x00001005}, ++ {0x78C0, 0x00FE0000}, ++ {0x78FC, 0x00000000}, ++ {0x700, 0x00000030}, ++ {0x704, 0x601E0102}, ++ {0x704, 0x601E0100}, ++ {0x704, 0x601E0502}, ++ {0x20FC, 0x00000000}, ++ {0x20F8, 0x00000000}, ++ {0x20F0, 0x00000000}, ++ {0x9C0, 0x00000001}, ++ {0x9C0, 0x00000000}, ++ {0x9C0, 0x00000001}, ++ {0x9C0, 0x00000000}, ++ {0x4AE8, 0x00000744}, ++ {0x4AF0, 0x00000744}, ++ {0x1010, 0x00000010}, ++ {0x3010, 0x00000010}, ++ {0x4AD4, 0x00000040}, ++ {0x4AE0, 0x00000040}, ++ {0x4AE4, 0x0079E99E}, ++ {0x4AEC, 0x0079E99E}, ++ {0x300, 0xF30CE31C}, ++ {0x304, 0x13EF1F19}, ++ {0x308, 0x0C0CF3F3}, ++ {0x30C, 0x0C0C0C0C}, ++ {0x310, 0x80496000}, ++ {0x314, 0x0041E000}, ++ {0x318, 0x20022042}, ++ {0x31C, 0x20448009}, ++ {0x320, 0x00010031}, ++ {0x324, 0xE000E000}, ++ {0x328, 0xE000E000}, ++ {0x32C, 0xE000E000}, ++ {0x12BC, 0x10104041}, ++ {0x12C0, 0x14411111}, ++ {0x32BC, 0x10104041}, ++ {0x32C0, 0x14411111}, ++ {0x010, 0x0005FFFF}, ++ {0x028, 0x0000F381}, ++ {0x02C, 0x0000F381}, ++ {0x620, 0x00141230}, ++ {0x704, 0x601C05FF}, ++ {0x720, 0x20000000}, ++ {0x738, 0x004100CC}, ++ {0x12A0, 0x24903056}, ++ {0x12AC, 0x12333121}, ++ {0x12B8, 0x30020000}, ++ {0x12E4, 0x30D52A68}, ++ {0x2000, 0x50BBBF04}, ++ {0x32A0, 0x24903056}, ++ {0x32AC, 0x12333121}, ++ {0x32B8, 0x30020000}, ++ {0x32E4, 0x30D52A68}, ++ {0x5800, 0x03FF807F}, ++ {0x5804, 0x04237040}, ++ {0x5808, 0x04237040}, ++ {0x7800, 0x03FF807F}, ++ {0x7804, 0x04237040}, ++ {0x7808, 0x04237040}, ++ {0x73C, 0x00000002}, ++ {0x74C, 0x00000001}, ++ {0x748, 0x00000002}, ++ {0x5818, 0x082C1800}, ++ {0x7818, 0x082C1800}, ++ {0x624, 0x0101030A}, ++ {0xC14, 0x85010000}, ++ {0xDD4, 0x00000001}, ++ {0x241C, 0x00000001}, ++ {0x1200, 0x00010142}, ++ {0x3200, 0x00010142}, ++ {0xC0F8, 0x00000001}, ++ {0xC1F8, 0x00000001}, ++ {0x35C, 0x000004C4}, ++ {0x0F0, 0x00000002}, ++ {0x0F4, 0x00000028}, ++ {0x0F8, 0x20220408}, ++}; ++ ++static const struct rtw89_reg2_def rtw89_8852b_phy_bb_reg_gain[] = { ++ {0x000, 0x18FBDDB7}, ++ {0x001, 0x006F5436}, ++ {0x002, 0x00004F31}, ++ {0x100, 0x1BFEE0B7}, ++ {0x101, 0x006C5238}, ++ {0x102, 0x00005031}, ++ {0x10000, 0x07E6C39E}, ++ {0x10001, 0x00654526}, ++ {0x10002, 0x00006750}, ++ {0x10100, 0x09E9C69F}, ++ {0x10101, 0x00674627}, ++ {0x10102, 0x00006750}, ++ {0x20000, 0x06E8C49F}, ++ {0x20001, 0x00654526}, ++ {0x20002, 0x00006750}, ++ {0x20100, 0x07E9C6A0}, ++ {0x20101, 0x00674728}, ++ {0x20102, 0x00006850}, ++ {0x30000, 0x04E5C39D}, ++ {0x30001, 0x00634325}, ++ {0x30002, 0x00006750}, ++ {0x30100, 0x06E9C69F}, ++ {0x30101, 0x00654527}, ++ {0x30102, 0x00006750}, ++ {0x1000000, 0x000000F4}, ++ {0x1000010, 0x000000F8}, ++ {0x1000011, 0x0000F8F8}, ++ {0x1000100, 0x000000F8}, ++ {0x1000110, 0x00000000}, ++ {0x1000111, 0x00000000}, ++ {0x1010000, 0x000000F4}, ++ {0x1010010, 0x000000F8}, ++ {0x1010011, 0x0000F8F8}, ++ {0x1010020, 0x000000F8}, ++ {0x1010021, 0x0808E8E8}, ++ {0x1010029, 0x0000F8F8}, ++ {0x1010100, 0x000000F4}, ++ {0x1010110, 0x000000F8}, ++ {0x1010111, 0x0000F8F8}, ++ {0x1010120, 0x000000F8}, ++ {0x1010121, 0x0808E8E8}, ++ {0x1010129, 0x0000F8F8}, ++ {0x1020000, 0x000000F4}, ++ {0x1020010, 0x000000F8}, ++ {0x1020011, 0x0000F8F8}, ++ {0x1020020, 0x000000F8}, ++ {0x1020021, 0x0808E8E8}, ++ {0x1020029, 0x0000F8F8}, ++ {0x1020100, 0x000000F4}, ++ {0x1020110, 0x000000F8}, ++ {0x1020111, 0x0000F8F8}, ++ {0x1020120, 0x000000F8}, ++ {0x1020121, 0x0808E8E8}, ++ {0x1020129, 0x0000F8F8}, ++ {0x1030000, 0x000000F4}, ++ {0x1030010, 0x000000F8}, ++ {0x1030011, 0x0000F8F8}, ++ {0x1030020, 0x000000F8}, ++ {0x1030021, 0x0808E8E8}, ++ {0x1030029, 0x0000F8F8}, ++ {0x1030100, 0x000000F4}, ++ {0x1030110, 0x000000F8}, ++ {0x1030111, 0x0000F8F8}, ++ {0x1030120, 0x000000F8}, ++ {0x1030121, 0x0808E8E8}, ++ {0x1030129, 0x0000F8F8}, ++}; ++ ++static const struct rtw89_reg2_def rtw89_8852b_phy_radioa_regs[] = { ++ {0xF0010000, 0x00000000}, ++ {0xF0020000, 0x00000001}, ++ {0xF0010001, 0x00000002}, ++ {0xF0020001, 0x00000003}, ++ {0xF0030001, 0x00000004}, ++ {0xF0040001, 0x00000005}, ++ {0xF0050001, 0x00000006}, ++ {0xF0060001, 0x00000007}, ++ {0xF0070001, 0x00000008}, ++ {0xF0080001, 0x00000009}, ++ {0xF0290001, 0x0000000A}, ++ {0xF02B0001, 0x0000000B}, ++ {0x005, 0x00000000}, ++ {0x000, 0x00030000}, ++ {0x10000, 0x00030000}, ++ {0x018, 0x00011124}, ++ {0x10018, 0x00011124}, ++ {0x000, 0x00033C00}, ++ {0x10000, 0x00033C00}, ++ {0x01A, 0x00040004}, ++ {0x011, 0x00014073}, ++ {0x067, 0x00000070}, ++ {0x059, 0x000A0000}, ++ {0x066, 0x00000100}, ++ {0x057, 0x0000D589}, ++ {0x05A, 0x0007FFFF}, ++ {0x0A4, 0x0006FF12}, ++ {0x043, 0x00005000}, ++ {0x0E1, 0x00000001}, ++ {0x0DD, 0x000001A0}, ++ {0x0CA, 0x00002000}, ++ {0x0D3, 0x00000003}, ++ {0x0B3, 0x0004EFE0}, ++ {0x0B4, 0x0007C07E}, ++ {0x0B5, 0x0003A701}, ++ {0x0B6, 0x000581E0}, ++ {0x0B7, 0x00001A0A}, ++ {0x0BB, 0x000C7000}, ++ {0x0ED, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00000543}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00000542}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00000541}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00000521}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x00000343}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x00000342}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000341}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x00000321}, ++ {0x033, 0x00000008}, ++ {0x03F, 0x000005C3}, ++ {0x033, 0x00000009}, ++ {0x03F, 0x000005C2}, ++ {0x033, 0x0000000A}, ++ {0x03F, 0x000005C1}, ++ {0x033, 0x0000000B}, ++ {0x03F, 0x000005A1}, ++ {0x033, 0x0000000C}, ++ {0x03F, 0x000002C3}, ++ {0x033, 0x0000000D}, ++ {0x03F, 0x000002C2}, ++ {0x033, 0x0000000E}, ++ {0x03F, 0x000002C1}, ++ {0x033, 0x0000000F}, ++ {0x03F, 0x000002A1}, ++ {0x0ED, 0x00000000}, ++ {0x0ED, 0x00002000}, ++ {0x033, 0x00000002}, ++ {0x03D, 0x0004A883}, ++ {0x03E, 0x00000000}, ++ {0x03F, 0x00000001}, ++ {0x033, 0x00000006}, ++ {0x03D, 0x0004A883}, ++ {0x03E, 0x00000000}, ++ {0x03F, 0x00000001}, ++ {0x0ED, 0x00000000}, ++ {0x018, 0x00001001}, ++ {0x10018, 0x00001001}, ++ {0x002, 0x0000000D}, ++ {0x10002, 0x0000000D}, ++ {0x0EE, 0x00000004}, ++ {0x033, 0x0000000B}, ++ {0x03F, 0x0000000B}, ++ {0x033, 0x0000000C}, ++ {0x03F, 0x00000012}, ++ {0x033, 0x0000000D}, ++ {0x03F, 0x00000019}, ++ {0x0EE, 0x00000000}, ++ {0x08F, 0x000D0F7A}, ++ {0x0EF, 0x00080000}, ++ {0x033, 0x00000008}, ++ {0x03E, 0x000000C4}, ++ {0x03F, 0x000034C0}, ++ {0x033, 0x0000000A}, ++ {0x03E, 0x000000C4}, ++ {0x03F, 0x000035D0}, ++ {0x033, 0x0000000B}, ++ {0x03E, 0x000000C4}, ++ {0x03F, 0x000035C8}, ++ {0x033, 0x0000008A}, ++ {0x03E, 0x000000C4}, ++ {0x03F, 0x000035F7}, ++ {0x0EF, 0x00000000}, ++ {0x08D, 0x000CC800}, ++ {0x0EF, 0x00004000}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000700}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x00090600}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000A3500}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000A3400}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00008B00}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00001B00}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00003A00}, ++ {0x033, 0x0000000F}, ++ {0x03F, 0x00000700}, ++ {0x033, 0x0000000E}, ++ {0x03F, 0x00000700}, ++ {0x033, 0x0000000D}, ++ {0x03F, 0x00090600}, ++ {0x033, 0x0000000C}, ++ {0x03F, 0x000A3500}, ++ {0x033, 0x0000000B}, ++ {0x03F, 0x000A3400}, ++ {0x033, 0x0000000A}, ++ {0x03F, 0x00008B00}, ++ {0x033, 0x00000009}, ++ {0x03F, 0x00001B00}, ++ {0x033, 0x00000008}, ++ {0x03F, 0x00003A00}, ++ {0x0EF, 0x00000000}, ++ {0x0EE, 0x00000010}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000008}, ++ {0x03F, 0x00000001}, ++ {0x0EE, 0x00000000}, ++ {0x0EF, 0x00001000}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00000017}, ++ {0x0EF, 0x00000000}, ++ {0x0EF, 0x00008000}, ++ {0x033, 0x00000000}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000001}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000002}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000003}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x00000004}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x00000005}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x00000006}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000008}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000009}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x0000000A}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x0000000B}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x0000000C}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x0000000D}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x0000000E}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000010}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000011}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000012}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000013}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x00000014}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x00000015}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x00000016}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000020}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000021}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000022}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000023}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x00000024}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x00000025}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x00000026}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000028}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000029}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x0000002A}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x0000002B}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x0000002C}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x0000002D}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x0000002E}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000030}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000031}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000032}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000033}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x00000034}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x00000035}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x00000036}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x0EF, 0x00000000}, ++ {0x0EF, 0x00000100}, ++ {0x033, 0x00000000}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000001}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000002}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00004376}, ++ {0x033, 0x00000004}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000005}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00004376}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x00004376}, ++ {0x033, 0x00000008}, ++ {0x03F, 0x00004376}, ++ {0x033, 0x00000009}, ++ {0x03F, 0x00004376}, ++ {0x033, 0x0000000A}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000D}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000E}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000F}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000010}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000011}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000012}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000013}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000014}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000015}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000016}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000017}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000020}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000021}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000022}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000023}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000024}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000025}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000026}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000027}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004386}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004396}, ++ {0xB0000000, 0x00000000}, ++ {0x0EF, 0x00000000}, ++ {0x067, 0x00008072}, ++ {0x0EF, 0x00000010}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00000ED5}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00000FC7}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00000783}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x00000973}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x00000762}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000762}, ++ {0x0EF, 0x00000000}, ++ {0x0EF, 0x00000080}, ++ {0x033, 0x00000000}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000001}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000002}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000003}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000004}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000005}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000006}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000007}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000008}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000009}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000A}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000B}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000C}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000D}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000E}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000F}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000010}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000011}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000012}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000013}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023958}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000014}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000015}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000016}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000017}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000018}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000019}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001A}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001B}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001C}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001D}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001E}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001F}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000020}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000021}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000022}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000023}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000024}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000025}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000026}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000027}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000028}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000029}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002A}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002B}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002C}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002D}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002E}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002F}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000030}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000031}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000032}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000033}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000034}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000035}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000036}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000037}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000038}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000039}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026858}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000003A}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000003B}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00023A58}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x0002C758}, ++ {0xB0000000, 0x00000000}, ++ {0x0EF, 0x00000000}, ++ {0x0EE, 0x00000800}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00000001}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00000005}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00000007}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x00000001}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000006}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x00000007}, ++ {0x0EE, 0x00000000}, ++ {0x0EE, 0x00001000}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00003000}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00003001}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00003003}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00003007}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x0000300F}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x0000310F}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x0000330F}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x0000330F}, ++ {0x033, 0x00000008}, ++ {0x03F, 0x00003000}, ++ {0x033, 0x00000009}, ++ {0x03F, 0x00003001}, ++ {0x033, 0x0000000A}, ++ {0x03F, 0x00003003}, ++ {0x033, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00003103}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000D}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00002307}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000E}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000F}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0xB0000000, 0x00000000}, ++ {0x0EE, 0x00000000}, ++ {0x0EE, 0x00000200}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00000001}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00000005}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00000007}, ++ {0x0EE, 0x00000000}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000100}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000100}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x0EC, 0x00000100}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000004}, ++ {0x03D, 0x00000078}, ++ {0x03E, 0x00080000}, ++ {0x03F, 0x00000000}, ++ {0x033, 0x00000005}, ++ {0x03D, 0x0000007B}, ++ {0x03E, 0x00020000}, ++ {0x03F, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x0DE, 0x00000000}, ++ {0x0EF, 0x00000000}, ++ {0x033, 0x00000000}, ++ {0x008, 0x00060280}, ++ {0x009, 0x00030400}, ++ {0x0EF, 0x00000000}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x000001F7}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x000001F7}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0xA0000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x000001F7}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FF}, ++ {0xB0000000, 0x00000000}, ++ {0x0EF, 0x00000200}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x0000017F}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x0000017F}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000017F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x0000007F}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x0000007F}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x0000007F}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x0000007F}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x0000007F}, ++ {0x0EF, 0x00000000}, ++ {0x06E, 0x00077A18}, ++ {0x06F, 0x00077A18}, ++ {0x06D, 0x00000C31}, ++ {0x0EF, 0x00020000}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000005FF}, ++ {0x0EF, 0x00000000}, ++ {0x005, 0x00000001}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0xA0000000, 0x00000000}, ++ {0x094, 0x000001FC}, ++ {0xB0000000, 0x00000000}, ++ {0x100EE, 0x00002000}, ++ {0x10033, 0x00000080}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000081}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000082}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F0}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000083}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000ED}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000084}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000EA}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000085}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000E7}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000086}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000087}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000088}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000063}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000089}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000060}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008A}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000026}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000023}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000020}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008D}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008E}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001A}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008F}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000017}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000090}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000014}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A1}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A2}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F0}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A3}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000ED}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A4}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000EA}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A5}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000E7}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A6}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A7}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A8}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000063}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A9}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000060}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AA}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000026}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AB}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000023}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AC}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000020}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AD}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AE}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001A}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AF}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000017}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000B0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000014}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C1}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C2}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F0}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C3}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000ED}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C4}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000EA}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C5}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000E7}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C6}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C7}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C8}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000063}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C9}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000060}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CA}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000026}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CB}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000023}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CC}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000020}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CD}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CE}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001A}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CF}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000017}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000D0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000014}, ++ {0xB0000000, 0x00000000}, ++ {0x100EE, 0x00000000}, ++ {0x100EE, 0x00004000}, ++ {0x10033, 0x00000080}, ++ {0x1003F, 0x000001A9}, ++ {0x10033, 0x00000081}, ++ {0x1003F, 0x000001A3}, ++ {0x10033, 0x00000082}, ++ {0x1003F, 0x0000019D}, ++ {0x10033, 0x00000083}, ++ {0x1003F, 0x00000197}, ++ {0x10033, 0x00000084}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000191}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000085}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000018B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000086}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000014D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000087}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000010B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000088}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000089}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008A}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000093}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008D}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008E}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000053}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008F}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000090}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000091}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A0}, ++ {0x1003F, 0x000001A9}, ++ {0x10033, 0x000000A1}, ++ {0x1003F, 0x000001A3}, ++ {0x10033, 0x000000A2}, ++ {0x1003F, 0x0000019D}, ++ {0x10033, 0x000000A3}, ++ {0x1003F, 0x00000197}, ++ {0x10033, 0x000000A4}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000191}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A5}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000018B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A6}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000014D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A7}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000010B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A8}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A9}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AA}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AB}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AC}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000093}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AD}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AE}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000053}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AF}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000B0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000B1}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C0}, ++ {0x1003F, 0x000001A9}, ++ {0x10033, 0x000000C1}, ++ {0x1003F, 0x000001A3}, ++ {0x10033, 0x000000C2}, ++ {0x1003F, 0x0000019D}, ++ {0x10033, 0x000000C3}, ++ {0x1003F, 0x00000197}, ++ {0x10033, 0x000000C4}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000191}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C5}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000018B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C6}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000014D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C7}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000010B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C8}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C9}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CA}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CB}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CC}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000093}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CD}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CE}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000053}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CF}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000D0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000D1}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xB0000000, 0x00000000}, ++ {0x100EE, 0x00000000}, ++ {0x100EE, 0x00002000}, ++ {0x10033, 0x00000000}, ++ {0x1003F, 0x000000F6}, ++ {0x10033, 0x00000001}, ++ {0x1003F, 0x000000F3}, ++ {0x10033, 0x00000002}, ++ {0x1003F, 0x000000F0}, ++ {0x10033, 0x00000003}, ++ {0x1003F, 0x000000ED}, ++ {0x10033, 0x00000004}, ++ {0x1003F, 0x000000EA}, ++ {0x10033, 0x00000005}, ++ {0x1003F, 0x000000E7}, ++ {0x10033, 0x00000006}, ++ {0x1003F, 0x000000A6}, ++ {0x10033, 0x00000007}, ++ {0x1003F, 0x000000A3}, ++ {0x10033, 0x00000008}, ++ {0x1003F, 0x00000063}, ++ {0x10033, 0x00000009}, ++ {0x1003F, 0x00000060}, ++ {0x10033, 0x0000000A}, ++ {0x1003F, 0x00000023}, ++ {0x10033, 0x0000000B}, ++ {0x1003F, 0x00000020}, ++ {0x10033, 0x0000000C}, ++ {0x1003F, 0x0000001D}, ++ {0x10033, 0x0000000D}, ++ {0x1003F, 0x0000001A}, ++ {0x10033, 0x0000000E}, ++ {0x1003F, 0x00000017}, ++ {0x10033, 0x0000000F}, ++ {0x1003F, 0x00000014}, ++ {0x10033, 0x00000010}, ++ {0x1003F, 0x00000011}, ++ {0x100EE, 0x00000000}, ++ {0x100EE, 0x00004000}, ++ {0x10033, 0x00000000}, ++ {0x1003F, 0x000001AF}, ++ {0x10033, 0x00000001}, ++ {0x1003F, 0x000001A9}, ++ {0x10033, 0x00000002}, ++ {0x1003F, 0x000001A3}, ++ {0x10033, 0x00000003}, ++ {0x1003F, 0x0000019D}, ++ {0x10033, 0x00000004}, ++ {0x1003F, 0x00000197}, ++ {0x10033, 0x00000005}, ++ {0x1003F, 0x0000015F}, ++ {0x10033, 0x00000006}, ++ {0x1003F, 0x00000159}, ++ {0x10033, 0x00000007}, ++ {0x1003F, 0x0000011F}, ++ {0x10033, 0x00000008}, ++ {0x1003F, 0x00000119}, ++ {0x10033, 0x00000009}, ++ {0x1003F, 0x000000DF}, ++ {0x10033, 0x0000000A}, ++ {0x1003F, 0x000000D9}, ++ {0x10033, 0x0000000B}, ++ {0x1003F, 0x0000009F}, ++ {0x10033, 0x0000000C}, ++ {0x1003F, 0x00000099}, ++ {0x10033, 0x0000000D}, ++ {0x1003F, 0x0000005F}, ++ {0x10033, 0x0000000E}, ++ {0x1003F, 0x00000059}, ++ {0x10033, 0x0000000F}, ++ {0x1003F, 0x0000001F}, ++ {0x10033, 0x00000010}, ++ {0x1003F, 0x00000019}, ++ {0x10033, 0x00000011}, ++ {0x1003F, 0x00000013}, ++ {0x100EE, 0x00000000}, ++ {0x10005, 0x00000001}, ++ {0x09F, 0x00000032}, ++}; ++ ++static const struct rtw89_reg2_def rtw89_8852b_phy_radiob_regs[] = { ++ {0xF0010000, 0x00000000}, ++ {0xF0020000, 0x00000001}, ++ {0xF0010001, 0x00000002}, ++ {0xF0020001, 0x00000003}, ++ {0xF0030001, 0x00000004}, ++ {0xF0040001, 0x00000005}, ++ {0xF0050001, 0x00000006}, ++ {0xF0060001, 0x00000007}, ++ {0xF0070001, 0x00000008}, ++ {0xF0080001, 0x00000009}, ++ {0xF0290001, 0x0000000A}, ++ {0xF02B0001, 0x0000000B}, ++ {0x005, 0x00000000}, ++ {0x000, 0x00030000}, ++ {0x10000, 0x00030000}, ++ {0x018, 0x00011124}, ++ {0x10018, 0x00011124}, ++ {0x000, 0x00033C00}, ++ {0x10000, 0x00033C00}, ++ {0x01A, 0x00040004}, ++ {0x011, 0x00014073}, ++ {0x067, 0x00000070}, ++ {0x059, 0x000A0000}, ++ {0x066, 0x00000100}, ++ {0x05A, 0x0007F000}, ++ {0x0A4, 0x0006FF12}, ++ {0x043, 0x00005000}, ++ {0x0E1, 0x00000001}, ++ {0x0DD, 0x000001A0}, ++ {0x0CA, 0x00002000}, ++ {0x0D3, 0x00000003}, ++ {0x0B3, 0x0004EFE0}, ++ {0x0B4, 0x0007C03E}, ++ {0x0B5, 0x0003A201}, ++ {0x0BB, 0x000C7000}, ++ {0x0ED, 0x00002000}, ++ {0x033, 0x00000002}, ++ {0x03D, 0x0004A883}, ++ {0x03E, 0x00000000}, ++ {0x03F, 0x00000001}, ++ {0x033, 0x00000006}, ++ {0x03D, 0x0004A883}, ++ {0x03E, 0x00000000}, ++ {0x03F, 0x00000001}, ++ {0x0ED, 0x00000000}, ++ {0x018, 0x00001001}, ++ {0x10018, 0x00001001}, ++ {0x002, 0x0000000D}, ++ {0x10002, 0x0000000D}, ++ {0x0EE, 0x00000004}, ++ {0x033, 0x0000000B}, ++ {0x03F, 0x0000000B}, ++ {0x033, 0x0000000C}, ++ {0x03F, 0x00000012}, ++ {0x033, 0x0000000D}, ++ {0x03F, 0x00000019}, ++ {0x0EE, 0x00000000}, ++ {0x08F, 0x000D0F7A}, ++ {0x0EF, 0x00080000}, ++ {0x033, 0x00000008}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D30}, ++ {0xA0000000, 0x00000000}, ++ {0x03E, 0x000000C4}, ++ {0x03F, 0x000034C0}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000A}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D74}, ++ {0xA0000000, 0x00000000}, ++ {0x03E, 0x000000C4}, ++ {0x03F, 0x000035D0}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D72}, ++ {0xA0000000, 0x00000000}, ++ {0x03E, 0x000000C4}, ++ {0x03F, 0x000035C8}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000008A}, ++ {0x03E, 0x00000031}, ++ {0x03F, 0x00000D7D}, ++ {0x0EF, 0x00000000}, ++ {0x08D, 0x000CC800}, ++ {0x0EF, 0x00004000}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x00000700}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000700}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x00090600}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000A3500}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000A3400}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00008B00}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00001B00}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00003A00}, ++ {0x033, 0x0000000F}, ++ {0x03F, 0x00000700}, ++ {0x033, 0x0000000E}, ++ {0x03F, 0x00000700}, ++ {0x033, 0x0000000D}, ++ {0x03F, 0x00090600}, ++ {0x033, 0x0000000C}, ++ {0x03F, 0x000A3500}, ++ {0x033, 0x0000000B}, ++ {0x03F, 0x000A3400}, ++ {0x033, 0x0000000A}, ++ {0x03F, 0x00008B00}, ++ {0x033, 0x00000009}, ++ {0x03F, 0x00001B00}, ++ {0x033, 0x00000008}, ++ {0x03F, 0x00003A00}, ++ {0x033, 0x00000017}, ++ {0x03F, 0x00000705}, ++ {0x033, 0x00000016}, ++ {0x03F, 0x00000705}, ++ {0x033, 0x00000015}, ++ {0x03F, 0x00090605}, ++ {0x033, 0x00000014}, ++ {0x03F, 0x000A3505}, ++ {0x033, 0x00000013}, ++ {0x03F, 0x000A3405}, ++ {0x033, 0x00000012}, ++ {0x03F, 0x00008B05}, ++ {0x033, 0x00000011}, ++ {0x03F, 0x00001B05}, ++ {0x033, 0x00000010}, ++ {0x03F, 0x00003A05}, ++ {0x0EF, 0x00000000}, ++ {0x0EE, 0x00000010}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000008}, ++ {0x03F, 0x00000001}, ++ {0x0EE, 0x00000000}, ++ {0x0EF, 0x00001000}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x033, 0x00000001}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000002}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000015}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00000017}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000003}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000005}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00000007}, ++ {0xB0000000, 0x00000000}, ++ {0x0EF, 0x00000000}, ++ {0x0EF, 0x00008000}, ++ {0x033, 0x00000000}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000001}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000002}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000003}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x00000004}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x00000005}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x00000006}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000008}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000009}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x0000000A}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x0000000B}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x0000000C}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x0000000D}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x0000000E}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000010}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000011}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000012}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000013}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x00000014}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x00000015}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x00000016}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000020}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000021}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000022}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000023}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x00000024}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x00000025}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x00000026}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000028}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000029}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x0000002A}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x0000002B}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x0000002C}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x0000002D}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x0000002E}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x033, 0x00000030}, ++ {0x03E, 0x00004FC0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000031}, ++ {0x03E, 0x000046C0}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000032}, ++ {0x03E, 0x00004240}, ++ {0x03F, 0x00000087}, ++ {0x033, 0x00000033}, ++ {0x03E, 0x00008010}, ++ {0x03F, 0x00000147}, ++ {0x033, 0x00000034}, ++ {0x03E, 0x0000A048}, ++ {0x03F, 0x0000004F}, ++ {0x033, 0x00000035}, ++ {0x03E, 0x0000A030}, ++ {0x03F, 0x0000005F}, ++ {0x033, 0x00000036}, ++ {0x03E, 0x0000A000}, ++ {0x03F, 0x0000009F}, ++ {0x0EF, 0x00000000}, ++ {0x0EF, 0x00000100}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00004346}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00004346}, ++ {0x033, 0x00000003}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x00004346}, ++ {0x033, 0x00000005}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004317}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000006}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000007}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000008}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000009}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004376}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000A}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000D}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x000043A6}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000E}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000F}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000010}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000011}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000012}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000013}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000014}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000015}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000016}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000017}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000020}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000021}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004347}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000022}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00004346}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00004366}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000023}, ++ {0x03F, 0x00004386}, ++ {0x033, 0x00000024}, ++ {0x03F, 0x00004386}, ++ {0x033, 0x00000025}, ++ {0x03F, 0x00004386}, ++ {0x033, 0x00000026}, ++ {0x03F, 0x00004386}, ++ {0x033, 0x00000027}, ++ {0x03F, 0x00004386}, ++ {0x0EF, 0x00000000}, ++ {0x067, 0x00008072}, ++ {0x0EF, 0x00000010}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00000ED5}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00000FC5}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00000A93}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x00000973}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x00000761}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000761}, ++ {0x0EF, 0x00000000}, ++ {0x0EF, 0x00000080}, ++ {0x033, 0x00000000}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000001}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000002}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000003}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000004}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000005}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000006}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000007}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000008}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000009}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000A}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000B}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000C}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000D}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000E}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000F}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000010}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000011}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000012}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000013}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020758}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000014}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000015}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000016}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000017}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000018}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000019}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001A}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001B}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001C}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001D}, ++ {0x03E, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001E}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000001F}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000020}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000021}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000022}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000023}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000024}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000025}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000026}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000027}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000028}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000029}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002A}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002B}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002C}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002D}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002E}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000002F}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000030}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000031}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000032}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000033}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000034}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000035}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000036}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000037}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000038}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000039}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022658}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00026458}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000003A}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00022858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000003B}, ++ {0x03E, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00020858}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00027558}, ++ {0xB0000000, 0x00000000}, ++ {0x0EF, 0x00000000}, ++ {0x0EE, 0x00000800}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00000001}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00000005}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00000007}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x00000001}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x00000006}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x00000007}, ++ {0x0EE, 0x00000000}, ++ {0x0EE, 0x00001000}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00003000}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00003001}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00003003}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00003007}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x0000300F}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x0000310F}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x0000330F}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x0000330F}, ++ {0x033, 0x00000008}, ++ {0x03F, 0x00003000}, ++ {0x033, 0x00000009}, ++ {0x03F, 0x00003001}, ++ {0x033, 0x0000000A}, ++ {0x03F, 0x00003003}, ++ {0x033, 0x0000000B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003007}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00003103}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003107}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000D}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00003307}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00002307}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000E}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00001307}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x0000000F}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0xA0000000, 0x00000000}, ++ {0x03F, 0x00000307}, ++ {0xB0000000, 0x00000000}, ++ {0x0EE, 0x00000000}, ++ {0x0EE, 0x00000200}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x00000001}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x00000003}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x00000005}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x00000007}, ++ {0x0EE, 0x00000000}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000100}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000100}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x0EC, 0x00000100}, ++ {0xB0000000, 0x00000000}, ++ {0x033, 0x00000004}, ++ {0x03D, 0x00000078}, ++ {0x03E, 0x00080000}, ++ {0x03F, 0x00000000}, ++ {0x033, 0x00000005}, ++ {0x03D, 0x0000007B}, ++ {0x03E, 0x00020000}, ++ {0x03F, 0x00000000}, ++ {0x0EC, 0x00000000}, ++ {0x0DE, 0x00000000}, ++ {0x0EF, 0x00000000}, ++ {0x033, 0x00000000}, ++ {0x008, 0x00060280}, ++ {0x009, 0x00030400}, ++ {0x0EF, 0x00000000}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x000001F7}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x000001F7}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000013F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FB}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FB}, ++ {0xA0000000, 0x00000000}, ++ {0x0EF, 0x00000400}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x000001FF}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x000001F7}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x000000FF}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x000000FF}, ++ {0xB0000000, 0x00000000}, ++ {0x0EF, 0x00000200}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x0000017F}, ++ {0x033, 0x00000001}, ++ {0x03F, 0x0000017F}, ++ {0x033, 0x00000002}, ++ {0x03F, 0x0000017F}, ++ {0x033, 0x00000003}, ++ {0x03F, 0x0000007F}, ++ {0x033, 0x00000004}, ++ {0x03F, 0x0000007F}, ++ {0x033, 0x00000005}, ++ {0x03F, 0x0000007F}, ++ {0x033, 0x00000006}, ++ {0x03F, 0x0000007F}, ++ {0x033, 0x00000007}, ++ {0x03F, 0x0000007F}, ++ {0x0EF, 0x00000000}, ++ {0x06E, 0x00077A18}, ++ {0x06F, 0x00077A18}, ++ {0x06D, 0x00000C31}, ++ {0x0EF, 0x00020000}, ++ {0x033, 0x00000000}, ++ {0x03F, 0x000005FF}, ++ {0x0EF, 0x00000000}, ++ {0x005, 0x00000001}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x094, 0x000000FC}, ++ {0xA0000000, 0x00000000}, ++ {0x094, 0x000001FC}, ++ {0xB0000000, 0x00000000}, ++ {0x100EE, 0x00002000}, ++ {0x10033, 0x00000080}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000081}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000082}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F0}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000083}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000ED}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000084}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000EA}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000085}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000E7}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000086}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000087}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000088}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000063}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000089}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000060}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008A}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000026}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000023}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000020}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008D}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008E}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001A}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008F}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000017}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000090}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000014}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A1}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A2}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F0}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A3}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000ED}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A4}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000EA}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A5}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000E7}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A6}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A7}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A8}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000063}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A9}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000060}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AA}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000026}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AB}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000023}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AC}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000020}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AD}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AE}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001A}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AF}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000017}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000B0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000014}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000FB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C1}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C2}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F5}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000F0}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C3}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000F2}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000ED}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C4}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000EA}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C5}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000EC}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000E7}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C6}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000AB}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A6}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C7}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000A8}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000A3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C8}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000068}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000063}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C9}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000065}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000060}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CA}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000002B}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000026}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CB}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000028}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000023}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CC}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000025}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000020}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CD}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000022}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CE}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000001A}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CF}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001C}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000017}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000D0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000014}, ++ {0xB0000000, 0x00000000}, ++ {0x100EE, 0x00000000}, ++ {0x100EE, 0x00004000}, ++ {0x10033, 0x00000080}, ++ {0x1003F, 0x000001A9}, ++ {0x10033, 0x00000081}, ++ {0x1003F, 0x000001A3}, ++ {0x10033, 0x00000082}, ++ {0x1003F, 0x0000019D}, ++ {0x10033, 0x00000083}, ++ {0x1003F, 0x00000197}, ++ {0x10033, 0x00000084}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000191}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000085}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000018B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000086}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000014D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000087}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000010B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000088}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000089}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008A}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008B}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008C}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000093}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008D}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008E}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000053}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x0000008F}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000090}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x00000091}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A0}, ++ {0x1003F, 0x000001A9}, ++ {0x10033, 0x000000A1}, ++ {0x1003F, 0x000001A3}, ++ {0x10033, 0x000000A2}, ++ {0x1003F, 0x0000019D}, ++ {0x10033, 0x000000A3}, ++ {0x1003F, 0x00000197}, ++ {0x10033, 0x000000A4}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000191}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A5}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000018B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A6}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000014D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A7}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000010B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A8}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000A9}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AA}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AB}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AC}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000093}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AD}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AE}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000053}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000AF}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000B0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000B1}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C0}, ++ {0x1003F, 0x000001A9}, ++ {0x10033, 0x000000C1}, ++ {0x1003F, 0x000001A3}, ++ {0x10033, 0x000000C2}, ++ {0x1003F, 0x0000019D}, ++ {0x10033, 0x000000C3}, ++ {0x1003F, 0x00000197}, ++ {0x10033, 0x000000C4}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000158}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000191}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C5}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000011F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000018B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C6}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000119}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000014D}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C7}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000010B}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C8}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000DF}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000C9}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000009F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D9}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CA}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x000000D3}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CB}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000005F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000099}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CC}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000093}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CD}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000001F}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000059}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CE}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000053}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000CF}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000019}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000D0}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x00000013}, ++ {0xB0000000, 0x00000000}, ++ {0x10033, 0x000000D1}, ++ {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90060001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90080001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x90290001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0x902b0001, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x1003F, 0x00000007}, ++ {0xA0000000, 0x00000000}, ++ {0x1003F, 0x0000000D}, ++ {0xB0000000, 0x00000000}, ++ {0x100EE, 0x00000000}, ++ {0x100EE, 0x00002000}, ++ {0x10033, 0x00000000}, ++ {0x1003F, 0x000000F6}, ++ {0x10033, 0x00000001}, ++ {0x1003F, 0x000000F3}, ++ {0x10033, 0x00000002}, ++ {0x1003F, 0x000000F0}, ++ {0x10033, 0x00000003}, ++ {0x1003F, 0x000000ED}, ++ {0x10033, 0x00000004}, ++ {0x1003F, 0x000000EA}, ++ {0x10033, 0x00000005}, ++ {0x1003F, 0x000000E7}, ++ {0x10033, 0x00000006}, ++ {0x1003F, 0x000000A6}, ++ {0x10033, 0x00000007}, ++ {0x1003F, 0x000000A3}, ++ {0x10033, 0x00000008}, ++ {0x1003F, 0x00000063}, ++ {0x10033, 0x00000009}, ++ {0x1003F, 0x00000060}, ++ {0x10033, 0x0000000A}, ++ {0x1003F, 0x00000023}, ++ {0x10033, 0x0000000B}, ++ {0x1003F, 0x00000020}, ++ {0x10033, 0x0000000C}, ++ {0x1003F, 0x0000001D}, ++ {0x10033, 0x0000000D}, ++ {0x1003F, 0x0000001A}, ++ {0x10033, 0x0000000E}, ++ {0x1003F, 0x00000017}, ++ {0x10033, 0x0000000F}, ++ {0x1003F, 0x00000014}, ++ {0x10033, 0x00000010}, ++ {0x1003F, 0x00000011}, ++ {0x100EE, 0x00000000}, ++ {0x100EE, 0x00004000}, ++ {0x10033, 0x00000000}, ++ {0x1003F, 0x000001AF}, ++ {0x10033, 0x00000001}, ++ {0x1003F, 0x000001A9}, ++ {0x10033, 0x00000002}, ++ {0x1003F, 0x000001A3}, ++ {0x10033, 0x00000003}, ++ {0x1003F, 0x0000019D}, ++ {0x10033, 0x00000004}, ++ {0x1003F, 0x00000197}, ++ {0x10033, 0x00000005}, ++ {0x1003F, 0x0000015F}, ++ {0x10033, 0x00000006}, ++ {0x1003F, 0x00000159}, ++ {0x10033, 0x00000007}, ++ {0x1003F, 0x0000011F}, ++ {0x10033, 0x00000008}, ++ {0x1003F, 0x00000119}, ++ {0x10033, 0x00000009}, ++ {0x1003F, 0x000000DF}, ++ {0x10033, 0x0000000A}, ++ {0x1003F, 0x000000D9}, ++ {0x10033, 0x0000000B}, ++ {0x1003F, 0x0000009F}, ++ {0x10033, 0x0000000C}, ++ {0x1003F, 0x00000099}, ++ {0x10033, 0x0000000D}, ++ {0x1003F, 0x0000005F}, ++ {0x10033, 0x0000000E}, ++ {0x1003F, 0x00000059}, ++ {0x10033, 0x0000000F}, ++ {0x1003F, 0x0000001F}, ++ {0x10033, 0x00000010}, ++ {0x1003F, 0x00000019}, ++ {0x10033, 0x00000011}, ++ {0x1003F, 0x00000013}, ++ {0x100EE, 0x00000000}, ++ {0x10005, 0x00000001}, ++ {0x09F, 0x00000032}, ++}; ++ ++static const struct rtw89_reg2_def rtw89_8852b_phy_nctl_regs[] = { ++ {0x8000, 0x00000008}, ++ {0x8008, 0x00000000}, ++ {0x8004, 0xf0862966}, ++ {0x800c, 0x78000000}, ++ {0x8010, 0x88015000}, ++ {0x8014, 0x80010100}, ++ {0x8018, 0x10010100}, ++ {0x801c, 0xa210bc00}, ++ {0x8020, 0x000403e0}, ++ {0x8024, 0x00072160}, ++ {0x8028, 0x00180e00}, ++ {0x8030, 0x400000c0}, ++ {0x8034, 0x11000830}, ++ {0x8038, 0x00000009}, ++ {0x803c, 0x00000008}, ++ {0x8040, 0x00000046}, ++ {0x8044, 0x0010001f}, ++ {0x8048, 0xf0000003}, ++ {0x804c, 0x62ac6162}, ++ {0x8050, 0xf2acf162}, ++ {0x8054, 0x62ac6162}, ++ {0x8058, 0xf2acf162}, ++ {0x805c, 0x150c0b02}, ++ {0x8060, 0x150c0b02}, ++ {0x8064, 0x2aa00047}, ++ {0x8074, 0x80000000}, ++ {0x807c, 0x000000ee}, ++ {0x8088, 0x80000000}, ++ {0x8098, 0x0000ff00}, ++ {0x809c, 0x0000001f}, ++ {0x80a0, 0x00010300}, ++ {0x80b8, 0x00001000}, ++ {0x80b0, 0x00000000}, ++ {0x80d0, 0x00000000}, ++ {0x80ec, 0x00000002}, ++ {0x810c, 0x33112200}, ++ {0x8110, 0x33112200}, ++ {0x8114, 0x00000000}, ++ {0x8120, 0x10010000}, ++ {0x8124, 0x00000000}, ++ {0x812c, 0x0000c000}, ++ {0x8138, 0x40000000}, ++ {0x813c, 0x40000000}, ++ {0x8140, 0x00000000}, ++ {0x8144, 0x0b040b03}, ++ {0x8148, 0x0a050b04}, ++ {0x814c, 0x0a050b04}, ++ {0x8150, 0xe4e40000}, ++ {0x8158, 0xffffffff}, ++ {0x815c, 0xffffffff}, ++ {0x8160, 0xffffffff}, ++ {0x8164, 0xffffffff}, ++ {0x8168, 0xffffffff}, ++ {0x816c, 0x1fffffff}, ++ {0x81a0, 0x00000000}, ++ {0x81ac, 0x003f2e2e}, ++ {0x81b0, 0x003f2e2e}, ++ {0x81bc, 0x005b5b5b}, ++ {0x81c0, 0x005b5b5b}, ++ {0x81b4, 0x00600060}, ++ {0x81b8, 0x00600060}, ++ {0x81cc, 0x00000000}, ++ {0x81dc, 0x00000002}, ++ {0x81e0, 0x00000000}, ++ {0x81e4, 0x00000001}, ++ {0x820c, 0x33112200}, ++ {0x8210, 0x33112200}, ++ {0x8214, 0x00000000}, ++ {0x8220, 0x10010000}, ++ {0x8224, 0x00000000}, ++ {0x822c, 0x0000d000}, ++ {0x8238, 0x40000000}, ++ {0x823c, 0x40000000}, ++ {0x8240, 0x00000000}, ++ {0x8244, 0x0b040b03}, ++ {0x8248, 0x0a050b04}, ++ {0x824c, 0x0a050b04}, ++ {0x8250, 0xe4e40000}, ++ {0x8258, 0xffffffff}, ++ {0x825c, 0xffffffff}, ++ {0x8260, 0xffffffff}, ++ {0x8264, 0xffffffff}, ++ {0x8268, 0xffffffff}, ++ {0x826c, 0x1fffffff}, ++ {0x82a0, 0x00000000}, ++ {0x82ac, 0x003f2e2e}, ++ {0x82b0, 0x003f2e2e}, ++ {0x82bc, 0x005b5b5b}, ++ {0x82c0, 0x005b5b5b}, ++ {0x82b4, 0x00600060}, ++ {0x82b8, 0x00600060}, ++ {0x82cc, 0x00000000}, ++ {0x82dc, 0x00000002}, ++ {0x82e0, 0x00100000}, ++ {0x82e4, 0x00000001}, ++ {0x81d8, 0x00000001}, ++ {0x82d8, 0x00000001}, ++ {0x8d00, 0x00000000}, ++ {0x8d04, 0x00000000}, ++ {0x8d08, 0x00000000}, ++ {0x8d0c, 0x00000000}, ++ {0x8d10, 0x00000000}, ++ {0x8d14, 0x00000000}, ++ {0x8d18, 0x00000000}, ++ {0x8d1c, 0x00000000}, ++ {0x8d20, 0x00000000}, ++ {0x8d24, 0x00000000}, ++ {0x8d28, 0x00000000}, ++ {0x8d2c, 0x00000000}, ++ {0x8d30, 0x00000000}, ++ {0x8d34, 0x00000000}, ++ {0x8d38, 0x00000000}, ++ {0x8d3c, 0x00000000}, ++ {0x8d40, 0x00000000}, ++ {0x8d44, 0x00000000}, ++ {0x8d48, 0x00000000}, ++ {0x8d4c, 0x00000000}, ++ {0x8d50, 0x00000000}, ++ {0x8d54, 0x00000000}, ++ {0x8d58, 0x00000000}, ++ {0x8d5c, 0x00000000}, ++ {0x8d60, 0x00000000}, ++ {0x8d64, 0x00000000}, ++ {0x8d68, 0x00000000}, ++ {0x8d6c, 0x00000000}, ++ {0x8d70, 0x00000000}, ++ {0x8d74, 0x00000000}, ++ {0x8d78, 0x00000000}, ++ {0x8d7c, 0x00000000}, ++ {0x8d80, 0x00000000}, ++ {0x8d84, 0x00000000}, ++ {0x8d88, 0x00000000}, ++ {0x8d8c, 0x00000000}, ++ {0x8d90, 0x00000000}, ++ {0x8d94, 0x00000000}, ++ {0x8d98, 0x00000000}, ++ {0x8d9c, 0x00000000}, ++ {0x8da0, 0x00000000}, ++ {0x8da4, 0x00000000}, ++ {0x8da8, 0x00000000}, ++ {0x8dac, 0x00000000}, ++ {0x8db0, 0x00000000}, ++ {0x8db4, 0x00000000}, ++ {0x8db8, 0x00000000}, ++ {0x8dbc, 0x00000000}, ++ {0x8dc0, 0x00000000}, ++ {0x8dc4, 0x00000000}, ++ {0x8dc8, 0x00000000}, ++ {0x8dcc, 0x00000000}, ++ {0x8dd0, 0x00000000}, ++ {0x8dd4, 0x00000000}, ++ {0x8dd8, 0x00000000}, ++ {0x8ddc, 0x00000000}, ++ {0x8de0, 0x00000000}, ++ {0x8de4, 0x00000000}, ++ {0x8de8, 0x00000000}, ++ {0x8dec, 0x00000000}, ++ {0x8df0, 0x00000000}, ++ {0x8df4, 0x00000000}, ++ {0x8df8, 0x00000000}, ++ {0x8dfc, 0x00000000}, ++ {0x8e00, 0x00000000}, ++ {0x8e04, 0x00000000}, ++ {0x8e08, 0x00000000}, ++ {0x8e0c, 0x00000000}, ++ {0x8e10, 0x00000000}, ++ {0x8e14, 0x00000000}, ++ {0x8e18, 0x00000000}, ++ {0x8e1c, 0x00000000}, ++ {0x8e20, 0x00000000}, ++ {0x8e24, 0x00000000}, ++ {0x8e28, 0x00000000}, ++ {0x8e2c, 0x00000000}, ++ {0x8e30, 0x00000000}, ++ {0x8e34, 0x00000000}, ++ {0x8e38, 0x00000000}, ++ {0x8e3c, 0x00000000}, ++ {0x8e40, 0x00000000}, ++ {0x8e44, 0x00000000}, ++ {0x8e48, 0x00000000}, ++ {0x8e4c, 0x00000000}, ++ {0x8e50, 0x00000000}, ++ {0x8e54, 0x00000000}, ++ {0x8e58, 0x00000000}, ++ {0x8e5c, 0x00000000}, ++ {0x8e60, 0x00000000}, ++ {0x8e64, 0x00000000}, ++ {0x8e68, 0x00000000}, ++ {0x8e6c, 0x00000000}, ++ {0x8e70, 0x00000000}, ++ {0x8e74, 0x00000000}, ++ {0x8e78, 0x00000000}, ++ {0x8e7c, 0x00000000}, ++ {0x8e80, 0x00000000}, ++ {0x8e84, 0x00000000}, ++ {0x8e88, 0x00000000}, ++ {0x8e8c, 0x00000000}, ++ {0x8e90, 0x00000000}, ++ {0x8e94, 0x00000000}, ++ {0x8e98, 0x00000000}, ++ {0x8e9c, 0x00000000}, ++ {0x8ea0, 0x00000000}, ++ {0x8ea4, 0x00000000}, ++ {0x8ea8, 0x00000000}, ++ {0x8eac, 0x00000000}, ++ {0x8eb0, 0x00000000}, ++ {0x8eb4, 0x00000000}, ++ {0x8eb8, 0x00000000}, ++ {0x8ebc, 0x00000000}, ++ {0x8ec0, 0x00000000}, ++ {0x8ec4, 0x00000000}, ++ {0x8ec8, 0x00000000}, ++ {0x8ecc, 0x00000000}, ++ {0x8ed0, 0x00000000}, ++ {0x8ed4, 0x00000000}, ++ {0x8ed8, 0x00000000}, ++ {0x8edc, 0x00000000}, ++ {0x8ee0, 0x00000000}, ++ {0x8ee4, 0x00000000}, ++ {0x8ee8, 0x00000000}, ++ {0x8eec, 0x00000000}, ++ {0x8ef0, 0x00000000}, ++ {0x8ef4, 0x00000000}, ++ {0x8ef8, 0x00000000}, ++ {0x8efc, 0x00000000}, ++ {0x8f00, 0x00000000}, ++ {0x8f04, 0x00000000}, ++ {0x8f08, 0x00000000}, ++ {0x8f0c, 0x00000000}, ++ {0x8f10, 0x00000000}, ++ {0x8f14, 0x00000000}, ++ {0x8f18, 0x00000000}, ++ {0x8f1c, 0x00000000}, ++ {0x8f20, 0x00000000}, ++ {0x8f24, 0x00000000}, ++ {0x8f28, 0x00000000}, ++ {0x8f2c, 0x00000000}, ++ {0x8f30, 0x00000000}, ++ {0x8f34, 0x00000000}, ++ {0x8f38, 0x00000000}, ++ {0x8f3c, 0x00000000}, ++ {0x8f40, 0x00000000}, ++ {0x8f44, 0x00000000}, ++ {0x8f48, 0x00000000}, ++ {0x8f4c, 0x00000000}, ++ {0x8f50, 0x00000000}, ++ {0x8f54, 0x00000000}, ++ {0x8f58, 0x00000000}, ++ {0x8f5c, 0x00000000}, ++ {0x8f60, 0x00000000}, ++ {0x8f64, 0x00000000}, ++ {0x8f68, 0x00000000}, ++ {0x8f6c, 0x00000000}, ++ {0x8f70, 0x00000000}, ++ {0x8f74, 0x00000000}, ++ {0x8f78, 0x00000000}, ++ {0x8f7c, 0x00000000}, ++ {0x8f80, 0x00000000}, ++ {0x8f84, 0x00000000}, ++ {0x8f88, 0x00000000}, ++ {0x8f8c, 0x00000000}, ++ {0x8f90, 0x00000000}, ++ {0x8f94, 0x00000000}, ++ {0x8f98, 0x00000000}, ++ {0x8f9c, 0x00000000}, ++ {0x8fa0, 0x00000000}, ++ {0x8fa4, 0x00000000}, ++ {0x8fa8, 0x00000000}, ++ {0x8fac, 0x00000000}, ++ {0x8fb0, 0x00000000}, ++ {0x8fb4, 0x00000000}, ++ {0x8fb8, 0x00000000}, ++ {0x8fbc, 0x00000000}, ++ {0x8fc0, 0x00000000}, ++ {0x8fc4, 0x00000000}, ++ {0x8fc8, 0x00000000}, ++ {0x8fcc, 0x00000000}, ++ {0x8fd0, 0x00000000}, ++ {0x8fd4, 0x00000000}, ++ {0x8fd8, 0x00000000}, ++ {0x8fdc, 0x00000000}, ++ {0x8fe0, 0x00000000}, ++ {0x8fe4, 0x00000000}, ++ {0x8fe8, 0x00000000}, ++ {0x8fec, 0x00000000}, ++ {0x8ff0, 0x00000000}, ++ {0x8ff4, 0x00000000}, ++ {0x8ff8, 0x00000000}, ++ {0x8ffc, 0x00000000}, ++ {0x9000, 0x00000000}, ++ {0x9004, 0x00000000}, ++ {0x9008, 0x00000000}, ++ {0x900c, 0x00000000}, ++ {0x9010, 0x00000000}, ++ {0x9014, 0x00000000}, ++ {0x9018, 0x00000000}, ++ {0x901c, 0x00000000}, ++ {0x9020, 0x00000000}, ++ {0x9024, 0x00000000}, ++ {0x9028, 0x00000000}, ++ {0x902c, 0x00000000}, ++ {0x9030, 0x00000000}, ++ {0x9034, 0x00000000}, ++ {0x9038, 0x00000000}, ++ {0x903c, 0x00000000}, ++ {0x9040, 0x00000000}, ++ {0x9044, 0x00000000}, ++ {0x9048, 0x00000000}, ++ {0x904c, 0x00000000}, ++ {0x9050, 0x00000000}, ++ {0x9054, 0x00000000}, ++ {0x9058, 0x00000000}, ++ {0x905c, 0x00000000}, ++ {0x9060, 0x00000000}, ++ {0x9064, 0x00000000}, ++ {0x9068, 0x00000000}, ++ {0x906c, 0x00000000}, ++ {0x9070, 0x00000000}, ++ {0x9074, 0x00000000}, ++ {0x9078, 0x00000000}, ++ {0x907c, 0x00000000}, ++ {0x9080, 0x00000000}, ++ {0x9084, 0x00000000}, ++ {0x9088, 0x00000000}, ++ {0x908c, 0x00000000}, ++ {0x9090, 0x00000000}, ++ {0x9094, 0x00000000}, ++ {0x9098, 0x00000000}, ++ {0x909c, 0x00000000}, ++ {0x90a0, 0x00000000}, ++ {0x90a4, 0x00000000}, ++ {0x90a8, 0x00000000}, ++ {0x90ac, 0x00000000}, ++ {0x90b0, 0x00000000}, ++ {0x90b4, 0x00000000}, ++ {0x90b8, 0x00000000}, ++ {0x90bc, 0x00000000}, ++ {0x9100, 0x00000000}, ++ {0x9104, 0x00000000}, ++ {0x9108, 0x00000000}, ++ {0x910c, 0x00000000}, ++ {0x9110, 0x00000000}, ++ {0x9114, 0x00000000}, ++ {0x9118, 0x00000000}, ++ {0x911c, 0x00000000}, ++ {0x9120, 0x00000000}, ++ {0x9124, 0x00000000}, ++ {0x9128, 0x00000000}, ++ {0x912c, 0x00000000}, ++ {0x9130, 0x00000000}, ++ {0x9134, 0x00000000}, ++ {0x9138, 0x00000000}, ++ {0x913c, 0x00000000}, ++ {0x9140, 0x00000000}, ++ {0x9144, 0x00000000}, ++ {0x9148, 0x00000000}, ++ {0x914c, 0x00000000}, ++ {0x9150, 0x00000000}, ++ {0x9154, 0x00000000}, ++ {0x9158, 0x00000000}, ++ {0x915c, 0x00000000}, ++ {0x9160, 0x00000000}, ++ {0x9164, 0x00000000}, ++ {0x9168, 0x00000000}, ++ {0x916c, 0x00000000}, ++ {0x9170, 0x00000000}, ++ {0x9174, 0x00000000}, ++ {0x9178, 0x00000000}, ++ {0x917c, 0x00000000}, ++ {0x9180, 0x00000000}, ++ {0x9184, 0x00000000}, ++ {0x9188, 0x00000000}, ++ {0x918c, 0x00000000}, ++ {0x9190, 0x00000000}, ++ {0x9194, 0x00000000}, ++ {0x9198, 0x00000000}, ++ {0x919c, 0x00000000}, ++ {0x91a0, 0x00000000}, ++ {0x91a4, 0x00000000}, ++ {0x91a8, 0x00000000}, ++ {0x91ac, 0x00000000}, ++ {0x91b0, 0x00000000}, ++ {0x91b4, 0x00000000}, ++ {0x91b8, 0x00000000}, ++ {0x91bc, 0x00000000}, ++ {0x91c0, 0x00000000}, ++ {0x91c4, 0x00000000}, ++ {0x91c8, 0x00000000}, ++ {0x91cc, 0x00000000}, ++ {0x91d0, 0x00000000}, ++ {0x91d4, 0x00000000}, ++ {0x91d8, 0x00000000}, ++ {0x91dc, 0x00000000}, ++ {0x91e0, 0x00000000}, ++ {0x91e4, 0x00000000}, ++ {0x91e8, 0x00000000}, ++ {0x91ec, 0x00000000}, ++ {0x91f0, 0x00000000}, ++ {0x91f4, 0x00000000}, ++ {0x91f8, 0x00000000}, ++ {0x91fc, 0x00000000}, ++ {0x9200, 0x00000000}, ++ {0x9204, 0x00000000}, ++ {0x9208, 0x00000000}, ++ {0x920c, 0x00000000}, ++ {0x9210, 0x00000000}, ++ {0x9214, 0x00000000}, ++ {0x9218, 0x00000000}, ++ {0x921c, 0x00000000}, ++ {0x9220, 0x00000000}, ++ {0x9224, 0x00000000}, ++ {0x9228, 0x00000000}, ++ {0x922c, 0x00000000}, ++ {0x9230, 0x00000000}, ++ {0x9234, 0x00000000}, ++ {0x9238, 0x00000000}, ++ {0x923c, 0x00000000}, ++ {0x9240, 0x00000000}, ++ {0x9244, 0x00000000}, ++ {0x9248, 0x00000000}, ++ {0x924c, 0x00000000}, ++ {0x9250, 0x00000000}, ++ {0x9254, 0x00000000}, ++ {0x9258, 0x00000000}, ++ {0x925c, 0x00000000}, ++ {0x9260, 0x00000000}, ++ {0x9264, 0x00000000}, ++ {0x9268, 0x00000000}, ++ {0x926c, 0x00000000}, ++ {0x9270, 0x00000000}, ++ {0x9274, 0x00000000}, ++ {0x9278, 0x00000000}, ++ {0x927c, 0x00000000}, ++ {0x9280, 0x00000000}, ++ {0x9284, 0x00000000}, ++ {0x9288, 0x00000000}, ++ {0x928c, 0x00000000}, ++ {0x9290, 0x00000000}, ++ {0x9294, 0x00000000}, ++ {0x9298, 0x00000000}, ++ {0x929c, 0x00000000}, ++ {0x92a0, 0x00000000}, ++ {0x92a4, 0x00000000}, ++ {0x92a8, 0x00000000}, ++ {0x92ac, 0x00000000}, ++ {0x92b0, 0x00000000}, ++ {0x92b4, 0x00000000}, ++ {0x92b8, 0x00000000}, ++ {0x92bc, 0x00000000}, ++ {0x92c0, 0x00000000}, ++ {0x92c4, 0x00000000}, ++ {0x92c8, 0x00000000}, ++ {0x92cc, 0x00000000}, ++ {0x92d0, 0x00000000}, ++ {0x92d4, 0x00000000}, ++ {0x92d8, 0x00000000}, ++ {0x92dc, 0x00000000}, ++ {0x92e0, 0x00000000}, ++ {0x92e4, 0x00000000}, ++ {0x92e8, 0x00000000}, ++ {0x92ec, 0x00000000}, ++ {0x92f0, 0x00000000}, ++ {0x92f4, 0x00000000}, ++ {0x92f8, 0x00000000}, ++ {0x92fc, 0x00000000}, ++ {0x9300, 0x00000000}, ++ {0x9304, 0x00000000}, ++ {0x9308, 0x00000000}, ++ {0x930c, 0x00000000}, ++ {0x9310, 0x00000000}, ++ {0x9314, 0x00000000}, ++ {0x9318, 0x00000000}, ++ {0x931c, 0x00000000}, ++ {0x9320, 0x00000000}, ++ {0x9324, 0x00000000}, ++ {0x9328, 0x00000000}, ++ {0x932c, 0x00000000}, ++ {0x9330, 0x00000000}, ++ {0x9334, 0x00000000}, ++ {0x9338, 0x00000000}, ++ {0x933c, 0x00000000}, ++ {0x9340, 0x00000000}, ++ {0x9344, 0x00000000}, ++ {0x9348, 0x00000000}, ++ {0x934c, 0x00000000}, ++ {0x9350, 0x00000000}, ++ {0x9354, 0x00000000}, ++ {0x9358, 0x00000000}, ++ {0x935c, 0x00000000}, ++ {0x9360, 0x00000000}, ++ {0x9364, 0x00000000}, ++ {0x9368, 0x00000000}, ++ {0x936c, 0x00000000}, ++ {0x9370, 0x00000000}, ++ {0x9374, 0x00000000}, ++ {0x9378, 0x00000000}, ++ {0x937c, 0x00000000}, ++ {0x9380, 0x00000000}, ++ {0x9384, 0x00000000}, ++ {0x9388, 0x00000000}, ++ {0x938c, 0x00000000}, ++ {0x9390, 0x00000000}, ++ {0x9394, 0x00000000}, ++ {0x9398, 0x00000000}, ++ {0x939c, 0x00000000}, ++ {0x93a0, 0x00000000}, ++ {0x93a4, 0x00000000}, ++ {0x93a8, 0x00000000}, ++ {0x93ac, 0x00000000}, ++ {0x93b0, 0x00000000}, ++ {0x93b4, 0x00000000}, ++ {0x93b8, 0x00000000}, ++ {0x93bc, 0x00000000}, ++ {0x93c0, 0x00000000}, ++ {0x93c4, 0x00000000}, ++ {0x93c8, 0x00000000}, ++ {0x93cc, 0x00000000}, ++ {0x93d0, 0x00000000}, ++ {0x93d4, 0x00000000}, ++ {0x93d8, 0x00000000}, ++ {0x93dc, 0x00000000}, ++ {0x93e0, 0x00000000}, ++ {0x93e4, 0x00000000}, ++ {0x93e8, 0x00000000}, ++ {0x93ec, 0x00000000}, ++ {0x93f0, 0x00000000}, ++ {0x93f4, 0x00000000}, ++ {0x93f8, 0x00000000}, ++ {0x93fc, 0x00000000}, ++ {0x9400, 0x00000000}, ++ {0x9404, 0x00000000}, ++ {0x9408, 0x00000000}, ++ {0x940c, 0x00000000}, ++ {0x9410, 0x00000000}, ++ {0x9414, 0x00000000}, ++ {0x9418, 0x00000000}, ++ {0x941c, 0x00000000}, ++ {0x9420, 0x00000000}, ++ {0x9424, 0x00000000}, ++ {0x9428, 0x00000000}, ++ {0x942c, 0x00000000}, ++ {0x9430, 0x00000000}, ++ {0x9434, 0x00000000}, ++ {0x9438, 0x00000000}, ++ {0x943c, 0x00000000}, ++ {0x9440, 0x00000000}, ++ {0x9444, 0x00000000}, ++ {0x9448, 0x00000000}, ++ {0x944c, 0x00000000}, ++ {0x9450, 0x00000000}, ++ {0x9454, 0x00000000}, ++ {0x9458, 0x00000000}, ++ {0x945c, 0x00000000}, ++ {0x9460, 0x00000000}, ++ {0x9464, 0x00000000}, ++ {0x9468, 0x00000000}, ++ {0x946c, 0x00000000}, ++ {0x9470, 0x00000000}, ++ {0x9474, 0x00000000}, ++ {0x9478, 0x00000000}, ++ {0x947c, 0x00000000}, ++ {0x9480, 0x00000000}, ++ {0x9484, 0x00000000}, ++ {0x9488, 0x00000000}, ++ {0x948c, 0x00000000}, ++ {0x9490, 0x00000000}, ++ {0x9494, 0x00000000}, ++ {0x9498, 0x00000000}, ++ {0x949c, 0x00000000}, ++ {0x94a0, 0x00000000}, ++ {0x94a4, 0x00000000}, ++ {0x94a8, 0x00000000}, ++ {0x94ac, 0x00000000}, ++ {0x94b0, 0x00000000}, ++ {0x94b4, 0x00000000}, ++ {0x94b8, 0x00000000}, ++ {0x94bc, 0x00000000}, ++ {0xa220, 0x00000000}, ++ {0xa224, 0x00000000}, ++ {0xa228, 0x00000000}, ++ {0xa22c, 0x00000000}, ++ {0xa230, 0x00000000}, ++ {0xa234, 0x00000000}, ++ {0xa238, 0x00000000}, ++ {0xa23c, 0x00000000}, ++ {0xa240, 0x00000000}, ++ {0xa244, 0x00000000}, ++ {0xa248, 0x00000000}, ++ {0xa24c, 0x00000000}, ++ {0xa250, 0x00000000}, ++ {0xa254, 0x00000000}, ++ {0xa258, 0x00000000}, ++ {0xa25c, 0x00000000}, ++ {0xa260, 0x00000000}, ++ {0xa264, 0x00000000}, ++ {0xa268, 0x00000000}, ++ {0xa26c, 0x00000000}, ++ {0xa270, 0x00000000}, ++ {0xa274, 0x00000000}, ++ {0xa278, 0x00000000}, ++ {0xa27c, 0x00000000}, ++ {0xa280, 0x00000000}, ++ {0xa284, 0x00000000}, ++ {0xa288, 0x00000000}, ++ {0xa28c, 0x00000000}, ++ {0xa290, 0x00000000}, ++ {0xa294, 0x00000000}, ++ {0xa298, 0x00000000}, ++ {0xa29c, 0x00000000}, ++ {0xa2a0, 0x00000000}, ++ {0xa2a4, 0x00000000}, ++ {0xa2a8, 0x00000000}, ++ {0xa2ac, 0x00000000}, ++ {0xa2b0, 0x00000000}, ++ {0xa2b4, 0x00000000}, ++ {0xa2b8, 0x00000000}, ++ {0xa2bc, 0x00000000}, ++ {0xa2c0, 0x00000000}, ++ {0xa2c4, 0x00000000}, ++ {0xa2c8, 0x00000000}, ++ {0xa2cc, 0x00000000}, ++ {0xa2d0, 0x00000000}, ++ {0xa2d4, 0x00000000}, ++ {0xa2d8, 0x00000000}, ++ {0xa2dc, 0x00000000}, ++ {0xa2e0, 0x00000000}, ++ {0xa2e4, 0x00000000}, ++ {0xa2e8, 0x00000000}, ++ {0xa2ec, 0x00000000}, ++ {0xa2f0, 0x00000000}, ++ {0xa2f4, 0x00000000}, ++ {0xa2f8, 0x00000000}, ++ {0xa2fc, 0x00000000}, ++ {0xa300, 0x00000000}, ++ {0xa304, 0x00000000}, ++ {0xa308, 0x00000000}, ++ {0xa30c, 0x00000000}, ++ {0xa310, 0x00000000}, ++ {0xa314, 0x00000000}, ++ {0xa318, 0x00000000}, ++ {0xa31c, 0x00000000}, ++ {0xa320, 0x00000000}, ++ {0xa324, 0x00000000}, ++ {0xa328, 0x00000000}, ++ {0xa32c, 0x00000000}, ++ {0xa330, 0x00000000}, ++ {0xa334, 0x00000000}, ++ {0xa338, 0x00000000}, ++ {0xa33c, 0x00000000}, ++ {0xa340, 0x00000000}, ++ {0xa344, 0x00000000}, ++ {0xa348, 0x00000000}, ++ {0xa34c, 0x00000000}, ++ {0xa350, 0x00000000}, ++ {0xa354, 0x00000000}, ++ {0xa358, 0x00000000}, ++ {0xa35c, 0x00000000}, ++ {0xa360, 0x00000000}, ++ {0xa364, 0x00000000}, ++ {0xa368, 0x00000000}, ++ {0xa36c, 0x00000000}, ++ {0xa370, 0x00000000}, ++ {0xa374, 0x00000000}, ++ {0xa378, 0x00000000}, ++ {0xa37c, 0x00000000}, ++ {0xa380, 0x00000000}, ++ {0xa384, 0x00000000}, ++ {0xa388, 0x00000000}, ++ {0xa38c, 0x00000000}, ++ {0xa390, 0x00000000}, ++ {0xa394, 0x00000000}, ++ {0xa398, 0x00000000}, ++ {0xa39c, 0x00000000}, ++ {0xa3a0, 0x00000000}, ++ {0xa3a4, 0x00000000}, ++ {0xa3a8, 0x00000000}, ++ {0xa3ac, 0x00000000}, ++ {0xa3b0, 0x00000000}, ++ {0xa3b4, 0x00000000}, ++ {0xa3b8, 0x00000000}, ++ {0xa3bc, 0x00000000}, ++ {0xa620, 0x00000000}, ++ {0xa624, 0x00000000}, ++ {0xa628, 0x00000000}, ++ {0xa62c, 0x00000000}, ++ {0xa630, 0x00000000}, ++ {0xa634, 0x00000000}, ++ {0xa638, 0x00000000}, ++ {0xa63c, 0x00000000}, ++ {0xa640, 0x00000000}, ++ {0xa644, 0x00000000}, ++ {0xa648, 0x00000000}, ++ {0xa64c, 0x00000000}, ++ {0xa650, 0x00000000}, ++ {0xa654, 0x00000000}, ++ {0xa658, 0x00000000}, ++ {0xa65c, 0x00000000}, ++ {0xa660, 0x00000000}, ++ {0xa664, 0x00000000}, ++ {0xa668, 0x00000000}, ++ {0xa66c, 0x00000000}, ++ {0xa670, 0x00000000}, ++ {0xa674, 0x00000000}, ++ {0xa678, 0x00000000}, ++ {0xa67c, 0x00000000}, ++ {0xa680, 0x00000000}, ++ {0xa684, 0x00000000}, ++ {0xa688, 0x00000000}, ++ {0xa68c, 0x00000000}, ++ {0xa690, 0x00000000}, ++ {0xa694, 0x00000000}, ++ {0xa698, 0x00000000}, ++ {0xa69c, 0x00000000}, ++ {0xa6a0, 0x00000000}, ++ {0xa6a4, 0x00000000}, ++ {0xa6a8, 0x00000000}, ++ {0xa6ac, 0x00000000}, ++ {0xa6b0, 0x00000000}, ++ {0xa6b4, 0x00000000}, ++ {0xa6b8, 0x00000000}, ++ {0xa6bc, 0x00000000}, ++ {0xa6c0, 0x00000000}, ++ {0xa6c4, 0x00000000}, ++ {0xa6c8, 0x00000000}, ++ {0xa6cc, 0x00000000}, ++ {0xa6d0, 0x00000000}, ++ {0xa6d4, 0x00000000}, ++ {0xa6d8, 0x00000000}, ++ {0xa6dc, 0x00000000}, ++ {0xa6e0, 0x00000000}, ++ {0xa6e4, 0x00000000}, ++ {0xa6e8, 0x00000000}, ++ {0xa6ec, 0x00000000}, ++ {0xa6f0, 0x00000000}, ++ {0xa6f4, 0x00000000}, ++ {0xa6f8, 0x00000000}, ++ {0xa6fc, 0x00000000}, ++ {0xa700, 0x00000000}, ++ {0xa704, 0x00000000}, ++ {0xa708, 0x00000000}, ++ {0xa70c, 0x00000000}, ++ {0xa710, 0x00000000}, ++ {0xa714, 0x00000000}, ++ {0xa718, 0x00000000}, ++ {0xa71c, 0x00000000}, ++ {0xa720, 0x00000000}, ++ {0xa724, 0x00000000}, ++ {0xa728, 0x00000000}, ++ {0xa72c, 0x00000000}, ++ {0xa730, 0x00000000}, ++ {0xa734, 0x00000000}, ++ {0xa738, 0x00000000}, ++ {0xa73c, 0x00000000}, ++ {0xa740, 0x00000000}, ++ {0xa744, 0x00000000}, ++ {0xa748, 0x00000000}, ++ {0xa74c, 0x00000000}, ++ {0xa750, 0x00000000}, ++ {0xa754, 0x00000000}, ++ {0xa758, 0x00000000}, ++ {0xa75c, 0x00000000}, ++ {0xa760, 0x00000000}, ++ {0xa764, 0x00000000}, ++ {0xa768, 0x00000000}, ++ {0xa76c, 0x00000000}, ++ {0xa770, 0x00000000}, ++ {0xa774, 0x00000000}, ++ {0xa778, 0x00000000}, ++ {0xa77c, 0x00000000}, ++ {0xa780, 0x00000000}, ++ {0xa784, 0x00000000}, ++ {0xa788, 0x00000000}, ++ {0xa78c, 0x00000000}, ++ {0xa790, 0x00000000}, ++ {0xa794, 0x00000000}, ++ {0xa798, 0x00000000}, ++ {0xa79c, 0x00000000}, ++ {0xa7a0, 0x00000000}, ++ {0xa7a4, 0x00000000}, ++ {0xa7a8, 0x00000000}, ++ {0xa7ac, 0x00000000}, ++ {0xa7b0, 0x00000000}, ++ {0xa7b4, 0x00000000}, ++ {0xa7b8, 0x00000000}, ++ {0xa7bc, 0x00000000}, ++ {0x81d8, 0x00000000}, ++ {0x82d8, 0x00000000}, ++ {0x9f04, 0x2b251f19}, ++ {0x9f08, 0x433d3731}, ++ {0x9f0c, 0x5b554f49}, ++ {0x9f10, 0x736d6761}, ++ {0x9f14, 0x7f7f7f79}, ++ {0x9f18, 0x120f7f7f}, ++ {0x9f1c, 0x1e1b1815}, ++ {0x9f20, 0x2a272421}, ++ {0x9f24, 0x3633302d}, ++ {0x9f28, 0x3f3f3c39}, ++ {0x9f2c, 0x3f3f3f3f}, ++ {0x8008, 0x00000080}, ++ {0x8088, 0x807f030a}, ++ {0x80c8, 0x708f0bf1}, ++ {0x80c8, 0x708e0aa5}, ++ {0x80c8, 0x708d097d}, ++ {0x80c8, 0x708c0875}, ++ {0x80c8, 0x708b0789}, ++ {0x80c8, 0x708a06b7}, ++ {0x80c8, 0x708905fc}, ++ {0x80c8, 0x70880556}, ++ {0x80c8, 0x708704c1}, ++ {0x80c8, 0x7086043d}, ++ {0x80c8, 0x708503c7}, ++ {0x80c8, 0x7084035e}, ++ {0x80c8, 0x708302ac}, ++ {0x80c8, 0x70820262}, ++ {0x80c8, 0x70810220}, ++ {0x80c8, 0x70800000}, ++ {0x80c8, 0x7090011f}, ++ {0x80c8, 0x7010011f}, ++ {0x8088, 0x80000000}, ++ {0x8008, 0x00000000}, ++ {0x8088, 0x00000110}, ++ {0x8000, 0x00000008}, ++ {0x8080, 0x00000005}, ++ {0x8500, 0x80000008}, ++ {0x8504, 0x43000004}, ++ {0x8508, 0x4b044a00}, ++ {0x850c, 0x40098604}, ++ {0x8510, 0x0004e020}, ++ {0x8514, 0x87044b05}, ++ {0x8518, 0xe020400b}, ++ {0x851c, 0x4b000004}, ++ {0x8520, 0x21e07410}, ++ {0x8524, 0x74300000}, ++ {0x8528, 0x43800004}, ++ {0x852c, 0x4c000007}, ++ {0x8530, 0x43000004}, ++ {0x8534, 0x42fe5700}, ++ {0x8538, 0x42004000}, ++ {0x853c, 0x30005055}, ++ {0x8540, 0xa50fb41a}, ++ {0x8544, 0xf11ce3c7}, ++ {0x8548, 0xf31cf21c}, ++ {0x854c, 0xf61cf41c}, ++ {0x8550, 0xf91cf81c}, ++ {0x8554, 0xfb1cfa1c}, ++ {0x8558, 0xfd1cfc1c}, ++ {0x855c, 0xff1cfe1c}, ++ {0x8560, 0xf11cf01c}, ++ {0x8564, 0xf31cf21c}, ++ {0x8568, 0xf51cf41c}, ++ {0x856c, 0xf71cf61c}, ++ {0x8570, 0xf91cf81c}, ++ {0x8574, 0xe3c7a504}, ++ {0x8578, 0xf11af01a}, ++ {0x857c, 0x30580001}, ++ {0x8580, 0x30b030c9}, ++ {0x8584, 0x30ff30fc}, ++ {0x8588, 0x310f3102}, ++ {0x858c, 0x3148311c}, ++ {0x8590, 0x31603158}, ++ {0x8594, 0x30c7320e}, ++ {0x8598, 0x32293225}, ++ {0x859c, 0x32433242}, ++ {0x85a0, 0x3286327a}, ++ {0x85a4, 0x329d328a}, ++ {0x85a8, 0x32aa32a8}, ++ {0x85ac, 0x320331c5}, ++ {0x85b0, 0x7410e2c1}, ++ {0x85b4, 0x020020a8}, ++ {0x85b8, 0x2098140f}, ++ {0x85bc, 0x140f0200}, ++ {0x85c0, 0x02002088}, ++ {0x85c4, 0x7430140f}, ++ {0x85c8, 0x5b10e31c}, ++ {0x85cc, 0x20a87410}, ++ {0x85d0, 0x140f0201}, ++ {0x85d4, 0x00002080}, ++ {0x85d8, 0x5507140f}, ++ {0x85dc, 0x5c065661}, ++ {0x85e0, 0x7410e308}, ++ {0x85e4, 0x02002088}, ++ {0x85e8, 0x5517140f}, ++ {0x85ec, 0x7410e308}, ++ {0x85f0, 0x020020a8}, ++ {0x85f4, 0x5517140f}, ++ {0x85f8, 0x5c025641}, ++ {0x85fc, 0x7410e308}, ++ {0x8600, 0x00002080}, ++ {0x8604, 0x1407140f}, ++ {0x8608, 0xe3085507}, ++ {0x860c, 0x7508e2b4}, ++ {0x8610, 0xe312468e}, ++ {0x8614, 0x5b10e0f4}, ++ {0x8618, 0x20a87410}, ++ {0x861c, 0x140f0201}, ++ {0x8620, 0x00002090}, ++ {0x8624, 0x5507140f}, ++ {0x8628, 0x5c065661}, ++ {0x862c, 0x7410e308}, ++ {0x8630, 0x02002098}, ++ {0x8634, 0x5517140f}, ++ {0x8638, 0x7410e308}, ++ {0x863c, 0x020020a8}, ++ {0x8640, 0x5517140f}, ++ {0x8644, 0x5c025641}, ++ {0x8648, 0x7410e308}, ++ {0x864c, 0x00002090}, ++ {0x8650, 0x5507140f}, ++ {0x8654, 0x7509e308}, ++ {0x8658, 0xe3124696}, ++ {0x865c, 0x0001e0f4}, ++ {0x8660, 0x74105b10}, ++ {0x8664, 0x000020a0}, ++ {0x8668, 0x5507140f}, ++ {0x866c, 0xe3085601}, ++ {0x8670, 0x20a87410}, ++ {0x8674, 0x140f0200}, ++ {0x8678, 0xe3085517}, ++ {0x867c, 0x750ae2b4}, ++ {0x8680, 0xe3124686}, ++ {0x8684, 0x5500e0f4}, ++ {0x8688, 0x5501e304}, ++ {0x868c, 0xe2c10001}, ++ {0x8690, 0x5b10e31c}, ++ {0x8694, 0x20807410}, ++ {0x8698, 0x140f0000}, ++ {0x869c, 0x02002098}, ++ {0x86a0, 0xf204140f}, ++ {0x86a4, 0x020020a8}, ++ {0x86a8, 0x5507140f}, ++ {0x86ac, 0xe3085601}, ++ {0x86b0, 0x20887410}, ++ {0x86b4, 0x140f0200}, ++ {0x86b8, 0xe3085517}, ++ {0x86bc, 0x7508e2b4}, ++ {0x86c0, 0xe312468e}, ++ {0x86c4, 0x7410e0f4}, ++ {0x86c8, 0x00002090}, ++ {0x86cc, 0x5507140f}, ++ {0x86d0, 0x7410e308}, ++ {0x86d4, 0x02002098}, ++ {0x86d8, 0x5517140f}, ++ {0x86dc, 0x7509e308}, ++ {0x86e0, 0xe3124696}, ++ {0x86e4, 0x0001e0f4}, ++ {0x86e8, 0x74207900}, ++ {0x86ec, 0x57005710}, ++ {0x86f0, 0x9700140f}, ++ {0x86f4, 0x00017430}, ++ {0x86f8, 0xe31ce2c1}, ++ {0x86fc, 0xe2ca0001}, ++ {0x8700, 0x0001e34b}, ++ {0x8704, 0x312ae2c1}, ++ {0x8708, 0xe3ba0023}, ++ {0x870c, 0x54ed0002}, ++ {0x8710, 0x00230baa}, ++ {0x8714, 0x0002e3ba}, ++ {0x8718, 0xe2b9e367}, ++ {0x871c, 0xe2c10001}, ++ {0x8720, 0x00223125}, ++ {0x8724, 0x0002e3ba}, ++ {0x8728, 0x0baa54ec}, ++ {0x872c, 0xe3ba0022}, ++ {0x8730, 0xe3670002}, ++ {0x8734, 0x0001e2b9}, ++ {0x8738, 0x0baae2c1}, ++ {0x873c, 0x6d0f6c67}, ++ {0x8740, 0xe3bae31c}, ++ {0x8744, 0xe31c6c8b}, ++ {0x8748, 0x0bace3ba}, ++ {0x874c, 0x6d0f6cb3}, ++ {0x8750, 0xe3bae31c}, ++ {0x8754, 0x6cdb0bad}, ++ {0x8758, 0xe31c6d0f}, ++ {0x875c, 0x6cf7e3ba}, ++ {0x8760, 0xe31c6d0f}, ++ {0x8764, 0x6c09e3ba}, ++ {0x8768, 0xe31c6d00}, ++ {0x876c, 0x6c25e3ba}, ++ {0x8770, 0xe3bae31c}, ++ {0x8774, 0x6c4df8ca}, ++ {0x8778, 0xe3bae31c}, ++ {0x877c, 0x6c75f9d3}, ++ {0x8780, 0xe3bae31c}, ++ {0x8784, 0xe31c6c99}, ++ {0x8788, 0xe367e3ba}, ++ {0x878c, 0x0001e2b9}, ++ {0x8790, 0x4380e2ca}, ++ {0x8794, 0x43006344}, ++ {0x8798, 0x00223188}, ++ {0x879c, 0x0002e3bf}, ++ {0x87a0, 0x0baa54ec}, ++ {0x87a4, 0xe3bf0022}, ++ {0x87a8, 0xe3670002}, ++ {0x87ac, 0x0001e2c5}, ++ {0x87b0, 0x4380e2ca}, ++ {0x87b4, 0x43006344}, ++ {0x87b8, 0xe367317b}, ++ {0x87bc, 0x0001e2c5}, ++ {0x87c0, 0x4380e2ca}, ++ {0x87c4, 0x4300634d}, ++ {0x87c8, 0x74100ba6}, ++ {0x87cc, 0x000921e8}, ++ {0x87d0, 0x6f0f6e67}, ++ {0x87d4, 0xe3bfe34b}, ++ {0x87d8, 0x000a21e8}, ++ {0x87dc, 0xe34b6e77}, ++ {0x87e0, 0x21e8e3bf}, ++ {0x87e4, 0x6e8b000b}, ++ {0x87e8, 0xe3bfe34b}, ++ {0x87ec, 0x000c21e8}, ++ {0x87f0, 0xe34b6e9f}, ++ {0x87f4, 0x0baae3bf}, ++ {0x87f8, 0x21e87410}, ++ {0x87fc, 0x6eb3000d}, ++ {0x8800, 0xe34b6f0f}, ++ {0x8804, 0x21e8e3bf}, ++ {0x8808, 0x6ec7000e}, ++ {0x880c, 0xe3bfe34b}, ++ {0x8810, 0x74100bac}, ++ {0x8814, 0x000f21e8}, ++ {0x8818, 0x6f0f6edb}, ++ {0x881c, 0xe3bfe34b}, ++ {0x8820, 0x001021e8}, ++ {0x8824, 0xe34b6eef}, ++ {0x8828, 0xe3bfe3bf}, ++ {0x882c, 0x001321e8}, ++ {0x8830, 0x6f006e11}, ++ {0x8834, 0xe3bfe34b}, ++ {0x8838, 0x21e8e3bf}, ++ {0x883c, 0x6e250014}, ++ {0x8840, 0xe3bfe34b}, ++ {0x8844, 0x21e8fbab}, ++ {0x8848, 0x6e390015}, ++ {0x884c, 0xe3bfe34b}, ++ {0x8850, 0x001621e8}, ++ {0x8854, 0xe34b6e4d}, ++ {0x8858, 0xfcb0e3bf}, ++ {0x885c, 0x001721e8}, ++ {0x8860, 0xe34b6e61}, ++ {0x8864, 0x21e8e3bf}, ++ {0x8868, 0x6e750018}, ++ {0x886c, 0xe3bfe34b}, ++ {0x8870, 0x001921e8}, ++ {0x8874, 0xe34b6e89}, ++ {0x8878, 0x21e8e3bf}, ++ {0x887c, 0x6e99001a}, ++ {0x8880, 0xe3bfe34b}, ++ {0x8884, 0xe2c5e367}, ++ {0x8888, 0x00040001}, ++ {0x888c, 0x42fc0004}, ++ {0x8890, 0x60010007}, ++ {0x8894, 0x42000004}, ++ {0x8898, 0x62200007}, ++ {0x889c, 0x00046200}, ++ {0x88a0, 0x5b005501}, ++ {0x88a4, 0x5b40e304}, ++ {0x88a8, 0x00076605}, ++ {0x88ac, 0x63006200}, ++ {0x88b0, 0x0004e388}, ++ {0x88b4, 0x0a010900}, ++ {0x88b8, 0x0d000b40}, ++ {0x88bc, 0x00320e01}, ++ {0x88c0, 0x95090004}, ++ {0x88c4, 0x790442fb}, ++ {0x88c8, 0x43804200}, ++ {0x88cc, 0x4d010007}, ++ {0x88d0, 0x43000004}, ++ {0x88d4, 0x05620007}, ++ {0x88d8, 0x961d05a3}, ++ {0x88dc, 0x0004e388}, ++ {0x88e0, 0x0007e304}, ++ {0x88e4, 0x07a306a2}, ++ {0x88e8, 0x0004e388}, ++ {0x88ec, 0xe378e304}, ++ {0x88f0, 0xe3800002}, ++ {0x88f4, 0x00074380}, ++ {0x88f8, 0x00044d00}, ++ {0x88fc, 0x42fe4300}, ++ {0x8900, 0x42007900}, ++ {0x8904, 0x00040001}, ++ {0x8908, 0x000742fc}, ++ {0x890c, 0x00046003}, ++ {0x8910, 0x31cc4200}, ++ {0x8914, 0x06a20007}, ++ {0x8918, 0x31f807a3}, ++ {0x891c, 0x77000005}, ++ {0x8920, 0x52000007}, ++ {0x8924, 0x42fe0004}, ++ {0x8928, 0x60000007}, ++ {0x892c, 0x42000004}, ++ {0x8930, 0x60004380}, ++ {0x8934, 0x62016100}, ++ {0x8938, 0x00056310}, ++ {0x893c, 0x55004100}, ++ {0x8940, 0x5c020007}, ++ {0x8944, 0x43000004}, ++ {0x8948, 0xe2d70001}, ++ {0x894c, 0x73000005}, ++ {0x8950, 0xe2d70001}, ++ {0x8954, 0x5d000006}, ++ {0x8958, 0x42f70004}, ++ {0x895c, 0x6c000005}, ++ {0x8960, 0x42000004}, ++ {0x8964, 0x0004e2de}, ++ {0x8968, 0x00074380}, ++ {0x896c, 0x4a004e00}, ++ {0x8970, 0x00064c00}, ++ {0x8974, 0x60007f00}, ++ {0x8978, 0x00046f00}, ++ {0x897c, 0x00054300}, ++ {0x8980, 0x00017300}, ++ {0x8984, 0xe2d70001}, ++ {0x8988, 0x5d010006}, ++ {0x898c, 0x61006002}, ++ {0x8990, 0x00055601}, ++ {0x8994, 0xe2e27710}, ++ {0x8998, 0x73000005}, ++ {0x899c, 0x43800004}, ++ {0x89a0, 0x5e010007}, ++ {0x89a4, 0x4d205e00}, ++ {0x89a8, 0x4a084e20}, ++ {0x89ac, 0x4c3f4960}, ++ {0x89b0, 0x00064301}, ++ {0x89b4, 0x63807f01}, ++ {0x89b8, 0x00046010}, ++ {0x89bc, 0x00064300}, ++ {0x89c0, 0x00077402}, ++ {0x89c4, 0x40004001}, ++ {0x89c8, 0x0006ab00}, ++ {0x89cc, 0x00077404}, ++ {0x89d0, 0x40004001}, ++ {0x89d4, 0x0004ab00}, ++ {0x89d8, 0x00074380}, ++ {0x89dc, 0x4e004d00}, ++ {0x89e0, 0x4c004a00}, ++ {0x89e4, 0x00064300}, ++ {0x89e8, 0x63007f00}, ++ {0x89ec, 0x00046000}, ++ {0x89f0, 0x00014300}, ++ {0x89f4, 0x73800005}, ++ {0x89f8, 0x42fe0004}, ++ {0x89fc, 0x6c010005}, ++ {0x8a00, 0x000514c8}, ++ {0x8a04, 0x00046c00}, ++ {0x8a08, 0x00014200}, ++ {0x8a0c, 0x0005e2ce}, ++ {0x8a10, 0x00017300}, ++ {0x8a14, 0x00040006}, ++ {0x8a18, 0x42fa4380}, ++ {0x8a1c, 0x42007c05}, ++ {0x8a20, 0x7c5b0006}, ++ {0x8a24, 0x7e5b7d5b}, ++ {0x8a28, 0x00077f00}, ++ {0x8a2c, 0x415b405b}, ++ {0x8a30, 0x4300425b}, ++ {0x8a34, 0x43000004}, ++ {0x8a38, 0x00040001}, ++ {0x8a3c, 0x60004380}, ++ {0x8a40, 0x62016100}, ++ {0x8a44, 0x42fa6310}, ++ {0x8a48, 0x42007c00}, ++ {0x8a4c, 0x00014300}, ++ {0x8a50, 0x0001e2e5}, ++ {0x8a54, 0x55000007}, ++ {0x8a58, 0x74200004}, ++ {0x8a5c, 0x79017711}, ++ {0x8a60, 0x57005710}, ++ {0x8a64, 0x00019700}, ++ {0x8a68, 0x4e004f02}, ++ {0x8a6c, 0x52015302}, ++ {0x8a70, 0x43800001}, ++ {0x8a74, 0x78006505}, ++ {0x8a78, 0x7a007900}, ++ {0x8a7c, 0x43007b00}, ++ {0x8a80, 0x43800001}, ++ {0x8a84, 0x43006500}, ++ {0x8a88, 0x43800001}, ++ {0x8a8c, 0x7c006405}, ++ {0x8a90, 0x00014300}, ++ {0x8a94, 0x64004380}, ++ {0x8a98, 0x00014300}, ++ {0x8a9c, 0x74200004}, ++ {0x8aa0, 0x0005e392}, ++ {0x8aa4, 0x73807388}, ++ {0x8aa8, 0xe3a08f00}, ++ {0x8aac, 0xe3920001}, ++ {0x8ab0, 0x73810005}, ++ {0x8ab4, 0x93007380}, ++ {0x8ab8, 0x0001e3a0}, ++ {0x8abc, 0xe2e5e3a7}, ++ {0x8ac0, 0x0001e3ae}, ++ {0x8ac4, 0xe3aee3a7}, ++ {0x8ac8, 0x00040001}, ++ {0x8acc, 0x24207410}, ++ {0x8ad0, 0x14c80000}, ++ {0x8ad4, 0x00002428}, ++ {0x8ad8, 0x1a4215f4}, ++ {0x8adc, 0x74300008}, ++ {0x8ae0, 0x43800001}, ++ {0x8ae4, 0x7a907b48}, ++ {0x8ae8, 0x78027900}, ++ {0x8aec, 0x55034300}, ++ {0x8af0, 0x43803308}, ++ {0x8af4, 0x7a807b38}, ++ {0x8af8, 0x55134300}, ++ {0x8afc, 0x43803308}, ++ {0x8b00, 0x7a007b40}, ++ {0x8b04, 0x55234300}, ++ {0x8b08, 0x74007401}, ++ {0x8b0c, 0x00018e00}, ++ {0x8b10, 0x52300007}, ++ {0x8b14, 0x74310004}, ++ {0x8b18, 0x8e007430}, ++ {0x8b1c, 0x52200007}, ++ {0x8b20, 0x00010004}, ++ {0x8b24, 0x57005702}, ++ {0x8b28, 0x00018e00}, ++ {0x8b2c, 0x561042ef}, ++ {0x8b30, 0x42005600}, ++ {0x8b34, 0x00018c00}, ++ {0x8b38, 0x4e004f78}, ++ {0x8b3c, 0x52015388}, ++ {0x8b40, 0xe32b5b20}, ++ {0x8b44, 0x54005480}, ++ {0x8b48, 0x54005481}, ++ {0x8b4c, 0x54005482}, ++ {0x8b50, 0xbf1de336}, ++ {0x8b54, 0xe2f13010}, ++ {0x8b58, 0xe2ffe2f9}, ++ {0x8b5c, 0xe3b3e312}, ++ {0x8b60, 0xe3085523}, ++ {0x8b64, 0xe3125525}, ++ {0x8b68, 0x0001e3b3}, ++ {0x8b6c, 0x54c054bf}, ++ {0x8b70, 0x54c154a3}, ++ {0x8b74, 0x4c1854a4}, ++ {0x8b78, 0x54c2bf07}, ++ {0x8b7c, 0xbf0454a4}, ++ {0x8b80, 0x54a354c1}, ++ {0x8b84, 0xe3c4bf01}, ++ {0x8b88, 0x000154df}, ++ {0x8b8c, 0x54e554bf}, ++ {0x8b90, 0x54df050a}, ++ {0x8b94, 0x16570001}, ++ {0x8b98, 0x74307b80}, ++ {0x8b9c, 0x7f404380}, ++ {0x8ba0, 0x7d007e00}, ++ {0x8ba4, 0x43007c02}, ++ {0x8ba8, 0x55015b40}, ++ {0x8bac, 0xe3165c01}, ++ {0x8bb0, 0x54005480}, ++ {0x8bb4, 0x54005481}, ++ {0x8bb8, 0x54005482}, ++ {0x8bbc, 0x74107b00}, ++ {0x8bc0, 0xbfe5e336}, ++ {0x8bc4, 0x56103010}, ++ {0x8bc8, 0x8c005600}, ++ {0x8bcc, 0x57040001}, ++ {0x8bd0, 0x8e005700}, ++ {0x8bd4, 0x57005708}, ++ {0x8bd8, 0x57818e00}, ++ {0x8bdc, 0x8e005780}, ++ {0x8be0, 0x00074380}, ++ {0x8be4, 0x5c005c01}, ++ {0x8be8, 0x00041403}, ++ {0x8bec, 0x00014300}, ++ {0x8bf0, 0x0007427f}, ++ {0x8bf4, 0x62006280}, ++ {0x8bf8, 0x00049200}, ++ {0x8bfc, 0x00014200}, ++ {0x8c00, 0x0007427f}, ++ {0x8c04, 0x63146394}, ++ {0x8c08, 0x00049200}, ++ {0x8c0c, 0x00014200}, ++ {0x8c10, 0x42fe0004}, ++ {0x8c14, 0x42007901}, ++ {0x8c18, 0x14037420}, ++ {0x8c1c, 0x57005710}, ++ {0x8c20, 0x0001140f}, ++ {0x8c24, 0x56010006}, ++ {0x8c28, 0x54005502}, ++ {0x8c2c, 0x7f000005}, ++ {0x8c30, 0x77107e12}, ++ {0x8c34, 0x75007600}, ++ {0x8c38, 0x00047400}, ++ {0x8c3c, 0x00014270}, ++ {0x8c40, 0x42000004}, ++ {0x8c44, 0x77000005}, ++ {0x8c48, 0x56000006}, ++ {0x8c4c, 0x00060001}, ++ {0x8c50, 0x5f005f80}, ++ {0x8c54, 0x00059900}, ++ {0x8c58, 0x00017300}, ++ {0x8c5c, 0x63800006}, ++ {0x8c60, 0x98006300}, ++ {0x8c64, 0x549f0001}, ++ {0x8c68, 0x5c015400}, ++ {0x8c6c, 0x540054df}, ++ {0x8c70, 0x00015c02}, ++ {0x8c74, 0x07145c01}, ++ {0x8c78, 0x5c025400}, ++ {0x8c7c, 0x5c020001}, ++ {0x8c80, 0x54000714}, ++ {0x8c84, 0x00015c01}, ++ {0x8c88, 0x4c184c98}, ++ {0x8c8c, 0x00040001}, ++ {0x8c90, 0x74305c02}, ++ {0x8c94, 0x0c010901}, ++ {0x8c98, 0x00050ba6}, ++ {0x8c9c, 0x00077780}, ++ {0x8ca0, 0x00045220}, ++ {0x8ca4, 0x60084380}, ++ {0x8ca8, 0x6200610a}, ++ {0x8cac, 0x000763ce}, ++ {0x8cb0, 0x00045c00}, ++ {0x8cb4, 0x00014300}, ++ {0x8080, 0x00000004}, ++ {0x8080, 0x00000000}, ++ {0x8088, 0x00000000}, ++}; ++ ++static const struct rtw89_txpwr_byrate_cfg rtw89_8852b_txpwr_byrate[] = { ++ { 0, 0, 0, 0, 4, 0x50505050, }, ++ { 0, 0, 1, 0, 4, 0x50505050, }, ++ { 0, 0, 1, 4, 4, 0x484c5050, }, ++ { 0, 0, 2, 0, 4, 0x50505050, }, ++ { 0, 0, 2, 4, 4, 0x44484c50, }, ++ { 0, 0, 2, 8, 4, 0x34383c40, }, ++ { 0, 0, 3, 0, 4, 0x50505050, }, ++ { 0, 1, 2, 0, 4, 0x50505050, }, ++ { 0, 1, 2, 4, 4, 0x44484c50, }, ++ { 0, 1, 2, 8, 4, 0x34383c40, }, ++ { 0, 1, 3, 0, 4, 0x50505050, }, ++ { 0, 0, 4, 1, 4, 0x00000000, }, ++ { 0, 0, 4, 0, 1, 0x00000000, }, ++ { 1, 0, 1, 0, 4, 0x50505050, }, ++ { 1, 0, 1, 4, 4, 0x484c5050, }, ++ { 1, 0, 2, 0, 4, 0x50505050, }, ++ { 1, 0, 2, 4, 4, 0x44484c50, }, ++ { 1, 0, 2, 8, 4, 0x34383c40, }, ++ { 1, 0, 3, 0, 4, 0x50505050, }, ++ { 1, 1, 2, 0, 4, 0x50505050, }, ++ { 1, 1, 2, 4, 4, 0x44484c50, }, ++ { 1, 1, 2, 8, 4, 0x34383c40, }, ++ { 1, 1, 3, 0, 4, 0x50505050, }, ++ { 1, 0, 4, 0, 4, 0x00000000, }, ++}; ++ ++static const s8 _txpwr_track_delta_swingidx_5gb_n[][DELTA_SWINGIDX_SIZE] = { ++ {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, ++ 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8}, ++ {0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, ++ 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8}, ++ {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, ++ 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12}, ++}; ++ ++static const s8 _txpwr_track_delta_swingidx_5gb_p[][DELTA_SWINGIDX_SIZE] = { ++ {0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, ++ 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8}, ++ {0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, ++ 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8}, ++ {0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, ++ 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9}, ++}; ++ ++static const s8 _txpwr_track_delta_swingidx_5ga_n[][DELTA_SWINGIDX_SIZE] = { ++ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, ++ 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4}, ++ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3}, ++ {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3}, ++}; ++ ++static const s8 _txpwr_track_delta_swingidx_5ga_p[][DELTA_SWINGIDX_SIZE] = { ++ {0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, ++ 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7}, ++ {0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, ++ 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9}, ++ {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, ++ 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9}, ++}; ++ ++static const s8 _txpwr_track_delta_swingidx_2gb_n[] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2}; ++ ++static const s8 _txpwr_track_delta_swingidx_2gb_p[] = { ++ 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, ++ 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6}; ++ ++static const s8 _txpwr_track_delta_swingidx_2ga_n[] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ ++static const s8 _txpwr_track_delta_swingidx_2ga_p[] = { ++ 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, ++ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5}; ++ ++static const s8 _txpwr_track_delta_swingidx_2g_cck_b_n[] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; ++ ++static const s8 _txpwr_track_delta_swingidx_2g_cck_b_p[] = { ++ 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, ++ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6}; ++ ++static const s8 _txpwr_track_delta_swingidx_2g_cck_a_n[] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -2, -2, ++ -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -3}; ++ ++static const s8 _txpwr_track_delta_swingidx_2g_cck_a_p[] = { ++ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; ++ ++const u8 rtw89_8852b_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] ++ [RTW89_REGD_NUM] = { ++ [0][0][RTW89_ACMA] = 0, ++ [0][0][RTW89_CHILE] = 0, ++ [0][0][RTW89_CN] = 0, ++ [0][0][RTW89_ETSI] = 0, ++ [0][0][RTW89_FCC] = 1, ++ [0][0][RTW89_IC] = 1, ++ [0][0][RTW89_KCC] = 0, ++ [0][0][RTW89_MEXICO] = 1, ++ [0][0][RTW89_MKK] = 0, ++ [0][0][RTW89_QATAR] = 0, ++ [0][0][RTW89_UK] = 0, ++ [0][0][RTW89_UKRAINE] = 0, ++ [0][1][RTW89_ACMA] = 0, ++ [0][1][RTW89_CHILE] = 0, ++ [0][1][RTW89_CN] = 0, ++ [0][1][RTW89_ETSI] = 0, ++ [0][1][RTW89_FCC] = 3, ++ [0][1][RTW89_IC] = 3, ++ [0][1][RTW89_KCC] = 0, ++ [0][1][RTW89_MEXICO] = 3, ++ [0][1][RTW89_MKK] = 0, ++ [0][1][RTW89_QATAR] = 0, ++ [0][1][RTW89_UK] = 0, ++ [0][1][RTW89_UKRAINE] = 0, ++ [1][1][RTW89_ACMA] = 0, ++ [1][1][RTW89_CHILE] = 0, ++ [1][1][RTW89_CN] = 0, ++ [1][1][RTW89_ETSI] = 0, ++ [1][1][RTW89_FCC] = 3, ++ [1][1][RTW89_IC] = 3, ++ [1][1][RTW89_KCC] = 0, ++ [1][1][RTW89_MEXICO] = 3, ++ [1][1][RTW89_MKK] = 0, ++ [1][1][RTW89_QATAR] = 0, ++ [1][1][RTW89_UK] = 0, ++ [1][1][RTW89_UKRAINE] = 0, ++}; ++ ++const s8 rtw89_8852b_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] ++ [RTW89_RS_LMT_NUM][RTW89_BF_NUM] ++ [RTW89_REGD_NUM][RTW89_2G_CH_NUM] = { ++ [0][0][0][0][RTW89_WW][0] = 58, ++ [0][0][0][0][RTW89_WW][1] = 58, ++ [0][0][0][0][RTW89_WW][2] = 58, ++ [0][0][0][0][RTW89_WW][3] = 58, ++ [0][0][0][0][RTW89_WW][4] = 58, ++ [0][0][0][0][RTW89_WW][5] = 58, ++ [0][0][0][0][RTW89_WW][6] = 58, ++ [0][0][0][0][RTW89_WW][7] = 58, ++ [0][0][0][0][RTW89_WW][8] = 58, ++ [0][0][0][0][RTW89_WW][9] = 58, ++ [0][0][0][0][RTW89_WW][10] = 58, ++ [0][0][0][0][RTW89_WW][11] = 58, ++ [0][0][0][0][RTW89_WW][12] = 56, ++ [0][0][0][0][RTW89_WW][13] = 76, ++ [0][1][0][0][RTW89_WW][0] = 46, ++ [0][1][0][0][RTW89_WW][1] = 46, ++ [0][1][0][0][RTW89_WW][2] = 46, ++ [0][1][0][0][RTW89_WW][3] = 46, ++ [0][1][0][0][RTW89_WW][4] = 46, ++ [0][1][0][0][RTW89_WW][5] = 46, ++ [0][1][0][0][RTW89_WW][6] = 46, ++ [0][1][0][0][RTW89_WW][7] = 46, ++ [0][1][0][0][RTW89_WW][8] = 46, ++ [0][1][0][0][RTW89_WW][9] = 46, ++ [0][1][0][0][RTW89_WW][10] = 46, ++ [0][1][0][0][RTW89_WW][11] = 46, ++ [0][1][0][0][RTW89_WW][12] = 42, ++ [0][1][0][0][RTW89_WW][13] = 64, ++ [1][0][0][0][RTW89_WW][0] = 0, ++ [1][0][0][0][RTW89_WW][1] = 0, ++ [1][0][0][0][RTW89_WW][2] = 50, ++ [1][0][0][0][RTW89_WW][3] = 50, ++ [1][0][0][0][RTW89_WW][4] = 50, ++ [1][0][0][0][RTW89_WW][5] = 58, ++ [1][0][0][0][RTW89_WW][6] = 50, ++ [1][0][0][0][RTW89_WW][7] = 50, ++ [1][0][0][0][RTW89_WW][8] = 50, ++ [1][0][0][0][RTW89_WW][9] = 42, ++ [1][0][0][0][RTW89_WW][10] = 30, ++ [1][0][0][0][RTW89_WW][11] = 0, ++ [1][0][0][0][RTW89_WW][12] = 0, ++ [1][0][0][0][RTW89_WW][13] = 0, ++ [1][1][0][0][RTW89_WW][0] = 0, ++ [1][1][0][0][RTW89_WW][1] = 0, ++ [1][1][0][0][RTW89_WW][2] = 46, ++ [1][1][0][0][RTW89_WW][3] = 46, ++ [1][1][0][0][RTW89_WW][4] = 46, ++ [1][1][0][0][RTW89_WW][5] = 46, ++ [1][1][0][0][RTW89_WW][6] = 34, ++ [1][1][0][0][RTW89_WW][7] = 34, ++ [1][1][0][0][RTW89_WW][8] = 34, ++ [1][1][0][0][RTW89_WW][9] = 30, ++ [1][1][0][0][RTW89_WW][10] = 30, ++ [1][1][0][0][RTW89_WW][11] = 0, ++ [1][1][0][0][RTW89_WW][12] = 0, ++ [1][1][0][0][RTW89_WW][13] = 0, ++ [0][0][1][0][RTW89_WW][0] = 58, ++ [0][0][1][0][RTW89_WW][1] = 58, ++ [0][0][1][0][RTW89_WW][2] = 58, ++ [0][0][1][0][RTW89_WW][3] = 58, ++ [0][0][1][0][RTW89_WW][4] = 58, ++ [0][0][1][0][RTW89_WW][5] = 58, ++ [0][0][1][0][RTW89_WW][6] = 58, ++ [0][0][1][0][RTW89_WW][7] = 58, ++ [0][0][1][0][RTW89_WW][8] = 58, ++ [0][0][1][0][RTW89_WW][9] = 58, ++ [0][0][1][0][RTW89_WW][10] = 58, ++ [0][0][1][0][RTW89_WW][11] = 54, ++ [0][0][1][0][RTW89_WW][12] = 50, ++ [0][0][1][0][RTW89_WW][13] = 0, ++ [0][1][1][0][RTW89_WW][0] = 46, ++ [0][1][1][0][RTW89_WW][1] = 46, ++ [0][1][1][0][RTW89_WW][2] = 46, ++ [0][1][1][0][RTW89_WW][3] = 46, ++ [0][1][1][0][RTW89_WW][4] = 46, ++ [0][1][1][0][RTW89_WW][5] = 46, ++ [0][1][1][0][RTW89_WW][6] = 46, ++ [0][1][1][0][RTW89_WW][7] = 46, ++ [0][1][1][0][RTW89_WW][8] = 46, ++ [0][1][1][0][RTW89_WW][9] = 46, ++ [0][1][1][0][RTW89_WW][10] = 46, ++ [0][1][1][0][RTW89_WW][11] = 46, ++ [0][1][1][0][RTW89_WW][12] = 42, ++ [0][1][1][0][RTW89_WW][13] = 0, ++ [0][0][2][0][RTW89_WW][0] = 58, ++ [0][0][2][0][RTW89_WW][1] = 58, ++ [0][0][2][0][RTW89_WW][2] = 58, ++ [0][0][2][0][RTW89_WW][3] = 58, ++ [0][0][2][0][RTW89_WW][4] = 58, ++ [0][0][2][0][RTW89_WW][5] = 58, ++ [0][0][2][0][RTW89_WW][6] = 58, ++ [0][0][2][0][RTW89_WW][7] = 58, ++ [0][0][2][0][RTW89_WW][8] = 58, ++ [0][0][2][0][RTW89_WW][9] = 58, ++ [0][0][2][0][RTW89_WW][10] = 58, ++ [0][0][2][0][RTW89_WW][11] = 54, ++ [0][0][2][0][RTW89_WW][12] = 50, ++ [0][0][2][0][RTW89_WW][13] = 0, ++ [0][1][2][0][RTW89_WW][0] = 46, ++ [0][1][2][0][RTW89_WW][1] = 46, ++ [0][1][2][0][RTW89_WW][2] = 46, ++ [0][1][2][0][RTW89_WW][3] = 46, ++ [0][1][2][0][RTW89_WW][4] = 46, ++ [0][1][2][0][RTW89_WW][5] = 46, ++ [0][1][2][0][RTW89_WW][6] = 46, ++ [0][1][2][0][RTW89_WW][7] = 46, ++ [0][1][2][0][RTW89_WW][8] = 46, ++ [0][1][2][0][RTW89_WW][9] = 46, ++ [0][1][2][0][RTW89_WW][10] = 46, ++ [0][1][2][0][RTW89_WW][11] = 46, ++ [0][1][2][0][RTW89_WW][12] = 42, ++ [0][1][2][0][RTW89_WW][13] = 0, ++ [0][1][2][1][RTW89_WW][0] = 34, ++ [0][1][2][1][RTW89_WW][1] = 34, ++ [0][1][2][1][RTW89_WW][2] = 34, ++ [0][1][2][1][RTW89_WW][3] = 34, ++ [0][1][2][1][RTW89_WW][4] = 34, ++ [0][1][2][1][RTW89_WW][5] = 34, ++ [0][1][2][1][RTW89_WW][6] = 34, ++ [0][1][2][1][RTW89_WW][7] = 34, ++ [0][1][2][1][RTW89_WW][8] = 34, ++ [0][1][2][1][RTW89_WW][9] = 34, ++ [0][1][2][1][RTW89_WW][10] = 34, ++ [0][1][2][1][RTW89_WW][11] = 34, ++ [0][1][2][1][RTW89_WW][12] = 34, ++ [0][1][2][1][RTW89_WW][13] = 0, ++ [1][0][2][0][RTW89_WW][0] = 0, ++ [1][0][2][0][RTW89_WW][1] = 0, ++ [1][0][2][0][RTW89_WW][2] = 58, ++ [1][0][2][0][RTW89_WW][3] = 58, ++ [1][0][2][0][RTW89_WW][4] = 58, ++ [1][0][2][0][RTW89_WW][5] = 58, ++ [1][0][2][0][RTW89_WW][6] = 58, ++ [1][0][2][0][RTW89_WW][7] = 58, ++ [1][0][2][0][RTW89_WW][8] = 58, ++ [1][0][2][0][RTW89_WW][9] = 58, ++ [1][0][2][0][RTW89_WW][10] = 58, ++ [1][0][2][0][RTW89_WW][11] = 0, ++ [1][0][2][0][RTW89_WW][12] = 0, ++ [1][0][2][0][RTW89_WW][13] = 0, ++ [1][1][2][0][RTW89_WW][0] = 0, ++ [1][1][2][0][RTW89_WW][1] = 0, ++ [1][1][2][0][RTW89_WW][2] = 46, ++ [1][1][2][0][RTW89_WW][3] = 46, ++ [1][1][2][0][RTW89_WW][4] = 46, ++ [1][1][2][0][RTW89_WW][5] = 46, ++ [1][1][2][0][RTW89_WW][6] = 46, ++ [1][1][2][0][RTW89_WW][7] = 46, ++ [1][1][2][0][RTW89_WW][8] = 46, ++ [1][1][2][0][RTW89_WW][9] = 42, ++ [1][1][2][0][RTW89_WW][10] = 38, ++ [1][1][2][0][RTW89_WW][11] = 0, ++ [1][1][2][0][RTW89_WW][12] = 0, ++ [1][1][2][0][RTW89_WW][13] = 0, ++ [1][1][2][1][RTW89_WW][0] = 0, ++ [1][1][2][1][RTW89_WW][1] = 0, ++ [1][1][2][1][RTW89_WW][2] = 34, ++ [1][1][2][1][RTW89_WW][3] = 34, ++ [1][1][2][1][RTW89_WW][4] = 34, ++ [1][1][2][1][RTW89_WW][5] = 34, ++ [1][1][2][1][RTW89_WW][6] = 34, ++ [1][1][2][1][RTW89_WW][7] = 34, ++ [1][1][2][1][RTW89_WW][8] = 34, ++ [1][1][2][1][RTW89_WW][9] = 34, ++ [1][1][2][1][RTW89_WW][10] = 34, ++ [1][1][2][1][RTW89_WW][11] = 0, ++ [1][1][2][1][RTW89_WW][12] = 0, ++ [1][1][2][1][RTW89_WW][13] = 0, ++ [0][0][0][0][RTW89_FCC][0] = 78, ++ [0][0][0][0][RTW89_ETSI][0] = 58, ++ [0][0][0][0][RTW89_MKK][0] = 68, ++ [0][0][0][0][RTW89_IC][0] = 78, ++ [0][0][0][0][RTW89_KCC][0] = 68, ++ [0][0][0][0][RTW89_ACMA][0] = 58, ++ [0][0][0][0][RTW89_CHILE][0] = 64, ++ [0][0][0][0][RTW89_UKRAINE][0] = 58, ++ [0][0][0][0][RTW89_MEXICO][0] = 78, ++ [0][0][0][0][RTW89_CN][0] = 58, ++ [0][0][0][0][RTW89_QATAR][0] = 58, ++ [0][0][0][0][RTW89_UK][0] = 58, ++ [0][0][0][0][RTW89_FCC][1] = 78, ++ [0][0][0][0][RTW89_ETSI][1] = 58, ++ [0][0][0][0][RTW89_MKK][1] = 68, ++ [0][0][0][0][RTW89_IC][1] = 78, ++ [0][0][0][0][RTW89_KCC][1] = 68, ++ [0][0][0][0][RTW89_ACMA][1] = 58, ++ [0][0][0][0][RTW89_CHILE][1] = 64, ++ [0][0][0][0][RTW89_UKRAINE][1] = 58, ++ [0][0][0][0][RTW89_MEXICO][1] = 78, ++ [0][0][0][0][RTW89_CN][1] = 58, ++ [0][0][0][0][RTW89_QATAR][1] = 58, ++ [0][0][0][0][RTW89_UK][1] = 58, ++ [0][0][0][0][RTW89_FCC][2] = 78, ++ [0][0][0][0][RTW89_ETSI][2] = 58, ++ [0][0][0][0][RTW89_MKK][2] = 68, ++ [0][0][0][0][RTW89_IC][2] = 78, ++ [0][0][0][0][RTW89_KCC][2] = 68, ++ [0][0][0][0][RTW89_ACMA][2] = 58, ++ [0][0][0][0][RTW89_CHILE][2] = 64, ++ [0][0][0][0][RTW89_UKRAINE][2] = 58, ++ [0][0][0][0][RTW89_MEXICO][2] = 78, ++ [0][0][0][0][RTW89_CN][2] = 58, ++ [0][0][0][0][RTW89_QATAR][2] = 58, ++ [0][0][0][0][RTW89_UK][2] = 58, ++ [0][0][0][0][RTW89_FCC][3] = 78, ++ [0][0][0][0][RTW89_ETSI][3] = 58, ++ [0][0][0][0][RTW89_MKK][3] = 68, ++ [0][0][0][0][RTW89_IC][3] = 78, ++ [0][0][0][0][RTW89_KCC][3] = 68, ++ [0][0][0][0][RTW89_ACMA][3] = 58, ++ [0][0][0][0][RTW89_CHILE][3] = 64, ++ [0][0][0][0][RTW89_UKRAINE][3] = 58, ++ [0][0][0][0][RTW89_MEXICO][3] = 78, ++ [0][0][0][0][RTW89_CN][3] = 58, ++ [0][0][0][0][RTW89_QATAR][3] = 58, ++ [0][0][0][0][RTW89_UK][3] = 58, ++ [0][0][0][0][RTW89_FCC][4] = 78, ++ [0][0][0][0][RTW89_ETSI][4] = 58, ++ [0][0][0][0][RTW89_MKK][4] = 68, ++ [0][0][0][0][RTW89_IC][4] = 78, ++ [0][0][0][0][RTW89_KCC][4] = 70, ++ [0][0][0][0][RTW89_ACMA][4] = 58, ++ [0][0][0][0][RTW89_CHILE][4] = 64, ++ [0][0][0][0][RTW89_UKRAINE][4] = 58, ++ [0][0][0][0][RTW89_MEXICO][4] = 78, ++ [0][0][0][0][RTW89_CN][4] = 58, ++ [0][0][0][0][RTW89_QATAR][4] = 58, ++ [0][0][0][0][RTW89_UK][4] = 58, ++ [0][0][0][0][RTW89_FCC][5] = 78, ++ [0][0][0][0][RTW89_ETSI][5] = 58, ++ [0][0][0][0][RTW89_MKK][5] = 68, ++ [0][0][0][0][RTW89_IC][5] = 78, ++ [0][0][0][0][RTW89_KCC][5] = 70, ++ [0][0][0][0][RTW89_ACMA][5] = 58, ++ [0][0][0][0][RTW89_CHILE][5] = 64, ++ [0][0][0][0][RTW89_UKRAINE][5] = 58, ++ [0][0][0][0][RTW89_MEXICO][5] = 78, ++ [0][0][0][0][RTW89_CN][5] = 58, ++ [0][0][0][0][RTW89_QATAR][5] = 58, ++ [0][0][0][0][RTW89_UK][5] = 58, ++ [0][0][0][0][RTW89_FCC][6] = 78, ++ [0][0][0][0][RTW89_ETSI][6] = 58, ++ [0][0][0][0][RTW89_MKK][6] = 68, ++ [0][0][0][0][RTW89_IC][6] = 78, ++ [0][0][0][0][RTW89_KCC][6] = 70, ++ [0][0][0][0][RTW89_ACMA][6] = 58, ++ [0][0][0][0][RTW89_CHILE][6] = 64, ++ [0][0][0][0][RTW89_UKRAINE][6] = 58, ++ [0][0][0][0][RTW89_MEXICO][6] = 78, ++ [0][0][0][0][RTW89_CN][6] = 58, ++ [0][0][0][0][RTW89_QATAR][6] = 58, ++ [0][0][0][0][RTW89_UK][6] = 58, ++ [0][0][0][0][RTW89_FCC][7] = 78, ++ [0][0][0][0][RTW89_ETSI][7] = 58, ++ [0][0][0][0][RTW89_MKK][7] = 68, ++ [0][0][0][0][RTW89_IC][7] = 78, ++ [0][0][0][0][RTW89_KCC][7] = 70, ++ [0][0][0][0][RTW89_ACMA][7] = 58, ++ [0][0][0][0][RTW89_CHILE][7] = 64, ++ [0][0][0][0][RTW89_UKRAINE][7] = 58, ++ [0][0][0][0][RTW89_MEXICO][7] = 78, ++ [0][0][0][0][RTW89_CN][7] = 58, ++ [0][0][0][0][RTW89_QATAR][7] = 58, ++ [0][0][0][0][RTW89_UK][7] = 58, ++ [0][0][0][0][RTW89_FCC][8] = 78, ++ [0][0][0][0][RTW89_ETSI][8] = 58, ++ [0][0][0][0][RTW89_MKK][8] = 68, ++ [0][0][0][0][RTW89_IC][8] = 78, ++ [0][0][0][0][RTW89_KCC][8] = 70, ++ [0][0][0][0][RTW89_ACMA][8] = 58, ++ [0][0][0][0][RTW89_CHILE][8] = 64, ++ [0][0][0][0][RTW89_UKRAINE][8] = 58, ++ [0][0][0][0][RTW89_MEXICO][8] = 78, ++ [0][0][0][0][RTW89_CN][8] = 58, ++ [0][0][0][0][RTW89_QATAR][8] = 58, ++ [0][0][0][0][RTW89_UK][8] = 58, ++ [0][0][0][0][RTW89_FCC][9] = 78, ++ [0][0][0][0][RTW89_ETSI][9] = 58, ++ [0][0][0][0][RTW89_MKK][9] = 68, ++ [0][0][0][0][RTW89_IC][9] = 78, ++ [0][0][0][0][RTW89_KCC][9] = 70, ++ [0][0][0][0][RTW89_ACMA][9] = 58, ++ [0][0][0][0][RTW89_CHILE][9] = 64, ++ [0][0][0][0][RTW89_UKRAINE][9] = 58, ++ [0][0][0][0][RTW89_MEXICO][9] = 78, ++ [0][0][0][0][RTW89_CN][9] = 58, ++ [0][0][0][0][RTW89_QATAR][9] = 58, ++ [0][0][0][0][RTW89_UK][9] = 58, ++ [0][0][0][0][RTW89_FCC][10] = 78, ++ [0][0][0][0][RTW89_ETSI][10] = 58, ++ [0][0][0][0][RTW89_MKK][10] = 68, ++ [0][0][0][0][RTW89_IC][10] = 78, ++ [0][0][0][0][RTW89_KCC][10] = 70, ++ [0][0][0][0][RTW89_ACMA][10] = 58, ++ [0][0][0][0][RTW89_CHILE][10] = 66, ++ [0][0][0][0][RTW89_UKRAINE][10] = 58, ++ [0][0][0][0][RTW89_MEXICO][10] = 78, ++ [0][0][0][0][RTW89_CN][10] = 58, ++ [0][0][0][0][RTW89_QATAR][10] = 58, ++ [0][0][0][0][RTW89_UK][10] = 58, ++ [0][0][0][0][RTW89_FCC][11] = 70, ++ [0][0][0][0][RTW89_ETSI][11] = 58, ++ [0][0][0][0][RTW89_MKK][11] = 68, ++ [0][0][0][0][RTW89_IC][11] = 70, ++ [0][0][0][0][RTW89_KCC][11] = 70, ++ [0][0][0][0][RTW89_ACMA][11] = 58, ++ [0][0][0][0][RTW89_CHILE][11] = 64, ++ [0][0][0][0][RTW89_UKRAINE][11] = 58, ++ [0][0][0][0][RTW89_MEXICO][11] = 70, ++ [0][0][0][0][RTW89_CN][11] = 58, ++ [0][0][0][0][RTW89_QATAR][11] = 58, ++ [0][0][0][0][RTW89_UK][11] = 58, ++ [0][0][0][0][RTW89_FCC][12] = 56, ++ [0][0][0][0][RTW89_ETSI][12] = 58, ++ [0][0][0][0][RTW89_MKK][12] = 68, ++ [0][0][0][0][RTW89_IC][12] = 56, ++ [0][0][0][0][RTW89_KCC][12] = 70, ++ [0][0][0][0][RTW89_ACMA][12] = 58, ++ [0][0][0][0][RTW89_CHILE][12] = 56, ++ [0][0][0][0][RTW89_UKRAINE][12] = 58, ++ [0][0][0][0][RTW89_MEXICO][12] = 56, ++ [0][0][0][0][RTW89_CN][12] = 58, ++ [0][0][0][0][RTW89_QATAR][12] = 58, ++ [0][0][0][0][RTW89_UK][12] = 58, ++ [0][0][0][0][RTW89_FCC][13] = 127, ++ [0][0][0][0][RTW89_ETSI][13] = 127, ++ [0][0][0][0][RTW89_MKK][13] = 76, ++ [0][0][0][0][RTW89_IC][13] = 127, ++ [0][0][0][0][RTW89_KCC][13] = 127, ++ [0][0][0][0][RTW89_ACMA][13] = 127, ++ [0][0][0][0][RTW89_CHILE][13] = 127, ++ [0][0][0][0][RTW89_UKRAINE][13] = 127, ++ [0][0][0][0][RTW89_MEXICO][13] = 127, ++ [0][0][0][0][RTW89_CN][13] = 127, ++ [0][0][0][0][RTW89_QATAR][13] = 127, ++ [0][0][0][0][RTW89_UK][13] = 127, ++ [0][1][0][0][RTW89_FCC][0] = 74, ++ [0][1][0][0][RTW89_ETSI][0] = 46, ++ [0][1][0][0][RTW89_MKK][0] = 56, ++ [0][1][0][0][RTW89_IC][0] = 74, ++ [0][1][0][0][RTW89_KCC][0] = 58, ++ [0][1][0][0][RTW89_ACMA][0] = 46, ++ [0][1][0][0][RTW89_CHILE][0] = 50, ++ [0][1][0][0][RTW89_UKRAINE][0] = 46, ++ [0][1][0][0][RTW89_MEXICO][0] = 74, ++ [0][1][0][0][RTW89_CN][0] = 46, ++ [0][1][0][0][RTW89_QATAR][0] = 46, ++ [0][1][0][0][RTW89_UK][0] = 46, ++ [0][1][0][0][RTW89_FCC][1] = 74, ++ [0][1][0][0][RTW89_ETSI][1] = 46, ++ [0][1][0][0][RTW89_MKK][1] = 56, ++ [0][1][0][0][RTW89_IC][1] = 74, ++ [0][1][0][0][RTW89_KCC][1] = 58, ++ [0][1][0][0][RTW89_ACMA][1] = 46, ++ [0][1][0][0][RTW89_CHILE][1] = 50, ++ [0][1][0][0][RTW89_UKRAINE][1] = 46, ++ [0][1][0][0][RTW89_MEXICO][1] = 74, ++ [0][1][0][0][RTW89_CN][1] = 46, ++ [0][1][0][0][RTW89_QATAR][1] = 46, ++ [0][1][0][0][RTW89_UK][1] = 46, ++ [0][1][0][0][RTW89_FCC][2] = 74, ++ [0][1][0][0][RTW89_ETSI][2] = 46, ++ [0][1][0][0][RTW89_MKK][2] = 56, ++ [0][1][0][0][RTW89_IC][2] = 74, ++ [0][1][0][0][RTW89_KCC][2] = 58, ++ [0][1][0][0][RTW89_ACMA][2] = 46, ++ [0][1][0][0][RTW89_CHILE][2] = 50, ++ [0][1][0][0][RTW89_UKRAINE][2] = 46, ++ [0][1][0][0][RTW89_MEXICO][2] = 74, ++ [0][1][0][0][RTW89_CN][2] = 46, ++ [0][1][0][0][RTW89_QATAR][2] = 46, ++ [0][1][0][0][RTW89_UK][2] = 46, ++ [0][1][0][0][RTW89_FCC][3] = 74, ++ [0][1][0][0][RTW89_ETSI][3] = 46, ++ [0][1][0][0][RTW89_MKK][3] = 56, ++ [0][1][0][0][RTW89_IC][3] = 74, ++ [0][1][0][0][RTW89_KCC][3] = 58, ++ [0][1][0][0][RTW89_ACMA][3] = 46, ++ [0][1][0][0][RTW89_CHILE][3] = 50, ++ [0][1][0][0][RTW89_UKRAINE][3] = 46, ++ [0][1][0][0][RTW89_MEXICO][3] = 74, ++ [0][1][0][0][RTW89_CN][3] = 46, ++ [0][1][0][0][RTW89_QATAR][3] = 46, ++ [0][1][0][0][RTW89_UK][3] = 46, ++ [0][1][0][0][RTW89_FCC][4] = 74, ++ [0][1][0][0][RTW89_ETSI][4] = 46, ++ [0][1][0][0][RTW89_MKK][4] = 56, ++ [0][1][0][0][RTW89_IC][4] = 74, ++ [0][1][0][0][RTW89_KCC][4] = 56, ++ [0][1][0][0][RTW89_ACMA][4] = 46, ++ [0][1][0][0][RTW89_CHILE][4] = 50, ++ [0][1][0][0][RTW89_UKRAINE][4] = 46, ++ [0][1][0][0][RTW89_MEXICO][4] = 74, ++ [0][1][0][0][RTW89_CN][4] = 46, ++ [0][1][0][0][RTW89_QATAR][4] = 46, ++ [0][1][0][0][RTW89_UK][4] = 46, ++ [0][1][0][0][RTW89_FCC][5] = 74, ++ [0][1][0][0][RTW89_ETSI][5] = 46, ++ [0][1][0][0][RTW89_MKK][5] = 56, ++ [0][1][0][0][RTW89_IC][5] = 74, ++ [0][1][0][0][RTW89_KCC][5] = 56, ++ [0][1][0][0][RTW89_ACMA][5] = 46, ++ [0][1][0][0][RTW89_CHILE][5] = 50, ++ [0][1][0][0][RTW89_UKRAINE][5] = 46, ++ [0][1][0][0][RTW89_MEXICO][5] = 74, ++ [0][1][0][0][RTW89_CN][5] = 46, ++ [0][1][0][0][RTW89_QATAR][5] = 46, ++ [0][1][0][0][RTW89_UK][5] = 46, ++ [0][1][0][0][RTW89_FCC][6] = 74, ++ [0][1][0][0][RTW89_ETSI][6] = 46, ++ [0][1][0][0][RTW89_MKK][6] = 56, ++ [0][1][0][0][RTW89_IC][6] = 74, ++ [0][1][0][0][RTW89_KCC][6] = 56, ++ [0][1][0][0][RTW89_ACMA][6] = 46, ++ [0][1][0][0][RTW89_CHILE][6] = 52, ++ [0][1][0][0][RTW89_UKRAINE][6] = 46, ++ [0][1][0][0][RTW89_MEXICO][6] = 74, ++ [0][1][0][0][RTW89_CN][6] = 46, ++ [0][1][0][0][RTW89_QATAR][6] = 46, ++ [0][1][0][0][RTW89_UK][6] = 46, ++ [0][1][0][0][RTW89_FCC][7] = 74, ++ [0][1][0][0][RTW89_ETSI][7] = 46, ++ [0][1][0][0][RTW89_MKK][7] = 56, ++ [0][1][0][0][RTW89_IC][7] = 74, ++ [0][1][0][0][RTW89_KCC][7] = 56, ++ [0][1][0][0][RTW89_ACMA][7] = 46, ++ [0][1][0][0][RTW89_CHILE][7] = 50, ++ [0][1][0][0][RTW89_UKRAINE][7] = 46, ++ [0][1][0][0][RTW89_MEXICO][7] = 74, ++ [0][1][0][0][RTW89_CN][7] = 46, ++ [0][1][0][0][RTW89_QATAR][7] = 46, ++ [0][1][0][0][RTW89_UK][7] = 46, ++ [0][1][0][0][RTW89_FCC][8] = 74, ++ [0][1][0][0][RTW89_ETSI][8] = 46, ++ [0][1][0][0][RTW89_MKK][8] = 56, ++ [0][1][0][0][RTW89_IC][8] = 74, ++ [0][1][0][0][RTW89_KCC][8] = 56, ++ [0][1][0][0][RTW89_ACMA][8] = 46, ++ [0][1][0][0][RTW89_CHILE][8] = 50, ++ [0][1][0][0][RTW89_UKRAINE][8] = 46, ++ [0][1][0][0][RTW89_MEXICO][8] = 74, ++ [0][1][0][0][RTW89_CN][8] = 46, ++ [0][1][0][0][RTW89_QATAR][8] = 46, ++ [0][1][0][0][RTW89_UK][8] = 46, ++ [0][1][0][0][RTW89_FCC][9] = 74, ++ [0][1][0][0][RTW89_ETSI][9] = 46, ++ [0][1][0][0][RTW89_MKK][9] = 56, ++ [0][1][0][0][RTW89_IC][9] = 74, ++ [0][1][0][0][RTW89_KCC][9] = 54, ++ [0][1][0][0][RTW89_ACMA][9] = 46, ++ [0][1][0][0][RTW89_CHILE][9] = 50, ++ [0][1][0][0][RTW89_UKRAINE][9] = 46, ++ [0][1][0][0][RTW89_MEXICO][9] = 74, ++ [0][1][0][0][RTW89_CN][9] = 46, ++ [0][1][0][0][RTW89_QATAR][9] = 46, ++ [0][1][0][0][RTW89_UK][9] = 46, ++ [0][1][0][0][RTW89_FCC][10] = 74, ++ [0][1][0][0][RTW89_ETSI][10] = 46, ++ [0][1][0][0][RTW89_MKK][10] = 56, ++ [0][1][0][0][RTW89_IC][10] = 74, ++ [0][1][0][0][RTW89_KCC][10] = 54, ++ [0][1][0][0][RTW89_ACMA][10] = 46, ++ [0][1][0][0][RTW89_CHILE][10] = 52, ++ [0][1][0][0][RTW89_UKRAINE][10] = 46, ++ [0][1][0][0][RTW89_MEXICO][10] = 74, ++ [0][1][0][0][RTW89_CN][10] = 46, ++ [0][1][0][0][RTW89_QATAR][10] = 46, ++ [0][1][0][0][RTW89_UK][10] = 46, ++ [0][1][0][0][RTW89_FCC][11] = 54, ++ [0][1][0][0][RTW89_ETSI][11] = 46, ++ [0][1][0][0][RTW89_MKK][11] = 56, ++ [0][1][0][0][RTW89_IC][11] = 54, ++ [0][1][0][0][RTW89_KCC][11] = 54, ++ [0][1][0][0][RTW89_ACMA][11] = 46, ++ [0][1][0][0][RTW89_CHILE][11] = 50, ++ [0][1][0][0][RTW89_UKRAINE][11] = 46, ++ [0][1][0][0][RTW89_MEXICO][11] = 54, ++ [0][1][0][0][RTW89_CN][11] = 46, ++ [0][1][0][0][RTW89_QATAR][11] = 46, ++ [0][1][0][0][RTW89_UK][11] = 46, ++ [0][1][0][0][RTW89_FCC][12] = 42, ++ [0][1][0][0][RTW89_ETSI][12] = 46, ++ [0][1][0][0][RTW89_MKK][12] = 56, ++ [0][1][0][0][RTW89_IC][12] = 42, ++ [0][1][0][0][RTW89_KCC][12] = 54, ++ [0][1][0][0][RTW89_ACMA][12] = 46, ++ [0][1][0][0][RTW89_CHILE][12] = 42, ++ [0][1][0][0][RTW89_UKRAINE][12] = 46, ++ [0][1][0][0][RTW89_MEXICO][12] = 42, ++ [0][1][0][0][RTW89_CN][12] = 46, ++ [0][1][0][0][RTW89_QATAR][12] = 46, ++ [0][1][0][0][RTW89_UK][12] = 46, ++ [0][1][0][0][RTW89_FCC][13] = 127, ++ [0][1][0][0][RTW89_ETSI][13] = 127, ++ [0][1][0][0][RTW89_MKK][13] = 64, ++ [0][1][0][0][RTW89_IC][13] = 127, ++ [0][1][0][0][RTW89_KCC][13] = 127, ++ [0][1][0][0][RTW89_ACMA][13] = 127, ++ [0][1][0][0][RTW89_CHILE][13] = 127, ++ [0][1][0][0][RTW89_UKRAINE][13] = 127, ++ [0][1][0][0][RTW89_MEXICO][13] = 127, ++ [0][1][0][0][RTW89_CN][13] = 127, ++ [0][1][0][0][RTW89_QATAR][13] = 127, ++ [0][1][0][0][RTW89_UK][13] = 127, ++ [1][0][0][0][RTW89_FCC][0] = 127, ++ [1][0][0][0][RTW89_ETSI][0] = 127, ++ [1][0][0][0][RTW89_MKK][0] = 127, ++ [1][0][0][0][RTW89_IC][0] = 127, ++ [1][0][0][0][RTW89_KCC][0] = 127, ++ [1][0][0][0][RTW89_ACMA][0] = 127, ++ [1][0][0][0][RTW89_CHILE][0] = 127, ++ [1][0][0][0][RTW89_UKRAINE][0] = 127, ++ [1][0][0][0][RTW89_MEXICO][0] = 127, ++ [1][0][0][0][RTW89_CN][0] = 127, ++ [1][0][0][0][RTW89_QATAR][0] = 127, ++ [1][0][0][0][RTW89_UK][0] = 127, ++ [1][0][0][0][RTW89_FCC][1] = 127, ++ [1][0][0][0][RTW89_ETSI][1] = 127, ++ [1][0][0][0][RTW89_MKK][1] = 127, ++ [1][0][0][0][RTW89_IC][1] = 127, ++ [1][0][0][0][RTW89_KCC][1] = 127, ++ [1][0][0][0][RTW89_ACMA][1] = 127, ++ [1][0][0][0][RTW89_CHILE][1] = 127, ++ [1][0][0][0][RTW89_UKRAINE][1] = 127, ++ [1][0][0][0][RTW89_MEXICO][1] = 127, ++ [1][0][0][0][RTW89_CN][1] = 127, ++ [1][0][0][0][RTW89_QATAR][1] = 127, ++ [1][0][0][0][RTW89_UK][1] = 127, ++ [1][0][0][0][RTW89_FCC][2] = 50, ++ [1][0][0][0][RTW89_ETSI][2] = 58, ++ [1][0][0][0][RTW89_MKK][2] = 76, ++ [1][0][0][0][RTW89_IC][2] = 50, ++ [1][0][0][0][RTW89_KCC][2] = 70, ++ [1][0][0][0][RTW89_ACMA][2] = 58, ++ [1][0][0][0][RTW89_CHILE][2] = 62, ++ [1][0][0][0][RTW89_UKRAINE][2] = 58, ++ [1][0][0][0][RTW89_MEXICO][2] = 50, ++ [1][0][0][0][RTW89_CN][2] = 58, ++ [1][0][0][0][RTW89_QATAR][2] = 58, ++ [1][0][0][0][RTW89_UK][2] = 58, ++ [1][0][0][0][RTW89_FCC][3] = 50, ++ [1][0][0][0][RTW89_ETSI][3] = 58, ++ [1][0][0][0][RTW89_MKK][3] = 76, ++ [1][0][0][0][RTW89_IC][3] = 50, ++ [1][0][0][0][RTW89_KCC][3] = 70, ++ [1][0][0][0][RTW89_ACMA][3] = 58, ++ [1][0][0][0][RTW89_CHILE][3] = 62, ++ [1][0][0][0][RTW89_UKRAINE][3] = 58, ++ [1][0][0][0][RTW89_MEXICO][3] = 50, ++ [1][0][0][0][RTW89_CN][3] = 58, ++ [1][0][0][0][RTW89_QATAR][3] = 58, ++ [1][0][0][0][RTW89_UK][3] = 58, ++ [1][0][0][0][RTW89_FCC][4] = 50, ++ [1][0][0][0][RTW89_ETSI][4] = 58, ++ [1][0][0][0][RTW89_MKK][4] = 76, ++ [1][0][0][0][RTW89_IC][4] = 50, ++ [1][0][0][0][RTW89_KCC][4] = 70, ++ [1][0][0][0][RTW89_ACMA][4] = 58, ++ [1][0][0][0][RTW89_CHILE][4] = 62, ++ [1][0][0][0][RTW89_UKRAINE][4] = 58, ++ [1][0][0][0][RTW89_MEXICO][4] = 50, ++ [1][0][0][0][RTW89_CN][4] = 58, ++ [1][0][0][0][RTW89_QATAR][4] = 58, ++ [1][0][0][0][RTW89_UK][4] = 58, ++ [1][0][0][0][RTW89_FCC][5] = 66, ++ [1][0][0][0][RTW89_ETSI][5] = 58, ++ [1][0][0][0][RTW89_MKK][5] = 76, ++ [1][0][0][0][RTW89_IC][5] = 66, ++ [1][0][0][0][RTW89_KCC][5] = 70, ++ [1][0][0][0][RTW89_ACMA][5] = 58, ++ [1][0][0][0][RTW89_CHILE][5] = 62, ++ [1][0][0][0][RTW89_UKRAINE][5] = 58, ++ [1][0][0][0][RTW89_MEXICO][5] = 66, ++ [1][0][0][0][RTW89_CN][5] = 58, ++ [1][0][0][0][RTW89_QATAR][5] = 58, ++ [1][0][0][0][RTW89_UK][5] = 58, ++ [1][0][0][0][RTW89_FCC][6] = 50, ++ [1][0][0][0][RTW89_ETSI][6] = 58, ++ [1][0][0][0][RTW89_MKK][6] = 76, ++ [1][0][0][0][RTW89_IC][6] = 50, ++ [1][0][0][0][RTW89_KCC][6] = 70, ++ [1][0][0][0][RTW89_ACMA][6] = 58, ++ [1][0][0][0][RTW89_CHILE][6] = 62, ++ [1][0][0][0][RTW89_UKRAINE][6] = 58, ++ [1][0][0][0][RTW89_MEXICO][6] = 50, ++ [1][0][0][0][RTW89_CN][6] = 58, ++ [1][0][0][0][RTW89_QATAR][6] = 58, ++ [1][0][0][0][RTW89_UK][6] = 58, ++ [1][0][0][0][RTW89_FCC][7] = 50, ++ [1][0][0][0][RTW89_ETSI][7] = 58, ++ [1][0][0][0][RTW89_MKK][7] = 76, ++ [1][0][0][0][RTW89_IC][7] = 50, ++ [1][0][0][0][RTW89_KCC][7] = 70, ++ [1][0][0][0][RTW89_ACMA][7] = 58, ++ [1][0][0][0][RTW89_CHILE][7] = 62, ++ [1][0][0][0][RTW89_UKRAINE][7] = 58, ++ [1][0][0][0][RTW89_MEXICO][7] = 50, ++ [1][0][0][0][RTW89_CN][7] = 58, ++ [1][0][0][0][RTW89_QATAR][7] = 58, ++ [1][0][0][0][RTW89_UK][7] = 58, ++ [1][0][0][0][RTW89_FCC][8] = 50, ++ [1][0][0][0][RTW89_ETSI][8] = 58, ++ [1][0][0][0][RTW89_MKK][8] = 76, ++ [1][0][0][0][RTW89_IC][8] = 50, ++ [1][0][0][0][RTW89_KCC][8] = 70, ++ [1][0][0][0][RTW89_ACMA][8] = 58, ++ [1][0][0][0][RTW89_CHILE][8] = 62, ++ [1][0][0][0][RTW89_UKRAINE][8] = 58, ++ [1][0][0][0][RTW89_MEXICO][8] = 50, ++ [1][0][0][0][RTW89_CN][8] = 58, ++ [1][0][0][0][RTW89_QATAR][8] = 58, ++ [1][0][0][0][RTW89_UK][8] = 58, ++ [1][0][0][0][RTW89_FCC][9] = 42, ++ [1][0][0][0][RTW89_ETSI][9] = 58, ++ [1][0][0][0][RTW89_MKK][9] = 76, ++ [1][0][0][0][RTW89_IC][9] = 42, ++ [1][0][0][0][RTW89_KCC][9] = 70, ++ [1][0][0][0][RTW89_ACMA][9] = 58, ++ [1][0][0][0][RTW89_CHILE][9] = 42, ++ [1][0][0][0][RTW89_UKRAINE][9] = 58, ++ [1][0][0][0][RTW89_MEXICO][9] = 42, ++ [1][0][0][0][RTW89_CN][9] = 58, ++ [1][0][0][0][RTW89_QATAR][9] = 58, ++ [1][0][0][0][RTW89_UK][9] = 58, ++ [1][0][0][0][RTW89_FCC][10] = 30, ++ [1][0][0][0][RTW89_ETSI][10] = 58, ++ [1][0][0][0][RTW89_MKK][10] = 72, ++ [1][0][0][0][RTW89_IC][10] = 30, ++ [1][0][0][0][RTW89_KCC][10] = 70, ++ [1][0][0][0][RTW89_ACMA][10] = 58, ++ [1][0][0][0][RTW89_CHILE][10] = 30, ++ [1][0][0][0][RTW89_UKRAINE][10] = 58, ++ [1][0][0][0][RTW89_MEXICO][10] = 30, ++ [1][0][0][0][RTW89_CN][10] = 58, ++ [1][0][0][0][RTW89_QATAR][10] = 58, ++ [1][0][0][0][RTW89_UK][10] = 58, ++ [1][0][0][0][RTW89_FCC][11] = 127, ++ [1][0][0][0][RTW89_ETSI][11] = 127, ++ [1][0][0][0][RTW89_MKK][11] = 127, ++ [1][0][0][0][RTW89_IC][11] = 127, ++ [1][0][0][0][RTW89_KCC][11] = 127, ++ [1][0][0][0][RTW89_ACMA][11] = 127, ++ [1][0][0][0][RTW89_CHILE][11] = 127, ++ [1][0][0][0][RTW89_UKRAINE][11] = 127, ++ [1][0][0][0][RTW89_MEXICO][11] = 127, ++ [1][0][0][0][RTW89_CN][11] = 127, ++ [1][0][0][0][RTW89_QATAR][11] = 127, ++ [1][0][0][0][RTW89_UK][11] = 127, ++ [1][0][0][0][RTW89_FCC][12] = 127, ++ [1][0][0][0][RTW89_ETSI][12] = 127, ++ [1][0][0][0][RTW89_MKK][12] = 127, ++ [1][0][0][0][RTW89_IC][12] = 127, ++ [1][0][0][0][RTW89_KCC][12] = 127, ++ [1][0][0][0][RTW89_ACMA][12] = 127, ++ [1][0][0][0][RTW89_CHILE][12] = 127, ++ [1][0][0][0][RTW89_UKRAINE][12] = 127, ++ [1][0][0][0][RTW89_MEXICO][12] = 127, ++ [1][0][0][0][RTW89_CN][12] = 127, ++ [1][0][0][0][RTW89_QATAR][12] = 127, ++ [1][0][0][0][RTW89_UK][12] = 127, ++ [1][0][0][0][RTW89_FCC][13] = 127, ++ [1][0][0][0][RTW89_ETSI][13] = 127, ++ [1][0][0][0][RTW89_MKK][13] = 127, ++ [1][0][0][0][RTW89_IC][13] = 127, ++ [1][0][0][0][RTW89_KCC][13] = 127, ++ [1][0][0][0][RTW89_ACMA][13] = 127, ++ [1][0][0][0][RTW89_CHILE][13] = 127, ++ [1][0][0][0][RTW89_UKRAINE][13] = 127, ++ [1][0][0][0][RTW89_MEXICO][13] = 127, ++ [1][0][0][0][RTW89_CN][13] = 127, ++ [1][0][0][0][RTW89_QATAR][13] = 127, ++ [1][0][0][0][RTW89_UK][13] = 127, ++ [1][1][0][0][RTW89_FCC][0] = 127, ++ [1][1][0][0][RTW89_ETSI][0] = 127, ++ [1][1][0][0][RTW89_MKK][0] = 127, ++ [1][1][0][0][RTW89_IC][0] = 127, ++ [1][1][0][0][RTW89_KCC][0] = 127, ++ [1][1][0][0][RTW89_ACMA][0] = 127, ++ [1][1][0][0][RTW89_CHILE][0] = 127, ++ [1][1][0][0][RTW89_UKRAINE][0] = 127, ++ [1][1][0][0][RTW89_MEXICO][0] = 127, ++ [1][1][0][0][RTW89_CN][0] = 127, ++ [1][1][0][0][RTW89_QATAR][0] = 127, ++ [1][1][0][0][RTW89_UK][0] = 127, ++ [1][1][0][0][RTW89_FCC][1] = 127, ++ [1][1][0][0][RTW89_ETSI][1] = 127, ++ [1][1][0][0][RTW89_MKK][1] = 127, ++ [1][1][0][0][RTW89_IC][1] = 127, ++ [1][1][0][0][RTW89_KCC][1] = 127, ++ [1][1][0][0][RTW89_ACMA][1] = 127, ++ [1][1][0][0][RTW89_CHILE][1] = 127, ++ [1][1][0][0][RTW89_UKRAINE][1] = 127, ++ [1][1][0][0][RTW89_MEXICO][1] = 127, ++ [1][1][0][0][RTW89_CN][1] = 127, ++ [1][1][0][0][RTW89_QATAR][1] = 127, ++ [1][1][0][0][RTW89_UK][1] = 127, ++ [1][1][0][0][RTW89_FCC][2] = 46, ++ [1][1][0][0][RTW89_ETSI][2] = 46, ++ [1][1][0][0][RTW89_MKK][2] = 64, ++ [1][1][0][0][RTW89_IC][2] = 46, ++ [1][1][0][0][RTW89_KCC][2] = 58, ++ [1][1][0][0][RTW89_ACMA][2] = 46, ++ [1][1][0][0][RTW89_CHILE][2] = 50, ++ [1][1][0][0][RTW89_UKRAINE][2] = 46, ++ [1][1][0][0][RTW89_MEXICO][2] = 46, ++ [1][1][0][0][RTW89_CN][2] = 46, ++ [1][1][0][0][RTW89_QATAR][2] = 46, ++ [1][1][0][0][RTW89_UK][2] = 46, ++ [1][1][0][0][RTW89_FCC][3] = 46, ++ [1][1][0][0][RTW89_ETSI][3] = 46, ++ [1][1][0][0][RTW89_MKK][3] = 64, ++ [1][1][0][0][RTW89_IC][3] = 46, ++ [1][1][0][0][RTW89_KCC][3] = 58, ++ [1][1][0][0][RTW89_ACMA][3] = 46, ++ [1][1][0][0][RTW89_CHILE][3] = 50, ++ [1][1][0][0][RTW89_UKRAINE][3] = 46, ++ [1][1][0][0][RTW89_MEXICO][3] = 46, ++ [1][1][0][0][RTW89_CN][3] = 46, ++ [1][1][0][0][RTW89_QATAR][3] = 46, ++ [1][1][0][0][RTW89_UK][3] = 46, ++ [1][1][0][0][RTW89_FCC][4] = 46, ++ [1][1][0][0][RTW89_ETSI][4] = 46, ++ [1][1][0][0][RTW89_MKK][4] = 64, ++ [1][1][0][0][RTW89_IC][4] = 46, ++ [1][1][0][0][RTW89_KCC][4] = 58, ++ [1][1][0][0][RTW89_ACMA][4] = 46, ++ [1][1][0][0][RTW89_CHILE][4] = 50, ++ [1][1][0][0][RTW89_UKRAINE][4] = 46, ++ [1][1][0][0][RTW89_MEXICO][4] = 46, ++ [1][1][0][0][RTW89_CN][4] = 46, ++ [1][1][0][0][RTW89_QATAR][4] = 46, ++ [1][1][0][0][RTW89_UK][4] = 46, ++ [1][1][0][0][RTW89_FCC][5] = 62, ++ [1][1][0][0][RTW89_ETSI][5] = 46, ++ [1][1][0][0][RTW89_MKK][5] = 64, ++ [1][1][0][0][RTW89_IC][5] = 62, ++ [1][1][0][0][RTW89_KCC][5] = 58, ++ [1][1][0][0][RTW89_ACMA][5] = 46, ++ [1][1][0][0][RTW89_CHILE][5] = 50, ++ [1][1][0][0][RTW89_UKRAINE][5] = 46, ++ [1][1][0][0][RTW89_MEXICO][5] = 62, ++ [1][1][0][0][RTW89_CN][5] = 46, ++ [1][1][0][0][RTW89_QATAR][5] = 46, ++ [1][1][0][0][RTW89_UK][5] = 46, ++ [1][1][0][0][RTW89_FCC][6] = 34, ++ [1][1][0][0][RTW89_ETSI][6] = 46, ++ [1][1][0][0][RTW89_MKK][6] = 64, ++ [1][1][0][0][RTW89_IC][6] = 34, ++ [1][1][0][0][RTW89_KCC][6] = 58, ++ [1][1][0][0][RTW89_ACMA][6] = 46, ++ [1][1][0][0][RTW89_CHILE][6] = 50, ++ [1][1][0][0][RTW89_UKRAINE][6] = 46, ++ [1][1][0][0][RTW89_MEXICO][6] = 34, ++ [1][1][0][0][RTW89_CN][6] = 46, ++ [1][1][0][0][RTW89_QATAR][6] = 46, ++ [1][1][0][0][RTW89_UK][6] = 46, ++ [1][1][0][0][RTW89_FCC][7] = 34, ++ [1][1][0][0][RTW89_ETSI][7] = 46, ++ [1][1][0][0][RTW89_MKK][7] = 64, ++ [1][1][0][0][RTW89_IC][7] = 34, ++ [1][1][0][0][RTW89_KCC][7] = 58, ++ [1][1][0][0][RTW89_ACMA][7] = 46, ++ [1][1][0][0][RTW89_CHILE][7] = 50, ++ [1][1][0][0][RTW89_UKRAINE][7] = 46, ++ [1][1][0][0][RTW89_MEXICO][7] = 34, ++ [1][1][0][0][RTW89_CN][7] = 46, ++ [1][1][0][0][RTW89_QATAR][7] = 46, ++ [1][1][0][0][RTW89_UK][7] = 46, ++ [1][1][0][0][RTW89_FCC][8] = 34, ++ [1][1][0][0][RTW89_ETSI][8] = 46, ++ [1][1][0][0][RTW89_MKK][8] = 64, ++ [1][1][0][0][RTW89_IC][8] = 34, ++ [1][1][0][0][RTW89_KCC][8] = 58, ++ [1][1][0][0][RTW89_ACMA][8] = 46, ++ [1][1][0][0][RTW89_CHILE][8] = 50, ++ [1][1][0][0][RTW89_UKRAINE][8] = 46, ++ [1][1][0][0][RTW89_MEXICO][8] = 34, ++ [1][1][0][0][RTW89_CN][8] = 46, ++ [1][1][0][0][RTW89_QATAR][8] = 46, ++ [1][1][0][0][RTW89_UK][8] = 46, ++ [1][1][0][0][RTW89_FCC][9] = 30, ++ [1][1][0][0][RTW89_ETSI][9] = 46, ++ [1][1][0][0][RTW89_MKK][9] = 64, ++ [1][1][0][0][RTW89_IC][9] = 30, ++ [1][1][0][0][RTW89_KCC][9] = 58, ++ [1][1][0][0][RTW89_ACMA][9] = 46, ++ [1][1][0][0][RTW89_CHILE][9] = 30, ++ [1][1][0][0][RTW89_UKRAINE][9] = 46, ++ [1][1][0][0][RTW89_MEXICO][9] = 30, ++ [1][1][0][0][RTW89_CN][9] = 46, ++ [1][1][0][0][RTW89_QATAR][9] = 46, ++ [1][1][0][0][RTW89_UK][9] = 46, ++ [1][1][0][0][RTW89_FCC][10] = 30, ++ [1][1][0][0][RTW89_ETSI][10] = 46, ++ [1][1][0][0][RTW89_MKK][10] = 64, ++ [1][1][0][0][RTW89_IC][10] = 30, ++ [1][1][0][0][RTW89_KCC][10] = 58, ++ [1][1][0][0][RTW89_ACMA][10] = 46, ++ [1][1][0][0][RTW89_CHILE][10] = 30, ++ [1][1][0][0][RTW89_UKRAINE][10] = 46, ++ [1][1][0][0][RTW89_MEXICO][10] = 30, ++ [1][1][0][0][RTW89_CN][10] = 46, ++ [1][1][0][0][RTW89_QATAR][10] = 46, ++ [1][1][0][0][RTW89_UK][10] = 46, ++ [1][1][0][0][RTW89_FCC][11] = 127, ++ [1][1][0][0][RTW89_ETSI][11] = 127, ++ [1][1][0][0][RTW89_MKK][11] = 127, ++ [1][1][0][0][RTW89_IC][11] = 127, ++ [1][1][0][0][RTW89_KCC][11] = 127, ++ [1][1][0][0][RTW89_ACMA][11] = 127, ++ [1][1][0][0][RTW89_CHILE][11] = 127, ++ [1][1][0][0][RTW89_UKRAINE][11] = 127, ++ [1][1][0][0][RTW89_MEXICO][11] = 127, ++ [1][1][0][0][RTW89_CN][11] = 127, ++ [1][1][0][0][RTW89_QATAR][11] = 127, ++ [1][1][0][0][RTW89_UK][11] = 127, ++ [1][1][0][0][RTW89_FCC][12] = 127, ++ [1][1][0][0][RTW89_ETSI][12] = 127, ++ [1][1][0][0][RTW89_MKK][12] = 127, ++ [1][1][0][0][RTW89_IC][12] = 127, ++ [1][1][0][0][RTW89_KCC][12] = 127, ++ [1][1][0][0][RTW89_ACMA][12] = 127, ++ [1][1][0][0][RTW89_CHILE][12] = 127, ++ [1][1][0][0][RTW89_UKRAINE][12] = 127, ++ [1][1][0][0][RTW89_MEXICO][12] = 127, ++ [1][1][0][0][RTW89_CN][12] = 127, ++ [1][1][0][0][RTW89_QATAR][12] = 127, ++ [1][1][0][0][RTW89_UK][12] = 127, ++ [1][1][0][0][RTW89_FCC][13] = 127, ++ [1][1][0][0][RTW89_ETSI][13] = 127, ++ [1][1][0][0][RTW89_MKK][13] = 127, ++ [1][1][0][0][RTW89_IC][13] = 127, ++ [1][1][0][0][RTW89_KCC][13] = 127, ++ [1][1][0][0][RTW89_ACMA][13] = 127, ++ [1][1][0][0][RTW89_CHILE][13] = 127, ++ [1][1][0][0][RTW89_UKRAINE][13] = 127, ++ [1][1][0][0][RTW89_MEXICO][13] = 127, ++ [1][1][0][0][RTW89_CN][13] = 127, ++ [1][1][0][0][RTW89_QATAR][13] = 127, ++ [1][1][0][0][RTW89_UK][13] = 127, ++ [0][0][1][0][RTW89_FCC][0] = 76, ++ [0][0][1][0][RTW89_ETSI][0] = 58, ++ [0][0][1][0][RTW89_MKK][0] = 74, ++ [0][0][1][0][RTW89_IC][0] = 76, ++ [0][0][1][0][RTW89_KCC][0] = 76, ++ [0][0][1][0][RTW89_ACMA][0] = 58, ++ [0][0][1][0][RTW89_CHILE][0] = 66, ++ [0][0][1][0][RTW89_UKRAINE][0] = 58, ++ [0][0][1][0][RTW89_MEXICO][0] = 76, ++ [0][0][1][0][RTW89_CN][0] = 58, ++ [0][0][1][0][RTW89_QATAR][0] = 58, ++ [0][0][1][0][RTW89_UK][0] = 58, ++ [0][0][1][0][RTW89_FCC][1] = 76, ++ [0][0][1][0][RTW89_ETSI][1] = 58, ++ [0][0][1][0][RTW89_MKK][1] = 76, ++ [0][0][1][0][RTW89_IC][1] = 76, ++ [0][0][1][0][RTW89_KCC][1] = 76, ++ [0][0][1][0][RTW89_ACMA][1] = 58, ++ [0][0][1][0][RTW89_CHILE][1] = 66, ++ [0][0][1][0][RTW89_UKRAINE][1] = 58, ++ [0][0][1][0][RTW89_MEXICO][1] = 76, ++ [0][0][1][0][RTW89_CN][1] = 58, ++ [0][0][1][0][RTW89_QATAR][1] = 58, ++ [0][0][1][0][RTW89_UK][1] = 58, ++ [0][0][1][0][RTW89_FCC][2] = 78, ++ [0][0][1][0][RTW89_ETSI][2] = 58, ++ [0][0][1][0][RTW89_MKK][2] = 76, ++ [0][0][1][0][RTW89_IC][2] = 78, ++ [0][0][1][0][RTW89_KCC][2] = 76, ++ [0][0][1][0][RTW89_ACMA][2] = 58, ++ [0][0][1][0][RTW89_CHILE][2] = 66, ++ [0][0][1][0][RTW89_UKRAINE][2] = 58, ++ [0][0][1][0][RTW89_MEXICO][2] = 78, ++ [0][0][1][0][RTW89_CN][2] = 58, ++ [0][0][1][0][RTW89_QATAR][2] = 58, ++ [0][0][1][0][RTW89_UK][2] = 58, ++ [0][0][1][0][RTW89_FCC][3] = 78, ++ [0][0][1][0][RTW89_ETSI][3] = 58, ++ [0][0][1][0][RTW89_MKK][3] = 76, ++ [0][0][1][0][RTW89_IC][3] = 78, ++ [0][0][1][0][RTW89_KCC][3] = 76, ++ [0][0][1][0][RTW89_ACMA][3] = 58, ++ [0][0][1][0][RTW89_CHILE][3] = 66, ++ [0][0][1][0][RTW89_UKRAINE][3] = 58, ++ [0][0][1][0][RTW89_MEXICO][3] = 78, ++ [0][0][1][0][RTW89_CN][3] = 58, ++ [0][0][1][0][RTW89_QATAR][3] = 58, ++ [0][0][1][0][RTW89_UK][3] = 58, ++ [0][0][1][0][RTW89_FCC][4] = 78, ++ [0][0][1][0][RTW89_ETSI][4] = 58, ++ [0][0][1][0][RTW89_MKK][4] = 76, ++ [0][0][1][0][RTW89_IC][4] = 78, ++ [0][0][1][0][RTW89_KCC][4] = 76, ++ [0][0][1][0][RTW89_ACMA][4] = 58, ++ [0][0][1][0][RTW89_CHILE][4] = 66, ++ [0][0][1][0][RTW89_UKRAINE][4] = 58, ++ [0][0][1][0][RTW89_MEXICO][4] = 78, ++ [0][0][1][0][RTW89_CN][4] = 58, ++ [0][0][1][0][RTW89_QATAR][4] = 58, ++ [0][0][1][0][RTW89_UK][4] = 58, ++ [0][0][1][0][RTW89_FCC][5] = 78, ++ [0][0][1][0][RTW89_ETSI][5] = 58, ++ [0][0][1][0][RTW89_MKK][5] = 76, ++ [0][0][1][0][RTW89_IC][5] = 78, ++ [0][0][1][0][RTW89_KCC][5] = 76, ++ [0][0][1][0][RTW89_ACMA][5] = 58, ++ [0][0][1][0][RTW89_CHILE][5] = 66, ++ [0][0][1][0][RTW89_UKRAINE][5] = 58, ++ [0][0][1][0][RTW89_MEXICO][5] = 78, ++ [0][0][1][0][RTW89_CN][5] = 58, ++ [0][0][1][0][RTW89_QATAR][5] = 58, ++ [0][0][1][0][RTW89_UK][5] = 58, ++ [0][0][1][0][RTW89_FCC][6] = 78, ++ [0][0][1][0][RTW89_ETSI][6] = 58, ++ [0][0][1][0][RTW89_MKK][6] = 76, ++ [0][0][1][0][RTW89_IC][6] = 78, ++ [0][0][1][0][RTW89_KCC][6] = 76, ++ [0][0][1][0][RTW89_ACMA][6] = 58, ++ [0][0][1][0][RTW89_CHILE][6] = 66, ++ [0][0][1][0][RTW89_UKRAINE][6] = 58, ++ [0][0][1][0][RTW89_MEXICO][6] = 78, ++ [0][0][1][0][RTW89_CN][6] = 58, ++ [0][0][1][0][RTW89_QATAR][6] = 58, ++ [0][0][1][0][RTW89_UK][6] = 58, ++ [0][0][1][0][RTW89_FCC][7] = 78, ++ [0][0][1][0][RTW89_ETSI][7] = 58, ++ [0][0][1][0][RTW89_MKK][7] = 76, ++ [0][0][1][0][RTW89_IC][7] = 78, ++ [0][0][1][0][RTW89_KCC][7] = 76, ++ [0][0][1][0][RTW89_ACMA][7] = 58, ++ [0][0][1][0][RTW89_CHILE][7] = 66, ++ [0][0][1][0][RTW89_UKRAINE][7] = 58, ++ [0][0][1][0][RTW89_MEXICO][7] = 78, ++ [0][0][1][0][RTW89_CN][7] = 58, ++ [0][0][1][0][RTW89_QATAR][7] = 58, ++ [0][0][1][0][RTW89_UK][7] = 58, ++ [0][0][1][0][RTW89_FCC][8] = 78, ++ [0][0][1][0][RTW89_ETSI][8] = 58, ++ [0][0][1][0][RTW89_MKK][8] = 76, ++ [0][0][1][0][RTW89_IC][8] = 78, ++ [0][0][1][0][RTW89_KCC][8] = 76, ++ [0][0][1][0][RTW89_ACMA][8] = 58, ++ [0][0][1][0][RTW89_CHILE][8] = 66, ++ [0][0][1][0][RTW89_UKRAINE][8] = 58, ++ [0][0][1][0][RTW89_MEXICO][8] = 78, ++ [0][0][1][0][RTW89_CN][8] = 58, ++ [0][0][1][0][RTW89_QATAR][8] = 58, ++ [0][0][1][0][RTW89_UK][8] = 58, ++ [0][0][1][0][RTW89_FCC][9] = 74, ++ [0][0][1][0][RTW89_ETSI][9] = 58, ++ [0][0][1][0][RTW89_MKK][9] = 76, ++ [0][0][1][0][RTW89_IC][9] = 74, ++ [0][0][1][0][RTW89_KCC][9] = 76, ++ [0][0][1][0][RTW89_ACMA][9] = 58, ++ [0][0][1][0][RTW89_CHILE][9] = 66, ++ [0][0][1][0][RTW89_UKRAINE][9] = 58, ++ [0][0][1][0][RTW89_MEXICO][9] = 74, ++ [0][0][1][0][RTW89_CN][9] = 58, ++ [0][0][1][0][RTW89_QATAR][9] = 58, ++ [0][0][1][0][RTW89_UK][9] = 58, ++ [0][0][1][0][RTW89_FCC][10] = 74, ++ [0][0][1][0][RTW89_ETSI][10] = 58, ++ [0][0][1][0][RTW89_MKK][10] = 76, ++ [0][0][1][0][RTW89_IC][10] = 74, ++ [0][0][1][0][RTW89_KCC][10] = 76, ++ [0][0][1][0][RTW89_ACMA][10] = 58, ++ [0][0][1][0][RTW89_CHILE][10] = 66, ++ [0][0][1][0][RTW89_UKRAINE][10] = 58, ++ [0][0][1][0][RTW89_MEXICO][10] = 74, ++ [0][0][1][0][RTW89_CN][10] = 58, ++ [0][0][1][0][RTW89_QATAR][10] = 58, ++ [0][0][1][0][RTW89_UK][10] = 58, ++ [0][0][1][0][RTW89_FCC][11] = 54, ++ [0][0][1][0][RTW89_ETSI][11] = 58, ++ [0][0][1][0][RTW89_MKK][11] = 76, ++ [0][0][1][0][RTW89_IC][11] = 54, ++ [0][0][1][0][RTW89_KCC][11] = 76, ++ [0][0][1][0][RTW89_ACMA][11] = 58, ++ [0][0][1][0][RTW89_CHILE][11] = 54, ++ [0][0][1][0][RTW89_UKRAINE][11] = 58, ++ [0][0][1][0][RTW89_MEXICO][11] = 54, ++ [0][0][1][0][RTW89_CN][11] = 58, ++ [0][0][1][0][RTW89_QATAR][11] = 58, ++ [0][0][1][0][RTW89_UK][11] = 58, ++ [0][0][1][0][RTW89_FCC][12] = 50, ++ [0][0][1][0][RTW89_ETSI][12] = 58, ++ [0][0][1][0][RTW89_MKK][12] = 76, ++ [0][0][1][0][RTW89_IC][12] = 50, ++ [0][0][1][0][RTW89_KCC][12] = 76, ++ [0][0][1][0][RTW89_ACMA][12] = 58, ++ [0][0][1][0][RTW89_CHILE][12] = 50, ++ [0][0][1][0][RTW89_UKRAINE][12] = 58, ++ [0][0][1][0][RTW89_MEXICO][12] = 50, ++ [0][0][1][0][RTW89_CN][12] = 58, ++ [0][0][1][0][RTW89_QATAR][12] = 58, ++ [0][0][1][0][RTW89_UK][12] = 58, ++ [0][0][1][0][RTW89_FCC][13] = 127, ++ [0][0][1][0][RTW89_ETSI][13] = 127, ++ [0][0][1][0][RTW89_MKK][13] = 127, ++ [0][0][1][0][RTW89_IC][13] = 127, ++ [0][0][1][0][RTW89_KCC][13] = 127, ++ [0][0][1][0][RTW89_ACMA][13] = 127, ++ [0][0][1][0][RTW89_CHILE][13] = 127, ++ [0][0][1][0][RTW89_UKRAINE][13] = 127, ++ [0][0][1][0][RTW89_MEXICO][13] = 127, ++ [0][0][1][0][RTW89_CN][13] = 127, ++ [0][0][1][0][RTW89_QATAR][13] = 127, ++ [0][0][1][0][RTW89_UK][13] = 127, ++ [0][1][1][0][RTW89_FCC][0] = 62, ++ [0][1][1][0][RTW89_ETSI][0] = 46, ++ [0][1][1][0][RTW89_MKK][0] = 64, ++ [0][1][1][0][RTW89_IC][0] = 62, ++ [0][1][1][0][RTW89_KCC][0] = 66, ++ [0][1][1][0][RTW89_ACMA][0] = 46, ++ [0][1][1][0][RTW89_CHILE][0] = 50, ++ [0][1][1][0][RTW89_UKRAINE][0] = 46, ++ [0][1][1][0][RTW89_MEXICO][0] = 62, ++ [0][1][1][0][RTW89_CN][0] = 46, ++ [0][1][1][0][RTW89_QATAR][0] = 46, ++ [0][1][1][0][RTW89_UK][0] = 46, ++ [0][1][1][0][RTW89_FCC][1] = 62, ++ [0][1][1][0][RTW89_ETSI][1] = 46, ++ [0][1][1][0][RTW89_MKK][1] = 64, ++ [0][1][1][0][RTW89_IC][1] = 62, ++ [0][1][1][0][RTW89_KCC][1] = 66, ++ [0][1][1][0][RTW89_ACMA][1] = 46, ++ [0][1][1][0][RTW89_CHILE][1] = 50, ++ [0][1][1][0][RTW89_UKRAINE][1] = 46, ++ [0][1][1][0][RTW89_MEXICO][1] = 62, ++ [0][1][1][0][RTW89_CN][1] = 46, ++ [0][1][1][0][RTW89_QATAR][1] = 46, ++ [0][1][1][0][RTW89_UK][1] = 46, ++ [0][1][1][0][RTW89_FCC][2] = 66, ++ [0][1][1][0][RTW89_ETSI][2] = 46, ++ [0][1][1][0][RTW89_MKK][2] = 64, ++ [0][1][1][0][RTW89_IC][2] = 66, ++ [0][1][1][0][RTW89_KCC][2] = 66, ++ [0][1][1][0][RTW89_ACMA][2] = 46, ++ [0][1][1][0][RTW89_CHILE][2] = 50, ++ [0][1][1][0][RTW89_UKRAINE][2] = 46, ++ [0][1][1][0][RTW89_MEXICO][2] = 66, ++ [0][1][1][0][RTW89_CN][2] = 46, ++ [0][1][1][0][RTW89_QATAR][2] = 46, ++ [0][1][1][0][RTW89_UK][2] = 46, ++ [0][1][1][0][RTW89_FCC][3] = 70, ++ [0][1][1][0][RTW89_ETSI][3] = 46, ++ [0][1][1][0][RTW89_MKK][3] = 64, ++ [0][1][1][0][RTW89_IC][3] = 70, ++ [0][1][1][0][RTW89_KCC][3] = 66, ++ [0][1][1][0][RTW89_ACMA][3] = 46, ++ [0][1][1][0][RTW89_CHILE][3] = 50, ++ [0][1][1][0][RTW89_UKRAINE][3] = 46, ++ [0][1][1][0][RTW89_MEXICO][3] = 70, ++ [0][1][1][0][RTW89_CN][3] = 46, ++ [0][1][1][0][RTW89_QATAR][3] = 46, ++ [0][1][1][0][RTW89_UK][3] = 46, ++ [0][1][1][0][RTW89_FCC][4] = 78, ++ [0][1][1][0][RTW89_ETSI][4] = 46, ++ [0][1][1][0][RTW89_MKK][4] = 64, ++ [0][1][1][0][RTW89_IC][4] = 78, ++ [0][1][1][0][RTW89_KCC][4] = 64, ++ [0][1][1][0][RTW89_ACMA][4] = 46, ++ [0][1][1][0][RTW89_CHILE][4] = 50, ++ [0][1][1][0][RTW89_UKRAINE][4] = 46, ++ [0][1][1][0][RTW89_MEXICO][4] = 78, ++ [0][1][1][0][RTW89_CN][4] = 46, ++ [0][1][1][0][RTW89_QATAR][4] = 46, ++ [0][1][1][0][RTW89_UK][4] = 46, ++ [0][1][1][0][RTW89_FCC][5] = 78, ++ [0][1][1][0][RTW89_ETSI][5] = 46, ++ [0][1][1][0][RTW89_MKK][5] = 64, ++ [0][1][1][0][RTW89_IC][5] = 78, ++ [0][1][1][0][RTW89_KCC][5] = 64, ++ [0][1][1][0][RTW89_ACMA][5] = 46, ++ [0][1][1][0][RTW89_CHILE][5] = 50, ++ [0][1][1][0][RTW89_UKRAINE][5] = 46, ++ [0][1][1][0][RTW89_MEXICO][5] = 78, ++ [0][1][1][0][RTW89_CN][5] = 46, ++ [0][1][1][0][RTW89_QATAR][5] = 46, ++ [0][1][1][0][RTW89_UK][5] = 46, ++ [0][1][1][0][RTW89_FCC][6] = 78, ++ [0][1][1][0][RTW89_ETSI][6] = 46, ++ [0][1][1][0][RTW89_MKK][6] = 64, ++ [0][1][1][0][RTW89_IC][6] = 78, ++ [0][1][1][0][RTW89_KCC][6] = 64, ++ [0][1][1][0][RTW89_ACMA][6] = 46, ++ [0][1][1][0][RTW89_CHILE][6] = 50, ++ [0][1][1][0][RTW89_UKRAINE][6] = 46, ++ [0][1][1][0][RTW89_MEXICO][6] = 78, ++ [0][1][1][0][RTW89_CN][6] = 46, ++ [0][1][1][0][RTW89_QATAR][6] = 46, ++ [0][1][1][0][RTW89_UK][6] = 46, ++ [0][1][1][0][RTW89_FCC][7] = 70, ++ [0][1][1][0][RTW89_ETSI][7] = 46, ++ [0][1][1][0][RTW89_MKK][7] = 64, ++ [0][1][1][0][RTW89_IC][7] = 70, ++ [0][1][1][0][RTW89_KCC][7] = 64, ++ [0][1][1][0][RTW89_ACMA][7] = 46, ++ [0][1][1][0][RTW89_CHILE][7] = 50, ++ [0][1][1][0][RTW89_UKRAINE][7] = 46, ++ [0][1][1][0][RTW89_MEXICO][7] = 70, ++ [0][1][1][0][RTW89_CN][7] = 46, ++ [0][1][1][0][RTW89_QATAR][7] = 46, ++ [0][1][1][0][RTW89_UK][7] = 46, ++ [0][1][1][0][RTW89_FCC][8] = 66, ++ [0][1][1][0][RTW89_ETSI][8] = 46, ++ [0][1][1][0][RTW89_MKK][8] = 64, ++ [0][1][1][0][RTW89_IC][8] = 66, ++ [0][1][1][0][RTW89_KCC][8] = 64, ++ [0][1][1][0][RTW89_ACMA][8] = 46, ++ [0][1][1][0][RTW89_CHILE][8] = 50, ++ [0][1][1][0][RTW89_UKRAINE][8] = 46, ++ [0][1][1][0][RTW89_MEXICO][8] = 66, ++ [0][1][1][0][RTW89_CN][8] = 46, ++ [0][1][1][0][RTW89_QATAR][8] = 46, ++ [0][1][1][0][RTW89_UK][8] = 46, ++ [0][1][1][0][RTW89_FCC][9] = 62, ++ [0][1][1][0][RTW89_ETSI][9] = 46, ++ [0][1][1][0][RTW89_MKK][9] = 64, ++ [0][1][1][0][RTW89_IC][9] = 62, ++ [0][1][1][0][RTW89_KCC][9] = 64, ++ [0][1][1][0][RTW89_ACMA][9] = 46, ++ [0][1][1][0][RTW89_CHILE][9] = 50, ++ [0][1][1][0][RTW89_UKRAINE][9] = 46, ++ [0][1][1][0][RTW89_MEXICO][9] = 62, ++ [0][1][1][0][RTW89_CN][9] = 46, ++ [0][1][1][0][RTW89_QATAR][9] = 46, ++ [0][1][1][0][RTW89_UK][9] = 46, ++ [0][1][1][0][RTW89_FCC][10] = 62, ++ [0][1][1][0][RTW89_ETSI][10] = 46, ++ [0][1][1][0][RTW89_MKK][10] = 64, ++ [0][1][1][0][RTW89_IC][10] = 62, ++ [0][1][1][0][RTW89_KCC][10] = 64, ++ [0][1][1][0][RTW89_ACMA][10] = 46, ++ [0][1][1][0][RTW89_CHILE][10] = 52, ++ [0][1][1][0][RTW89_UKRAINE][10] = 46, ++ [0][1][1][0][RTW89_MEXICO][10] = 62, ++ [0][1][1][0][RTW89_CN][10] = 46, ++ [0][1][1][0][RTW89_QATAR][10] = 46, ++ [0][1][1][0][RTW89_UK][10] = 46, ++ [0][1][1][0][RTW89_FCC][11] = 46, ++ [0][1][1][0][RTW89_ETSI][11] = 46, ++ [0][1][1][0][RTW89_MKK][11] = 64, ++ [0][1][1][0][RTW89_IC][11] = 46, ++ [0][1][1][0][RTW89_KCC][11] = 64, ++ [0][1][1][0][RTW89_ACMA][11] = 46, ++ [0][1][1][0][RTW89_CHILE][11] = 46, ++ [0][1][1][0][RTW89_UKRAINE][11] = 46, ++ [0][1][1][0][RTW89_MEXICO][11] = 46, ++ [0][1][1][0][RTW89_CN][11] = 46, ++ [0][1][1][0][RTW89_QATAR][11] = 46, ++ [0][1][1][0][RTW89_UK][11] = 46, ++ [0][1][1][0][RTW89_FCC][12] = 42, ++ [0][1][1][0][RTW89_ETSI][12] = 46, ++ [0][1][1][0][RTW89_MKK][12] = 64, ++ [0][1][1][0][RTW89_IC][12] = 42, ++ [0][1][1][0][RTW89_KCC][12] = 64, ++ [0][1][1][0][RTW89_ACMA][12] = 46, ++ [0][1][1][0][RTW89_CHILE][12] = 42, ++ [0][1][1][0][RTW89_UKRAINE][12] = 46, ++ [0][1][1][0][RTW89_MEXICO][12] = 42, ++ [0][1][1][0][RTW89_CN][12] = 46, ++ [0][1][1][0][RTW89_QATAR][12] = 46, ++ [0][1][1][0][RTW89_UK][12] = 46, ++ [0][1][1][0][RTW89_FCC][13] = 127, ++ [0][1][1][0][RTW89_ETSI][13] = 127, ++ [0][1][1][0][RTW89_MKK][13] = 127, ++ [0][1][1][0][RTW89_IC][13] = 127, ++ [0][1][1][0][RTW89_KCC][13] = 127, ++ [0][1][1][0][RTW89_ACMA][13] = 127, ++ [0][1][1][0][RTW89_CHILE][13] = 127, ++ [0][1][1][0][RTW89_UKRAINE][13] = 127, ++ [0][1][1][0][RTW89_MEXICO][13] = 127, ++ [0][1][1][0][RTW89_CN][13] = 127, ++ [0][1][1][0][RTW89_QATAR][13] = 127, ++ [0][1][1][0][RTW89_UK][13] = 127, ++ [0][0][2][0][RTW89_FCC][0] = 76, ++ [0][0][2][0][RTW89_ETSI][0] = 58, ++ [0][0][2][0][RTW89_MKK][0] = 76, ++ [0][0][2][0][RTW89_IC][0] = 76, ++ [0][0][2][0][RTW89_KCC][0] = 76, ++ [0][0][2][0][RTW89_ACMA][0] = 58, ++ [0][0][2][0][RTW89_CHILE][0] = 66, ++ [0][0][2][0][RTW89_UKRAINE][0] = 58, ++ [0][0][2][0][RTW89_MEXICO][0] = 76, ++ [0][0][2][0][RTW89_CN][0] = 58, ++ [0][0][2][0][RTW89_QATAR][0] = 58, ++ [0][0][2][0][RTW89_UK][0] = 58, ++ [0][0][2][0][RTW89_FCC][1] = 76, ++ [0][0][2][0][RTW89_ETSI][1] = 58, ++ [0][0][2][0][RTW89_MKK][1] = 76, ++ [0][0][2][0][RTW89_IC][1] = 76, ++ [0][0][2][0][RTW89_KCC][1] = 76, ++ [0][0][2][0][RTW89_ACMA][1] = 58, ++ [0][0][2][0][RTW89_CHILE][1] = 66, ++ [0][0][2][0][RTW89_UKRAINE][1] = 58, ++ [0][0][2][0][RTW89_MEXICO][1] = 76, ++ [0][0][2][0][RTW89_CN][1] = 58, ++ [0][0][2][0][RTW89_QATAR][1] = 58, ++ [0][0][2][0][RTW89_UK][1] = 58, ++ [0][0][2][0][RTW89_FCC][2] = 78, ++ [0][0][2][0][RTW89_ETSI][2] = 58, ++ [0][0][2][0][RTW89_MKK][2] = 76, ++ [0][0][2][0][RTW89_IC][2] = 78, ++ [0][0][2][0][RTW89_KCC][2] = 76, ++ [0][0][2][0][RTW89_ACMA][2] = 58, ++ [0][0][2][0][RTW89_CHILE][2] = 66, ++ [0][0][2][0][RTW89_UKRAINE][2] = 58, ++ [0][0][2][0][RTW89_MEXICO][2] = 78, ++ [0][0][2][0][RTW89_CN][2] = 58, ++ [0][0][2][0][RTW89_QATAR][2] = 58, ++ [0][0][2][0][RTW89_UK][2] = 58, ++ [0][0][2][0][RTW89_FCC][3] = 78, ++ [0][0][2][0][RTW89_ETSI][3] = 58, ++ [0][0][2][0][RTW89_MKK][3] = 76, ++ [0][0][2][0][RTW89_IC][3] = 78, ++ [0][0][2][0][RTW89_KCC][3] = 76, ++ [0][0][2][0][RTW89_ACMA][3] = 58, ++ [0][0][2][0][RTW89_CHILE][3] = 66, ++ [0][0][2][0][RTW89_UKRAINE][3] = 58, ++ [0][0][2][0][RTW89_MEXICO][3] = 78, ++ [0][0][2][0][RTW89_CN][3] = 58, ++ [0][0][2][0][RTW89_QATAR][3] = 58, ++ [0][0][2][0][RTW89_UK][3] = 58, ++ [0][0][2][0][RTW89_FCC][4] = 78, ++ [0][0][2][0][RTW89_ETSI][4] = 58, ++ [0][0][2][0][RTW89_MKK][4] = 76, ++ [0][0][2][0][RTW89_IC][4] = 78, ++ [0][0][2][0][RTW89_KCC][4] = 76, ++ [0][0][2][0][RTW89_ACMA][4] = 58, ++ [0][0][2][0][RTW89_CHILE][4] = 66, ++ [0][0][2][0][RTW89_UKRAINE][4] = 58, ++ [0][0][2][0][RTW89_MEXICO][4] = 78, ++ [0][0][2][0][RTW89_CN][4] = 58, ++ [0][0][2][0][RTW89_QATAR][4] = 58, ++ [0][0][2][0][RTW89_UK][4] = 58, ++ [0][0][2][0][RTW89_FCC][5] = 78, ++ [0][0][2][0][RTW89_ETSI][5] = 58, ++ [0][0][2][0][RTW89_MKK][5] = 76, ++ [0][0][2][0][RTW89_IC][5] = 78, ++ [0][0][2][0][RTW89_KCC][5] = 76, ++ [0][0][2][0][RTW89_ACMA][5] = 58, ++ [0][0][2][0][RTW89_CHILE][5] = 66, ++ [0][0][2][0][RTW89_UKRAINE][5] = 58, ++ [0][0][2][0][RTW89_MEXICO][5] = 78, ++ [0][0][2][0][RTW89_CN][5] = 58, ++ [0][0][2][0][RTW89_QATAR][5] = 58, ++ [0][0][2][0][RTW89_UK][5] = 58, ++ [0][0][2][0][RTW89_FCC][6] = 78, ++ [0][0][2][0][RTW89_ETSI][6] = 58, ++ [0][0][2][0][RTW89_MKK][6] = 76, ++ [0][0][2][0][RTW89_IC][6] = 78, ++ [0][0][2][0][RTW89_KCC][6] = 76, ++ [0][0][2][0][RTW89_ACMA][6] = 58, ++ [0][0][2][0][RTW89_CHILE][6] = 66, ++ [0][0][2][0][RTW89_UKRAINE][6] = 58, ++ [0][0][2][0][RTW89_MEXICO][6] = 78, ++ [0][0][2][0][RTW89_CN][6] = 58, ++ [0][0][2][0][RTW89_QATAR][6] = 58, ++ [0][0][2][0][RTW89_UK][6] = 58, ++ [0][0][2][0][RTW89_FCC][7] = 78, ++ [0][0][2][0][RTW89_ETSI][7] = 58, ++ [0][0][2][0][RTW89_MKK][7] = 76, ++ [0][0][2][0][RTW89_IC][7] = 78, ++ [0][0][2][0][RTW89_KCC][7] = 76, ++ [0][0][2][0][RTW89_ACMA][7] = 58, ++ [0][0][2][0][RTW89_CHILE][7] = 66, ++ [0][0][2][0][RTW89_UKRAINE][7] = 58, ++ [0][0][2][0][RTW89_MEXICO][7] = 78, ++ [0][0][2][0][RTW89_CN][7] = 58, ++ [0][0][2][0][RTW89_QATAR][7] = 58, ++ [0][0][2][0][RTW89_UK][7] = 58, ++ [0][0][2][0][RTW89_FCC][8] = 76, ++ [0][0][2][0][RTW89_ETSI][8] = 58, ++ [0][0][2][0][RTW89_MKK][8] = 76, ++ [0][0][2][0][RTW89_IC][8] = 76, ++ [0][0][2][0][RTW89_KCC][8] = 76, ++ [0][0][2][0][RTW89_ACMA][8] = 58, ++ [0][0][2][0][RTW89_CHILE][8] = 66, ++ [0][0][2][0][RTW89_UKRAINE][8] = 58, ++ [0][0][2][0][RTW89_MEXICO][8] = 76, ++ [0][0][2][0][RTW89_CN][8] = 58, ++ [0][0][2][0][RTW89_QATAR][8] = 58, ++ [0][0][2][0][RTW89_UK][8] = 58, ++ [0][0][2][0][RTW89_FCC][9] = 72, ++ [0][0][2][0][RTW89_ETSI][9] = 58, ++ [0][0][2][0][RTW89_MKK][9] = 76, ++ [0][0][2][0][RTW89_IC][9] = 72, ++ [0][0][2][0][RTW89_KCC][9] = 76, ++ [0][0][2][0][RTW89_ACMA][9] = 58, ++ [0][0][2][0][RTW89_CHILE][9] = 66, ++ [0][0][2][0][RTW89_UKRAINE][9] = 58, ++ [0][0][2][0][RTW89_MEXICO][9] = 72, ++ [0][0][2][0][RTW89_CN][9] = 58, ++ [0][0][2][0][RTW89_QATAR][9] = 58, ++ [0][0][2][0][RTW89_UK][9] = 58, ++ [0][0][2][0][RTW89_FCC][10] = 72, ++ [0][0][2][0][RTW89_ETSI][10] = 58, ++ [0][0][2][0][RTW89_MKK][10] = 76, ++ [0][0][2][0][RTW89_IC][10] = 72, ++ [0][0][2][0][RTW89_KCC][10] = 76, ++ [0][0][2][0][RTW89_ACMA][10] = 58, ++ [0][0][2][0][RTW89_CHILE][10] = 66, ++ [0][0][2][0][RTW89_UKRAINE][10] = 58, ++ [0][0][2][0][RTW89_MEXICO][10] = 72, ++ [0][0][2][0][RTW89_CN][10] = 58, ++ [0][0][2][0][RTW89_QATAR][10] = 58, ++ [0][0][2][0][RTW89_UK][10] = 58, ++ [0][0][2][0][RTW89_FCC][11] = 54, ++ [0][0][2][0][RTW89_ETSI][11] = 58, ++ [0][0][2][0][RTW89_MKK][11] = 76, ++ [0][0][2][0][RTW89_IC][11] = 54, ++ [0][0][2][0][RTW89_KCC][11] = 76, ++ [0][0][2][0][RTW89_ACMA][11] = 58, ++ [0][0][2][0][RTW89_CHILE][11] = 54, ++ [0][0][2][0][RTW89_UKRAINE][11] = 58, ++ [0][0][2][0][RTW89_MEXICO][11] = 54, ++ [0][0][2][0][RTW89_CN][11] = 58, ++ [0][0][2][0][RTW89_QATAR][11] = 58, ++ [0][0][2][0][RTW89_UK][11] = 58, ++ [0][0][2][0][RTW89_FCC][12] = 50, ++ [0][0][2][0][RTW89_ETSI][12] = 58, ++ [0][0][2][0][RTW89_MKK][12] = 76, ++ [0][0][2][0][RTW89_IC][12] = 50, ++ [0][0][2][0][RTW89_KCC][12] = 76, ++ [0][0][2][0][RTW89_ACMA][12] = 58, ++ [0][0][2][0][RTW89_CHILE][12] = 50, ++ [0][0][2][0][RTW89_UKRAINE][12] = 58, ++ [0][0][2][0][RTW89_MEXICO][12] = 50, ++ [0][0][2][0][RTW89_CN][12] = 58, ++ [0][0][2][0][RTW89_QATAR][12] = 58, ++ [0][0][2][0][RTW89_UK][12] = 58, ++ [0][0][2][0][RTW89_FCC][13] = 127, ++ [0][0][2][0][RTW89_ETSI][13] = 127, ++ [0][0][2][0][RTW89_MKK][13] = 127, ++ [0][0][2][0][RTW89_IC][13] = 127, ++ [0][0][2][0][RTW89_KCC][13] = 127, ++ [0][0][2][0][RTW89_ACMA][13] = 127, ++ [0][0][2][0][RTW89_CHILE][13] = 127, ++ [0][0][2][0][RTW89_UKRAINE][13] = 127, ++ [0][0][2][0][RTW89_MEXICO][13] = 127, ++ [0][0][2][0][RTW89_CN][13] = 127, ++ [0][0][2][0][RTW89_QATAR][13] = 127, ++ [0][0][2][0][RTW89_UK][13] = 127, ++ [0][1][2][0][RTW89_FCC][0] = 58, ++ [0][1][2][0][RTW89_ETSI][0] = 46, ++ [0][1][2][0][RTW89_MKK][0] = 66, ++ [0][1][2][0][RTW89_IC][0] = 58, ++ [0][1][2][0][RTW89_KCC][0] = 62, ++ [0][1][2][0][RTW89_ACMA][0] = 46, ++ [0][1][2][0][RTW89_CHILE][0] = 50, ++ [0][1][2][0][RTW89_UKRAINE][0] = 46, ++ [0][1][2][0][RTW89_MEXICO][0] = 58, ++ [0][1][2][0][RTW89_CN][0] = 46, ++ [0][1][2][0][RTW89_QATAR][0] = 46, ++ [0][1][2][0][RTW89_UK][0] = 46, ++ [0][1][2][0][RTW89_FCC][1] = 58, ++ [0][1][2][0][RTW89_ETSI][1] = 46, ++ [0][1][2][0][RTW89_MKK][1] = 66, ++ [0][1][2][0][RTW89_IC][1] = 58, ++ [0][1][2][0][RTW89_KCC][1] = 62, ++ [0][1][2][0][RTW89_ACMA][1] = 46, ++ [0][1][2][0][RTW89_CHILE][1] = 50, ++ [0][1][2][0][RTW89_UKRAINE][1] = 46, ++ [0][1][2][0][RTW89_MEXICO][1] = 58, ++ [0][1][2][0][RTW89_CN][1] = 46, ++ [0][1][2][0][RTW89_QATAR][1] = 46, ++ [0][1][2][0][RTW89_UK][1] = 46, ++ [0][1][2][0][RTW89_FCC][2] = 62, ++ [0][1][2][0][RTW89_ETSI][2] = 46, ++ [0][1][2][0][RTW89_MKK][2] = 66, ++ [0][1][2][0][RTW89_IC][2] = 62, ++ [0][1][2][0][RTW89_KCC][2] = 62, ++ [0][1][2][0][RTW89_ACMA][2] = 46, ++ [0][1][2][0][RTW89_CHILE][2] = 50, ++ [0][1][2][0][RTW89_UKRAINE][2] = 46, ++ [0][1][2][0][RTW89_MEXICO][2] = 62, ++ [0][1][2][0][RTW89_CN][2] = 46, ++ [0][1][2][0][RTW89_QATAR][2] = 46, ++ [0][1][2][0][RTW89_UK][2] = 46, ++ [0][1][2][0][RTW89_FCC][3] = 66, ++ [0][1][2][0][RTW89_ETSI][3] = 46, ++ [0][1][2][0][RTW89_MKK][3] = 66, ++ [0][1][2][0][RTW89_IC][3] = 66, ++ [0][1][2][0][RTW89_KCC][3] = 62, ++ [0][1][2][0][RTW89_ACMA][3] = 46, ++ [0][1][2][0][RTW89_CHILE][3] = 50, ++ [0][1][2][0][RTW89_UKRAINE][3] = 46, ++ [0][1][2][0][RTW89_MEXICO][3] = 66, ++ [0][1][2][0][RTW89_CN][3] = 46, ++ [0][1][2][0][RTW89_QATAR][3] = 46, ++ [0][1][2][0][RTW89_UK][3] = 46, ++ [0][1][2][0][RTW89_FCC][4] = 72, ++ [0][1][2][0][RTW89_ETSI][4] = 46, ++ [0][1][2][0][RTW89_MKK][4] = 66, ++ [0][1][2][0][RTW89_IC][4] = 72, ++ [0][1][2][0][RTW89_KCC][4] = 62, ++ [0][1][2][0][RTW89_ACMA][4] = 46, ++ [0][1][2][0][RTW89_CHILE][4] = 50, ++ [0][1][2][0][RTW89_UKRAINE][4] = 46, ++ [0][1][2][0][RTW89_MEXICO][4] = 72, ++ [0][1][2][0][RTW89_CN][4] = 46, ++ [0][1][2][0][RTW89_QATAR][4] = 46, ++ [0][1][2][0][RTW89_UK][4] = 46, ++ [0][1][2][0][RTW89_FCC][5] = 78, ++ [0][1][2][0][RTW89_ETSI][5] = 46, ++ [0][1][2][0][RTW89_MKK][5] = 66, ++ [0][1][2][0][RTW89_IC][5] = 78, ++ [0][1][2][0][RTW89_KCC][5] = 62, ++ [0][1][2][0][RTW89_ACMA][5] = 46, ++ [0][1][2][0][RTW89_CHILE][5] = 50, ++ [0][1][2][0][RTW89_UKRAINE][5] = 46, ++ [0][1][2][0][RTW89_MEXICO][5] = 78, ++ [0][1][2][0][RTW89_CN][5] = 46, ++ [0][1][2][0][RTW89_QATAR][5] = 46, ++ [0][1][2][0][RTW89_UK][5] = 46, ++ [0][1][2][0][RTW89_FCC][6] = 74, ++ [0][1][2][0][RTW89_ETSI][6] = 46, ++ [0][1][2][0][RTW89_MKK][6] = 66, ++ [0][1][2][0][RTW89_IC][6] = 74, ++ [0][1][2][0][RTW89_KCC][6] = 62, ++ [0][1][2][0][RTW89_ACMA][6] = 46, ++ [0][1][2][0][RTW89_CHILE][6] = 50, ++ [0][1][2][0][RTW89_UKRAINE][6] = 46, ++ [0][1][2][0][RTW89_MEXICO][6] = 74, ++ [0][1][2][0][RTW89_CN][6] = 46, ++ [0][1][2][0][RTW89_QATAR][6] = 46, ++ [0][1][2][0][RTW89_UK][6] = 46, ++ [0][1][2][0][RTW89_FCC][7] = 66, ++ [0][1][2][0][RTW89_ETSI][7] = 46, ++ [0][1][2][0][RTW89_MKK][7] = 66, ++ [0][1][2][0][RTW89_IC][7] = 66, ++ [0][1][2][0][RTW89_KCC][7] = 62, ++ [0][1][2][0][RTW89_ACMA][7] = 46, ++ [0][1][2][0][RTW89_CHILE][7] = 50, ++ [0][1][2][0][RTW89_UKRAINE][7] = 46, ++ [0][1][2][0][RTW89_MEXICO][7] = 66, ++ [0][1][2][0][RTW89_CN][7] = 46, ++ [0][1][2][0][RTW89_QATAR][7] = 46, ++ [0][1][2][0][RTW89_UK][7] = 46, ++ [0][1][2][0][RTW89_FCC][8] = 62, ++ [0][1][2][0][RTW89_ETSI][8] = 46, ++ [0][1][2][0][RTW89_MKK][8] = 66, ++ [0][1][2][0][RTW89_IC][8] = 62, ++ [0][1][2][0][RTW89_KCC][8] = 62, ++ [0][1][2][0][RTW89_ACMA][8] = 46, ++ [0][1][2][0][RTW89_CHILE][8] = 50, ++ [0][1][2][0][RTW89_UKRAINE][8] = 46, ++ [0][1][2][0][RTW89_MEXICO][8] = 62, ++ [0][1][2][0][RTW89_CN][8] = 46, ++ [0][1][2][0][RTW89_QATAR][8] = 46, ++ [0][1][2][0][RTW89_UK][8] = 46, ++ [0][1][2][0][RTW89_FCC][9] = 58, ++ [0][1][2][0][RTW89_ETSI][9] = 46, ++ [0][1][2][0][RTW89_MKK][9] = 66, ++ [0][1][2][0][RTW89_IC][9] = 58, ++ [0][1][2][0][RTW89_KCC][9] = 60, ++ [0][1][2][0][RTW89_ACMA][9] = 46, ++ [0][1][2][0][RTW89_CHILE][9] = 50, ++ [0][1][2][0][RTW89_UKRAINE][9] = 46, ++ [0][1][2][0][RTW89_MEXICO][9] = 58, ++ [0][1][2][0][RTW89_CN][9] = 46, ++ [0][1][2][0][RTW89_QATAR][9] = 46, ++ [0][1][2][0][RTW89_UK][9] = 46, ++ [0][1][2][0][RTW89_FCC][10] = 58, ++ [0][1][2][0][RTW89_ETSI][10] = 46, ++ [0][1][2][0][RTW89_MKK][10] = 66, ++ [0][1][2][0][RTW89_IC][10] = 58, ++ [0][1][2][0][RTW89_KCC][10] = 60, ++ [0][1][2][0][RTW89_ACMA][10] = 46, ++ [0][1][2][0][RTW89_CHILE][10] = 50, ++ [0][1][2][0][RTW89_UKRAINE][10] = 46, ++ [0][1][2][0][RTW89_MEXICO][10] = 58, ++ [0][1][2][0][RTW89_CN][10] = 46, ++ [0][1][2][0][RTW89_QATAR][10] = 46, ++ [0][1][2][0][RTW89_UK][10] = 46, ++ [0][1][2][0][RTW89_FCC][11] = 46, ++ [0][1][2][0][RTW89_ETSI][11] = 46, ++ [0][1][2][0][RTW89_MKK][11] = 66, ++ [0][1][2][0][RTW89_IC][11] = 46, ++ [0][1][2][0][RTW89_KCC][11] = 60, ++ [0][1][2][0][RTW89_ACMA][11] = 46, ++ [0][1][2][0][RTW89_CHILE][11] = 46, ++ [0][1][2][0][RTW89_UKRAINE][11] = 46, ++ [0][1][2][0][RTW89_MEXICO][11] = 46, ++ [0][1][2][0][RTW89_CN][11] = 46, ++ [0][1][2][0][RTW89_QATAR][11] = 46, ++ [0][1][2][0][RTW89_UK][11] = 46, ++ [0][1][2][0][RTW89_FCC][12] = 42, ++ [0][1][2][0][RTW89_ETSI][12] = 46, ++ [0][1][2][0][RTW89_MKK][12] = 66, ++ [0][1][2][0][RTW89_IC][12] = 42, ++ [0][1][2][0][RTW89_KCC][12] = 60, ++ [0][1][2][0][RTW89_ACMA][12] = 46, ++ [0][1][2][0][RTW89_CHILE][12] = 42, ++ [0][1][2][0][RTW89_UKRAINE][12] = 46, ++ [0][1][2][0][RTW89_MEXICO][12] = 42, ++ [0][1][2][0][RTW89_CN][12] = 46, ++ [0][1][2][0][RTW89_QATAR][12] = 46, ++ [0][1][2][0][RTW89_UK][12] = 46, ++ [0][1][2][0][RTW89_FCC][13] = 127, ++ [0][1][2][0][RTW89_ETSI][13] = 127, ++ [0][1][2][0][RTW89_MKK][13] = 127, ++ [0][1][2][0][RTW89_IC][13] = 127, ++ [0][1][2][0][RTW89_KCC][13] = 127, ++ [0][1][2][0][RTW89_ACMA][13] = 127, ++ [0][1][2][0][RTW89_CHILE][13] = 127, ++ [0][1][2][0][RTW89_UKRAINE][13] = 127, ++ [0][1][2][0][RTW89_MEXICO][13] = 127, ++ [0][1][2][0][RTW89_CN][13] = 127, ++ [0][1][2][0][RTW89_QATAR][13] = 127, ++ [0][1][2][0][RTW89_UK][13] = 127, ++ [0][1][2][1][RTW89_FCC][0] = 58, ++ [0][1][2][1][RTW89_ETSI][0] = 34, ++ [0][1][2][1][RTW89_MKK][0] = 66, ++ [0][1][2][1][RTW89_IC][0] = 58, ++ [0][1][2][1][RTW89_KCC][0] = 62, ++ [0][1][2][1][RTW89_ACMA][0] = 34, ++ [0][1][2][1][RTW89_CHILE][0] = 42, ++ [0][1][2][1][RTW89_UKRAINE][0] = 34, ++ [0][1][2][1][RTW89_MEXICO][0] = 58, ++ [0][1][2][1][RTW89_CN][0] = 34, ++ [0][1][2][1][RTW89_QATAR][0] = 34, ++ [0][1][2][1][RTW89_UK][0] = 34, ++ [0][1][2][1][RTW89_FCC][1] = 58, ++ [0][1][2][1][RTW89_ETSI][1] = 34, ++ [0][1][2][1][RTW89_MKK][1] = 66, ++ [0][1][2][1][RTW89_IC][1] = 58, ++ [0][1][2][1][RTW89_KCC][1] = 62, ++ [0][1][2][1][RTW89_ACMA][1] = 34, ++ [0][1][2][1][RTW89_CHILE][1] = 40, ++ [0][1][2][1][RTW89_UKRAINE][1] = 34, ++ [0][1][2][1][RTW89_MEXICO][1] = 58, ++ [0][1][2][1][RTW89_CN][1] = 34, ++ [0][1][2][1][RTW89_QATAR][1] = 34, ++ [0][1][2][1][RTW89_UK][1] = 34, ++ [0][1][2][1][RTW89_FCC][2] = 62, ++ [0][1][2][1][RTW89_ETSI][2] = 34, ++ [0][1][2][1][RTW89_MKK][2] = 66, ++ [0][1][2][1][RTW89_IC][2] = 62, ++ [0][1][2][1][RTW89_KCC][2] = 62, ++ [0][1][2][1][RTW89_ACMA][2] = 34, ++ [0][1][2][1][RTW89_CHILE][2] = 40, ++ [0][1][2][1][RTW89_UKRAINE][2] = 34, ++ [0][1][2][1][RTW89_MEXICO][2] = 62, ++ [0][1][2][1][RTW89_CN][2] = 34, ++ [0][1][2][1][RTW89_QATAR][2] = 34, ++ [0][1][2][1][RTW89_UK][2] = 34, ++ [0][1][2][1][RTW89_FCC][3] = 66, ++ [0][1][2][1][RTW89_ETSI][3] = 34, ++ [0][1][2][1][RTW89_MKK][3] = 66, ++ [0][1][2][1][RTW89_IC][3] = 66, ++ [0][1][2][1][RTW89_KCC][3] = 62, ++ [0][1][2][1][RTW89_ACMA][3] = 34, ++ [0][1][2][1][RTW89_CHILE][3] = 40, ++ [0][1][2][1][RTW89_UKRAINE][3] = 34, ++ [0][1][2][1][RTW89_MEXICO][3] = 66, ++ [0][1][2][1][RTW89_CN][3] = 34, ++ [0][1][2][1][RTW89_QATAR][3] = 34, ++ [0][1][2][1][RTW89_UK][3] = 34, ++ [0][1][2][1][RTW89_FCC][4] = 72, ++ [0][1][2][1][RTW89_ETSI][4] = 34, ++ [0][1][2][1][RTW89_MKK][4] = 66, ++ [0][1][2][1][RTW89_IC][4] = 72, ++ [0][1][2][1][RTW89_KCC][4] = 62, ++ [0][1][2][1][RTW89_ACMA][4] = 34, ++ [0][1][2][1][RTW89_CHILE][4] = 40, ++ [0][1][2][1][RTW89_UKRAINE][4] = 34, ++ [0][1][2][1][RTW89_MEXICO][4] = 72, ++ [0][1][2][1][RTW89_CN][4] = 34, ++ [0][1][2][1][RTW89_QATAR][4] = 34, ++ [0][1][2][1][RTW89_UK][4] = 34, ++ [0][1][2][1][RTW89_FCC][5] = 78, ++ [0][1][2][1][RTW89_ETSI][5] = 34, ++ [0][1][2][1][RTW89_MKK][5] = 66, ++ [0][1][2][1][RTW89_IC][5] = 78, ++ [0][1][2][1][RTW89_KCC][5] = 62, ++ [0][1][2][1][RTW89_ACMA][5] = 34, ++ [0][1][2][1][RTW89_CHILE][5] = 42, ++ [0][1][2][1][RTW89_UKRAINE][5] = 34, ++ [0][1][2][1][RTW89_MEXICO][5] = 78, ++ [0][1][2][1][RTW89_CN][5] = 34, ++ [0][1][2][1][RTW89_QATAR][5] = 34, ++ [0][1][2][1][RTW89_UK][5] = 34, ++ [0][1][2][1][RTW89_FCC][6] = 74, ++ [0][1][2][1][RTW89_ETSI][6] = 34, ++ [0][1][2][1][RTW89_MKK][6] = 66, ++ [0][1][2][1][RTW89_IC][6] = 74, ++ [0][1][2][1][RTW89_KCC][6] = 62, ++ [0][1][2][1][RTW89_ACMA][6] = 34, ++ [0][1][2][1][RTW89_CHILE][6] = 40, ++ [0][1][2][1][RTW89_UKRAINE][6] = 34, ++ [0][1][2][1][RTW89_MEXICO][6] = 74, ++ [0][1][2][1][RTW89_CN][6] = 34, ++ [0][1][2][1][RTW89_QATAR][6] = 34, ++ [0][1][2][1][RTW89_UK][6] = 34, ++ [0][1][2][1][RTW89_FCC][7] = 66, ++ [0][1][2][1][RTW89_ETSI][7] = 34, ++ [0][1][2][1][RTW89_MKK][7] = 66, ++ [0][1][2][1][RTW89_IC][7] = 66, ++ [0][1][2][1][RTW89_KCC][7] = 62, ++ [0][1][2][1][RTW89_ACMA][7] = 34, ++ [0][1][2][1][RTW89_CHILE][7] = 40, ++ [0][1][2][1][RTW89_UKRAINE][7] = 34, ++ [0][1][2][1][RTW89_MEXICO][7] = 66, ++ [0][1][2][1][RTW89_CN][7] = 34, ++ [0][1][2][1][RTW89_QATAR][7] = 34, ++ [0][1][2][1][RTW89_UK][7] = 34, ++ [0][1][2][1][RTW89_FCC][8] = 62, ++ [0][1][2][1][RTW89_ETSI][8] = 34, ++ [0][1][2][1][RTW89_MKK][8] = 66, ++ [0][1][2][1][RTW89_IC][8] = 62, ++ [0][1][2][1][RTW89_KCC][8] = 62, ++ [0][1][2][1][RTW89_ACMA][8] = 34, ++ [0][1][2][1][RTW89_CHILE][8] = 40, ++ [0][1][2][1][RTW89_UKRAINE][8] = 34, ++ [0][1][2][1][RTW89_MEXICO][8] = 62, ++ [0][1][2][1][RTW89_CN][8] = 34, ++ [0][1][2][1][RTW89_QATAR][8] = 34, ++ [0][1][2][1][RTW89_UK][8] = 34, ++ [0][1][2][1][RTW89_FCC][9] = 58, ++ [0][1][2][1][RTW89_ETSI][9] = 34, ++ [0][1][2][1][RTW89_MKK][9] = 66, ++ [0][1][2][1][RTW89_IC][9] = 58, ++ [0][1][2][1][RTW89_KCC][9] = 60, ++ [0][1][2][1][RTW89_ACMA][9] = 34, ++ [0][1][2][1][RTW89_CHILE][9] = 40, ++ [0][1][2][1][RTW89_UKRAINE][9] = 34, ++ [0][1][2][1][RTW89_MEXICO][9] = 58, ++ [0][1][2][1][RTW89_CN][9] = 34, ++ [0][1][2][1][RTW89_QATAR][9] = 34, ++ [0][1][2][1][RTW89_UK][9] = 34, ++ [0][1][2][1][RTW89_FCC][10] = 58, ++ [0][1][2][1][RTW89_ETSI][10] = 34, ++ [0][1][2][1][RTW89_MKK][10] = 66, ++ [0][1][2][1][RTW89_IC][10] = 58, ++ [0][1][2][1][RTW89_KCC][10] = 60, ++ [0][1][2][1][RTW89_ACMA][10] = 34, ++ [0][1][2][1][RTW89_CHILE][10] = 40, ++ [0][1][2][1][RTW89_UKRAINE][10] = 34, ++ [0][1][2][1][RTW89_MEXICO][10] = 58, ++ [0][1][2][1][RTW89_CN][10] = 34, ++ [0][1][2][1][RTW89_QATAR][10] = 34, ++ [0][1][2][1][RTW89_UK][10] = 34, ++ [0][1][2][1][RTW89_FCC][11] = 46, ++ [0][1][2][1][RTW89_ETSI][11] = 34, ++ [0][1][2][1][RTW89_MKK][11] = 66, ++ [0][1][2][1][RTW89_IC][11] = 46, ++ [0][1][2][1][RTW89_KCC][11] = 60, ++ [0][1][2][1][RTW89_ACMA][11] = 34, ++ [0][1][2][1][RTW89_CHILE][11] = 40, ++ [0][1][2][1][RTW89_UKRAINE][11] = 34, ++ [0][1][2][1][RTW89_MEXICO][11] = 46, ++ [0][1][2][1][RTW89_CN][11] = 34, ++ [0][1][2][1][RTW89_QATAR][11] = 34, ++ [0][1][2][1][RTW89_UK][11] = 34, ++ [0][1][2][1][RTW89_FCC][12] = 42, ++ [0][1][2][1][RTW89_ETSI][12] = 34, ++ [0][1][2][1][RTW89_MKK][12] = 66, ++ [0][1][2][1][RTW89_IC][12] = 42, ++ [0][1][2][1][RTW89_KCC][12] = 60, ++ [0][1][2][1][RTW89_ACMA][12] = 34, ++ [0][1][2][1][RTW89_CHILE][12] = 40, ++ [0][1][2][1][RTW89_UKRAINE][12] = 34, ++ [0][1][2][1][RTW89_MEXICO][12] = 42, ++ [0][1][2][1][RTW89_CN][12] = 34, ++ [0][1][2][1][RTW89_QATAR][12] = 34, ++ [0][1][2][1][RTW89_UK][12] = 34, ++ [0][1][2][1][RTW89_FCC][13] = 127, ++ [0][1][2][1][RTW89_ETSI][13] = 127, ++ [0][1][2][1][RTW89_MKK][13] = 127, ++ [0][1][2][1][RTW89_IC][13] = 127, ++ [0][1][2][1][RTW89_KCC][13] = 127, ++ [0][1][2][1][RTW89_ACMA][13] = 127, ++ [0][1][2][1][RTW89_CHILE][13] = 127, ++ [0][1][2][1][RTW89_UKRAINE][13] = 127, ++ [0][1][2][1][RTW89_MEXICO][13] = 127, ++ [0][1][2][1][RTW89_CN][13] = 127, ++ [0][1][2][1][RTW89_QATAR][13] = 127, ++ [0][1][2][1][RTW89_UK][13] = 127, ++ [1][0][2][0][RTW89_FCC][0] = 127, ++ [1][0][2][0][RTW89_ETSI][0] = 127, ++ [1][0][2][0][RTW89_MKK][0] = 127, ++ [1][0][2][0][RTW89_IC][0] = 127, ++ [1][0][2][0][RTW89_KCC][0] = 127, ++ [1][0][2][0][RTW89_ACMA][0] = 127, ++ [1][0][2][0][RTW89_CHILE][0] = 127, ++ [1][0][2][0][RTW89_UKRAINE][0] = 127, ++ [1][0][2][0][RTW89_MEXICO][0] = 127, ++ [1][0][2][0][RTW89_CN][0] = 127, ++ [1][0][2][0][RTW89_QATAR][0] = 127, ++ [1][0][2][0][RTW89_UK][0] = 127, ++ [1][0][2][0][RTW89_FCC][1] = 127, ++ [1][0][2][0][RTW89_ETSI][1] = 127, ++ [1][0][2][0][RTW89_MKK][1] = 127, ++ [1][0][2][0][RTW89_IC][1] = 127, ++ [1][0][2][0][RTW89_KCC][1] = 127, ++ [1][0][2][0][RTW89_ACMA][1] = 127, ++ [1][0][2][0][RTW89_CHILE][1] = 127, ++ [1][0][2][0][RTW89_UKRAINE][1] = 127, ++ [1][0][2][0][RTW89_MEXICO][1] = 127, ++ [1][0][2][0][RTW89_CN][1] = 127, ++ [1][0][2][0][RTW89_QATAR][1] = 127, ++ [1][0][2][0][RTW89_UK][1] = 127, ++ [1][0][2][0][RTW89_FCC][2] = 70, ++ [1][0][2][0][RTW89_ETSI][2] = 58, ++ [1][0][2][0][RTW89_MKK][2] = 74, ++ [1][0][2][0][RTW89_IC][2] = 70, ++ [1][0][2][0][RTW89_KCC][2] = 74, ++ [1][0][2][0][RTW89_ACMA][2] = 58, ++ [1][0][2][0][RTW89_CHILE][2] = 66, ++ [1][0][2][0][RTW89_UKRAINE][2] = 58, ++ [1][0][2][0][RTW89_MEXICO][2] = 70, ++ [1][0][2][0][RTW89_CN][2] = 58, ++ [1][0][2][0][RTW89_QATAR][2] = 58, ++ [1][0][2][0][RTW89_UK][2] = 58, ++ [1][0][2][0][RTW89_FCC][3] = 70, ++ [1][0][2][0][RTW89_ETSI][3] = 58, ++ [1][0][2][0][RTW89_MKK][3] = 74, ++ [1][0][2][0][RTW89_IC][3] = 70, ++ [1][0][2][0][RTW89_KCC][3] = 74, ++ [1][0][2][0][RTW89_ACMA][3] = 58, ++ [1][0][2][0][RTW89_CHILE][3] = 66, ++ [1][0][2][0][RTW89_UKRAINE][3] = 58, ++ [1][0][2][0][RTW89_MEXICO][3] = 70, ++ [1][0][2][0][RTW89_CN][3] = 58, ++ [1][0][2][0][RTW89_QATAR][3] = 58, ++ [1][0][2][0][RTW89_UK][3] = 58, ++ [1][0][2][0][RTW89_FCC][4] = 72, ++ [1][0][2][0][RTW89_ETSI][4] = 58, ++ [1][0][2][0][RTW89_MKK][4] = 74, ++ [1][0][2][0][RTW89_IC][4] = 72, ++ [1][0][2][0][RTW89_KCC][4] = 74, ++ [1][0][2][0][RTW89_ACMA][4] = 58, ++ [1][0][2][0][RTW89_CHILE][4] = 66, ++ [1][0][2][0][RTW89_UKRAINE][4] = 58, ++ [1][0][2][0][RTW89_MEXICO][4] = 72, ++ [1][0][2][0][RTW89_CN][4] = 58, ++ [1][0][2][0][RTW89_QATAR][4] = 58, ++ [1][0][2][0][RTW89_UK][4] = 58, ++ [1][0][2][0][RTW89_FCC][5] = 72, ++ [1][0][2][0][RTW89_ETSI][5] = 58, ++ [1][0][2][0][RTW89_MKK][5] = 74, ++ [1][0][2][0][RTW89_IC][5] = 72, ++ [1][0][2][0][RTW89_KCC][5] = 74, ++ [1][0][2][0][RTW89_ACMA][5] = 58, ++ [1][0][2][0][RTW89_CHILE][5] = 66, ++ [1][0][2][0][RTW89_UKRAINE][5] = 58, ++ [1][0][2][0][RTW89_MEXICO][5] = 72, ++ [1][0][2][0][RTW89_CN][5] = 58, ++ [1][0][2][0][RTW89_QATAR][5] = 58, ++ [1][0][2][0][RTW89_UK][5] = 58, ++ [1][0][2][0][RTW89_FCC][6] = 72, ++ [1][0][2][0][RTW89_ETSI][6] = 58, ++ [1][0][2][0][RTW89_MKK][6] = 74, ++ [1][0][2][0][RTW89_IC][6] = 72, ++ [1][0][2][0][RTW89_KCC][6] = 74, ++ [1][0][2][0][RTW89_ACMA][6] = 58, ++ [1][0][2][0][RTW89_CHILE][6] = 66, ++ [1][0][2][0][RTW89_UKRAINE][6] = 58, ++ [1][0][2][0][RTW89_MEXICO][6] = 72, ++ [1][0][2][0][RTW89_CN][6] = 58, ++ [1][0][2][0][RTW89_QATAR][6] = 58, ++ [1][0][2][0][RTW89_UK][6] = 58, ++ [1][0][2][0][RTW89_FCC][7] = 68, ++ [1][0][2][0][RTW89_ETSI][7] = 58, ++ [1][0][2][0][RTW89_MKK][7] = 74, ++ [1][0][2][0][RTW89_IC][7] = 68, ++ [1][0][2][0][RTW89_KCC][7] = 74, ++ [1][0][2][0][RTW89_ACMA][7] = 58, ++ [1][0][2][0][RTW89_CHILE][7] = 66, ++ [1][0][2][0][RTW89_UKRAINE][7] = 58, ++ [1][0][2][0][RTW89_MEXICO][7] = 68, ++ [1][0][2][0][RTW89_CN][7] = 58, ++ [1][0][2][0][RTW89_QATAR][7] = 58, ++ [1][0][2][0][RTW89_UK][7] = 58, ++ [1][0][2][0][RTW89_FCC][8] = 68, ++ [1][0][2][0][RTW89_ETSI][8] = 58, ++ [1][0][2][0][RTW89_MKK][8] = 74, ++ [1][0][2][0][RTW89_IC][8] = 68, ++ [1][0][2][0][RTW89_KCC][8] = 74, ++ [1][0][2][0][RTW89_ACMA][8] = 58, ++ [1][0][2][0][RTW89_CHILE][8] = 66, ++ [1][0][2][0][RTW89_UKRAINE][8] = 58, ++ [1][0][2][0][RTW89_MEXICO][8] = 68, ++ [1][0][2][0][RTW89_CN][8] = 58, ++ [1][0][2][0][RTW89_QATAR][8] = 58, ++ [1][0][2][0][RTW89_UK][8] = 58, ++ [1][0][2][0][RTW89_FCC][9] = 68, ++ [1][0][2][0][RTW89_ETSI][9] = 58, ++ [1][0][2][0][RTW89_MKK][9] = 74, ++ [1][0][2][0][RTW89_IC][9] = 68, ++ [1][0][2][0][RTW89_KCC][9] = 74, ++ [1][0][2][0][RTW89_ACMA][9] = 58, ++ [1][0][2][0][RTW89_CHILE][9] = 66, ++ [1][0][2][0][RTW89_UKRAINE][9] = 58, ++ [1][0][2][0][RTW89_MEXICO][9] = 68, ++ [1][0][2][0][RTW89_CN][9] = 58, ++ [1][0][2][0][RTW89_QATAR][9] = 58, ++ [1][0][2][0][RTW89_UK][9] = 58, ++ [1][0][2][0][RTW89_FCC][10] = 66, ++ [1][0][2][0][RTW89_ETSI][10] = 58, ++ [1][0][2][0][RTW89_MKK][10] = 74, ++ [1][0][2][0][RTW89_IC][10] = 66, ++ [1][0][2][0][RTW89_KCC][10] = 74, ++ [1][0][2][0][RTW89_ACMA][10] = 58, ++ [1][0][2][0][RTW89_CHILE][10] = 66, ++ [1][0][2][0][RTW89_UKRAINE][10] = 58, ++ [1][0][2][0][RTW89_MEXICO][10] = 66, ++ [1][0][2][0][RTW89_CN][10] = 58, ++ [1][0][2][0][RTW89_QATAR][10] = 58, ++ [1][0][2][0][RTW89_UK][10] = 58, ++ [1][0][2][0][RTW89_FCC][11] = 127, ++ [1][0][2][0][RTW89_ETSI][11] = 127, ++ [1][0][2][0][RTW89_MKK][11] = 127, ++ [1][0][2][0][RTW89_IC][11] = 127, ++ [1][0][2][0][RTW89_KCC][11] = 127, ++ [1][0][2][0][RTW89_ACMA][11] = 127, ++ [1][0][2][0][RTW89_CHILE][11] = 127, ++ [1][0][2][0][RTW89_UKRAINE][11] = 127, ++ [1][0][2][0][RTW89_MEXICO][11] = 127, ++ [1][0][2][0][RTW89_CN][11] = 127, ++ [1][0][2][0][RTW89_QATAR][11] = 127, ++ [1][0][2][0][RTW89_UK][11] = 127, ++ [1][0][2][0][RTW89_FCC][12] = 127, ++ [1][0][2][0][RTW89_ETSI][12] = 127, ++ [1][0][2][0][RTW89_MKK][12] = 127, ++ [1][0][2][0][RTW89_IC][12] = 127, ++ [1][0][2][0][RTW89_KCC][12] = 127, ++ [1][0][2][0][RTW89_ACMA][12] = 127, ++ [1][0][2][0][RTW89_CHILE][12] = 127, ++ [1][0][2][0][RTW89_UKRAINE][12] = 127, ++ [1][0][2][0][RTW89_MEXICO][12] = 127, ++ [1][0][2][0][RTW89_CN][12] = 127, ++ [1][0][2][0][RTW89_QATAR][12] = 127, ++ [1][0][2][0][RTW89_UK][12] = 127, ++ [1][0][2][0][RTW89_FCC][13] = 127, ++ [1][0][2][0][RTW89_ETSI][13] = 127, ++ [1][0][2][0][RTW89_MKK][13] = 127, ++ [1][0][2][0][RTW89_IC][13] = 127, ++ [1][0][2][0][RTW89_KCC][13] = 127, ++ [1][0][2][0][RTW89_ACMA][13] = 127, ++ [1][0][2][0][RTW89_CHILE][13] = 127, ++ [1][0][2][0][RTW89_UKRAINE][13] = 127, ++ [1][0][2][0][RTW89_MEXICO][13] = 127, ++ [1][0][2][0][RTW89_CN][13] = 127, ++ [1][0][2][0][RTW89_QATAR][13] = 127, ++ [1][0][2][0][RTW89_UK][13] = 127, ++ [1][1][2][0][RTW89_FCC][0] = 127, ++ [1][1][2][0][RTW89_ETSI][0] = 127, ++ [1][1][2][0][RTW89_MKK][0] = 127, ++ [1][1][2][0][RTW89_IC][0] = 127, ++ [1][1][2][0][RTW89_KCC][0] = 127, ++ [1][1][2][0][RTW89_ACMA][0] = 127, ++ [1][1][2][0][RTW89_CHILE][0] = 127, ++ [1][1][2][0][RTW89_UKRAINE][0] = 127, ++ [1][1][2][0][RTW89_MEXICO][0] = 127, ++ [1][1][2][0][RTW89_CN][0] = 127, ++ [1][1][2][0][RTW89_QATAR][0] = 127, ++ [1][1][2][0][RTW89_UK][0] = 127, ++ [1][1][2][0][RTW89_FCC][1] = 127, ++ [1][1][2][0][RTW89_ETSI][1] = 127, ++ [1][1][2][0][RTW89_MKK][1] = 127, ++ [1][1][2][0][RTW89_IC][1] = 127, ++ [1][1][2][0][RTW89_KCC][1] = 127, ++ [1][1][2][0][RTW89_ACMA][1] = 127, ++ [1][1][2][0][RTW89_CHILE][1] = 127, ++ [1][1][2][0][RTW89_UKRAINE][1] = 127, ++ [1][1][2][0][RTW89_MEXICO][1] = 127, ++ [1][1][2][0][RTW89_CN][1] = 127, ++ [1][1][2][0][RTW89_QATAR][1] = 127, ++ [1][1][2][0][RTW89_UK][1] = 127, ++ [1][1][2][0][RTW89_FCC][2] = 54, ++ [1][1][2][0][RTW89_ETSI][2] = 46, ++ [1][1][2][0][RTW89_MKK][2] = 66, ++ [1][1][2][0][RTW89_IC][2] = 54, ++ [1][1][2][0][RTW89_KCC][2] = 62, ++ [1][1][2][0][RTW89_ACMA][2] = 46, ++ [1][1][2][0][RTW89_CHILE][2] = 52, ++ [1][1][2][0][RTW89_UKRAINE][2] = 46, ++ [1][1][2][0][RTW89_MEXICO][2] = 54, ++ [1][1][2][0][RTW89_CN][2] = 46, ++ [1][1][2][0][RTW89_QATAR][2] = 46, ++ [1][1][2][0][RTW89_UK][2] = 46, ++ [1][1][2][0][RTW89_FCC][3] = 54, ++ [1][1][2][0][RTW89_ETSI][3] = 46, ++ [1][1][2][0][RTW89_MKK][3] = 66, ++ [1][1][2][0][RTW89_IC][3] = 54, ++ [1][1][2][0][RTW89_KCC][3] = 62, ++ [1][1][2][0][RTW89_ACMA][3] = 46, ++ [1][1][2][0][RTW89_CHILE][3] = 52, ++ [1][1][2][0][RTW89_UKRAINE][3] = 46, ++ [1][1][2][0][RTW89_MEXICO][3] = 54, ++ [1][1][2][0][RTW89_CN][3] = 46, ++ [1][1][2][0][RTW89_QATAR][3] = 46, ++ [1][1][2][0][RTW89_UK][3] = 46, ++ [1][1][2][0][RTW89_FCC][4] = 58, ++ [1][1][2][0][RTW89_ETSI][4] = 46, ++ [1][1][2][0][RTW89_MKK][4] = 66, ++ [1][1][2][0][RTW89_IC][4] = 58, ++ [1][1][2][0][RTW89_KCC][4] = 62, ++ [1][1][2][0][RTW89_ACMA][4] = 46, ++ [1][1][2][0][RTW89_CHILE][4] = 52, ++ [1][1][2][0][RTW89_UKRAINE][4] = 46, ++ [1][1][2][0][RTW89_MEXICO][4] = 58, ++ [1][1][2][0][RTW89_CN][4] = 46, ++ [1][1][2][0][RTW89_QATAR][4] = 46, ++ [1][1][2][0][RTW89_UK][4] = 46, ++ [1][1][2][0][RTW89_FCC][5] = 66, ++ [1][1][2][0][RTW89_ETSI][5] = 46, ++ [1][1][2][0][RTW89_MKK][5] = 66, ++ [1][1][2][0][RTW89_IC][5] = 66, ++ [1][1][2][0][RTW89_KCC][5] = 62, ++ [1][1][2][0][RTW89_ACMA][5] = 46, ++ [1][1][2][0][RTW89_CHILE][5] = 54, ++ [1][1][2][0][RTW89_UKRAINE][5] = 46, ++ [1][1][2][0][RTW89_MEXICO][5] = 66, ++ [1][1][2][0][RTW89_CN][5] = 46, ++ [1][1][2][0][RTW89_QATAR][5] = 46, ++ [1][1][2][0][RTW89_UK][5] = 46, ++ [1][1][2][0][RTW89_FCC][6] = 58, ++ [1][1][2][0][RTW89_ETSI][6] = 46, ++ [1][1][2][0][RTW89_MKK][6] = 66, ++ [1][1][2][0][RTW89_IC][6] = 58, ++ [1][1][2][0][RTW89_KCC][6] = 62, ++ [1][1][2][0][RTW89_ACMA][6] = 46, ++ [1][1][2][0][RTW89_CHILE][6] = 52, ++ [1][1][2][0][RTW89_UKRAINE][6] = 46, ++ [1][1][2][0][RTW89_MEXICO][6] = 58, ++ [1][1][2][0][RTW89_CN][6] = 46, ++ [1][1][2][0][RTW89_QATAR][6] = 46, ++ [1][1][2][0][RTW89_UK][6] = 46, ++ [1][1][2][0][RTW89_FCC][7] = 54, ++ [1][1][2][0][RTW89_ETSI][7] = 46, ++ [1][1][2][0][RTW89_MKK][7] = 66, ++ [1][1][2][0][RTW89_IC][7] = 54, ++ [1][1][2][0][RTW89_KCC][7] = 62, ++ [1][1][2][0][RTW89_ACMA][7] = 46, ++ [1][1][2][0][RTW89_CHILE][7] = 52, ++ [1][1][2][0][RTW89_UKRAINE][7] = 46, ++ [1][1][2][0][RTW89_MEXICO][7] = 54, ++ [1][1][2][0][RTW89_CN][7] = 46, ++ [1][1][2][0][RTW89_QATAR][7] = 46, ++ [1][1][2][0][RTW89_UK][7] = 46, ++ [1][1][2][0][RTW89_FCC][8] = 54, ++ [1][1][2][0][RTW89_ETSI][8] = 46, ++ [1][1][2][0][RTW89_MKK][8] = 66, ++ [1][1][2][0][RTW89_IC][8] = 54, ++ [1][1][2][0][RTW89_KCC][8] = 62, ++ [1][1][2][0][RTW89_ACMA][8] = 46, ++ [1][1][2][0][RTW89_CHILE][8] = 52, ++ [1][1][2][0][RTW89_UKRAINE][8] = 46, ++ [1][1][2][0][RTW89_MEXICO][8] = 54, ++ [1][1][2][0][RTW89_CN][8] = 46, ++ [1][1][2][0][RTW89_QATAR][8] = 46, ++ [1][1][2][0][RTW89_UK][8] = 46, ++ [1][1][2][0][RTW89_FCC][9] = 42, ++ [1][1][2][0][RTW89_ETSI][9] = 46, ++ [1][1][2][0][RTW89_MKK][9] = 66, ++ [1][1][2][0][RTW89_IC][9] = 42, ++ [1][1][2][0][RTW89_KCC][9] = 62, ++ [1][1][2][0][RTW89_ACMA][9] = 46, ++ [1][1][2][0][RTW89_CHILE][9] = 42, ++ [1][1][2][0][RTW89_UKRAINE][9] = 46, ++ [1][1][2][0][RTW89_MEXICO][9] = 42, ++ [1][1][2][0][RTW89_CN][9] = 46, ++ [1][1][2][0][RTW89_QATAR][9] = 46, ++ [1][1][2][0][RTW89_UK][9] = 46, ++ [1][1][2][0][RTW89_FCC][10] = 38, ++ [1][1][2][0][RTW89_ETSI][10] = 46, ++ [1][1][2][0][RTW89_MKK][10] = 66, ++ [1][1][2][0][RTW89_IC][10] = 38, ++ [1][1][2][0][RTW89_KCC][10] = 62, ++ [1][1][2][0][RTW89_ACMA][10] = 46, ++ [1][1][2][0][RTW89_CHILE][10] = 38, ++ [1][1][2][0][RTW89_UKRAINE][10] = 46, ++ [1][1][2][0][RTW89_MEXICO][10] = 38, ++ [1][1][2][0][RTW89_CN][10] = 46, ++ [1][1][2][0][RTW89_QATAR][10] = 46, ++ [1][1][2][0][RTW89_UK][10] = 46, ++ [1][1][2][0][RTW89_FCC][11] = 127, ++ [1][1][2][0][RTW89_ETSI][11] = 127, ++ [1][1][2][0][RTW89_MKK][11] = 127, ++ [1][1][2][0][RTW89_IC][11] = 127, ++ [1][1][2][0][RTW89_KCC][11] = 127, ++ [1][1][2][0][RTW89_ACMA][11] = 127, ++ [1][1][2][0][RTW89_CHILE][11] = 127, ++ [1][1][2][0][RTW89_UKRAINE][11] = 127, ++ [1][1][2][0][RTW89_MEXICO][11] = 127, ++ [1][1][2][0][RTW89_CN][11] = 127, ++ [1][1][2][0][RTW89_QATAR][11] = 127, ++ [1][1][2][0][RTW89_UK][11] = 127, ++ [1][1][2][0][RTW89_FCC][12] = 127, ++ [1][1][2][0][RTW89_ETSI][12] = 127, ++ [1][1][2][0][RTW89_MKK][12] = 127, ++ [1][1][2][0][RTW89_IC][12] = 127, ++ [1][1][2][0][RTW89_KCC][12] = 127, ++ [1][1][2][0][RTW89_ACMA][12] = 127, ++ [1][1][2][0][RTW89_CHILE][12] = 127, ++ [1][1][2][0][RTW89_UKRAINE][12] = 127, ++ [1][1][2][0][RTW89_MEXICO][12] = 127, ++ [1][1][2][0][RTW89_CN][12] = 127, ++ [1][1][2][0][RTW89_QATAR][12] = 127, ++ [1][1][2][0][RTW89_UK][12] = 127, ++ [1][1][2][0][RTW89_FCC][13] = 127, ++ [1][1][2][0][RTW89_ETSI][13] = 127, ++ [1][1][2][0][RTW89_MKK][13] = 127, ++ [1][1][2][0][RTW89_IC][13] = 127, ++ [1][1][2][0][RTW89_KCC][13] = 127, ++ [1][1][2][0][RTW89_ACMA][13] = 127, ++ [1][1][2][0][RTW89_CHILE][13] = 127, ++ [1][1][2][0][RTW89_UKRAINE][13] = 127, ++ [1][1][2][0][RTW89_MEXICO][13] = 127, ++ [1][1][2][0][RTW89_CN][13] = 127, ++ [1][1][2][0][RTW89_QATAR][13] = 127, ++ [1][1][2][0][RTW89_UK][13] = 127, ++ [1][1][2][1][RTW89_FCC][0] = 127, ++ [1][1][2][1][RTW89_ETSI][0] = 127, ++ [1][1][2][1][RTW89_MKK][0] = 127, ++ [1][1][2][1][RTW89_IC][0] = 127, ++ [1][1][2][1][RTW89_KCC][0] = 127, ++ [1][1][2][1][RTW89_ACMA][0] = 127, ++ [1][1][2][1][RTW89_CHILE][0] = 127, ++ [1][1][2][1][RTW89_UKRAINE][0] = 127, ++ [1][1][2][1][RTW89_MEXICO][0] = 127, ++ [1][1][2][1][RTW89_CN][0] = 127, ++ [1][1][2][1][RTW89_QATAR][0] = 127, ++ [1][1][2][1][RTW89_UK][0] = 127, ++ [1][1][2][1][RTW89_FCC][1] = 127, ++ [1][1][2][1][RTW89_ETSI][1] = 127, ++ [1][1][2][1][RTW89_MKK][1] = 127, ++ [1][1][2][1][RTW89_IC][1] = 127, ++ [1][1][2][1][RTW89_KCC][1] = 127, ++ [1][1][2][1][RTW89_ACMA][1] = 127, ++ [1][1][2][1][RTW89_CHILE][1] = 127, ++ [1][1][2][1][RTW89_UKRAINE][1] = 127, ++ [1][1][2][1][RTW89_MEXICO][1] = 127, ++ [1][1][2][1][RTW89_CN][1] = 127, ++ [1][1][2][1][RTW89_QATAR][1] = 127, ++ [1][1][2][1][RTW89_UK][1] = 127, ++ [1][1][2][1][RTW89_FCC][2] = 54, ++ [1][1][2][1][RTW89_ETSI][2] = 34, ++ [1][1][2][1][RTW89_MKK][2] = 66, ++ [1][1][2][1][RTW89_IC][2] = 54, ++ [1][1][2][1][RTW89_KCC][2] = 62, ++ [1][1][2][1][RTW89_ACMA][2] = 34, ++ [1][1][2][1][RTW89_CHILE][2] = 42, ++ [1][1][2][1][RTW89_UKRAINE][2] = 34, ++ [1][1][2][1][RTW89_MEXICO][2] = 54, ++ [1][1][2][1][RTW89_CN][2] = 34, ++ [1][1][2][1][RTW89_QATAR][2] = 34, ++ [1][1][2][1][RTW89_UK][2] = 34, ++ [1][1][2][1][RTW89_FCC][3] = 54, ++ [1][1][2][1][RTW89_ETSI][3] = 34, ++ [1][1][2][1][RTW89_MKK][3] = 66, ++ [1][1][2][1][RTW89_IC][3] = 54, ++ [1][1][2][1][RTW89_KCC][3] = 62, ++ [1][1][2][1][RTW89_ACMA][3] = 34, ++ [1][1][2][1][RTW89_CHILE][3] = 42, ++ [1][1][2][1][RTW89_UKRAINE][3] = 34, ++ [1][1][2][1][RTW89_MEXICO][3] = 54, ++ [1][1][2][1][RTW89_CN][3] = 34, ++ [1][1][2][1][RTW89_QATAR][3] = 34, ++ [1][1][2][1][RTW89_UK][3] = 34, ++ [1][1][2][1][RTW89_FCC][4] = 58, ++ [1][1][2][1][RTW89_ETSI][4] = 34, ++ [1][1][2][1][RTW89_MKK][4] = 66, ++ [1][1][2][1][RTW89_IC][4] = 58, ++ [1][1][2][1][RTW89_KCC][4] = 62, ++ [1][1][2][1][RTW89_ACMA][4] = 34, ++ [1][1][2][1][RTW89_CHILE][4] = 42, ++ [1][1][2][1][RTW89_UKRAINE][4] = 34, ++ [1][1][2][1][RTW89_MEXICO][4] = 58, ++ [1][1][2][1][RTW89_CN][4] = 34, ++ [1][1][2][1][RTW89_QATAR][4] = 34, ++ [1][1][2][1][RTW89_UK][4] = 34, ++ [1][1][2][1][RTW89_FCC][5] = 66, ++ [1][1][2][1][RTW89_ETSI][5] = 34, ++ [1][1][2][1][RTW89_MKK][5] = 66, ++ [1][1][2][1][RTW89_IC][5] = 66, ++ [1][1][2][1][RTW89_KCC][5] = 62, ++ [1][1][2][1][RTW89_ACMA][5] = 34, ++ [1][1][2][1][RTW89_CHILE][5] = 42, ++ [1][1][2][1][RTW89_UKRAINE][5] = 34, ++ [1][1][2][1][RTW89_MEXICO][5] = 66, ++ [1][1][2][1][RTW89_CN][5] = 34, ++ [1][1][2][1][RTW89_QATAR][5] = 34, ++ [1][1][2][1][RTW89_UK][5] = 34, ++ [1][1][2][1][RTW89_FCC][6] = 58, ++ [1][1][2][1][RTW89_ETSI][6] = 34, ++ [1][1][2][1][RTW89_MKK][6] = 66, ++ [1][1][2][1][RTW89_IC][6] = 58, ++ [1][1][2][1][RTW89_KCC][6] = 62, ++ [1][1][2][1][RTW89_ACMA][6] = 34, ++ [1][1][2][1][RTW89_CHILE][6] = 42, ++ [1][1][2][1][RTW89_UKRAINE][6] = 34, ++ [1][1][2][1][RTW89_MEXICO][6] = 58, ++ [1][1][2][1][RTW89_CN][6] = 34, ++ [1][1][2][1][RTW89_QATAR][6] = 34, ++ [1][1][2][1][RTW89_UK][6] = 34, ++ [1][1][2][1][RTW89_FCC][7] = 54, ++ [1][1][2][1][RTW89_ETSI][7] = 34, ++ [1][1][2][1][RTW89_MKK][7] = 66, ++ [1][1][2][1][RTW89_IC][7] = 54, ++ [1][1][2][1][RTW89_KCC][7] = 62, ++ [1][1][2][1][RTW89_ACMA][7] = 34, ++ [1][1][2][1][RTW89_CHILE][7] = 42, ++ [1][1][2][1][RTW89_UKRAINE][7] = 34, ++ [1][1][2][1][RTW89_MEXICO][7] = 54, ++ [1][1][2][1][RTW89_CN][7] = 34, ++ [1][1][2][1][RTW89_QATAR][7] = 34, ++ [1][1][2][1][RTW89_UK][7] = 34, ++ [1][1][2][1][RTW89_FCC][8] = 54, ++ [1][1][2][1][RTW89_ETSI][8] = 34, ++ [1][1][2][1][RTW89_MKK][8] = 66, ++ [1][1][2][1][RTW89_IC][8] = 54, ++ [1][1][2][1][RTW89_KCC][8] = 62, ++ [1][1][2][1][RTW89_ACMA][8] = 34, ++ [1][1][2][1][RTW89_CHILE][8] = 42, ++ [1][1][2][1][RTW89_UKRAINE][8] = 34, ++ [1][1][2][1][RTW89_MEXICO][8] = 54, ++ [1][1][2][1][RTW89_CN][8] = 34, ++ [1][1][2][1][RTW89_QATAR][8] = 34, ++ [1][1][2][1][RTW89_UK][8] = 34, ++ [1][1][2][1][RTW89_FCC][9] = 42, ++ [1][1][2][1][RTW89_ETSI][9] = 34, ++ [1][1][2][1][RTW89_MKK][9] = 66, ++ [1][1][2][1][RTW89_IC][9] = 42, ++ [1][1][2][1][RTW89_KCC][9] = 62, ++ [1][1][2][1][RTW89_ACMA][9] = 34, ++ [1][1][2][1][RTW89_CHILE][9] = 42, ++ [1][1][2][1][RTW89_UKRAINE][9] = 34, ++ [1][1][2][1][RTW89_MEXICO][9] = 42, ++ [1][1][2][1][RTW89_CN][9] = 34, ++ [1][1][2][1][RTW89_QATAR][9] = 34, ++ [1][1][2][1][RTW89_UK][9] = 34, ++ [1][1][2][1][RTW89_FCC][10] = 38, ++ [1][1][2][1][RTW89_ETSI][10] = 34, ++ [1][1][2][1][RTW89_MKK][10] = 66, ++ [1][1][2][1][RTW89_IC][10] = 38, ++ [1][1][2][1][RTW89_KCC][10] = 62, ++ [1][1][2][1][RTW89_ACMA][10] = 34, ++ [1][1][2][1][RTW89_CHILE][10] = 38, ++ [1][1][2][1][RTW89_UKRAINE][10] = 34, ++ [1][1][2][1][RTW89_MEXICO][10] = 38, ++ [1][1][2][1][RTW89_CN][10] = 34, ++ [1][1][2][1][RTW89_QATAR][10] = 34, ++ [1][1][2][1][RTW89_UK][10] = 34, ++ [1][1][2][1][RTW89_FCC][11] = 127, ++ [1][1][2][1][RTW89_ETSI][11] = 127, ++ [1][1][2][1][RTW89_MKK][11] = 127, ++ [1][1][2][1][RTW89_IC][11] = 127, ++ [1][1][2][1][RTW89_KCC][11] = 127, ++ [1][1][2][1][RTW89_ACMA][11] = 127, ++ [1][1][2][1][RTW89_CHILE][11] = 127, ++ [1][1][2][1][RTW89_UKRAINE][11] = 127, ++ [1][1][2][1][RTW89_MEXICO][11] = 127, ++ [1][1][2][1][RTW89_CN][11] = 127, ++ [1][1][2][1][RTW89_QATAR][11] = 127, ++ [1][1][2][1][RTW89_UK][11] = 127, ++ [1][1][2][1][RTW89_FCC][12] = 127, ++ [1][1][2][1][RTW89_ETSI][12] = 127, ++ [1][1][2][1][RTW89_MKK][12] = 127, ++ [1][1][2][1][RTW89_IC][12] = 127, ++ [1][1][2][1][RTW89_KCC][12] = 127, ++ [1][1][2][1][RTW89_ACMA][12] = 127, ++ [1][1][2][1][RTW89_CHILE][12] = 127, ++ [1][1][2][1][RTW89_UKRAINE][12] = 127, ++ [1][1][2][1][RTW89_MEXICO][12] = 127, ++ [1][1][2][1][RTW89_CN][12] = 127, ++ [1][1][2][1][RTW89_QATAR][12] = 127, ++ [1][1][2][1][RTW89_UK][12] = 127, ++ [1][1][2][1][RTW89_FCC][13] = 127, ++ [1][1][2][1][RTW89_ETSI][13] = 127, ++ [1][1][2][1][RTW89_MKK][13] = 127, ++ [1][1][2][1][RTW89_IC][13] = 127, ++ [1][1][2][1][RTW89_KCC][13] = 127, ++ [1][1][2][1][RTW89_ACMA][13] = 127, ++ [1][1][2][1][RTW89_CHILE][13] = 127, ++ [1][1][2][1][RTW89_UKRAINE][13] = 127, ++ [1][1][2][1][RTW89_MEXICO][13] = 127, ++ [1][1][2][1][RTW89_CN][13] = 127, ++ [1][1][2][1][RTW89_QATAR][13] = 127, ++ [1][1][2][1][RTW89_UK][13] = 127, ++}; ++ ++const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] ++ [RTW89_RS_LMT_NUM][RTW89_BF_NUM] ++ [RTW89_REGD_NUM][RTW89_5G_CH_NUM] = { ++ [0][0][1][0][RTW89_WW][0] = 42, ++ [0][0][1][0][RTW89_WW][2] = 42, ++ [0][0][1][0][RTW89_WW][4] = 42, ++ [0][0][1][0][RTW89_WW][6] = 42, ++ [0][0][1][0][RTW89_WW][8] = 52, ++ [0][0][1][0][RTW89_WW][10] = 52, ++ [0][0][1][0][RTW89_WW][12] = 52, ++ [0][0][1][0][RTW89_WW][14] = 52, ++ [0][0][1][0][RTW89_WW][15] = 52, ++ [0][0][1][0][RTW89_WW][17] = 52, ++ [0][0][1][0][RTW89_WW][19] = 52, ++ [0][0][1][0][RTW89_WW][21] = 52, ++ [0][0][1][0][RTW89_WW][23] = 52, ++ [0][0][1][0][RTW89_WW][25] = 52, ++ [0][0][1][0][RTW89_WW][27] = 52, ++ [0][0][1][0][RTW89_WW][29] = 52, ++ [0][0][1][0][RTW89_WW][31] = 52, ++ [0][0][1][0][RTW89_WW][33] = 52, ++ [0][0][1][0][RTW89_WW][35] = 52, ++ [0][0][1][0][RTW89_WW][37] = 68, ++ [0][0][1][0][RTW89_WW][38] = 28, ++ [0][0][1][0][RTW89_WW][40] = 28, ++ [0][0][1][0][RTW89_WW][42] = 28, ++ [0][0][1][0][RTW89_WW][44] = 28, ++ [0][0][1][0][RTW89_WW][46] = 28, ++ [0][0][1][0][RTW89_WW][48] = 78, ++ [0][0][1][0][RTW89_WW][50] = 78, ++ [0][0][1][0][RTW89_WW][52] = 78, ++ [0][1][1][0][RTW89_WW][0] = 30, ++ [0][1][1][0][RTW89_WW][2] = 32, ++ [0][1][1][0][RTW89_WW][4] = 30, ++ [0][1][1][0][RTW89_WW][6] = 30, ++ [0][1][1][0][RTW89_WW][8] = 40, ++ [0][1][1][0][RTW89_WW][10] = 40, ++ [0][1][1][0][RTW89_WW][12] = 40, ++ [0][1][1][0][RTW89_WW][14] = 40, ++ [0][1][1][0][RTW89_WW][15] = 40, ++ [0][1][1][0][RTW89_WW][17] = 40, ++ [0][1][1][0][RTW89_WW][19] = 40, ++ [0][1][1][0][RTW89_WW][21] = 40, ++ [0][1][1][0][RTW89_WW][23] = 40, ++ [0][1][1][0][RTW89_WW][25] = 40, ++ [0][1][1][0][RTW89_WW][27] = 40, ++ [0][1][1][0][RTW89_WW][29] = 40, ++ [0][1][1][0][RTW89_WW][31] = 40, ++ [0][1][1][0][RTW89_WW][33] = 40, ++ [0][1][1][0][RTW89_WW][35] = 40, ++ [0][1][1][0][RTW89_WW][37] = 50, ++ [0][1][1][0][RTW89_WW][38] = 16, ++ [0][1][1][0][RTW89_WW][40] = 16, ++ [0][1][1][0][RTW89_WW][42] = 16, ++ [0][1][1][0][RTW89_WW][44] = 16, ++ [0][1][1][0][RTW89_WW][46] = 16, ++ [0][1][1][0][RTW89_WW][48] = 56, ++ [0][1][1][0][RTW89_WW][50] = 56, ++ [0][1][1][0][RTW89_WW][52] = 56, ++ [0][0][2][0][RTW89_WW][0] = 42, ++ [0][0][2][0][RTW89_WW][2] = 42, ++ [0][0][2][0][RTW89_WW][4] = 42, ++ [0][0][2][0][RTW89_WW][6] = 42, ++ [0][0][2][0][RTW89_WW][8] = 52, ++ [0][0][2][0][RTW89_WW][10] = 52, ++ [0][0][2][0][RTW89_WW][12] = 52, ++ [0][0][2][0][RTW89_WW][14] = 52, ++ [0][0][2][0][RTW89_WW][15] = 52, ++ [0][0][2][0][RTW89_WW][17] = 52, ++ [0][0][2][0][RTW89_WW][19] = 52, ++ [0][0][2][0][RTW89_WW][21] = 52, ++ [0][0][2][0][RTW89_WW][23] = 52, ++ [0][0][2][0][RTW89_WW][25] = 52, ++ [0][0][2][0][RTW89_WW][27] = 52, ++ [0][0][2][0][RTW89_WW][29] = 52, ++ [0][0][2][0][RTW89_WW][31] = 52, ++ [0][0][2][0][RTW89_WW][33] = 52, ++ [0][0][2][0][RTW89_WW][35] = 52, ++ [0][0][2][0][RTW89_WW][37] = 64, ++ [0][0][2][0][RTW89_WW][38] = 28, ++ [0][0][2][0][RTW89_WW][40] = 28, ++ [0][0][2][0][RTW89_WW][42] = 28, ++ [0][0][2][0][RTW89_WW][44] = 28, ++ [0][0][2][0][RTW89_WW][46] = 28, ++ [0][0][2][0][RTW89_WW][48] = 78, ++ [0][0][2][0][RTW89_WW][50] = 78, ++ [0][0][2][0][RTW89_WW][52] = 78, ++ [0][1][2][0][RTW89_WW][0] = 30, ++ [0][1][2][0][RTW89_WW][2] = 30, ++ [0][1][2][0][RTW89_WW][4] = 30, ++ [0][1][2][0][RTW89_WW][6] = 30, ++ [0][1][2][0][RTW89_WW][8] = 40, ++ [0][1][2][0][RTW89_WW][10] = 40, ++ [0][1][2][0][RTW89_WW][12] = 40, ++ [0][1][2][0][RTW89_WW][14] = 40, ++ [0][1][2][0][RTW89_WW][15] = 40, ++ [0][1][2][0][RTW89_WW][17] = 40, ++ [0][1][2][0][RTW89_WW][19] = 40, ++ [0][1][2][0][RTW89_WW][21] = 40, ++ [0][1][2][0][RTW89_WW][23] = 40, ++ [0][1][2][0][RTW89_WW][25] = 40, ++ [0][1][2][0][RTW89_WW][27] = 40, ++ [0][1][2][0][RTW89_WW][29] = 40, ++ [0][1][2][0][RTW89_WW][31] = 40, ++ [0][1][2][0][RTW89_WW][33] = 40, ++ [0][1][2][0][RTW89_WW][35] = 40, ++ [0][1][2][0][RTW89_WW][37] = 50, ++ [0][1][2][0][RTW89_WW][38] = 16, ++ [0][1][2][0][RTW89_WW][40] = 16, ++ [0][1][2][0][RTW89_WW][42] = 16, ++ [0][1][2][0][RTW89_WW][44] = 16, ++ [0][1][2][0][RTW89_WW][46] = 16, ++ [0][1][2][0][RTW89_WW][48] = 58, ++ [0][1][2][0][RTW89_WW][50] = 58, ++ [0][1][2][0][RTW89_WW][52] = 58, ++ [0][1][2][1][RTW89_WW][0] = 14, ++ [0][1][2][1][RTW89_WW][2] = 14, ++ [0][1][2][1][RTW89_WW][4] = 14, ++ [0][1][2][1][RTW89_WW][6] = 14, ++ [0][1][2][1][RTW89_WW][8] = 28, ++ [0][1][2][1][RTW89_WW][10] = 28, ++ [0][1][2][1][RTW89_WW][12] = 28, ++ [0][1][2][1][RTW89_WW][14] = 28, ++ [0][1][2][1][RTW89_WW][15] = 28, ++ [0][1][2][1][RTW89_WW][17] = 28, ++ [0][1][2][1][RTW89_WW][19] = 28, ++ [0][1][2][1][RTW89_WW][21] = 28, ++ [0][1][2][1][RTW89_WW][23] = 28, ++ [0][1][2][1][RTW89_WW][25] = 28, ++ [0][1][2][1][RTW89_WW][27] = 28, ++ [0][1][2][1][RTW89_WW][29] = 28, ++ [0][1][2][1][RTW89_WW][31] = 28, ++ [0][1][2][1][RTW89_WW][33] = 28, ++ [0][1][2][1][RTW89_WW][35] = 28, ++ [0][1][2][1][RTW89_WW][37] = 36, ++ [0][1][2][1][RTW89_WW][38] = 4, ++ [0][1][2][1][RTW89_WW][40] = 4, ++ [0][1][2][1][RTW89_WW][42] = 4, ++ [0][1][2][1][RTW89_WW][44] = 4, ++ [0][1][2][1][RTW89_WW][46] = 4, ++ [0][1][2][1][RTW89_WW][48] = 58, ++ [0][1][2][1][RTW89_WW][50] = 58, ++ [0][1][2][1][RTW89_WW][52] = 58, ++ [1][0][2][0][RTW89_WW][1] = 42, ++ [1][0][2][0][RTW89_WW][5] = 42, ++ [1][0][2][0][RTW89_WW][9] = 52, ++ [1][0][2][0][RTW89_WW][13] = 52, ++ [1][0][2][0][RTW89_WW][16] = 52, ++ [1][0][2][0][RTW89_WW][20] = 52, ++ [1][0][2][0][RTW89_WW][24] = 52, ++ [1][0][2][0][RTW89_WW][28] = 52, ++ [1][0][2][0][RTW89_WW][32] = 52, ++ [1][0][2][0][RTW89_WW][36] = 64, ++ [1][0][2][0][RTW89_WW][39] = 28, ++ [1][0][2][0][RTW89_WW][43] = 28, ++ [1][0][2][0][RTW89_WW][47] = 78, ++ [1][0][2][0][RTW89_WW][51] = 70, ++ [1][1][2][0][RTW89_WW][1] = 30, ++ [1][1][2][0][RTW89_WW][5] = 30, ++ [1][1][2][0][RTW89_WW][9] = 40, ++ [1][1][2][0][RTW89_WW][13] = 40, ++ [1][1][2][0][RTW89_WW][16] = 40, ++ [1][1][2][0][RTW89_WW][20] = 40, ++ [1][1][2][0][RTW89_WW][24] = 40, ++ [1][1][2][0][RTW89_WW][28] = 40, ++ [1][1][2][0][RTW89_WW][32] = 40, ++ [1][1][2][0][RTW89_WW][36] = 50, ++ [1][1][2][0][RTW89_WW][39] = 16, ++ [1][1][2][0][RTW89_WW][43] = 16, ++ [1][1][2][0][RTW89_WW][47] = 68, ++ [1][1][2][0][RTW89_WW][51] = 66, ++ [1][1][2][1][RTW89_WW][1] = 16, ++ [1][1][2][1][RTW89_WW][5] = 16, ++ [1][1][2][1][RTW89_WW][9] = 28, ++ [1][1][2][1][RTW89_WW][13] = 28, ++ [1][1][2][1][RTW89_WW][16] = 28, ++ [1][1][2][1][RTW89_WW][20] = 28, ++ [1][1][2][1][RTW89_WW][24] = 28, ++ [1][1][2][1][RTW89_WW][28] = 28, ++ [1][1][2][1][RTW89_WW][32] = 28, ++ [1][1][2][1][RTW89_WW][36] = 36, ++ [1][1][2][1][RTW89_WW][39] = 4, ++ [1][1][2][1][RTW89_WW][43] = 4, ++ [1][1][2][1][RTW89_WW][47] = 68, ++ [1][1][2][1][RTW89_WW][51] = 66, ++ [2][0][2][0][RTW89_WW][3] = 42, ++ [2][0][2][0][RTW89_WW][11] = 52, ++ [2][0][2][0][RTW89_WW][18] = 52, ++ [2][0][2][0][RTW89_WW][26] = 52, ++ [2][0][2][0][RTW89_WW][34] = 64, ++ [2][0][2][0][RTW89_WW][41] = 28, ++ [2][0][2][0][RTW89_WW][49] = 64, ++ [2][1][2][0][RTW89_WW][3] = 28, ++ [2][1][2][0][RTW89_WW][11] = 40, ++ [2][1][2][0][RTW89_WW][18] = 40, ++ [2][1][2][0][RTW89_WW][26] = 40, ++ [2][1][2][0][RTW89_WW][34] = 50, ++ [2][1][2][0][RTW89_WW][41] = 16, ++ [2][1][2][0][RTW89_WW][49] = 58, ++ [2][1][2][1][RTW89_WW][3] = 16, ++ [2][1][2][1][RTW89_WW][11] = 28, ++ [2][1][2][1][RTW89_WW][18] = 28, ++ [2][1][2][1][RTW89_WW][26] = 28, ++ [2][1][2][1][RTW89_WW][34] = 34, ++ [2][1][2][1][RTW89_WW][41] = 4, ++ [2][1][2][1][RTW89_WW][49] = 58, ++ [0][0][1][0][RTW89_FCC][0] = 78, ++ [0][0][1][0][RTW89_ETSI][0] = 58, ++ [0][0][1][0][RTW89_MKK][0] = 60, ++ [0][0][1][0][RTW89_IC][0] = 60, ++ [0][0][1][0][RTW89_KCC][0] = 76, ++ [0][0][1][0][RTW89_ACMA][0] = 58, ++ [0][0][1][0][RTW89_CHILE][0] = 42, ++ [0][0][1][0][RTW89_UKRAINE][0] = 52, ++ [0][0][1][0][RTW89_MEXICO][0] = 62, ++ [0][0][1][0][RTW89_CN][0] = 58, ++ [0][0][1][0][RTW89_QATAR][0] = 58, ++ [0][0][1][0][RTW89_UK][0] = 58, ++ [0][0][1][0][RTW89_FCC][2] = 78, ++ [0][0][1][0][RTW89_ETSI][2] = 58, ++ [0][0][1][0][RTW89_MKK][2] = 60, ++ [0][0][1][0][RTW89_IC][2] = 60, ++ [0][0][1][0][RTW89_KCC][2] = 76, ++ [0][0][1][0][RTW89_ACMA][2] = 58, ++ [0][0][1][0][RTW89_CHILE][2] = 42, ++ [0][0][1][0][RTW89_UKRAINE][2] = 52, ++ [0][0][1][0][RTW89_MEXICO][2] = 62, ++ [0][0][1][0][RTW89_CN][2] = 58, ++ [0][0][1][0][RTW89_QATAR][2] = 58, ++ [0][0][1][0][RTW89_UK][2] = 58, ++ [0][0][1][0][RTW89_FCC][4] = 78, ++ [0][0][1][0][RTW89_ETSI][4] = 58, ++ [0][0][1][0][RTW89_MKK][4] = 60, ++ [0][0][1][0][RTW89_IC][4] = 60, ++ [0][0][1][0][RTW89_KCC][4] = 76, ++ [0][0][1][0][RTW89_ACMA][4] = 58, ++ [0][0][1][0][RTW89_CHILE][4] = 42, ++ [0][0][1][0][RTW89_UKRAINE][4] = 52, ++ [0][0][1][0][RTW89_MEXICO][4] = 62, ++ [0][0][1][0][RTW89_CN][4] = 58, ++ [0][0][1][0][RTW89_QATAR][4] = 58, ++ [0][0][1][0][RTW89_UK][4] = 58, ++ [0][0][1][0][RTW89_FCC][6] = 78, ++ [0][0][1][0][RTW89_ETSI][6] = 58, ++ [0][0][1][0][RTW89_MKK][6] = 60, ++ [0][0][1][0][RTW89_IC][6] = 60, ++ [0][0][1][0][RTW89_KCC][6] = 50, ++ [0][0][1][0][RTW89_ACMA][6] = 58, ++ [0][0][1][0][RTW89_CHILE][6] = 42, ++ [0][0][1][0][RTW89_UKRAINE][6] = 52, ++ [0][0][1][0][RTW89_MEXICO][6] = 62, ++ [0][0][1][0][RTW89_CN][6] = 58, ++ [0][0][1][0][RTW89_QATAR][6] = 58, ++ [0][0][1][0][RTW89_UK][6] = 58, ++ [0][0][1][0][RTW89_FCC][8] = 78, ++ [0][0][1][0][RTW89_ETSI][8] = 58, ++ [0][0][1][0][RTW89_MKK][8] = 62, ++ [0][0][1][0][RTW89_IC][8] = 64, ++ [0][0][1][0][RTW89_KCC][8] = 70, ++ [0][0][1][0][RTW89_ACMA][8] = 58, ++ [0][0][1][0][RTW89_CHILE][8] = 66, ++ [0][0][1][0][RTW89_UKRAINE][8] = 52, ++ [0][0][1][0][RTW89_MEXICO][8] = 78, ++ [0][0][1][0][RTW89_CN][8] = 58, ++ [0][0][1][0][RTW89_QATAR][8] = 58, ++ [0][0][1][0][RTW89_UK][8] = 58, ++ [0][0][1][0][RTW89_FCC][10] = 78, ++ [0][0][1][0][RTW89_ETSI][10] = 58, ++ [0][0][1][0][RTW89_MKK][10] = 62, ++ [0][0][1][0][RTW89_IC][10] = 64, ++ [0][0][1][0][RTW89_KCC][10] = 70, ++ [0][0][1][0][RTW89_ACMA][10] = 58, ++ [0][0][1][0][RTW89_CHILE][10] = 66, ++ [0][0][1][0][RTW89_UKRAINE][10] = 52, ++ [0][0][1][0][RTW89_MEXICO][10] = 78, ++ [0][0][1][0][RTW89_CN][10] = 58, ++ [0][0][1][0][RTW89_QATAR][10] = 58, ++ [0][0][1][0][RTW89_UK][10] = 58, ++ [0][0][1][0][RTW89_FCC][12] = 78, ++ [0][0][1][0][RTW89_ETSI][12] = 58, ++ [0][0][1][0][RTW89_MKK][12] = 62, ++ [0][0][1][0][RTW89_IC][12] = 64, ++ [0][0][1][0][RTW89_KCC][12] = 74, ++ [0][0][1][0][RTW89_ACMA][12] = 58, ++ [0][0][1][0][RTW89_CHILE][12] = 66, ++ [0][0][1][0][RTW89_UKRAINE][12] = 52, ++ [0][0][1][0][RTW89_MEXICO][12] = 78, ++ [0][0][1][0][RTW89_CN][12] = 58, ++ [0][0][1][0][RTW89_QATAR][12] = 58, ++ [0][0][1][0][RTW89_UK][12] = 58, ++ [0][0][1][0][RTW89_FCC][14] = 78, ++ [0][0][1][0][RTW89_ETSI][14] = 58, ++ [0][0][1][0][RTW89_MKK][14] = 60, ++ [0][0][1][0][RTW89_IC][14] = 64, ++ [0][0][1][0][RTW89_KCC][14] = 74, ++ [0][0][1][0][RTW89_ACMA][14] = 58, ++ [0][0][1][0][RTW89_CHILE][14] = 66, ++ [0][0][1][0][RTW89_UKRAINE][14] = 52, ++ [0][0][1][0][RTW89_MEXICO][14] = 78, ++ [0][0][1][0][RTW89_CN][14] = 58, ++ [0][0][1][0][RTW89_QATAR][14] = 58, ++ [0][0][1][0][RTW89_UK][14] = 58, ++ [0][0][1][0][RTW89_FCC][15] = 76, ++ [0][0][1][0][RTW89_ETSI][15] = 58, ++ [0][0][1][0][RTW89_MKK][15] = 76, ++ [0][0][1][0][RTW89_IC][15] = 76, ++ [0][0][1][0][RTW89_KCC][15] = 74, ++ [0][0][1][0][RTW89_ACMA][15] = 58, ++ [0][0][1][0][RTW89_CHILE][15] = 66, ++ [0][0][1][0][RTW89_UKRAINE][15] = 52, ++ [0][0][1][0][RTW89_MEXICO][15] = 76, ++ [0][0][1][0][RTW89_CN][15] = 127, ++ [0][0][1][0][RTW89_QATAR][15] = 58, ++ [0][0][1][0][RTW89_UK][15] = 58, ++ [0][0][1][0][RTW89_FCC][17] = 78, ++ [0][0][1][0][RTW89_ETSI][17] = 58, ++ [0][0][1][0][RTW89_MKK][17] = 76, ++ [0][0][1][0][RTW89_IC][17] = 78, ++ [0][0][1][0][RTW89_KCC][17] = 74, ++ [0][0][1][0][RTW89_ACMA][17] = 58, ++ [0][0][1][0][RTW89_CHILE][17] = 66, ++ [0][0][1][0][RTW89_UKRAINE][17] = 52, ++ [0][0][1][0][RTW89_MEXICO][17] = 78, ++ [0][0][1][0][RTW89_CN][17] = 127, ++ [0][0][1][0][RTW89_QATAR][17] = 58, ++ [0][0][1][0][RTW89_UK][17] = 58, ++ [0][0][1][0][RTW89_FCC][19] = 78, ++ [0][0][1][0][RTW89_ETSI][19] = 58, ++ [0][0][1][0][RTW89_MKK][19] = 76, ++ [0][0][1][0][RTW89_IC][19] = 78, ++ [0][0][1][0][RTW89_KCC][19] = 74, ++ [0][0][1][0][RTW89_ACMA][19] = 58, ++ [0][0][1][0][RTW89_CHILE][19] = 66, ++ [0][0][1][0][RTW89_UKRAINE][19] = 52, ++ [0][0][1][0][RTW89_MEXICO][19] = 78, ++ [0][0][1][0][RTW89_CN][19] = 127, ++ [0][0][1][0][RTW89_QATAR][19] = 58, ++ [0][0][1][0][RTW89_UK][19] = 58, ++ [0][0][1][0][RTW89_FCC][21] = 78, ++ [0][0][1][0][RTW89_ETSI][21] = 58, ++ [0][0][1][0][RTW89_MKK][21] = 76, ++ [0][0][1][0][RTW89_IC][21] = 78, ++ [0][0][1][0][RTW89_KCC][21] = 74, ++ [0][0][1][0][RTW89_ACMA][21] = 58, ++ [0][0][1][0][RTW89_CHILE][21] = 68, ++ [0][0][1][0][RTW89_UKRAINE][21] = 52, ++ [0][0][1][0][RTW89_MEXICO][21] = 78, ++ [0][0][1][0][RTW89_CN][21] = 127, ++ [0][0][1][0][RTW89_QATAR][21] = 58, ++ [0][0][1][0][RTW89_UK][21] = 58, ++ [0][0][1][0][RTW89_FCC][23] = 78, ++ [0][0][1][0][RTW89_ETSI][23] = 58, ++ [0][0][1][0][RTW89_MKK][23] = 76, ++ [0][0][1][0][RTW89_IC][23] = 78, ++ [0][0][1][0][RTW89_KCC][23] = 74, ++ [0][0][1][0][RTW89_ACMA][23] = 58, ++ [0][0][1][0][RTW89_CHILE][23] = 68, ++ [0][0][1][0][RTW89_UKRAINE][23] = 52, ++ [0][0][1][0][RTW89_MEXICO][23] = 78, ++ [0][0][1][0][RTW89_CN][23] = 127, ++ [0][0][1][0][RTW89_QATAR][23] = 58, ++ [0][0][1][0][RTW89_UK][23] = 58, ++ [0][0][1][0][RTW89_FCC][25] = 78, ++ [0][0][1][0][RTW89_ETSI][25] = 58, ++ [0][0][1][0][RTW89_MKK][25] = 76, ++ [0][0][1][0][RTW89_IC][25] = 127, ++ [0][0][1][0][RTW89_KCC][25] = 74, ++ [0][0][1][0][RTW89_ACMA][25] = 127, ++ [0][0][1][0][RTW89_CHILE][25] = 68, ++ [0][0][1][0][RTW89_UKRAINE][25] = 52, ++ [0][0][1][0][RTW89_MEXICO][25] = 78, ++ [0][0][1][0][RTW89_CN][25] = 127, ++ [0][0][1][0][RTW89_QATAR][25] = 58, ++ [0][0][1][0][RTW89_UK][25] = 58, ++ [0][0][1][0][RTW89_FCC][27] = 78, ++ [0][0][1][0][RTW89_ETSI][27] = 58, ++ [0][0][1][0][RTW89_MKK][27] = 76, ++ [0][0][1][0][RTW89_IC][27] = 127, ++ [0][0][1][0][RTW89_KCC][27] = 74, ++ [0][0][1][0][RTW89_ACMA][27] = 127, ++ [0][0][1][0][RTW89_CHILE][27] = 66, ++ [0][0][1][0][RTW89_UKRAINE][27] = 52, ++ [0][0][1][0][RTW89_MEXICO][27] = 78, ++ [0][0][1][0][RTW89_CN][27] = 127, ++ [0][0][1][0][RTW89_QATAR][27] = 58, ++ [0][0][1][0][RTW89_UK][27] = 58, ++ [0][0][1][0][RTW89_FCC][29] = 78, ++ [0][0][1][0][RTW89_ETSI][29] = 58, ++ [0][0][1][0][RTW89_MKK][29] = 76, ++ [0][0][1][0][RTW89_IC][29] = 127, ++ [0][0][1][0][RTW89_KCC][29] = 74, ++ [0][0][1][0][RTW89_ACMA][29] = 127, ++ [0][0][1][0][RTW89_CHILE][29] = 66, ++ [0][0][1][0][RTW89_UKRAINE][29] = 52, ++ [0][0][1][0][RTW89_MEXICO][29] = 78, ++ [0][0][1][0][RTW89_CN][29] = 127, ++ [0][0][1][0][RTW89_QATAR][29] = 58, ++ [0][0][1][0][RTW89_UK][29] = 58, ++ [0][0][1][0][RTW89_FCC][31] = 78, ++ [0][0][1][0][RTW89_ETSI][31] = 58, ++ [0][0][1][0][RTW89_MKK][31] = 76, ++ [0][0][1][0][RTW89_IC][31] = 78, ++ [0][0][1][0][RTW89_KCC][31] = 72, ++ [0][0][1][0][RTW89_ACMA][31] = 58, ++ [0][0][1][0][RTW89_CHILE][31] = 66, ++ [0][0][1][0][RTW89_UKRAINE][31] = 52, ++ [0][0][1][0][RTW89_MEXICO][31] = 78, ++ [0][0][1][0][RTW89_CN][31] = 127, ++ [0][0][1][0][RTW89_QATAR][31] = 58, ++ [0][0][1][0][RTW89_UK][31] = 58, ++ [0][0][1][0][RTW89_FCC][33] = 78, ++ [0][0][1][0][RTW89_ETSI][33] = 58, ++ [0][0][1][0][RTW89_MKK][33] = 76, ++ [0][0][1][0][RTW89_IC][33] = 78, ++ [0][0][1][0][RTW89_KCC][33] = 72, ++ [0][0][1][0][RTW89_ACMA][33] = 58, ++ [0][0][1][0][RTW89_CHILE][33] = 66, ++ [0][0][1][0][RTW89_UKRAINE][33] = 52, ++ [0][0][1][0][RTW89_MEXICO][33] = 78, ++ [0][0][1][0][RTW89_CN][33] = 127, ++ [0][0][1][0][RTW89_QATAR][33] = 58, ++ [0][0][1][0][RTW89_UK][33] = 58, ++ [0][0][1][0][RTW89_FCC][35] = 70, ++ [0][0][1][0][RTW89_ETSI][35] = 58, ++ [0][0][1][0][RTW89_MKK][35] = 76, ++ [0][0][1][0][RTW89_IC][35] = 70, ++ [0][0][1][0][RTW89_KCC][35] = 72, ++ [0][0][1][0][RTW89_ACMA][35] = 58, ++ [0][0][1][0][RTW89_CHILE][35] = 66, ++ [0][0][1][0][RTW89_UKRAINE][35] = 52, ++ [0][0][1][0][RTW89_MEXICO][35] = 70, ++ [0][0][1][0][RTW89_CN][35] = 127, ++ [0][0][1][0][RTW89_QATAR][35] = 58, ++ [0][0][1][0][RTW89_UK][35] = 58, ++ [0][0][1][0][RTW89_FCC][37] = 78, ++ [0][0][1][0][RTW89_ETSI][37] = 127, ++ [0][0][1][0][RTW89_MKK][37] = 76, ++ [0][0][1][0][RTW89_IC][37] = 78, ++ [0][0][1][0][RTW89_KCC][37] = 72, ++ [0][0][1][0][RTW89_ACMA][37] = 76, ++ [0][0][1][0][RTW89_CHILE][37] = 68, ++ [0][0][1][0][RTW89_UKRAINE][37] = 127, ++ [0][0][1][0][RTW89_MEXICO][37] = 78, ++ [0][0][1][0][RTW89_CN][37] = 127, ++ [0][0][1][0][RTW89_QATAR][37] = 127, ++ [0][0][1][0][RTW89_UK][37] = 76, ++ [0][0][1][0][RTW89_FCC][38] = 78, ++ [0][0][1][0][RTW89_ETSI][38] = 28, ++ [0][0][1][0][RTW89_MKK][38] = 127, ++ [0][0][1][0][RTW89_IC][38] = 78, ++ [0][0][1][0][RTW89_KCC][38] = 74, ++ [0][0][1][0][RTW89_ACMA][38] = 76, ++ [0][0][1][0][RTW89_CHILE][38] = 68, ++ [0][0][1][0][RTW89_UKRAINE][38] = 28, ++ [0][0][1][0][RTW89_MEXICO][38] = 78, ++ [0][0][1][0][RTW89_CN][38] = 76, ++ [0][0][1][0][RTW89_QATAR][38] = 28, ++ [0][0][1][0][RTW89_UK][38] = 58, ++ [0][0][1][0][RTW89_FCC][40] = 78, ++ [0][0][1][0][RTW89_ETSI][40] = 28, ++ [0][0][1][0][RTW89_MKK][40] = 127, ++ [0][0][1][0][RTW89_IC][40] = 78, ++ [0][0][1][0][RTW89_KCC][40] = 74, ++ [0][0][1][0][RTW89_ACMA][40] = 76, ++ [0][0][1][0][RTW89_CHILE][40] = 68, ++ [0][0][1][0][RTW89_UKRAINE][40] = 28, ++ [0][0][1][0][RTW89_MEXICO][40] = 78, ++ [0][0][1][0][RTW89_CN][40] = 76, ++ [0][0][1][0][RTW89_QATAR][40] = 28, ++ [0][0][1][0][RTW89_UK][40] = 58, ++ [0][0][1][0][RTW89_FCC][42] = 78, ++ [0][0][1][0][RTW89_ETSI][42] = 28, ++ [0][0][1][0][RTW89_MKK][42] = 127, ++ [0][0][1][0][RTW89_IC][42] = 78, ++ [0][0][1][0][RTW89_KCC][42] = 74, ++ [0][0][1][0][RTW89_ACMA][42] = 76, ++ [0][0][1][0][RTW89_CHILE][42] = 66, ++ [0][0][1][0][RTW89_UKRAINE][42] = 28, ++ [0][0][1][0][RTW89_MEXICO][42] = 78, ++ [0][0][1][0][RTW89_CN][42] = 76, ++ [0][0][1][0][RTW89_QATAR][42] = 28, ++ [0][0][1][0][RTW89_UK][42] = 58, ++ [0][0][1][0][RTW89_FCC][44] = 78, ++ [0][0][1][0][RTW89_ETSI][44] = 28, ++ [0][0][1][0][RTW89_MKK][44] = 127, ++ [0][0][1][0][RTW89_IC][44] = 78, ++ [0][0][1][0][RTW89_KCC][44] = 74, ++ [0][0][1][0][RTW89_ACMA][44] = 76, ++ [0][0][1][0][RTW89_CHILE][44] = 68, ++ [0][0][1][0][RTW89_UKRAINE][44] = 28, ++ [0][0][1][0][RTW89_MEXICO][44] = 78, ++ [0][0][1][0][RTW89_CN][44] = 76, ++ [0][0][1][0][RTW89_QATAR][44] = 28, ++ [0][0][1][0][RTW89_UK][44] = 58, ++ [0][0][1][0][RTW89_FCC][46] = 78, ++ [0][0][1][0][RTW89_ETSI][46] = 28, ++ [0][0][1][0][RTW89_MKK][46] = 127, ++ [0][0][1][0][RTW89_IC][46] = 78, ++ [0][0][1][0][RTW89_KCC][46] = 74, ++ [0][0][1][0][RTW89_ACMA][46] = 76, ++ [0][0][1][0][RTW89_CHILE][46] = 68, ++ [0][0][1][0][RTW89_UKRAINE][46] = 28, ++ [0][0][1][0][RTW89_MEXICO][46] = 78, ++ [0][0][1][0][RTW89_CN][46] = 76, ++ [0][0][1][0][RTW89_QATAR][46] = 28, ++ [0][0][1][0][RTW89_UK][46] = 58, ++ [0][0][1][0][RTW89_FCC][48] = 78, ++ [0][0][1][0][RTW89_ETSI][48] = 127, ++ [0][0][1][0][RTW89_MKK][48] = 127, ++ [0][0][1][0][RTW89_IC][48] = 127, ++ [0][0][1][0][RTW89_KCC][48] = 127, ++ [0][0][1][0][RTW89_ACMA][48] = 127, ++ [0][0][1][0][RTW89_CHILE][48] = 127, ++ [0][0][1][0][RTW89_UKRAINE][48] = 127, ++ [0][0][1][0][RTW89_MEXICO][48] = 127, ++ [0][0][1][0][RTW89_CN][48] = 127, ++ [0][0][1][0][RTW89_QATAR][48] = 127, ++ [0][0][1][0][RTW89_UK][48] = 127, ++ [0][0][1][0][RTW89_FCC][50] = 78, ++ [0][0][1][0][RTW89_ETSI][50] = 127, ++ [0][0][1][0][RTW89_MKK][50] = 127, ++ [0][0][1][0][RTW89_IC][50] = 127, ++ [0][0][1][0][RTW89_KCC][50] = 127, ++ [0][0][1][0][RTW89_ACMA][50] = 127, ++ [0][0][1][0][RTW89_CHILE][50] = 127, ++ [0][0][1][0][RTW89_UKRAINE][50] = 127, ++ [0][0][1][0][RTW89_MEXICO][50] = 127, ++ [0][0][1][0][RTW89_CN][50] = 127, ++ [0][0][1][0][RTW89_QATAR][50] = 127, ++ [0][0][1][0][RTW89_UK][50] = 127, ++ [0][0][1][0][RTW89_FCC][52] = 78, ++ [0][0][1][0][RTW89_ETSI][52] = 127, ++ [0][0][1][0][RTW89_MKK][52] = 127, ++ [0][0][1][0][RTW89_IC][52] = 127, ++ [0][0][1][0][RTW89_KCC][52] = 127, ++ [0][0][1][0][RTW89_ACMA][52] = 127, ++ [0][0][1][0][RTW89_CHILE][52] = 127, ++ [0][0][1][0][RTW89_UKRAINE][52] = 127, ++ [0][0][1][0][RTW89_MEXICO][52] = 127, ++ [0][0][1][0][RTW89_CN][52] = 127, ++ [0][0][1][0][RTW89_QATAR][52] = 127, ++ [0][0][1][0][RTW89_UK][52] = 127, ++ [0][1][1][0][RTW89_FCC][0] = 68, ++ [0][1][1][0][RTW89_ETSI][0] = 46, ++ [0][1][1][0][RTW89_MKK][0] = 48, ++ [0][1][1][0][RTW89_IC][0] = 40, ++ [0][1][1][0][RTW89_KCC][0] = 64, ++ [0][1][1][0][RTW89_ACMA][0] = 46, ++ [0][1][1][0][RTW89_CHILE][0] = 30, ++ [0][1][1][0][RTW89_UKRAINE][0] = 40, ++ [0][1][1][0][RTW89_MEXICO][0] = 50, ++ [0][1][1][0][RTW89_CN][0] = 46, ++ [0][1][1][0][RTW89_QATAR][0] = 46, ++ [0][1][1][0][RTW89_UK][0] = 46, ++ [0][1][1][0][RTW89_FCC][2] = 68, ++ [0][1][1][0][RTW89_ETSI][2] = 46, ++ [0][1][1][0][RTW89_MKK][2] = 48, ++ [0][1][1][0][RTW89_IC][2] = 40, ++ [0][1][1][0][RTW89_KCC][2] = 64, ++ [0][1][1][0][RTW89_ACMA][2] = 46, ++ [0][1][1][0][RTW89_CHILE][2] = 32, ++ [0][1][1][0][RTW89_UKRAINE][2] = 40, ++ [0][1][1][0][RTW89_MEXICO][2] = 50, ++ [0][1][1][0][RTW89_CN][2] = 46, ++ [0][1][1][0][RTW89_QATAR][2] = 46, ++ [0][1][1][0][RTW89_UK][2] = 46, ++ [0][1][1][0][RTW89_FCC][4] = 68, ++ [0][1][1][0][RTW89_ETSI][4] = 46, ++ [0][1][1][0][RTW89_MKK][4] = 48, ++ [0][1][1][0][RTW89_IC][4] = 40, ++ [0][1][1][0][RTW89_KCC][4] = 64, ++ [0][1][1][0][RTW89_ACMA][4] = 46, ++ [0][1][1][0][RTW89_CHILE][4] = 30, ++ [0][1][1][0][RTW89_UKRAINE][4] = 40, ++ [0][1][1][0][RTW89_MEXICO][4] = 50, ++ [0][1][1][0][RTW89_CN][4] = 46, ++ [0][1][1][0][RTW89_QATAR][4] = 46, ++ [0][1][1][0][RTW89_UK][4] = 46, ++ [0][1][1][0][RTW89_FCC][6] = 68, ++ [0][1][1][0][RTW89_ETSI][6] = 46, ++ [0][1][1][0][RTW89_MKK][6] = 48, ++ [0][1][1][0][RTW89_IC][6] = 40, ++ [0][1][1][0][RTW89_KCC][6] = 38, ++ [0][1][1][0][RTW89_ACMA][6] = 46, ++ [0][1][1][0][RTW89_CHILE][6] = 30, ++ [0][1][1][0][RTW89_UKRAINE][6] = 40, ++ [0][1][1][0][RTW89_MEXICO][6] = 50, ++ [0][1][1][0][RTW89_CN][6] = 46, ++ [0][1][1][0][RTW89_QATAR][6] = 46, ++ [0][1][1][0][RTW89_UK][6] = 46, ++ [0][1][1][0][RTW89_FCC][8] = 68, ++ [0][1][1][0][RTW89_ETSI][8] = 46, ++ [0][1][1][0][RTW89_MKK][8] = 48, ++ [0][1][1][0][RTW89_IC][8] = 52, ++ [0][1][1][0][RTW89_KCC][8] = 64, ++ [0][1][1][0][RTW89_ACMA][8] = 46, ++ [0][1][1][0][RTW89_CHILE][8] = 52, ++ [0][1][1][0][RTW89_UKRAINE][8] = 40, ++ [0][1][1][0][RTW89_MEXICO][8] = 68, ++ [0][1][1][0][RTW89_CN][8] = 46, ++ [0][1][1][0][RTW89_QATAR][8] = 46, ++ [0][1][1][0][RTW89_UK][8] = 46, ++ [0][1][1][0][RTW89_FCC][10] = 68, ++ [0][1][1][0][RTW89_ETSI][10] = 46, ++ [0][1][1][0][RTW89_MKK][10] = 48, ++ [0][1][1][0][RTW89_IC][10] = 52, ++ [0][1][1][0][RTW89_KCC][10] = 64, ++ [0][1][1][0][RTW89_ACMA][10] = 46, ++ [0][1][1][0][RTW89_CHILE][10] = 52, ++ [0][1][1][0][RTW89_UKRAINE][10] = 40, ++ [0][1][1][0][RTW89_MEXICO][10] = 68, ++ [0][1][1][0][RTW89_CN][10] = 46, ++ [0][1][1][0][RTW89_QATAR][10] = 46, ++ [0][1][1][0][RTW89_UK][10] = 46, ++ [0][1][1][0][RTW89_FCC][12] = 68, ++ [0][1][1][0][RTW89_ETSI][12] = 46, ++ [0][1][1][0][RTW89_MKK][12] = 48, ++ [0][1][1][0][RTW89_IC][12] = 52, ++ [0][1][1][0][RTW89_KCC][12] = 64, ++ [0][1][1][0][RTW89_ACMA][12] = 46, ++ [0][1][1][0][RTW89_CHILE][12] = 52, ++ [0][1][1][0][RTW89_UKRAINE][12] = 40, ++ [0][1][1][0][RTW89_MEXICO][12] = 68, ++ [0][1][1][0][RTW89_CN][12] = 46, ++ [0][1][1][0][RTW89_QATAR][12] = 46, ++ [0][1][1][0][RTW89_UK][12] = 46, ++ [0][1][1][0][RTW89_FCC][14] = 68, ++ [0][1][1][0][RTW89_ETSI][14] = 46, ++ [0][1][1][0][RTW89_MKK][14] = 48, ++ [0][1][1][0][RTW89_IC][14] = 52, ++ [0][1][1][0][RTW89_KCC][14] = 64, ++ [0][1][1][0][RTW89_ACMA][14] = 46, ++ [0][1][1][0][RTW89_CHILE][14] = 52, ++ [0][1][1][0][RTW89_UKRAINE][14] = 40, ++ [0][1][1][0][RTW89_MEXICO][14] = 68, ++ [0][1][1][0][RTW89_CN][14] = 46, ++ [0][1][1][0][RTW89_QATAR][14] = 46, ++ [0][1][1][0][RTW89_UK][14] = 46, ++ [0][1][1][0][RTW89_FCC][15] = 66, ++ [0][1][1][0][RTW89_ETSI][15] = 46, ++ [0][1][1][0][RTW89_MKK][15] = 68, ++ [0][1][1][0][RTW89_IC][15] = 66, ++ [0][1][1][0][RTW89_KCC][15] = 62, ++ [0][1][1][0][RTW89_ACMA][15] = 46, ++ [0][1][1][0][RTW89_CHILE][15] = 48, ++ [0][1][1][0][RTW89_UKRAINE][15] = 40, ++ [0][1][1][0][RTW89_MEXICO][15] = 66, ++ [0][1][1][0][RTW89_CN][15] = 127, ++ [0][1][1][0][RTW89_QATAR][15] = 46, ++ [0][1][1][0][RTW89_UK][15] = 46, ++ [0][1][1][0][RTW89_FCC][17] = 68, ++ [0][1][1][0][RTW89_ETSI][17] = 46, ++ [0][1][1][0][RTW89_MKK][17] = 70, ++ [0][1][1][0][RTW89_IC][17] = 68, ++ [0][1][1][0][RTW89_KCC][17] = 62, ++ [0][1][1][0][RTW89_ACMA][17] = 46, ++ [0][1][1][0][RTW89_CHILE][17] = 48, ++ [0][1][1][0][RTW89_UKRAINE][17] = 40, ++ [0][1][1][0][RTW89_MEXICO][17] = 68, ++ [0][1][1][0][RTW89_CN][17] = 127, ++ [0][1][1][0][RTW89_QATAR][17] = 46, ++ [0][1][1][0][RTW89_UK][17] = 46, ++ [0][1][1][0][RTW89_FCC][19] = 68, ++ [0][1][1][0][RTW89_ETSI][19] = 46, ++ [0][1][1][0][RTW89_MKK][19] = 70, ++ [0][1][1][0][RTW89_IC][19] = 68, ++ [0][1][1][0][RTW89_KCC][19] = 62, ++ [0][1][1][0][RTW89_ACMA][19] = 46, ++ [0][1][1][0][RTW89_CHILE][19] = 48, ++ [0][1][1][0][RTW89_UKRAINE][19] = 40, ++ [0][1][1][0][RTW89_MEXICO][19] = 68, ++ [0][1][1][0][RTW89_CN][19] = 127, ++ [0][1][1][0][RTW89_QATAR][19] = 46, ++ [0][1][1][0][RTW89_UK][19] = 46, ++ [0][1][1][0][RTW89_FCC][21] = 68, ++ [0][1][1][0][RTW89_ETSI][21] = 46, ++ [0][1][1][0][RTW89_MKK][21] = 70, ++ [0][1][1][0][RTW89_IC][21] = 68, ++ [0][1][1][0][RTW89_KCC][21] = 62, ++ [0][1][1][0][RTW89_ACMA][21] = 46, ++ [0][1][1][0][RTW89_CHILE][21] = 48, ++ [0][1][1][0][RTW89_UKRAINE][21] = 40, ++ [0][1][1][0][RTW89_MEXICO][21] = 68, ++ [0][1][1][0][RTW89_CN][21] = 127, ++ [0][1][1][0][RTW89_QATAR][21] = 46, ++ [0][1][1][0][RTW89_UK][21] = 46, ++ [0][1][1][0][RTW89_FCC][23] = 68, ++ [0][1][1][0][RTW89_ETSI][23] = 46, ++ [0][1][1][0][RTW89_MKK][23] = 70, ++ [0][1][1][0][RTW89_IC][23] = 68, ++ [0][1][1][0][RTW89_KCC][23] = 62, ++ [0][1][1][0][RTW89_ACMA][23] = 46, ++ [0][1][1][0][RTW89_CHILE][23] = 48, ++ [0][1][1][0][RTW89_UKRAINE][23] = 40, ++ [0][1][1][0][RTW89_MEXICO][23] = 68, ++ [0][1][1][0][RTW89_CN][23] = 127, ++ [0][1][1][0][RTW89_QATAR][23] = 46, ++ [0][1][1][0][RTW89_UK][23] = 46, ++ [0][1][1][0][RTW89_FCC][25] = 68, ++ [0][1][1][0][RTW89_ETSI][25] = 46, ++ [0][1][1][0][RTW89_MKK][25] = 68, ++ [0][1][1][0][RTW89_IC][25] = 127, ++ [0][1][1][0][RTW89_KCC][25] = 62, ++ [0][1][1][0][RTW89_ACMA][25] = 127, ++ [0][1][1][0][RTW89_CHILE][25] = 48, ++ [0][1][1][0][RTW89_UKRAINE][25] = 40, ++ [0][1][1][0][RTW89_MEXICO][25] = 68, ++ [0][1][1][0][RTW89_CN][25] = 127, ++ [0][1][1][0][RTW89_QATAR][25] = 46, ++ [0][1][1][0][RTW89_UK][25] = 46, ++ [0][1][1][0][RTW89_FCC][27] = 68, ++ [0][1][1][0][RTW89_ETSI][27] = 46, ++ [0][1][1][0][RTW89_MKK][27] = 70, ++ [0][1][1][0][RTW89_IC][27] = 127, ++ [0][1][1][0][RTW89_KCC][27] = 62, ++ [0][1][1][0][RTW89_ACMA][27] = 127, ++ [0][1][1][0][RTW89_CHILE][27] = 50, ++ [0][1][1][0][RTW89_UKRAINE][27] = 40, ++ [0][1][1][0][RTW89_MEXICO][27] = 68, ++ [0][1][1][0][RTW89_CN][27] = 127, ++ [0][1][1][0][RTW89_QATAR][27] = 46, ++ [0][1][1][0][RTW89_UK][27] = 46, ++ [0][1][1][0][RTW89_FCC][29] = 68, ++ [0][1][1][0][RTW89_ETSI][29] = 46, ++ [0][1][1][0][RTW89_MKK][29] = 70, ++ [0][1][1][0][RTW89_IC][29] = 127, ++ [0][1][1][0][RTW89_KCC][29] = 62, ++ [0][1][1][0][RTW89_ACMA][29] = 127, ++ [0][1][1][0][RTW89_CHILE][29] = 50, ++ [0][1][1][0][RTW89_UKRAINE][29] = 40, ++ [0][1][1][0][RTW89_MEXICO][29] = 68, ++ [0][1][1][0][RTW89_CN][29] = 127, ++ [0][1][1][0][RTW89_QATAR][29] = 46, ++ [0][1][1][0][RTW89_UK][29] = 46, ++ [0][1][1][0][RTW89_FCC][31] = 68, ++ [0][1][1][0][RTW89_ETSI][31] = 46, ++ [0][1][1][0][RTW89_MKK][31] = 70, ++ [0][1][1][0][RTW89_IC][31] = 68, ++ [0][1][1][0][RTW89_KCC][31] = 62, ++ [0][1][1][0][RTW89_ACMA][31] = 46, ++ [0][1][1][0][RTW89_CHILE][31] = 50, ++ [0][1][1][0][RTW89_UKRAINE][31] = 40, ++ [0][1][1][0][RTW89_MEXICO][31] = 68, ++ [0][1][1][0][RTW89_CN][31] = 127, ++ [0][1][1][0][RTW89_QATAR][31] = 46, ++ [0][1][1][0][RTW89_UK][31] = 46, ++ [0][1][1][0][RTW89_FCC][33] = 68, ++ [0][1][1][0][RTW89_ETSI][33] = 46, ++ [0][1][1][0][RTW89_MKK][33] = 70, ++ [0][1][1][0][RTW89_IC][33] = 68, ++ [0][1][1][0][RTW89_KCC][33] = 62, ++ [0][1][1][0][RTW89_ACMA][33] = 46, ++ [0][1][1][0][RTW89_CHILE][33] = 50, ++ [0][1][1][0][RTW89_UKRAINE][33] = 40, ++ [0][1][1][0][RTW89_MEXICO][33] = 68, ++ [0][1][1][0][RTW89_CN][33] = 127, ++ [0][1][1][0][RTW89_QATAR][33] = 46, ++ [0][1][1][0][RTW89_UK][33] = 46, ++ [0][1][1][0][RTW89_FCC][35] = 66, ++ [0][1][1][0][RTW89_ETSI][35] = 46, ++ [0][1][1][0][RTW89_MKK][35] = 70, ++ [0][1][1][0][RTW89_IC][35] = 66, ++ [0][1][1][0][RTW89_KCC][35] = 62, ++ [0][1][1][0][RTW89_ACMA][35] = 46, ++ [0][1][1][0][RTW89_CHILE][35] = 50, ++ [0][1][1][0][RTW89_UKRAINE][35] = 40, ++ [0][1][1][0][RTW89_MEXICO][35] = 66, ++ [0][1][1][0][RTW89_CN][35] = 127, ++ [0][1][1][0][RTW89_QATAR][35] = 46, ++ [0][1][1][0][RTW89_UK][35] = 46, ++ [0][1][1][0][RTW89_FCC][37] = 68, ++ [0][1][1][0][RTW89_ETSI][37] = 127, ++ [0][1][1][0][RTW89_MKK][37] = 70, ++ [0][1][1][0][RTW89_IC][37] = 68, ++ [0][1][1][0][RTW89_KCC][37] = 62, ++ [0][1][1][0][RTW89_ACMA][37] = 70, ++ [0][1][1][0][RTW89_CHILE][37] = 50, ++ [0][1][1][0][RTW89_UKRAINE][37] = 127, ++ [0][1][1][0][RTW89_MEXICO][37] = 68, ++ [0][1][1][0][RTW89_CN][37] = 127, ++ [0][1][1][0][RTW89_QATAR][37] = 127, ++ [0][1][1][0][RTW89_UK][37] = 76, ++ [0][1][1][0][RTW89_FCC][38] = 78, ++ [0][1][1][0][RTW89_ETSI][38] = 16, ++ [0][1][1][0][RTW89_MKK][38] = 127, ++ [0][1][1][0][RTW89_IC][38] = 78, ++ [0][1][1][0][RTW89_KCC][38] = 60, ++ [0][1][1][0][RTW89_ACMA][38] = 72, ++ [0][1][1][0][RTW89_CHILE][38] = 48, ++ [0][1][1][0][RTW89_UKRAINE][38] = 16, ++ [0][1][1][0][RTW89_MEXICO][38] = 78, ++ [0][1][1][0][RTW89_CN][38] = 76, ++ [0][1][1][0][RTW89_QATAR][38] = 16, ++ [0][1][1][0][RTW89_UK][38] = 46, ++ [0][1][1][0][RTW89_FCC][40] = 78, ++ [0][1][1][0][RTW89_ETSI][40] = 16, ++ [0][1][1][0][RTW89_MKK][40] = 127, ++ [0][1][1][0][RTW89_IC][40] = 78, ++ [0][1][1][0][RTW89_KCC][40] = 60, ++ [0][1][1][0][RTW89_ACMA][40] = 72, ++ [0][1][1][0][RTW89_CHILE][40] = 48, ++ [0][1][1][0][RTW89_UKRAINE][40] = 16, ++ [0][1][1][0][RTW89_MEXICO][40] = 78, ++ [0][1][1][0][RTW89_CN][40] = 76, ++ [0][1][1][0][RTW89_QATAR][40] = 16, ++ [0][1][1][0][RTW89_UK][40] = 46, ++ [0][1][1][0][RTW89_FCC][42] = 78, ++ [0][1][1][0][RTW89_ETSI][42] = 16, ++ [0][1][1][0][RTW89_MKK][42] = 127, ++ [0][1][1][0][RTW89_IC][42] = 78, ++ [0][1][1][0][RTW89_KCC][42] = 60, ++ [0][1][1][0][RTW89_ACMA][42] = 76, ++ [0][1][1][0][RTW89_CHILE][42] = 48, ++ [0][1][1][0][RTW89_UKRAINE][42] = 16, ++ [0][1][1][0][RTW89_MEXICO][42] = 78, ++ [0][1][1][0][RTW89_CN][42] = 76, ++ [0][1][1][0][RTW89_QATAR][42] = 16, ++ [0][1][1][0][RTW89_UK][42] = 46, ++ [0][1][1][0][RTW89_FCC][44] = 78, ++ [0][1][1][0][RTW89_ETSI][44] = 16, ++ [0][1][1][0][RTW89_MKK][44] = 127, ++ [0][1][1][0][RTW89_IC][44] = 78, ++ [0][1][1][0][RTW89_KCC][44] = 60, ++ [0][1][1][0][RTW89_ACMA][44] = 76, ++ [0][1][1][0][RTW89_CHILE][44] = 48, ++ [0][1][1][0][RTW89_UKRAINE][44] = 16, ++ [0][1][1][0][RTW89_MEXICO][44] = 78, ++ [0][1][1][0][RTW89_CN][44] = 76, ++ [0][1][1][0][RTW89_QATAR][44] = 16, ++ [0][1][1][0][RTW89_UK][44] = 46, ++ [0][1][1][0][RTW89_FCC][46] = 78, ++ [0][1][1][0][RTW89_ETSI][46] = 16, ++ [0][1][1][0][RTW89_MKK][46] = 127, ++ [0][1][1][0][RTW89_IC][46] = 78, ++ [0][1][1][0][RTW89_KCC][46] = 60, ++ [0][1][1][0][RTW89_ACMA][46] = 76, ++ [0][1][1][0][RTW89_CHILE][46] = 48, ++ [0][1][1][0][RTW89_UKRAINE][46] = 16, ++ [0][1][1][0][RTW89_MEXICO][46] = 78, ++ [0][1][1][0][RTW89_CN][46] = 76, ++ [0][1][1][0][RTW89_QATAR][46] = 16, ++ [0][1][1][0][RTW89_UK][46] = 46, ++ [0][1][1][0][RTW89_FCC][48] = 56, ++ [0][1][1][0][RTW89_ETSI][48] = 127, ++ [0][1][1][0][RTW89_MKK][48] = 127, ++ [0][1][1][0][RTW89_IC][48] = 127, ++ [0][1][1][0][RTW89_KCC][48] = 127, ++ [0][1][1][0][RTW89_ACMA][48] = 127, ++ [0][1][1][0][RTW89_CHILE][48] = 127, ++ [0][1][1][0][RTW89_UKRAINE][48] = 127, ++ [0][1][1][0][RTW89_MEXICO][48] = 127, ++ [0][1][1][0][RTW89_CN][48] = 127, ++ [0][1][1][0][RTW89_QATAR][48] = 127, ++ [0][1][1][0][RTW89_UK][48] = 127, ++ [0][1][1][0][RTW89_FCC][50] = 56, ++ [0][1][1][0][RTW89_ETSI][50] = 127, ++ [0][1][1][0][RTW89_MKK][50] = 127, ++ [0][1][1][0][RTW89_IC][50] = 127, ++ [0][1][1][0][RTW89_KCC][50] = 127, ++ [0][1][1][0][RTW89_ACMA][50] = 127, ++ [0][1][1][0][RTW89_CHILE][50] = 127, ++ [0][1][1][0][RTW89_UKRAINE][50] = 127, ++ [0][1][1][0][RTW89_MEXICO][50] = 127, ++ [0][1][1][0][RTW89_CN][50] = 127, ++ [0][1][1][0][RTW89_QATAR][50] = 127, ++ [0][1][1][0][RTW89_UK][50] = 127, ++ [0][1][1][0][RTW89_FCC][52] = 56, ++ [0][1][1][0][RTW89_ETSI][52] = 127, ++ [0][1][1][0][RTW89_MKK][52] = 127, ++ [0][1][1][0][RTW89_IC][52] = 127, ++ [0][1][1][0][RTW89_KCC][52] = 127, ++ [0][1][1][0][RTW89_ACMA][52] = 127, ++ [0][1][1][0][RTW89_CHILE][52] = 127, ++ [0][1][1][0][RTW89_UKRAINE][52] = 127, ++ [0][1][1][0][RTW89_MEXICO][52] = 127, ++ [0][1][1][0][RTW89_CN][52] = 127, ++ [0][1][1][0][RTW89_QATAR][52] = 127, ++ [0][1][1][0][RTW89_UK][52] = 127, ++ [0][0][2][0][RTW89_FCC][0] = 78, ++ [0][0][2][0][RTW89_ETSI][0] = 60, ++ [0][0][2][0][RTW89_MKK][0] = 62, ++ [0][0][2][0][RTW89_IC][0] = 64, ++ [0][0][2][0][RTW89_KCC][0] = 74, ++ [0][0][2][0][RTW89_ACMA][0] = 60, ++ [0][0][2][0][RTW89_CHILE][0] = 42, ++ [0][0][2][0][RTW89_UKRAINE][0] = 52, ++ [0][0][2][0][RTW89_MEXICO][0] = 62, ++ [0][0][2][0][RTW89_CN][0] = 60, ++ [0][0][2][0][RTW89_QATAR][0] = 60, ++ [0][0][2][0][RTW89_UK][0] = 60, ++ [0][0][2][0][RTW89_FCC][2] = 78, ++ [0][0][2][0][RTW89_ETSI][2] = 60, ++ [0][0][2][0][RTW89_MKK][2] = 62, ++ [0][0][2][0][RTW89_IC][2] = 64, ++ [0][0][2][0][RTW89_KCC][2] = 74, ++ [0][0][2][0][RTW89_ACMA][2] = 60, ++ [0][0][2][0][RTW89_CHILE][2] = 42, ++ [0][0][2][0][RTW89_UKRAINE][2] = 52, ++ [0][0][2][0][RTW89_MEXICO][2] = 62, ++ [0][0][2][0][RTW89_CN][2] = 60, ++ [0][0][2][0][RTW89_QATAR][2] = 60, ++ [0][0][2][0][RTW89_UK][2] = 60, ++ [0][0][2][0][RTW89_FCC][4] = 78, ++ [0][0][2][0][RTW89_ETSI][4] = 60, ++ [0][0][2][0][RTW89_MKK][4] = 62, ++ [0][0][2][0][RTW89_IC][4] = 64, ++ [0][0][2][0][RTW89_KCC][4] = 74, ++ [0][0][2][0][RTW89_ACMA][4] = 60, ++ [0][0][2][0][RTW89_CHILE][4] = 42, ++ [0][0][2][0][RTW89_UKRAINE][4] = 52, ++ [0][0][2][0][RTW89_MEXICO][4] = 62, ++ [0][0][2][0][RTW89_CN][4] = 60, ++ [0][0][2][0][RTW89_QATAR][4] = 60, ++ [0][0][2][0][RTW89_UK][4] = 60, ++ [0][0][2][0][RTW89_FCC][6] = 78, ++ [0][0][2][0][RTW89_ETSI][6] = 60, ++ [0][0][2][0][RTW89_MKK][6] = 62, ++ [0][0][2][0][RTW89_IC][6] = 64, ++ [0][0][2][0][RTW89_KCC][6] = 50, ++ [0][0][2][0][RTW89_ACMA][6] = 60, ++ [0][0][2][0][RTW89_CHILE][6] = 42, ++ [0][0][2][0][RTW89_UKRAINE][6] = 52, ++ [0][0][2][0][RTW89_MEXICO][6] = 62, ++ [0][0][2][0][RTW89_CN][6] = 60, ++ [0][0][2][0][RTW89_QATAR][6] = 60, ++ [0][0][2][0][RTW89_UK][6] = 60, ++ [0][0][2][0][RTW89_FCC][8] = 78, ++ [0][0][2][0][RTW89_ETSI][8] = 60, ++ [0][0][2][0][RTW89_MKK][8] = 62, ++ [0][0][2][0][RTW89_IC][8] = 64, ++ [0][0][2][0][RTW89_KCC][8] = 74, ++ [0][0][2][0][RTW89_ACMA][8] = 60, ++ [0][0][2][0][RTW89_CHILE][8] = 66, ++ [0][0][2][0][RTW89_UKRAINE][8] = 52, ++ [0][0][2][0][RTW89_MEXICO][8] = 78, ++ [0][0][2][0][RTW89_CN][8] = 60, ++ [0][0][2][0][RTW89_QATAR][8] = 60, ++ [0][0][2][0][RTW89_UK][8] = 60, ++ [0][0][2][0][RTW89_FCC][10] = 78, ++ [0][0][2][0][RTW89_ETSI][10] = 60, ++ [0][0][2][0][RTW89_MKK][10] = 62, ++ [0][0][2][0][RTW89_IC][10] = 64, ++ [0][0][2][0][RTW89_KCC][10] = 74, ++ [0][0][2][0][RTW89_ACMA][10] = 60, ++ [0][0][2][0][RTW89_CHILE][10] = 66, ++ [0][0][2][0][RTW89_UKRAINE][10] = 52, ++ [0][0][2][0][RTW89_MEXICO][10] = 78, ++ [0][0][2][0][RTW89_CN][10] = 60, ++ [0][0][2][0][RTW89_QATAR][10] = 60, ++ [0][0][2][0][RTW89_UK][10] = 60, ++ [0][0][2][0][RTW89_FCC][12] = 78, ++ [0][0][2][0][RTW89_ETSI][12] = 60, ++ [0][0][2][0][RTW89_MKK][12] = 62, ++ [0][0][2][0][RTW89_IC][12] = 64, ++ [0][0][2][0][RTW89_KCC][12] = 74, ++ [0][0][2][0][RTW89_ACMA][12] = 60, ++ [0][0][2][0][RTW89_CHILE][12] = 66, ++ [0][0][2][0][RTW89_UKRAINE][12] = 52, ++ [0][0][2][0][RTW89_MEXICO][12] = 78, ++ [0][0][2][0][RTW89_CN][12] = 60, ++ [0][0][2][0][RTW89_QATAR][12] = 60, ++ [0][0][2][0][RTW89_UK][12] = 60, ++ [0][0][2][0][RTW89_FCC][14] = 78, ++ [0][0][2][0][RTW89_ETSI][14] = 60, ++ [0][0][2][0][RTW89_MKK][14] = 62, ++ [0][0][2][0][RTW89_IC][14] = 64, ++ [0][0][2][0][RTW89_KCC][14] = 74, ++ [0][0][2][0][RTW89_ACMA][14] = 60, ++ [0][0][2][0][RTW89_CHILE][14] = 66, ++ [0][0][2][0][RTW89_UKRAINE][14] = 52, ++ [0][0][2][0][RTW89_MEXICO][14] = 78, ++ [0][0][2][0][RTW89_CN][14] = 60, ++ [0][0][2][0][RTW89_QATAR][14] = 60, ++ [0][0][2][0][RTW89_UK][14] = 60, ++ [0][0][2][0][RTW89_FCC][15] = 74, ++ [0][0][2][0][RTW89_ETSI][15] = 60, ++ [0][0][2][0][RTW89_MKK][15] = 76, ++ [0][0][2][0][RTW89_IC][15] = 74, ++ [0][0][2][0][RTW89_KCC][15] = 74, ++ [0][0][2][0][RTW89_ACMA][15] = 60, ++ [0][0][2][0][RTW89_CHILE][15] = 64, ++ [0][0][2][0][RTW89_UKRAINE][15] = 52, ++ [0][0][2][0][RTW89_MEXICO][15] = 74, ++ [0][0][2][0][RTW89_CN][15] = 127, ++ [0][0][2][0][RTW89_QATAR][15] = 60, ++ [0][0][2][0][RTW89_UK][15] = 60, ++ [0][0][2][0][RTW89_FCC][17] = 78, ++ [0][0][2][0][RTW89_ETSI][17] = 60, ++ [0][0][2][0][RTW89_MKK][17] = 76, ++ [0][0][2][0][RTW89_IC][17] = 78, ++ [0][0][2][0][RTW89_KCC][17] = 74, ++ [0][0][2][0][RTW89_ACMA][17] = 60, ++ [0][0][2][0][RTW89_CHILE][17] = 64, ++ [0][0][2][0][RTW89_UKRAINE][17] = 52, ++ [0][0][2][0][RTW89_MEXICO][17] = 78, ++ [0][0][2][0][RTW89_CN][17] = 127, ++ [0][0][2][0][RTW89_QATAR][17] = 60, ++ [0][0][2][0][RTW89_UK][17] = 60, ++ [0][0][2][0][RTW89_FCC][19] = 78, ++ [0][0][2][0][RTW89_ETSI][19] = 60, ++ [0][0][2][0][RTW89_MKK][19] = 76, ++ [0][0][2][0][RTW89_IC][19] = 78, ++ [0][0][2][0][RTW89_KCC][19] = 74, ++ [0][0][2][0][RTW89_ACMA][19] = 60, ++ [0][0][2][0][RTW89_CHILE][19] = 64, ++ [0][0][2][0][RTW89_UKRAINE][19] = 52, ++ [0][0][2][0][RTW89_MEXICO][19] = 78, ++ [0][0][2][0][RTW89_CN][19] = 127, ++ [0][0][2][0][RTW89_QATAR][19] = 60, ++ [0][0][2][0][RTW89_UK][19] = 60, ++ [0][0][2][0][RTW89_FCC][21] = 78, ++ [0][0][2][0][RTW89_ETSI][21] = 60, ++ [0][0][2][0][RTW89_MKK][21] = 76, ++ [0][0][2][0][RTW89_IC][21] = 78, ++ [0][0][2][0][RTW89_KCC][21] = 74, ++ [0][0][2][0][RTW89_ACMA][21] = 60, ++ [0][0][2][0][RTW89_CHILE][21] = 66, ++ [0][0][2][0][RTW89_UKRAINE][21] = 52, ++ [0][0][2][0][RTW89_MEXICO][21] = 78, ++ [0][0][2][0][RTW89_CN][21] = 127, ++ [0][0][2][0][RTW89_QATAR][21] = 60, ++ [0][0][2][0][RTW89_UK][21] = 60, ++ [0][0][2][0][RTW89_FCC][23] = 78, ++ [0][0][2][0][RTW89_ETSI][23] = 60, ++ [0][0][2][0][RTW89_MKK][23] = 76, ++ [0][0][2][0][RTW89_IC][23] = 78, ++ [0][0][2][0][RTW89_KCC][23] = 74, ++ [0][0][2][0][RTW89_ACMA][23] = 60, ++ [0][0][2][0][RTW89_CHILE][23] = 66, ++ [0][0][2][0][RTW89_UKRAINE][23] = 52, ++ [0][0][2][0][RTW89_MEXICO][23] = 78, ++ [0][0][2][0][RTW89_CN][23] = 127, ++ [0][0][2][0][RTW89_QATAR][23] = 60, ++ [0][0][2][0][RTW89_UK][23] = 60, ++ [0][0][2][0][RTW89_FCC][25] = 78, ++ [0][0][2][0][RTW89_ETSI][25] = 60, ++ [0][0][2][0][RTW89_MKK][25] = 76, ++ [0][0][2][0][RTW89_IC][25] = 127, ++ [0][0][2][0][RTW89_KCC][25] = 74, ++ [0][0][2][0][RTW89_ACMA][25] = 127, ++ [0][0][2][0][RTW89_CHILE][25] = 66, ++ [0][0][2][0][RTW89_UKRAINE][25] = 52, ++ [0][0][2][0][RTW89_MEXICO][25] = 78, ++ [0][0][2][0][RTW89_CN][25] = 127, ++ [0][0][2][0][RTW89_QATAR][25] = 60, ++ [0][0][2][0][RTW89_UK][25] = 60, ++ [0][0][2][0][RTW89_FCC][27] = 78, ++ [0][0][2][0][RTW89_ETSI][27] = 60, ++ [0][0][2][0][RTW89_MKK][27] = 76, ++ [0][0][2][0][RTW89_IC][27] = 127, ++ [0][0][2][0][RTW89_KCC][27] = 74, ++ [0][0][2][0][RTW89_ACMA][27] = 127, ++ [0][0][2][0][RTW89_CHILE][27] = 64, ++ [0][0][2][0][RTW89_UKRAINE][27] = 52, ++ [0][0][2][0][RTW89_MEXICO][27] = 78, ++ [0][0][2][0][RTW89_CN][27] = 127, ++ [0][0][2][0][RTW89_QATAR][27] = 60, ++ [0][0][2][0][RTW89_UK][27] = 60, ++ [0][0][2][0][RTW89_FCC][29] = 78, ++ [0][0][2][0][RTW89_ETSI][29] = 60, ++ [0][0][2][0][RTW89_MKK][29] = 76, ++ [0][0][2][0][RTW89_IC][29] = 127, ++ [0][0][2][0][RTW89_KCC][29] = 74, ++ [0][0][2][0][RTW89_ACMA][29] = 127, ++ [0][0][2][0][RTW89_CHILE][29] = 64, ++ [0][0][2][0][RTW89_UKRAINE][29] = 52, ++ [0][0][2][0][RTW89_MEXICO][29] = 78, ++ [0][0][2][0][RTW89_CN][29] = 127, ++ [0][0][2][0][RTW89_QATAR][29] = 60, ++ [0][0][2][0][RTW89_UK][29] = 60, ++ [0][0][2][0][RTW89_FCC][31] = 78, ++ [0][0][2][0][RTW89_ETSI][31] = 60, ++ [0][0][2][0][RTW89_MKK][31] = 76, ++ [0][0][2][0][RTW89_IC][31] = 78, ++ [0][0][2][0][RTW89_KCC][31] = 74, ++ [0][0][2][0][RTW89_ACMA][31] = 60, ++ [0][0][2][0][RTW89_CHILE][31] = 64, ++ [0][0][2][0][RTW89_UKRAINE][31] = 52, ++ [0][0][2][0][RTW89_MEXICO][31] = 78, ++ [0][0][2][0][RTW89_CN][31] = 127, ++ [0][0][2][0][RTW89_QATAR][31] = 60, ++ [0][0][2][0][RTW89_UK][31] = 60, ++ [0][0][2][0][RTW89_FCC][33] = 78, ++ [0][0][2][0][RTW89_ETSI][33] = 60, ++ [0][0][2][0][RTW89_MKK][33] = 76, ++ [0][0][2][0][RTW89_IC][33] = 78, ++ [0][0][2][0][RTW89_KCC][33] = 74, ++ [0][0][2][0][RTW89_ACMA][33] = 60, ++ [0][0][2][0][RTW89_CHILE][33] = 64, ++ [0][0][2][0][RTW89_UKRAINE][33] = 52, ++ [0][0][2][0][RTW89_MEXICO][33] = 78, ++ [0][0][2][0][RTW89_CN][33] = 127, ++ [0][0][2][0][RTW89_QATAR][33] = 60, ++ [0][0][2][0][RTW89_UK][33] = 60, ++ [0][0][2][0][RTW89_FCC][35] = 70, ++ [0][0][2][0][RTW89_ETSI][35] = 60, ++ [0][0][2][0][RTW89_MKK][35] = 76, ++ [0][0][2][0][RTW89_IC][35] = 70, ++ [0][0][2][0][RTW89_KCC][35] = 74, ++ [0][0][2][0][RTW89_ACMA][35] = 60, ++ [0][0][2][0][RTW89_CHILE][35] = 64, ++ [0][0][2][0][RTW89_UKRAINE][35] = 52, ++ [0][0][2][0][RTW89_MEXICO][35] = 70, ++ [0][0][2][0][RTW89_CN][35] = 127, ++ [0][0][2][0][RTW89_QATAR][35] = 60, ++ [0][0][2][0][RTW89_UK][35] = 60, ++ [0][0][2][0][RTW89_FCC][37] = 78, ++ [0][0][2][0][RTW89_ETSI][37] = 127, ++ [0][0][2][0][RTW89_MKK][37] = 76, ++ [0][0][2][0][RTW89_IC][37] = 78, ++ [0][0][2][0][RTW89_KCC][37] = 74, ++ [0][0][2][0][RTW89_ACMA][37] = 76, ++ [0][0][2][0][RTW89_CHILE][37] = 64, ++ [0][0][2][0][RTW89_UKRAINE][37] = 127, ++ [0][0][2][0][RTW89_MEXICO][37] = 78, ++ [0][0][2][0][RTW89_CN][37] = 127, ++ [0][0][2][0][RTW89_QATAR][37] = 127, ++ [0][0][2][0][RTW89_UK][37] = 74, ++ [0][0][2][0][RTW89_FCC][38] = 78, ++ [0][0][2][0][RTW89_ETSI][38] = 28, ++ [0][0][2][0][RTW89_MKK][38] = 127, ++ [0][0][2][0][RTW89_IC][38] = 78, ++ [0][0][2][0][RTW89_KCC][38] = 72, ++ [0][0][2][0][RTW89_ACMA][38] = 76, ++ [0][0][2][0][RTW89_CHILE][38] = 64, ++ [0][0][2][0][RTW89_UKRAINE][38] = 28, ++ [0][0][2][0][RTW89_MEXICO][38] = 78, ++ [0][0][2][0][RTW89_CN][38] = 76, ++ [0][0][2][0][RTW89_QATAR][38] = 28, ++ [0][0][2][0][RTW89_UK][38] = 60, ++ [0][0][2][0][RTW89_FCC][40] = 78, ++ [0][0][2][0][RTW89_ETSI][40] = 28, ++ [0][0][2][0][RTW89_MKK][40] = 127, ++ [0][0][2][0][RTW89_IC][40] = 78, ++ [0][0][2][0][RTW89_KCC][40] = 72, ++ [0][0][2][0][RTW89_ACMA][40] = 76, ++ [0][0][2][0][RTW89_CHILE][40] = 64, ++ [0][0][2][0][RTW89_UKRAINE][40] = 28, ++ [0][0][2][0][RTW89_MEXICO][40] = 78, ++ [0][0][2][0][RTW89_CN][40] = 76, ++ [0][0][2][0][RTW89_QATAR][40] = 28, ++ [0][0][2][0][RTW89_UK][40] = 60, ++ [0][0][2][0][RTW89_FCC][42] = 78, ++ [0][0][2][0][RTW89_ETSI][42] = 28, ++ [0][0][2][0][RTW89_MKK][42] = 127, ++ [0][0][2][0][RTW89_IC][42] = 78, ++ [0][0][2][0][RTW89_KCC][42] = 72, ++ [0][0][2][0][RTW89_ACMA][42] = 76, ++ [0][0][2][0][RTW89_CHILE][42] = 64, ++ [0][0][2][0][RTW89_UKRAINE][42] = 28, ++ [0][0][2][0][RTW89_MEXICO][42] = 78, ++ [0][0][2][0][RTW89_CN][42] = 76, ++ [0][0][2][0][RTW89_QATAR][42] = 28, ++ [0][0][2][0][RTW89_UK][42] = 60, ++ [0][0][2][0][RTW89_FCC][44] = 78, ++ [0][0][2][0][RTW89_ETSI][44] = 28, ++ [0][0][2][0][RTW89_MKK][44] = 127, ++ [0][0][2][0][RTW89_IC][44] = 78, ++ [0][0][2][0][RTW89_KCC][44] = 72, ++ [0][0][2][0][RTW89_ACMA][44] = 76, ++ [0][0][2][0][RTW89_CHILE][44] = 66, ++ [0][0][2][0][RTW89_UKRAINE][44] = 28, ++ [0][0][2][0][RTW89_MEXICO][44] = 78, ++ [0][0][2][0][RTW89_CN][44] = 76, ++ [0][0][2][0][RTW89_QATAR][44] = 28, ++ [0][0][2][0][RTW89_UK][44] = 60, ++ [0][0][2][0][RTW89_FCC][46] = 78, ++ [0][0][2][0][RTW89_ETSI][46] = 28, ++ [0][0][2][0][RTW89_MKK][46] = 127, ++ [0][0][2][0][RTW89_IC][46] = 78, ++ [0][0][2][0][RTW89_KCC][46] = 72, ++ [0][0][2][0][RTW89_ACMA][46] = 76, ++ [0][0][2][0][RTW89_CHILE][46] = 66, ++ [0][0][2][0][RTW89_UKRAINE][46] = 28, ++ [0][0][2][0][RTW89_MEXICO][46] = 78, ++ [0][0][2][0][RTW89_CN][46] = 76, ++ [0][0][2][0][RTW89_QATAR][46] = 28, ++ [0][0][2][0][RTW89_UK][46] = 60, ++ [0][0][2][0][RTW89_FCC][48] = 78, ++ [0][0][2][0][RTW89_ETSI][48] = 127, ++ [0][0][2][0][RTW89_MKK][48] = 127, ++ [0][0][2][0][RTW89_IC][48] = 127, ++ [0][0][2][0][RTW89_KCC][48] = 127, ++ [0][0][2][0][RTW89_ACMA][48] = 127, ++ [0][0][2][0][RTW89_CHILE][48] = 127, ++ [0][0][2][0][RTW89_UKRAINE][48] = 127, ++ [0][0][2][0][RTW89_MEXICO][48] = 127, ++ [0][0][2][0][RTW89_CN][48] = 127, ++ [0][0][2][0][RTW89_QATAR][48] = 127, ++ [0][0][2][0][RTW89_UK][48] = 127, ++ [0][0][2][0][RTW89_FCC][50] = 78, ++ [0][0][2][0][RTW89_ETSI][50] = 127, ++ [0][0][2][0][RTW89_MKK][50] = 127, ++ [0][0][2][0][RTW89_IC][50] = 127, ++ [0][0][2][0][RTW89_KCC][50] = 127, ++ [0][0][2][0][RTW89_ACMA][50] = 127, ++ [0][0][2][0][RTW89_CHILE][50] = 127, ++ [0][0][2][0][RTW89_UKRAINE][50] = 127, ++ [0][0][2][0][RTW89_MEXICO][50] = 127, ++ [0][0][2][0][RTW89_CN][50] = 127, ++ [0][0][2][0][RTW89_QATAR][50] = 127, ++ [0][0][2][0][RTW89_UK][50] = 127, ++ [0][0][2][0][RTW89_FCC][52] = 78, ++ [0][0][2][0][RTW89_ETSI][52] = 127, ++ [0][0][2][0][RTW89_MKK][52] = 127, ++ [0][0][2][0][RTW89_IC][52] = 127, ++ [0][0][2][0][RTW89_KCC][52] = 127, ++ [0][0][2][0][RTW89_ACMA][52] = 127, ++ [0][0][2][0][RTW89_CHILE][52] = 127, ++ [0][0][2][0][RTW89_UKRAINE][52] = 127, ++ [0][0][2][0][RTW89_MEXICO][52] = 127, ++ [0][0][2][0][RTW89_CN][52] = 127, ++ [0][0][2][0][RTW89_QATAR][52] = 127, ++ [0][0][2][0][RTW89_UK][52] = 127, ++ [0][1][2][0][RTW89_FCC][0] = 70, ++ [0][1][2][0][RTW89_ETSI][0] = 48, ++ [0][1][2][0][RTW89_MKK][0] = 50, ++ [0][1][2][0][RTW89_IC][0] = 42, ++ [0][1][2][0][RTW89_KCC][0] = 62, ++ [0][1][2][0][RTW89_ACMA][0] = 48, ++ [0][1][2][0][RTW89_CHILE][0] = 30, ++ [0][1][2][0][RTW89_UKRAINE][0] = 40, ++ [0][1][2][0][RTW89_MEXICO][0] = 50, ++ [0][1][2][0][RTW89_CN][0] = 48, ++ [0][1][2][0][RTW89_QATAR][0] = 48, ++ [0][1][2][0][RTW89_UK][0] = 48, ++ [0][1][2][0][RTW89_FCC][2] = 70, ++ [0][1][2][0][RTW89_ETSI][2] = 48, ++ [0][1][2][0][RTW89_MKK][2] = 50, ++ [0][1][2][0][RTW89_IC][2] = 42, ++ [0][1][2][0][RTW89_KCC][2] = 62, ++ [0][1][2][0][RTW89_ACMA][2] = 48, ++ [0][1][2][0][RTW89_CHILE][2] = 30, ++ [0][1][2][0][RTW89_UKRAINE][2] = 40, ++ [0][1][2][0][RTW89_MEXICO][2] = 50, ++ [0][1][2][0][RTW89_CN][2] = 48, ++ [0][1][2][0][RTW89_QATAR][2] = 48, ++ [0][1][2][0][RTW89_UK][2] = 48, ++ [0][1][2][0][RTW89_FCC][4] = 70, ++ [0][1][2][0][RTW89_ETSI][4] = 48, ++ [0][1][2][0][RTW89_MKK][4] = 50, ++ [0][1][2][0][RTW89_IC][4] = 42, ++ [0][1][2][0][RTW89_KCC][4] = 62, ++ [0][1][2][0][RTW89_ACMA][4] = 48, ++ [0][1][2][0][RTW89_CHILE][4] = 30, ++ [0][1][2][0][RTW89_UKRAINE][4] = 40, ++ [0][1][2][0][RTW89_MEXICO][4] = 50, ++ [0][1][2][0][RTW89_CN][4] = 48, ++ [0][1][2][0][RTW89_QATAR][4] = 48, ++ [0][1][2][0][RTW89_UK][4] = 48, ++ [0][1][2][0][RTW89_FCC][6] = 70, ++ [0][1][2][0][RTW89_ETSI][6] = 48, ++ [0][1][2][0][RTW89_MKK][6] = 50, ++ [0][1][2][0][RTW89_IC][6] = 42, ++ [0][1][2][0][RTW89_KCC][6] = 34, ++ [0][1][2][0][RTW89_ACMA][6] = 48, ++ [0][1][2][0][RTW89_CHILE][6] = 30, ++ [0][1][2][0][RTW89_UKRAINE][6] = 40, ++ [0][1][2][0][RTW89_MEXICO][6] = 50, ++ [0][1][2][0][RTW89_CN][6] = 48, ++ [0][1][2][0][RTW89_QATAR][6] = 48, ++ [0][1][2][0][RTW89_UK][6] = 48, ++ [0][1][2][0][RTW89_FCC][8] = 70, ++ [0][1][2][0][RTW89_ETSI][8] = 48, ++ [0][1][2][0][RTW89_MKK][8] = 50, ++ [0][1][2][0][RTW89_IC][8] = 52, ++ [0][1][2][0][RTW89_KCC][8] = 62, ++ [0][1][2][0][RTW89_ACMA][8] = 48, ++ [0][1][2][0][RTW89_CHILE][8] = 50, ++ [0][1][2][0][RTW89_UKRAINE][8] = 40, ++ [0][1][2][0][RTW89_MEXICO][8] = 70, ++ [0][1][2][0][RTW89_CN][8] = 48, ++ [0][1][2][0][RTW89_QATAR][8] = 48, ++ [0][1][2][0][RTW89_UK][8] = 48, ++ [0][1][2][0][RTW89_FCC][10] = 70, ++ [0][1][2][0][RTW89_ETSI][10] = 48, ++ [0][1][2][0][RTW89_MKK][10] = 50, ++ [0][1][2][0][RTW89_IC][10] = 52, ++ [0][1][2][0][RTW89_KCC][10] = 62, ++ [0][1][2][0][RTW89_ACMA][10] = 48, ++ [0][1][2][0][RTW89_CHILE][10] = 50, ++ [0][1][2][0][RTW89_UKRAINE][10] = 40, ++ [0][1][2][0][RTW89_MEXICO][10] = 70, ++ [0][1][2][0][RTW89_CN][10] = 48, ++ [0][1][2][0][RTW89_QATAR][10] = 48, ++ [0][1][2][0][RTW89_UK][10] = 48, ++ [0][1][2][0][RTW89_FCC][12] = 70, ++ [0][1][2][0][RTW89_ETSI][12] = 48, ++ [0][1][2][0][RTW89_MKK][12] = 50, ++ [0][1][2][0][RTW89_IC][12] = 52, ++ [0][1][2][0][RTW89_KCC][12] = 62, ++ [0][1][2][0][RTW89_ACMA][12] = 48, ++ [0][1][2][0][RTW89_CHILE][12] = 50, ++ [0][1][2][0][RTW89_UKRAINE][12] = 40, ++ [0][1][2][0][RTW89_MEXICO][12] = 70, ++ [0][1][2][0][RTW89_CN][12] = 48, ++ [0][1][2][0][RTW89_QATAR][12] = 48, ++ [0][1][2][0][RTW89_UK][12] = 48, ++ [0][1][2][0][RTW89_FCC][14] = 70, ++ [0][1][2][0][RTW89_ETSI][14] = 48, ++ [0][1][2][0][RTW89_MKK][14] = 50, ++ [0][1][2][0][RTW89_IC][14] = 52, ++ [0][1][2][0][RTW89_KCC][14] = 62, ++ [0][1][2][0][RTW89_ACMA][14] = 48, ++ [0][1][2][0][RTW89_CHILE][14] = 50, ++ [0][1][2][0][RTW89_UKRAINE][14] = 40, ++ [0][1][2][0][RTW89_MEXICO][14] = 70, ++ [0][1][2][0][RTW89_CN][14] = 48, ++ [0][1][2][0][RTW89_QATAR][14] = 48, ++ [0][1][2][0][RTW89_UK][14] = 48, ++ [0][1][2][0][RTW89_FCC][15] = 68, ++ [0][1][2][0][RTW89_ETSI][15] = 48, ++ [0][1][2][0][RTW89_MKK][15] = 70, ++ [0][1][2][0][RTW89_IC][15] = 68, ++ [0][1][2][0][RTW89_KCC][15] = 62, ++ [0][1][2][0][RTW89_ACMA][15] = 48, ++ [0][1][2][0][RTW89_CHILE][15] = 48, ++ [0][1][2][0][RTW89_UKRAINE][15] = 40, ++ [0][1][2][0][RTW89_MEXICO][15] = 68, ++ [0][1][2][0][RTW89_CN][15] = 127, ++ [0][1][2][0][RTW89_QATAR][15] = 48, ++ [0][1][2][0][RTW89_UK][15] = 48, ++ [0][1][2][0][RTW89_FCC][17] = 70, ++ [0][1][2][0][RTW89_ETSI][17] = 48, ++ [0][1][2][0][RTW89_MKK][17] = 70, ++ [0][1][2][0][RTW89_IC][17] = 70, ++ [0][1][2][0][RTW89_KCC][17] = 62, ++ [0][1][2][0][RTW89_ACMA][17] = 48, ++ [0][1][2][0][RTW89_CHILE][17] = 48, ++ [0][1][2][0][RTW89_UKRAINE][17] = 40, ++ [0][1][2][0][RTW89_MEXICO][17] = 70, ++ [0][1][2][0][RTW89_CN][17] = 127, ++ [0][1][2][0][RTW89_QATAR][17] = 48, ++ [0][1][2][0][RTW89_UK][17] = 48, ++ [0][1][2][0][RTW89_FCC][19] = 70, ++ [0][1][2][0][RTW89_ETSI][19] = 48, ++ [0][1][2][0][RTW89_MKK][19] = 70, ++ [0][1][2][0][RTW89_IC][19] = 70, ++ [0][1][2][0][RTW89_KCC][19] = 62, ++ [0][1][2][0][RTW89_ACMA][19] = 48, ++ [0][1][2][0][RTW89_CHILE][19] = 48, ++ [0][1][2][0][RTW89_UKRAINE][19] = 40, ++ [0][1][2][0][RTW89_MEXICO][19] = 70, ++ [0][1][2][0][RTW89_CN][19] = 127, ++ [0][1][2][0][RTW89_QATAR][19] = 48, ++ [0][1][2][0][RTW89_UK][19] = 48, ++ [0][1][2][0][RTW89_FCC][21] = 70, ++ [0][1][2][0][RTW89_ETSI][21] = 48, ++ [0][1][2][0][RTW89_MKK][21] = 70, ++ [0][1][2][0][RTW89_IC][21] = 70, ++ [0][1][2][0][RTW89_KCC][21] = 62, ++ [0][1][2][0][RTW89_ACMA][21] = 48, ++ [0][1][2][0][RTW89_CHILE][21] = 48, ++ [0][1][2][0][RTW89_UKRAINE][21] = 40, ++ [0][1][2][0][RTW89_MEXICO][21] = 70, ++ [0][1][2][0][RTW89_CN][21] = 127, ++ [0][1][2][0][RTW89_QATAR][21] = 48, ++ [0][1][2][0][RTW89_UK][21] = 48, ++ [0][1][2][0][RTW89_FCC][23] = 70, ++ [0][1][2][0][RTW89_ETSI][23] = 48, ++ [0][1][2][0][RTW89_MKK][23] = 70, ++ [0][1][2][0][RTW89_IC][23] = 70, ++ [0][1][2][0][RTW89_KCC][23] = 62, ++ [0][1][2][0][RTW89_ACMA][23] = 48, ++ [0][1][2][0][RTW89_CHILE][23] = 48, ++ [0][1][2][0][RTW89_UKRAINE][23] = 40, ++ [0][1][2][0][RTW89_MEXICO][23] = 70, ++ [0][1][2][0][RTW89_CN][23] = 127, ++ [0][1][2][0][RTW89_QATAR][23] = 48, ++ [0][1][2][0][RTW89_UK][23] = 48, ++ [0][1][2][0][RTW89_FCC][25] = 70, ++ [0][1][2][0][RTW89_ETSI][25] = 48, ++ [0][1][2][0][RTW89_MKK][25] = 70, ++ [0][1][2][0][RTW89_IC][25] = 127, ++ [0][1][2][0][RTW89_KCC][25] = 62, ++ [0][1][2][0][RTW89_ACMA][25] = 127, ++ [0][1][2][0][RTW89_CHILE][25] = 48, ++ [0][1][2][0][RTW89_UKRAINE][25] = 40, ++ [0][1][2][0][RTW89_MEXICO][25] = 70, ++ [0][1][2][0][RTW89_CN][25] = 127, ++ [0][1][2][0][RTW89_QATAR][25] = 48, ++ [0][1][2][0][RTW89_UK][25] = 48, ++ [0][1][2][0][RTW89_FCC][27] = 70, ++ [0][1][2][0][RTW89_ETSI][27] = 48, ++ [0][1][2][0][RTW89_MKK][27] = 70, ++ [0][1][2][0][RTW89_IC][27] = 127, ++ [0][1][2][0][RTW89_KCC][27] = 62, ++ [0][1][2][0][RTW89_ACMA][27] = 127, ++ [0][1][2][0][RTW89_CHILE][27] = 50, ++ [0][1][2][0][RTW89_UKRAINE][27] = 40, ++ [0][1][2][0][RTW89_MEXICO][27] = 70, ++ [0][1][2][0][RTW89_CN][27] = 127, ++ [0][1][2][0][RTW89_QATAR][27] = 48, ++ [0][1][2][0][RTW89_UK][27] = 48, ++ [0][1][2][0][RTW89_FCC][29] = 70, ++ [0][1][2][0][RTW89_ETSI][29] = 48, ++ [0][1][2][0][RTW89_MKK][29] = 70, ++ [0][1][2][0][RTW89_IC][29] = 127, ++ [0][1][2][0][RTW89_KCC][29] = 62, ++ [0][1][2][0][RTW89_ACMA][29] = 127, ++ [0][1][2][0][RTW89_CHILE][29] = 50, ++ [0][1][2][0][RTW89_UKRAINE][29] = 40, ++ [0][1][2][0][RTW89_MEXICO][29] = 70, ++ [0][1][2][0][RTW89_CN][29] = 127, ++ [0][1][2][0][RTW89_QATAR][29] = 48, ++ [0][1][2][0][RTW89_UK][29] = 48, ++ [0][1][2][0][RTW89_FCC][31] = 70, ++ [0][1][2][0][RTW89_ETSI][31] = 48, ++ [0][1][2][0][RTW89_MKK][31] = 70, ++ [0][1][2][0][RTW89_IC][31] = 70, ++ [0][1][2][0][RTW89_KCC][31] = 62, ++ [0][1][2][0][RTW89_ACMA][31] = 48, ++ [0][1][2][0][RTW89_CHILE][31] = 50, ++ [0][1][2][0][RTW89_UKRAINE][31] = 40, ++ [0][1][2][0][RTW89_MEXICO][31] = 70, ++ [0][1][2][0][RTW89_CN][31] = 127, ++ [0][1][2][0][RTW89_QATAR][31] = 48, ++ [0][1][2][0][RTW89_UK][31] = 48, ++ [0][1][2][0][RTW89_FCC][33] = 70, ++ [0][1][2][0][RTW89_ETSI][33] = 48, ++ [0][1][2][0][RTW89_MKK][33] = 70, ++ [0][1][2][0][RTW89_IC][33] = 70, ++ [0][1][2][0][RTW89_KCC][33] = 62, ++ [0][1][2][0][RTW89_ACMA][33] = 48, ++ [0][1][2][0][RTW89_CHILE][33] = 50, ++ [0][1][2][0][RTW89_UKRAINE][33] = 40, ++ [0][1][2][0][RTW89_MEXICO][33] = 70, ++ [0][1][2][0][RTW89_CN][33] = 127, ++ [0][1][2][0][RTW89_QATAR][33] = 48, ++ [0][1][2][0][RTW89_UK][33] = 48, ++ [0][1][2][0][RTW89_FCC][35] = 66, ++ [0][1][2][0][RTW89_ETSI][35] = 48, ++ [0][1][2][0][RTW89_MKK][35] = 70, ++ [0][1][2][0][RTW89_IC][35] = 66, ++ [0][1][2][0][RTW89_KCC][35] = 62, ++ [0][1][2][0][RTW89_ACMA][35] = 48, ++ [0][1][2][0][RTW89_CHILE][35] = 50, ++ [0][1][2][0][RTW89_UKRAINE][35] = 40, ++ [0][1][2][0][RTW89_MEXICO][35] = 66, ++ [0][1][2][0][RTW89_CN][35] = 127, ++ [0][1][2][0][RTW89_QATAR][35] = 48, ++ [0][1][2][0][RTW89_UK][35] = 48, ++ [0][1][2][0][RTW89_FCC][37] = 70, ++ [0][1][2][0][RTW89_ETSI][37] = 127, ++ [0][1][2][0][RTW89_MKK][37] = 70, ++ [0][1][2][0][RTW89_IC][37] = 70, ++ [0][1][2][0][RTW89_KCC][37] = 62, ++ [0][1][2][0][RTW89_ACMA][37] = 70, ++ [0][1][2][0][RTW89_CHILE][37] = 50, ++ [0][1][2][0][RTW89_UKRAINE][37] = 127, ++ [0][1][2][0][RTW89_MEXICO][37] = 70, ++ [0][1][2][0][RTW89_CN][37] = 127, ++ [0][1][2][0][RTW89_QATAR][37] = 127, ++ [0][1][2][0][RTW89_UK][37] = 76, ++ [0][1][2][0][RTW89_FCC][38] = 78, ++ [0][1][2][0][RTW89_ETSI][38] = 16, ++ [0][1][2][0][RTW89_MKK][38] = 127, ++ [0][1][2][0][RTW89_IC][38] = 78, ++ [0][1][2][0][RTW89_KCC][38] = 62, ++ [0][1][2][0][RTW89_ACMA][38] = 74, ++ [0][1][2][0][RTW89_CHILE][38] = 50, ++ [0][1][2][0][RTW89_UKRAINE][38] = 16, ++ [0][1][2][0][RTW89_MEXICO][38] = 78, ++ [0][1][2][0][RTW89_CN][38] = 76, ++ [0][1][2][0][RTW89_QATAR][38] = 16, ++ [0][1][2][0][RTW89_UK][38] = 48, ++ [0][1][2][0][RTW89_FCC][40] = 78, ++ [0][1][2][0][RTW89_ETSI][40] = 16, ++ [0][1][2][0][RTW89_MKK][40] = 127, ++ [0][1][2][0][RTW89_IC][40] = 78, ++ [0][1][2][0][RTW89_KCC][40] = 62, ++ [0][1][2][0][RTW89_ACMA][40] = 74, ++ [0][1][2][0][RTW89_CHILE][40] = 50, ++ [0][1][2][0][RTW89_UKRAINE][40] = 16, ++ [0][1][2][0][RTW89_MEXICO][40] = 78, ++ [0][1][2][0][RTW89_CN][40] = 76, ++ [0][1][2][0][RTW89_QATAR][40] = 16, ++ [0][1][2][0][RTW89_UK][40] = 48, ++ [0][1][2][0][RTW89_FCC][42] = 78, ++ [0][1][2][0][RTW89_ETSI][42] = 16, ++ [0][1][2][0][RTW89_MKK][42] = 127, ++ [0][1][2][0][RTW89_IC][42] = 78, ++ [0][1][2][0][RTW89_KCC][42] = 62, ++ [0][1][2][0][RTW89_ACMA][42] = 76, ++ [0][1][2][0][RTW89_CHILE][42] = 52, ++ [0][1][2][0][RTW89_UKRAINE][42] = 16, ++ [0][1][2][0][RTW89_MEXICO][42] = 78, ++ [0][1][2][0][RTW89_CN][42] = 76, ++ [0][1][2][0][RTW89_QATAR][42] = 16, ++ [0][1][2][0][RTW89_UK][42] = 48, ++ [0][1][2][0][RTW89_FCC][44] = 78, ++ [0][1][2][0][RTW89_ETSI][44] = 16, ++ [0][1][2][0][RTW89_MKK][44] = 127, ++ [0][1][2][0][RTW89_IC][44] = 78, ++ [0][1][2][0][RTW89_KCC][44] = 62, ++ [0][1][2][0][RTW89_ACMA][44] = 76, ++ [0][1][2][0][RTW89_CHILE][44] = 52, ++ [0][1][2][0][RTW89_UKRAINE][44] = 16, ++ [0][1][2][0][RTW89_MEXICO][44] = 78, ++ [0][1][2][0][RTW89_CN][44] = 76, ++ [0][1][2][0][RTW89_QATAR][44] = 16, ++ [0][1][2][0][RTW89_UK][44] = 48, ++ [0][1][2][0][RTW89_FCC][46] = 78, ++ [0][1][2][0][RTW89_ETSI][46] = 16, ++ [0][1][2][0][RTW89_MKK][46] = 127, ++ [0][1][2][0][RTW89_IC][46] = 78, ++ [0][1][2][0][RTW89_KCC][46] = 62, ++ [0][1][2][0][RTW89_ACMA][46] = 76, ++ [0][1][2][0][RTW89_CHILE][46] = 52, ++ [0][1][2][0][RTW89_UKRAINE][46] = 16, ++ [0][1][2][0][RTW89_MEXICO][46] = 78, ++ [0][1][2][0][RTW89_CN][46] = 76, ++ [0][1][2][0][RTW89_QATAR][46] = 16, ++ [0][1][2][0][RTW89_UK][46] = 48, ++ [0][1][2][0][RTW89_FCC][48] = 58, ++ [0][1][2][0][RTW89_ETSI][48] = 127, ++ [0][1][2][0][RTW89_MKK][48] = 127, ++ [0][1][2][0][RTW89_IC][48] = 127, ++ [0][1][2][0][RTW89_KCC][48] = 127, ++ [0][1][2][0][RTW89_ACMA][48] = 127, ++ [0][1][2][0][RTW89_CHILE][48] = 127, ++ [0][1][2][0][RTW89_UKRAINE][48] = 127, ++ [0][1][2][0][RTW89_MEXICO][48] = 127, ++ [0][1][2][0][RTW89_CN][48] = 127, ++ [0][1][2][0][RTW89_QATAR][48] = 127, ++ [0][1][2][0][RTW89_UK][48] = 127, ++ [0][1][2][0][RTW89_FCC][50] = 58, ++ [0][1][2][0][RTW89_ETSI][50] = 127, ++ [0][1][2][0][RTW89_MKK][50] = 127, ++ [0][1][2][0][RTW89_IC][50] = 127, ++ [0][1][2][0][RTW89_KCC][50] = 127, ++ [0][1][2][0][RTW89_ACMA][50] = 127, ++ [0][1][2][0][RTW89_CHILE][50] = 127, ++ [0][1][2][0][RTW89_UKRAINE][50] = 127, ++ [0][1][2][0][RTW89_MEXICO][50] = 127, ++ [0][1][2][0][RTW89_CN][50] = 127, ++ [0][1][2][0][RTW89_QATAR][50] = 127, ++ [0][1][2][0][RTW89_UK][50] = 127, ++ [0][1][2][0][RTW89_FCC][52] = 58, ++ [0][1][2][0][RTW89_ETSI][52] = 127, ++ [0][1][2][0][RTW89_MKK][52] = 127, ++ [0][1][2][0][RTW89_IC][52] = 127, ++ [0][1][2][0][RTW89_KCC][52] = 127, ++ [0][1][2][0][RTW89_ACMA][52] = 127, ++ [0][1][2][0][RTW89_CHILE][52] = 127, ++ [0][1][2][0][RTW89_UKRAINE][52] = 127, ++ [0][1][2][0][RTW89_MEXICO][52] = 127, ++ [0][1][2][0][RTW89_CN][52] = 127, ++ [0][1][2][0][RTW89_QATAR][52] = 127, ++ [0][1][2][0][RTW89_UK][52] = 127, ++ [0][1][2][1][RTW89_FCC][0] = 68, ++ [0][1][2][1][RTW89_ETSI][0] = 36, ++ [0][1][2][1][RTW89_MKK][0] = 50, ++ [0][1][2][1][RTW89_IC][0] = 40, ++ [0][1][2][1][RTW89_KCC][0] = 62, ++ [0][1][2][1][RTW89_ACMA][0] = 36, ++ [0][1][2][1][RTW89_CHILE][0] = 14, ++ [0][1][2][1][RTW89_UKRAINE][0] = 28, ++ [0][1][2][1][RTW89_MEXICO][0] = 50, ++ [0][1][2][1][RTW89_CN][0] = 36, ++ [0][1][2][1][RTW89_QATAR][0] = 36, ++ [0][1][2][1][RTW89_UK][0] = 36, ++ [0][1][2][1][RTW89_FCC][2] = 68, ++ [0][1][2][1][RTW89_ETSI][2] = 36, ++ [0][1][2][1][RTW89_MKK][2] = 50, ++ [0][1][2][1][RTW89_IC][2] = 40, ++ [0][1][2][1][RTW89_KCC][2] = 62, ++ [0][1][2][1][RTW89_ACMA][2] = 36, ++ [0][1][2][1][RTW89_CHILE][2] = 14, ++ [0][1][2][1][RTW89_UKRAINE][2] = 28, ++ [0][1][2][1][RTW89_MEXICO][2] = 50, ++ [0][1][2][1][RTW89_CN][2] = 36, ++ [0][1][2][1][RTW89_QATAR][2] = 36, ++ [0][1][2][1][RTW89_UK][2] = 36, ++ [0][1][2][1][RTW89_FCC][4] = 68, ++ [0][1][2][1][RTW89_ETSI][4] = 36, ++ [0][1][2][1][RTW89_MKK][4] = 50, ++ [0][1][2][1][RTW89_IC][4] = 40, ++ [0][1][2][1][RTW89_KCC][4] = 62, ++ [0][1][2][1][RTW89_ACMA][4] = 36, ++ [0][1][2][1][RTW89_CHILE][4] = 14, ++ [0][1][2][1][RTW89_UKRAINE][4] = 28, ++ [0][1][2][1][RTW89_MEXICO][4] = 50, ++ [0][1][2][1][RTW89_CN][4] = 36, ++ [0][1][2][1][RTW89_QATAR][4] = 36, ++ [0][1][2][1][RTW89_UK][4] = 36, ++ [0][1][2][1][RTW89_FCC][6] = 68, ++ [0][1][2][1][RTW89_ETSI][6] = 36, ++ [0][1][2][1][RTW89_MKK][6] = 50, ++ [0][1][2][1][RTW89_IC][6] = 40, ++ [0][1][2][1][RTW89_KCC][6] = 34, ++ [0][1][2][1][RTW89_ACMA][6] = 36, ++ [0][1][2][1][RTW89_CHILE][6] = 14, ++ [0][1][2][1][RTW89_UKRAINE][6] = 28, ++ [0][1][2][1][RTW89_MEXICO][6] = 50, ++ [0][1][2][1][RTW89_CN][6] = 36, ++ [0][1][2][1][RTW89_QATAR][6] = 36, ++ [0][1][2][1][RTW89_UK][6] = 36, ++ [0][1][2][1][RTW89_FCC][8] = 68, ++ [0][1][2][1][RTW89_ETSI][8] = 36, ++ [0][1][2][1][RTW89_MKK][8] = 50, ++ [0][1][2][1][RTW89_IC][8] = 40, ++ [0][1][2][1][RTW89_KCC][8] = 62, ++ [0][1][2][1][RTW89_ACMA][8] = 36, ++ [0][1][2][1][RTW89_CHILE][8] = 36, ++ [0][1][2][1][RTW89_UKRAINE][8] = 28, ++ [0][1][2][1][RTW89_MEXICO][8] = 68, ++ [0][1][2][1][RTW89_CN][8] = 36, ++ [0][1][2][1][RTW89_QATAR][8] = 36, ++ [0][1][2][1][RTW89_UK][8] = 36, ++ [0][1][2][1][RTW89_FCC][10] = 68, ++ [0][1][2][1][RTW89_ETSI][10] = 36, ++ [0][1][2][1][RTW89_MKK][10] = 50, ++ [0][1][2][1][RTW89_IC][10] = 40, ++ [0][1][2][1][RTW89_KCC][10] = 62, ++ [0][1][2][1][RTW89_ACMA][10] = 36, ++ [0][1][2][1][RTW89_CHILE][10] = 36, ++ [0][1][2][1][RTW89_UKRAINE][10] = 28, ++ [0][1][2][1][RTW89_MEXICO][10] = 68, ++ [0][1][2][1][RTW89_CN][10] = 36, ++ [0][1][2][1][RTW89_QATAR][10] = 36, ++ [0][1][2][1][RTW89_UK][10] = 36, ++ [0][1][2][1][RTW89_FCC][12] = 68, ++ [0][1][2][1][RTW89_ETSI][12] = 36, ++ [0][1][2][1][RTW89_MKK][12] = 50, ++ [0][1][2][1][RTW89_IC][12] = 40, ++ [0][1][2][1][RTW89_KCC][12] = 62, ++ [0][1][2][1][RTW89_ACMA][12] = 36, ++ [0][1][2][1][RTW89_CHILE][12] = 36, ++ [0][1][2][1][RTW89_UKRAINE][12] = 28, ++ [0][1][2][1][RTW89_MEXICO][12] = 68, ++ [0][1][2][1][RTW89_CN][12] = 36, ++ [0][1][2][1][RTW89_QATAR][12] = 36, ++ [0][1][2][1][RTW89_UK][12] = 36, ++ [0][1][2][1][RTW89_FCC][14] = 68, ++ [0][1][2][1][RTW89_ETSI][14] = 36, ++ [0][1][2][1][RTW89_MKK][14] = 50, ++ [0][1][2][1][RTW89_IC][14] = 40, ++ [0][1][2][1][RTW89_KCC][14] = 62, ++ [0][1][2][1][RTW89_ACMA][14] = 36, ++ [0][1][2][1][RTW89_CHILE][14] = 36, ++ [0][1][2][1][RTW89_UKRAINE][14] = 28, ++ [0][1][2][1][RTW89_MEXICO][14] = 68, ++ [0][1][2][1][RTW89_CN][14] = 36, ++ [0][1][2][1][RTW89_QATAR][14] = 36, ++ [0][1][2][1][RTW89_UK][14] = 36, ++ [0][1][2][1][RTW89_FCC][15] = 68, ++ [0][1][2][1][RTW89_ETSI][15] = 36, ++ [0][1][2][1][RTW89_MKK][15] = 70, ++ [0][1][2][1][RTW89_IC][15] = 68, ++ [0][1][2][1][RTW89_KCC][15] = 62, ++ [0][1][2][1][RTW89_ACMA][15] = 36, ++ [0][1][2][1][RTW89_CHILE][15] = 36, ++ [0][1][2][1][RTW89_UKRAINE][15] = 28, ++ [0][1][2][1][RTW89_MEXICO][15] = 68, ++ [0][1][2][1][RTW89_CN][15] = 127, ++ [0][1][2][1][RTW89_QATAR][15] = 36, ++ [0][1][2][1][RTW89_UK][15] = 36, ++ [0][1][2][1][RTW89_FCC][17] = 68, ++ [0][1][2][1][RTW89_ETSI][17] = 36, ++ [0][1][2][1][RTW89_MKK][17] = 70, ++ [0][1][2][1][RTW89_IC][17] = 68, ++ [0][1][2][1][RTW89_KCC][17] = 62, ++ [0][1][2][1][RTW89_ACMA][17] = 36, ++ [0][1][2][1][RTW89_CHILE][17] = 36, ++ [0][1][2][1][RTW89_UKRAINE][17] = 28, ++ [0][1][2][1][RTW89_MEXICO][17] = 68, ++ [0][1][2][1][RTW89_CN][17] = 127, ++ [0][1][2][1][RTW89_QATAR][17] = 36, ++ [0][1][2][1][RTW89_UK][17] = 36, ++ [0][1][2][1][RTW89_FCC][19] = 68, ++ [0][1][2][1][RTW89_ETSI][19] = 36, ++ [0][1][2][1][RTW89_MKK][19] = 70, ++ [0][1][2][1][RTW89_IC][19] = 68, ++ [0][1][2][1][RTW89_KCC][19] = 62, ++ [0][1][2][1][RTW89_ACMA][19] = 36, ++ [0][1][2][1][RTW89_CHILE][19] = 36, ++ [0][1][2][1][RTW89_UKRAINE][19] = 28, ++ [0][1][2][1][RTW89_MEXICO][19] = 68, ++ [0][1][2][1][RTW89_CN][19] = 127, ++ [0][1][2][1][RTW89_QATAR][19] = 36, ++ [0][1][2][1][RTW89_UK][19] = 36, ++ [0][1][2][1][RTW89_FCC][21] = 68, ++ [0][1][2][1][RTW89_ETSI][21] = 36, ++ [0][1][2][1][RTW89_MKK][21] = 70, ++ [0][1][2][1][RTW89_IC][21] = 68, ++ [0][1][2][1][RTW89_KCC][21] = 62, ++ [0][1][2][1][RTW89_ACMA][21] = 36, ++ [0][1][2][1][RTW89_CHILE][21] = 36, ++ [0][1][2][1][RTW89_UKRAINE][21] = 28, ++ [0][1][2][1][RTW89_MEXICO][21] = 68, ++ [0][1][2][1][RTW89_CN][21] = 127, ++ [0][1][2][1][RTW89_QATAR][21] = 36, ++ [0][1][2][1][RTW89_UK][21] = 36, ++ [0][1][2][1][RTW89_FCC][23] = 68, ++ [0][1][2][1][RTW89_ETSI][23] = 36, ++ [0][1][2][1][RTW89_MKK][23] = 70, ++ [0][1][2][1][RTW89_IC][23] = 68, ++ [0][1][2][1][RTW89_KCC][23] = 62, ++ [0][1][2][1][RTW89_ACMA][23] = 36, ++ [0][1][2][1][RTW89_CHILE][23] = 36, ++ [0][1][2][1][RTW89_UKRAINE][23] = 28, ++ [0][1][2][1][RTW89_MEXICO][23] = 68, ++ [0][1][2][1][RTW89_CN][23] = 127, ++ [0][1][2][1][RTW89_QATAR][23] = 36, ++ [0][1][2][1][RTW89_UK][23] = 36, ++ [0][1][2][1][RTW89_FCC][25] = 66, ++ [0][1][2][1][RTW89_ETSI][25] = 36, ++ [0][1][2][1][RTW89_MKK][25] = 70, ++ [0][1][2][1][RTW89_IC][25] = 127, ++ [0][1][2][1][RTW89_KCC][25] = 62, ++ [0][1][2][1][RTW89_ACMA][25] = 127, ++ [0][1][2][1][RTW89_CHILE][25] = 36, ++ [0][1][2][1][RTW89_UKRAINE][25] = 28, ++ [0][1][2][1][RTW89_MEXICO][25] = 66, ++ [0][1][2][1][RTW89_CN][25] = 127, ++ [0][1][2][1][RTW89_QATAR][25] = 36, ++ [0][1][2][1][RTW89_UK][25] = 36, ++ [0][1][2][1][RTW89_FCC][27] = 66, ++ [0][1][2][1][RTW89_ETSI][27] = 36, ++ [0][1][2][1][RTW89_MKK][27] = 70, ++ [0][1][2][1][RTW89_IC][27] = 127, ++ [0][1][2][1][RTW89_KCC][27] = 62, ++ [0][1][2][1][RTW89_ACMA][27] = 127, ++ [0][1][2][1][RTW89_CHILE][27] = 36, ++ [0][1][2][1][RTW89_UKRAINE][27] = 28, ++ [0][1][2][1][RTW89_MEXICO][27] = 66, ++ [0][1][2][1][RTW89_CN][27] = 127, ++ [0][1][2][1][RTW89_QATAR][27] = 36, ++ [0][1][2][1][RTW89_UK][27] = 36, ++ [0][1][2][1][RTW89_FCC][29] = 66, ++ [0][1][2][1][RTW89_ETSI][29] = 36, ++ [0][1][2][1][RTW89_MKK][29] = 70, ++ [0][1][2][1][RTW89_IC][29] = 127, ++ [0][1][2][1][RTW89_KCC][29] = 62, ++ [0][1][2][1][RTW89_ACMA][29] = 127, ++ [0][1][2][1][RTW89_CHILE][29] = 36, ++ [0][1][2][1][RTW89_UKRAINE][29] = 28, ++ [0][1][2][1][RTW89_MEXICO][29] = 66, ++ [0][1][2][1][RTW89_CN][29] = 127, ++ [0][1][2][1][RTW89_QATAR][29] = 36, ++ [0][1][2][1][RTW89_UK][29] = 36, ++ [0][1][2][1][RTW89_FCC][31] = 66, ++ [0][1][2][1][RTW89_ETSI][31] = 36, ++ [0][1][2][1][RTW89_MKK][31] = 70, ++ [0][1][2][1][RTW89_IC][31] = 66, ++ [0][1][2][1][RTW89_KCC][31] = 62, ++ [0][1][2][1][RTW89_ACMA][31] = 36, ++ [0][1][2][1][RTW89_CHILE][31] = 36, ++ [0][1][2][1][RTW89_UKRAINE][31] = 28, ++ [0][1][2][1][RTW89_MEXICO][31] = 66, ++ [0][1][2][1][RTW89_CN][31] = 127, ++ [0][1][2][1][RTW89_QATAR][31] = 36, ++ [0][1][2][1][RTW89_UK][31] = 36, ++ [0][1][2][1][RTW89_FCC][33] = 66, ++ [0][1][2][1][RTW89_ETSI][33] = 36, ++ [0][1][2][1][RTW89_MKK][33] = 70, ++ [0][1][2][1][RTW89_IC][33] = 66, ++ [0][1][2][1][RTW89_KCC][33] = 62, ++ [0][1][2][1][RTW89_ACMA][33] = 36, ++ [0][1][2][1][RTW89_CHILE][33] = 36, ++ [0][1][2][1][RTW89_UKRAINE][33] = 28, ++ [0][1][2][1][RTW89_MEXICO][33] = 66, ++ [0][1][2][1][RTW89_CN][33] = 127, ++ [0][1][2][1][RTW89_QATAR][33] = 36, ++ [0][1][2][1][RTW89_UK][33] = 36, ++ [0][1][2][1][RTW89_FCC][35] = 66, ++ [0][1][2][1][RTW89_ETSI][35] = 36, ++ [0][1][2][1][RTW89_MKK][35] = 70, ++ [0][1][2][1][RTW89_IC][35] = 66, ++ [0][1][2][1][RTW89_KCC][35] = 62, ++ [0][1][2][1][RTW89_ACMA][35] = 36, ++ [0][1][2][1][RTW89_CHILE][35] = 36, ++ [0][1][2][1][RTW89_UKRAINE][35] = 28, ++ [0][1][2][1][RTW89_MEXICO][35] = 66, ++ [0][1][2][1][RTW89_CN][35] = 127, ++ [0][1][2][1][RTW89_QATAR][35] = 36, ++ [0][1][2][1][RTW89_UK][35] = 36, ++ [0][1][2][1][RTW89_FCC][37] = 68, ++ [0][1][2][1][RTW89_ETSI][37] = 127, ++ [0][1][2][1][RTW89_MKK][37] = 70, ++ [0][1][2][1][RTW89_IC][37] = 68, ++ [0][1][2][1][RTW89_KCC][37] = 62, ++ [0][1][2][1][RTW89_ACMA][37] = 70, ++ [0][1][2][1][RTW89_CHILE][37] = 36, ++ [0][1][2][1][RTW89_UKRAINE][37] = 127, ++ [0][1][2][1][RTW89_MEXICO][37] = 68, ++ [0][1][2][1][RTW89_CN][37] = 127, ++ [0][1][2][1][RTW89_QATAR][37] = 127, ++ [0][1][2][1][RTW89_UK][37] = 62, ++ [0][1][2][1][RTW89_FCC][38] = 78, ++ [0][1][2][1][RTW89_ETSI][38] = 4, ++ [0][1][2][1][RTW89_MKK][38] = 127, ++ [0][1][2][1][RTW89_IC][38] = 78, ++ [0][1][2][1][RTW89_KCC][38] = 62, ++ [0][1][2][1][RTW89_ACMA][38] = 74, ++ [0][1][2][1][RTW89_CHILE][38] = 36, ++ [0][1][2][1][RTW89_UKRAINE][38] = 4, ++ [0][1][2][1][RTW89_MEXICO][38] = 78, ++ [0][1][2][1][RTW89_CN][38] = 72, ++ [0][1][2][1][RTW89_QATAR][38] = 4, ++ [0][1][2][1][RTW89_UK][38] = 36, ++ [0][1][2][1][RTW89_FCC][40] = 78, ++ [0][1][2][1][RTW89_ETSI][40] = 4, ++ [0][1][2][1][RTW89_MKK][40] = 127, ++ [0][1][2][1][RTW89_IC][40] = 78, ++ [0][1][2][1][RTW89_KCC][40] = 62, ++ [0][1][2][1][RTW89_ACMA][40] = 74, ++ [0][1][2][1][RTW89_CHILE][40] = 36, ++ [0][1][2][1][RTW89_UKRAINE][40] = 4, ++ [0][1][2][1][RTW89_MEXICO][40] = 78, ++ [0][1][2][1][RTW89_CN][40] = 72, ++ [0][1][2][1][RTW89_QATAR][40] = 4, ++ [0][1][2][1][RTW89_UK][40] = 36, ++ [0][1][2][1][RTW89_FCC][42] = 78, ++ [0][1][2][1][RTW89_ETSI][42] = 4, ++ [0][1][2][1][RTW89_MKK][42] = 127, ++ [0][1][2][1][RTW89_IC][42] = 78, ++ [0][1][2][1][RTW89_KCC][42] = 62, ++ [0][1][2][1][RTW89_ACMA][42] = 76, ++ [0][1][2][1][RTW89_CHILE][42] = 36, ++ [0][1][2][1][RTW89_UKRAINE][42] = 4, ++ [0][1][2][1][RTW89_MEXICO][42] = 78, ++ [0][1][2][1][RTW89_CN][42] = 72, ++ [0][1][2][1][RTW89_QATAR][42] = 4, ++ [0][1][2][1][RTW89_UK][42] = 36, ++ [0][1][2][1][RTW89_FCC][44] = 78, ++ [0][1][2][1][RTW89_ETSI][44] = 4, ++ [0][1][2][1][RTW89_MKK][44] = 127, ++ [0][1][2][1][RTW89_IC][44] = 78, ++ [0][1][2][1][RTW89_KCC][44] = 62, ++ [0][1][2][1][RTW89_ACMA][44] = 76, ++ [0][1][2][1][RTW89_CHILE][44] = 36, ++ [0][1][2][1][RTW89_UKRAINE][44] = 4, ++ [0][1][2][1][RTW89_MEXICO][44] = 78, ++ [0][1][2][1][RTW89_CN][44] = 76, ++ [0][1][2][1][RTW89_QATAR][44] = 4, ++ [0][1][2][1][RTW89_UK][44] = 36, ++ [0][1][2][1][RTW89_FCC][46] = 78, ++ [0][1][2][1][RTW89_ETSI][46] = 4, ++ [0][1][2][1][RTW89_MKK][46] = 127, ++ [0][1][2][1][RTW89_IC][46] = 78, ++ [0][1][2][1][RTW89_KCC][46] = 62, ++ [0][1][2][1][RTW89_ACMA][46] = 76, ++ [0][1][2][1][RTW89_CHILE][46] = 36, ++ [0][1][2][1][RTW89_UKRAINE][46] = 4, ++ [0][1][2][1][RTW89_MEXICO][46] = 78, ++ [0][1][2][1][RTW89_CN][46] = 76, ++ [0][1][2][1][RTW89_QATAR][46] = 4, ++ [0][1][2][1][RTW89_UK][46] = 36, ++ [0][1][2][1][RTW89_FCC][48] = 58, ++ [0][1][2][1][RTW89_ETSI][48] = 127, ++ [0][1][2][1][RTW89_MKK][48] = 127, ++ [0][1][2][1][RTW89_IC][48] = 127, ++ [0][1][2][1][RTW89_KCC][48] = 127, ++ [0][1][2][1][RTW89_ACMA][48] = 127, ++ [0][1][2][1][RTW89_CHILE][48] = 127, ++ [0][1][2][1][RTW89_UKRAINE][48] = 127, ++ [0][1][2][1][RTW89_MEXICO][48] = 127, ++ [0][1][2][1][RTW89_CN][48] = 127, ++ [0][1][2][1][RTW89_QATAR][48] = 127, ++ [0][1][2][1][RTW89_UK][48] = 127, ++ [0][1][2][1][RTW89_FCC][50] = 58, ++ [0][1][2][1][RTW89_ETSI][50] = 127, ++ [0][1][2][1][RTW89_MKK][50] = 127, ++ [0][1][2][1][RTW89_IC][50] = 127, ++ [0][1][2][1][RTW89_KCC][50] = 127, ++ [0][1][2][1][RTW89_ACMA][50] = 127, ++ [0][1][2][1][RTW89_CHILE][50] = 127, ++ [0][1][2][1][RTW89_UKRAINE][50] = 127, ++ [0][1][2][1][RTW89_MEXICO][50] = 127, ++ [0][1][2][1][RTW89_CN][50] = 127, ++ [0][1][2][1][RTW89_QATAR][50] = 127, ++ [0][1][2][1][RTW89_UK][50] = 127, ++ [0][1][2][1][RTW89_FCC][52] = 58, ++ [0][1][2][1][RTW89_ETSI][52] = 127, ++ [0][1][2][1][RTW89_MKK][52] = 127, ++ [0][1][2][1][RTW89_IC][52] = 127, ++ [0][1][2][1][RTW89_KCC][52] = 127, ++ [0][1][2][1][RTW89_ACMA][52] = 127, ++ [0][1][2][1][RTW89_CHILE][52] = 127, ++ [0][1][2][1][RTW89_UKRAINE][52] = 127, ++ [0][1][2][1][RTW89_MEXICO][52] = 127, ++ [0][1][2][1][RTW89_CN][52] = 127, ++ [0][1][2][1][RTW89_QATAR][52] = 127, ++ [0][1][2][1][RTW89_UK][52] = 127, ++ [1][0][2][0][RTW89_FCC][1] = 66, ++ [1][0][2][0][RTW89_ETSI][1] = 64, ++ [1][0][2][0][RTW89_MKK][1] = 62, ++ [1][0][2][0][RTW89_IC][1] = 64, ++ [1][0][2][0][RTW89_KCC][1] = 70, ++ [1][0][2][0][RTW89_ACMA][1] = 64, ++ [1][0][2][0][RTW89_CHILE][1] = 42, ++ [1][0][2][0][RTW89_UKRAINE][1] = 52, ++ [1][0][2][0][RTW89_MEXICO][1] = 62, ++ [1][0][2][0][RTW89_CN][1] = 62, ++ [1][0][2][0][RTW89_QATAR][1] = 64, ++ [1][0][2][0][RTW89_UK][1] = 64, ++ [1][0][2][0][RTW89_FCC][5] = 78, ++ [1][0][2][0][RTW89_ETSI][5] = 64, ++ [1][0][2][0][RTW89_MKK][5] = 62, ++ [1][0][2][0][RTW89_IC][5] = 64, ++ [1][0][2][0][RTW89_KCC][5] = 66, ++ [1][0][2][0][RTW89_ACMA][5] = 64, ++ [1][0][2][0][RTW89_CHILE][5] = 42, ++ [1][0][2][0][RTW89_UKRAINE][5] = 52, ++ [1][0][2][0][RTW89_MEXICO][5] = 62, ++ [1][0][2][0][RTW89_CN][5] = 62, ++ [1][0][2][0][RTW89_QATAR][5] = 64, ++ [1][0][2][0][RTW89_UK][5] = 64, ++ [1][0][2][0][RTW89_FCC][9] = 78, ++ [1][0][2][0][RTW89_ETSI][9] = 64, ++ [1][0][2][0][RTW89_MKK][9] = 62, ++ [1][0][2][0][RTW89_IC][9] = 64, ++ [1][0][2][0][RTW89_KCC][9] = 74, ++ [1][0][2][0][RTW89_ACMA][9] = 64, ++ [1][0][2][0][RTW89_CHILE][9] = 66, ++ [1][0][2][0][RTW89_UKRAINE][9] = 52, ++ [1][0][2][0][RTW89_MEXICO][9] = 78, ++ [1][0][2][0][RTW89_CN][9] = 62, ++ [1][0][2][0][RTW89_QATAR][9] = 64, ++ [1][0][2][0][RTW89_UK][9] = 64, ++ [1][0][2][0][RTW89_FCC][13] = 66, ++ [1][0][2][0][RTW89_ETSI][13] = 64, ++ [1][0][2][0][RTW89_MKK][13] = 62, ++ [1][0][2][0][RTW89_IC][13] = 64, ++ [1][0][2][0][RTW89_KCC][13] = 68, ++ [1][0][2][0][RTW89_ACMA][13] = 64, ++ [1][0][2][0][RTW89_CHILE][13] = 66, ++ [1][0][2][0][RTW89_UKRAINE][13] = 52, ++ [1][0][2][0][RTW89_MEXICO][13] = 66, ++ [1][0][2][0][RTW89_CN][13] = 62, ++ [1][0][2][0][RTW89_QATAR][13] = 64, ++ [1][0][2][0][RTW89_UK][13] = 64, ++ [1][0][2][0][RTW89_FCC][16] = 64, ++ [1][0][2][0][RTW89_ETSI][16] = 64, ++ [1][0][2][0][RTW89_MKK][16] = 74, ++ [1][0][2][0][RTW89_IC][16] = 64, ++ [1][0][2][0][RTW89_KCC][16] = 70, ++ [1][0][2][0][RTW89_ACMA][16] = 64, ++ [1][0][2][0][RTW89_CHILE][16] = 64, ++ [1][0][2][0][RTW89_UKRAINE][16] = 52, ++ [1][0][2][0][RTW89_MEXICO][16] = 64, ++ [1][0][2][0][RTW89_CN][16] = 127, ++ [1][0][2][0][RTW89_QATAR][16] = 64, ++ [1][0][2][0][RTW89_UK][16] = 64, ++ [1][0][2][0][RTW89_FCC][20] = 78, ++ [1][0][2][0][RTW89_ETSI][20] = 64, ++ [1][0][2][0][RTW89_MKK][20] = 74, ++ [1][0][2][0][RTW89_IC][20] = 78, ++ [1][0][2][0][RTW89_KCC][20] = 70, ++ [1][0][2][0][RTW89_ACMA][20] = 64, ++ [1][0][2][0][RTW89_CHILE][20] = 62, ++ [1][0][2][0][RTW89_UKRAINE][20] = 52, ++ [1][0][2][0][RTW89_MEXICO][20] = 78, ++ [1][0][2][0][RTW89_CN][20] = 127, ++ [1][0][2][0][RTW89_QATAR][20] = 64, ++ [1][0][2][0][RTW89_UK][20] = 64, ++ [1][0][2][0][RTW89_FCC][24] = 78, ++ [1][0][2][0][RTW89_ETSI][24] = 64, ++ [1][0][2][0][RTW89_MKK][24] = 74, ++ [1][0][2][0][RTW89_IC][24] = 127, ++ [1][0][2][0][RTW89_KCC][24] = 70, ++ [1][0][2][0][RTW89_ACMA][24] = 127, ++ [1][0][2][0][RTW89_CHILE][24] = 62, ++ [1][0][2][0][RTW89_UKRAINE][24] = 52, ++ [1][0][2][0][RTW89_MEXICO][24] = 78, ++ [1][0][2][0][RTW89_CN][24] = 127, ++ [1][0][2][0][RTW89_QATAR][24] = 64, ++ [1][0][2][0][RTW89_UK][24] = 64, ++ [1][0][2][0][RTW89_FCC][28] = 78, ++ [1][0][2][0][RTW89_ETSI][28] = 64, ++ [1][0][2][0][RTW89_MKK][28] = 74, ++ [1][0][2][0][RTW89_IC][28] = 127, ++ [1][0][2][0][RTW89_KCC][28] = 74, ++ [1][0][2][0][RTW89_ACMA][28] = 127, ++ [1][0][2][0][RTW89_CHILE][28] = 64, ++ [1][0][2][0][RTW89_UKRAINE][28] = 52, ++ [1][0][2][0][RTW89_MEXICO][28] = 78, ++ [1][0][2][0][RTW89_CN][28] = 127, ++ [1][0][2][0][RTW89_QATAR][28] = 64, ++ [1][0][2][0][RTW89_UK][28] = 64, ++ [1][0][2][0][RTW89_FCC][32] = 76, ++ [1][0][2][0][RTW89_ETSI][32] = 64, ++ [1][0][2][0][RTW89_MKK][32] = 74, ++ [1][0][2][0][RTW89_IC][32] = 76, ++ [1][0][2][0][RTW89_KCC][32] = 74, ++ [1][0][2][0][RTW89_ACMA][32] = 64, ++ [1][0][2][0][RTW89_CHILE][32] = 64, ++ [1][0][2][0][RTW89_UKRAINE][32] = 52, ++ [1][0][2][0][RTW89_MEXICO][32] = 76, ++ [1][0][2][0][RTW89_CN][32] = 127, ++ [1][0][2][0][RTW89_QATAR][32] = 64, ++ [1][0][2][0][RTW89_UK][32] = 64, ++ [1][0][2][0][RTW89_FCC][36] = 78, ++ [1][0][2][0][RTW89_ETSI][36] = 127, ++ [1][0][2][0][RTW89_MKK][36] = 74, ++ [1][0][2][0][RTW89_IC][36] = 78, ++ [1][0][2][0][RTW89_KCC][36] = 74, ++ [1][0][2][0][RTW89_ACMA][36] = 74, ++ [1][0][2][0][RTW89_CHILE][36] = 64, ++ [1][0][2][0][RTW89_UKRAINE][36] = 127, ++ [1][0][2][0][RTW89_MEXICO][36] = 78, ++ [1][0][2][0][RTW89_CN][36] = 127, ++ [1][0][2][0][RTW89_QATAR][36] = 127, ++ [1][0][2][0][RTW89_UK][36] = 74, ++ [1][0][2][0][RTW89_FCC][39] = 78, ++ [1][0][2][0][RTW89_ETSI][39] = 28, ++ [1][0][2][0][RTW89_MKK][39] = 127, ++ [1][0][2][0][RTW89_IC][39] = 78, ++ [1][0][2][0][RTW89_KCC][39] = 74, ++ [1][0][2][0][RTW89_ACMA][39] = 74, ++ [1][0][2][0][RTW89_CHILE][39] = 64, ++ [1][0][2][0][RTW89_UKRAINE][39] = 28, ++ [1][0][2][0][RTW89_MEXICO][39] = 78, ++ [1][0][2][0][RTW89_CN][39] = 70, ++ [1][0][2][0][RTW89_QATAR][39] = 28, ++ [1][0][2][0][RTW89_UK][39] = 64, ++ [1][0][2][0][RTW89_FCC][43] = 78, ++ [1][0][2][0][RTW89_ETSI][43] = 28, ++ [1][0][2][0][RTW89_MKK][43] = 127, ++ [1][0][2][0][RTW89_IC][43] = 78, ++ [1][0][2][0][RTW89_KCC][43] = 74, ++ [1][0][2][0][RTW89_ACMA][43] = 74, ++ [1][0][2][0][RTW89_CHILE][43] = 64, ++ [1][0][2][0][RTW89_UKRAINE][43] = 28, ++ [1][0][2][0][RTW89_MEXICO][43] = 78, ++ [1][0][2][0][RTW89_CN][43] = 74, ++ [1][0][2][0][RTW89_QATAR][43] = 28, ++ [1][0][2][0][RTW89_UK][43] = 62, ++ [1][0][2][0][RTW89_FCC][47] = 78, ++ [1][0][2][0][RTW89_ETSI][47] = 127, ++ [1][0][2][0][RTW89_MKK][47] = 127, ++ [1][0][2][0][RTW89_IC][47] = 127, ++ [1][0][2][0][RTW89_KCC][47] = 127, ++ [1][0][2][0][RTW89_ACMA][47] = 127, ++ [1][0][2][0][RTW89_CHILE][47] = 127, ++ [1][0][2][0][RTW89_UKRAINE][47] = 127, ++ [1][0][2][0][RTW89_MEXICO][47] = 127, ++ [1][0][2][0][RTW89_CN][47] = 127, ++ [1][0][2][0][RTW89_QATAR][47] = 127, ++ [1][0][2][0][RTW89_UK][47] = 127, ++ [1][0][2][0][RTW89_FCC][51] = 70, ++ [1][0][2][0][RTW89_ETSI][51] = 127, ++ [1][0][2][0][RTW89_MKK][51] = 127, ++ [1][0][2][0][RTW89_IC][51] = 127, ++ [1][0][2][0][RTW89_KCC][51] = 127, ++ [1][0][2][0][RTW89_ACMA][51] = 127, ++ [1][0][2][0][RTW89_CHILE][51] = 127, ++ [1][0][2][0][RTW89_UKRAINE][51] = 127, ++ [1][0][2][0][RTW89_MEXICO][51] = 127, ++ [1][0][2][0][RTW89_CN][51] = 127, ++ [1][0][2][0][RTW89_QATAR][51] = 127, ++ [1][0][2][0][RTW89_UK][51] = 127, ++ [1][1][2][0][RTW89_FCC][1] = 62, ++ [1][1][2][0][RTW89_ETSI][1] = 52, ++ [1][1][2][0][RTW89_MKK][1] = 50, ++ [1][1][2][0][RTW89_IC][1] = 52, ++ [1][1][2][0][RTW89_KCC][1] = 58, ++ [1][1][2][0][RTW89_ACMA][1] = 52, ++ [1][1][2][0][RTW89_CHILE][1] = 30, ++ [1][1][2][0][RTW89_UKRAINE][1] = 40, ++ [1][1][2][0][RTW89_MEXICO][1] = 50, ++ [1][1][2][0][RTW89_CN][1] = 50, ++ [1][1][2][0][RTW89_QATAR][1] = 52, ++ [1][1][2][0][RTW89_UK][1] = 52, ++ [1][1][2][0][RTW89_FCC][5] = 76, ++ [1][1][2][0][RTW89_ETSI][5] = 52, ++ [1][1][2][0][RTW89_MKK][5] = 50, ++ [1][1][2][0][RTW89_IC][5] = 52, ++ [1][1][2][0][RTW89_KCC][5] = 48, ++ [1][1][2][0][RTW89_ACMA][5] = 52, ++ [1][1][2][0][RTW89_CHILE][5] = 30, ++ [1][1][2][0][RTW89_UKRAINE][5] = 40, ++ [1][1][2][0][RTW89_MEXICO][5] = 50, ++ [1][1][2][0][RTW89_CN][5] = 50, ++ [1][1][2][0][RTW89_QATAR][5] = 52, ++ [1][1][2][0][RTW89_UK][5] = 52, ++ [1][1][2][0][RTW89_FCC][9] = 76, ++ [1][1][2][0][RTW89_ETSI][9] = 52, ++ [1][1][2][0][RTW89_MKK][9] = 50, ++ [1][1][2][0][RTW89_IC][9] = 52, ++ [1][1][2][0][RTW89_KCC][9] = 60, ++ [1][1][2][0][RTW89_ACMA][9] = 52, ++ [1][1][2][0][RTW89_CHILE][9] = 50, ++ [1][1][2][0][RTW89_UKRAINE][9] = 40, ++ [1][1][2][0][RTW89_MEXICO][9] = 76, ++ [1][1][2][0][RTW89_CN][9] = 50, ++ [1][1][2][0][RTW89_QATAR][9] = 52, ++ [1][1][2][0][RTW89_UK][9] = 52, ++ [1][1][2][0][RTW89_FCC][13] = 62, ++ [1][1][2][0][RTW89_ETSI][13] = 52, ++ [1][1][2][0][RTW89_MKK][13] = 50, ++ [1][1][2][0][RTW89_IC][13] = 52, ++ [1][1][2][0][RTW89_KCC][13] = 58, ++ [1][1][2][0][RTW89_ACMA][13] = 52, ++ [1][1][2][0][RTW89_CHILE][13] = 48, ++ [1][1][2][0][RTW89_UKRAINE][13] = 40, ++ [1][1][2][0][RTW89_MEXICO][13] = 62, ++ [1][1][2][0][RTW89_CN][13] = 50, ++ [1][1][2][0][RTW89_QATAR][13] = 52, ++ [1][1][2][0][RTW89_UK][13] = 52, ++ [1][1][2][0][RTW89_FCC][16] = 56, ++ [1][1][2][0][RTW89_ETSI][16] = 52, ++ [1][1][2][0][RTW89_MKK][16] = 70, ++ [1][1][2][0][RTW89_IC][16] = 56, ++ [1][1][2][0][RTW89_KCC][16] = 58, ++ [1][1][2][0][RTW89_ACMA][16] = 52, ++ [1][1][2][0][RTW89_CHILE][16] = 48, ++ [1][1][2][0][RTW89_UKRAINE][16] = 40, ++ [1][1][2][0][RTW89_MEXICO][16] = 56, ++ [1][1][2][0][RTW89_CN][16] = 127, ++ [1][1][2][0][RTW89_QATAR][16] = 52, ++ [1][1][2][0][RTW89_UK][16] = 52, ++ [1][1][2][0][RTW89_FCC][20] = 76, ++ [1][1][2][0][RTW89_ETSI][20] = 52, ++ [1][1][2][0][RTW89_MKK][20] = 70, ++ [1][1][2][0][RTW89_IC][20] = 76, ++ [1][1][2][0][RTW89_KCC][20] = 58, ++ [1][1][2][0][RTW89_ACMA][20] = 52, ++ [1][1][2][0][RTW89_CHILE][20] = 50, ++ [1][1][2][0][RTW89_UKRAINE][20] = 40, ++ [1][1][2][0][RTW89_MEXICO][20] = 76, ++ [1][1][2][0][RTW89_CN][20] = 127, ++ [1][1][2][0][RTW89_QATAR][20] = 52, ++ [1][1][2][0][RTW89_UK][20] = 52, ++ [1][1][2][0][RTW89_FCC][24] = 76, ++ [1][1][2][0][RTW89_ETSI][24] = 52, ++ [1][1][2][0][RTW89_MKK][24] = 70, ++ [1][1][2][0][RTW89_IC][24] = 127, ++ [1][1][2][0][RTW89_KCC][24] = 58, ++ [1][1][2][0][RTW89_ACMA][24] = 127, ++ [1][1][2][0][RTW89_CHILE][24] = 50, ++ [1][1][2][0][RTW89_UKRAINE][24] = 40, ++ [1][1][2][0][RTW89_MEXICO][24] = 76, ++ [1][1][2][0][RTW89_CN][24] = 127, ++ [1][1][2][0][RTW89_QATAR][24] = 52, ++ [1][1][2][0][RTW89_UK][24] = 52, ++ [1][1][2][0][RTW89_FCC][28] = 76, ++ [1][1][2][0][RTW89_ETSI][28] = 52, ++ [1][1][2][0][RTW89_MKK][28] = 70, ++ [1][1][2][0][RTW89_IC][28] = 127, ++ [1][1][2][0][RTW89_KCC][28] = 60, ++ [1][1][2][0][RTW89_ACMA][28] = 127, ++ [1][1][2][0][RTW89_CHILE][28] = 48, ++ [1][1][2][0][RTW89_UKRAINE][28] = 40, ++ [1][1][2][0][RTW89_MEXICO][28] = 76, ++ [1][1][2][0][RTW89_CN][28] = 127, ++ [1][1][2][0][RTW89_QATAR][28] = 52, ++ [1][1][2][0][RTW89_UK][28] = 52, ++ [1][1][2][0][RTW89_FCC][32] = 68, ++ [1][1][2][0][RTW89_ETSI][32] = 52, ++ [1][1][2][0][RTW89_MKK][32] = 70, ++ [1][1][2][0][RTW89_IC][32] = 68, ++ [1][1][2][0][RTW89_KCC][32] = 60, ++ [1][1][2][0][RTW89_ACMA][32] = 52, ++ [1][1][2][0][RTW89_CHILE][32] = 48, ++ [1][1][2][0][RTW89_UKRAINE][32] = 40, ++ [1][1][2][0][RTW89_MEXICO][32] = 68, ++ [1][1][2][0][RTW89_CN][32] = 127, ++ [1][1][2][0][RTW89_QATAR][32] = 52, ++ [1][1][2][0][RTW89_UK][32] = 52, ++ [1][1][2][0][RTW89_FCC][36] = 76, ++ [1][1][2][0][RTW89_ETSI][36] = 127, ++ [1][1][2][0][RTW89_MKK][36] = 70, ++ [1][1][2][0][RTW89_IC][36] = 76, ++ [1][1][2][0][RTW89_KCC][36] = 60, ++ [1][1][2][0][RTW89_ACMA][36] = 74, ++ [1][1][2][0][RTW89_CHILE][36] = 50, ++ [1][1][2][0][RTW89_UKRAINE][36] = 127, ++ [1][1][2][0][RTW89_MEXICO][36] = 76, ++ [1][1][2][0][RTW89_CN][36] = 127, ++ [1][1][2][0][RTW89_QATAR][36] = 127, ++ [1][1][2][0][RTW89_UK][36] = 74, ++ [1][1][2][0][RTW89_FCC][39] = 78, ++ [1][1][2][0][RTW89_ETSI][39] = 16, ++ [1][1][2][0][RTW89_MKK][39] = 127, ++ [1][1][2][0][RTW89_IC][39] = 78, ++ [1][1][2][0][RTW89_KCC][39] = 58, ++ [1][1][2][0][RTW89_ACMA][39] = 72, ++ [1][1][2][0][RTW89_CHILE][39] = 52, ++ [1][1][2][0][RTW89_UKRAINE][39] = 16, ++ [1][1][2][0][RTW89_MEXICO][39] = 78, ++ [1][1][2][0][RTW89_CN][39] = 70, ++ [1][1][2][0][RTW89_QATAR][39] = 16, ++ [1][1][2][0][RTW89_UK][39] = 52, ++ [1][1][2][0][RTW89_FCC][43] = 78, ++ [1][1][2][0][RTW89_ETSI][43] = 16, ++ [1][1][2][0][RTW89_MKK][43] = 127, ++ [1][1][2][0][RTW89_IC][43] = 78, ++ [1][1][2][0][RTW89_KCC][43] = 58, ++ [1][1][2][0][RTW89_ACMA][43] = 74, ++ [1][1][2][0][RTW89_CHILE][43] = 52, ++ [1][1][2][0][RTW89_UKRAINE][43] = 16, ++ [1][1][2][0][RTW89_MEXICO][43] = 78, ++ [1][1][2][0][RTW89_CN][43] = 74, ++ [1][1][2][0][RTW89_QATAR][43] = 16, ++ [1][1][2][0][RTW89_UK][43] = 52, ++ [1][1][2][0][RTW89_FCC][47] = 68, ++ [1][1][2][0][RTW89_ETSI][47] = 127, ++ [1][1][2][0][RTW89_MKK][47] = 127, ++ [1][1][2][0][RTW89_IC][47] = 127, ++ [1][1][2][0][RTW89_KCC][47] = 127, ++ [1][1][2][0][RTW89_ACMA][47] = 127, ++ [1][1][2][0][RTW89_CHILE][47] = 127, ++ [1][1][2][0][RTW89_UKRAINE][47] = 127, ++ [1][1][2][0][RTW89_MEXICO][47] = 127, ++ [1][1][2][0][RTW89_CN][47] = 127, ++ [1][1][2][0][RTW89_QATAR][47] = 127, ++ [1][1][2][0][RTW89_UK][47] = 127, ++ [1][1][2][0][RTW89_FCC][51] = 66, ++ [1][1][2][0][RTW89_ETSI][51] = 127, ++ [1][1][2][0][RTW89_MKK][51] = 127, ++ [1][1][2][0][RTW89_IC][51] = 127, ++ [1][1][2][0][RTW89_KCC][51] = 127, ++ [1][1][2][0][RTW89_ACMA][51] = 127, ++ [1][1][2][0][RTW89_CHILE][51] = 127, ++ [1][1][2][0][RTW89_UKRAINE][51] = 127, ++ [1][1][2][0][RTW89_MEXICO][51] = 127, ++ [1][1][2][0][RTW89_CN][51] = 127, ++ [1][1][2][0][RTW89_QATAR][51] = 127, ++ [1][1][2][0][RTW89_UK][51] = 127, ++ [1][1][2][1][RTW89_FCC][1] = 62, ++ [1][1][2][1][RTW89_ETSI][1] = 40, ++ [1][1][2][1][RTW89_MKK][1] = 50, ++ [1][1][2][1][RTW89_IC][1] = 40, ++ [1][1][2][1][RTW89_KCC][1] = 58, ++ [1][1][2][1][RTW89_ACMA][1] = 40, ++ [1][1][2][1][RTW89_CHILE][1] = 16, ++ [1][1][2][1][RTW89_UKRAINE][1] = 28, ++ [1][1][2][1][RTW89_MEXICO][1] = 50, ++ [1][1][2][1][RTW89_CN][1] = 38, ++ [1][1][2][1][RTW89_QATAR][1] = 40, ++ [1][1][2][1][RTW89_UK][1] = 40, ++ [1][1][2][1][RTW89_FCC][5] = 68, ++ [1][1][2][1][RTW89_ETSI][5] = 40, ++ [1][1][2][1][RTW89_MKK][5] = 50, ++ [1][1][2][1][RTW89_IC][5] = 40, ++ [1][1][2][1][RTW89_KCC][5] = 48, ++ [1][1][2][1][RTW89_ACMA][5] = 40, ++ [1][1][2][1][RTW89_CHILE][5] = 16, ++ [1][1][2][1][RTW89_UKRAINE][5] = 28, ++ [1][1][2][1][RTW89_MEXICO][5] = 50, ++ [1][1][2][1][RTW89_CN][5] = 38, ++ [1][1][2][1][RTW89_QATAR][5] = 40, ++ [1][1][2][1][RTW89_UK][5] = 40, ++ [1][1][2][1][RTW89_FCC][9] = 68, ++ [1][1][2][1][RTW89_ETSI][9] = 40, ++ [1][1][2][1][RTW89_MKK][9] = 50, ++ [1][1][2][1][RTW89_IC][9] = 40, ++ [1][1][2][1][RTW89_KCC][9] = 60, ++ [1][1][2][1][RTW89_ACMA][9] = 40, ++ [1][1][2][1][RTW89_CHILE][9] = 36, ++ [1][1][2][1][RTW89_UKRAINE][9] = 28, ++ [1][1][2][1][RTW89_MEXICO][9] = 68, ++ [1][1][2][1][RTW89_CN][9] = 38, ++ [1][1][2][1][RTW89_QATAR][9] = 40, ++ [1][1][2][1][RTW89_UK][9] = 40, ++ [1][1][2][1][RTW89_FCC][13] = 62, ++ [1][1][2][1][RTW89_ETSI][13] = 40, ++ [1][1][2][1][RTW89_MKK][13] = 50, ++ [1][1][2][1][RTW89_IC][13] = 40, ++ [1][1][2][1][RTW89_KCC][13] = 58, ++ [1][1][2][1][RTW89_ACMA][13] = 40, ++ [1][1][2][1][RTW89_CHILE][13] = 36, ++ [1][1][2][1][RTW89_UKRAINE][13] = 28, ++ [1][1][2][1][RTW89_MEXICO][13] = 62, ++ [1][1][2][1][RTW89_CN][13] = 38, ++ [1][1][2][1][RTW89_QATAR][13] = 40, ++ [1][1][2][1][RTW89_UK][13] = 40, ++ [1][1][2][1][RTW89_FCC][16] = 56, ++ [1][1][2][1][RTW89_ETSI][16] = 40, ++ [1][1][2][1][RTW89_MKK][16] = 70, ++ [1][1][2][1][RTW89_IC][16] = 56, ++ [1][1][2][1][RTW89_KCC][16] = 58, ++ [1][1][2][1][RTW89_ACMA][16] = 40, ++ [1][1][2][1][RTW89_CHILE][16] = 36, ++ [1][1][2][1][RTW89_UKRAINE][16] = 28, ++ [1][1][2][1][RTW89_MEXICO][16] = 56, ++ [1][1][2][1][RTW89_CN][16] = 127, ++ [1][1][2][1][RTW89_QATAR][16] = 40, ++ [1][1][2][1][RTW89_UK][16] = 40, ++ [1][1][2][1][RTW89_FCC][20] = 68, ++ [1][1][2][1][RTW89_ETSI][20] = 40, ++ [1][1][2][1][RTW89_MKK][20] = 70, ++ [1][1][2][1][RTW89_IC][20] = 68, ++ [1][1][2][1][RTW89_KCC][20] = 58, ++ [1][1][2][1][RTW89_ACMA][20] = 40, ++ [1][1][2][1][RTW89_CHILE][20] = 36, ++ [1][1][2][1][RTW89_UKRAINE][20] = 28, ++ [1][1][2][1][RTW89_MEXICO][20] = 68, ++ [1][1][2][1][RTW89_CN][20] = 127, ++ [1][1][2][1][RTW89_QATAR][20] = 40, ++ [1][1][2][1][RTW89_UK][20] = 40, ++ [1][1][2][1][RTW89_FCC][24] = 68, ++ [1][1][2][1][RTW89_ETSI][24] = 40, ++ [1][1][2][1][RTW89_MKK][24] = 70, ++ [1][1][2][1][RTW89_IC][24] = 127, ++ [1][1][2][1][RTW89_KCC][24] = 58, ++ [1][1][2][1][RTW89_ACMA][24] = 127, ++ [1][1][2][1][RTW89_CHILE][24] = 36, ++ [1][1][2][1][RTW89_UKRAINE][24] = 28, ++ [1][1][2][1][RTW89_MEXICO][24] = 68, ++ [1][1][2][1][RTW89_CN][24] = 127, ++ [1][1][2][1][RTW89_QATAR][24] = 40, ++ [1][1][2][1][RTW89_UK][24] = 40, ++ [1][1][2][1][RTW89_FCC][28] = 68, ++ [1][1][2][1][RTW89_ETSI][28] = 40, ++ [1][1][2][1][RTW89_MKK][28] = 70, ++ [1][1][2][1][RTW89_IC][28] = 127, ++ [1][1][2][1][RTW89_KCC][28] = 60, ++ [1][1][2][1][RTW89_ACMA][28] = 127, ++ [1][1][2][1][RTW89_CHILE][28] = 36, ++ [1][1][2][1][RTW89_UKRAINE][28] = 28, ++ [1][1][2][1][RTW89_MEXICO][28] = 68, ++ [1][1][2][1][RTW89_CN][28] = 127, ++ [1][1][2][1][RTW89_QATAR][28] = 40, ++ [1][1][2][1][RTW89_UK][28] = 40, ++ [1][1][2][1][RTW89_FCC][32] = 68, ++ [1][1][2][1][RTW89_ETSI][32] = 40, ++ [1][1][2][1][RTW89_MKK][32] = 70, ++ [1][1][2][1][RTW89_IC][32] = 68, ++ [1][1][2][1][RTW89_KCC][32] = 60, ++ [1][1][2][1][RTW89_ACMA][32] = 40, ++ [1][1][2][1][RTW89_CHILE][32] = 36, ++ [1][1][2][1][RTW89_UKRAINE][32] = 28, ++ [1][1][2][1][RTW89_MEXICO][32] = 68, ++ [1][1][2][1][RTW89_CN][32] = 127, ++ [1][1][2][1][RTW89_QATAR][32] = 40, ++ [1][1][2][1][RTW89_UK][32] = 40, ++ [1][1][2][1][RTW89_FCC][36] = 68, ++ [1][1][2][1][RTW89_ETSI][36] = 127, ++ [1][1][2][1][RTW89_MKK][36] = 70, ++ [1][1][2][1][RTW89_IC][36] = 68, ++ [1][1][2][1][RTW89_KCC][36] = 60, ++ [1][1][2][1][RTW89_ACMA][36] = 70, ++ [1][1][2][1][RTW89_CHILE][36] = 36, ++ [1][1][2][1][RTW89_UKRAINE][36] = 127, ++ [1][1][2][1][RTW89_MEXICO][36] = 68, ++ [1][1][2][1][RTW89_CN][36] = 127, ++ [1][1][2][1][RTW89_QATAR][36] = 127, ++ [1][1][2][1][RTW89_UK][36] = 62, ++ [1][1][2][1][RTW89_FCC][39] = 78, ++ [1][1][2][1][RTW89_ETSI][39] = 4, ++ [1][1][2][1][RTW89_MKK][39] = 127, ++ [1][1][2][1][RTW89_IC][39] = 78, ++ [1][1][2][1][RTW89_KCC][39] = 58, ++ [1][1][2][1][RTW89_ACMA][39] = 72, ++ [1][1][2][1][RTW89_CHILE][39] = 36, ++ [1][1][2][1][RTW89_UKRAINE][39] = 4, ++ [1][1][2][1][RTW89_MEXICO][39] = 78, ++ [1][1][2][1][RTW89_CN][39] = 70, ++ [1][1][2][1][RTW89_QATAR][39] = 4, ++ [1][1][2][1][RTW89_UK][39] = 40, ++ [1][1][2][1][RTW89_FCC][43] = 78, ++ [1][1][2][1][RTW89_ETSI][43] = 4, ++ [1][1][2][1][RTW89_MKK][43] = 127, ++ [1][1][2][1][RTW89_IC][43] = 78, ++ [1][1][2][1][RTW89_KCC][43] = 58, ++ [1][1][2][1][RTW89_ACMA][43] = 74, ++ [1][1][2][1][RTW89_CHILE][43] = 36, ++ [1][1][2][1][RTW89_UKRAINE][43] = 4, ++ [1][1][2][1][RTW89_MEXICO][43] = 78, ++ [1][1][2][1][RTW89_CN][43] = 74, ++ [1][1][2][1][RTW89_QATAR][43] = 4, ++ [1][1][2][1][RTW89_UK][43] = 40, ++ [1][1][2][1][RTW89_FCC][47] = 68, ++ [1][1][2][1][RTW89_ETSI][47] = 127, ++ [1][1][2][1][RTW89_MKK][47] = 127, ++ [1][1][2][1][RTW89_IC][47] = 127, ++ [1][1][2][1][RTW89_KCC][47] = 127, ++ [1][1][2][1][RTW89_ACMA][47] = 127, ++ [1][1][2][1][RTW89_CHILE][47] = 127, ++ [1][1][2][1][RTW89_UKRAINE][47] = 127, ++ [1][1][2][1][RTW89_MEXICO][47] = 127, ++ [1][1][2][1][RTW89_CN][47] = 127, ++ [1][1][2][1][RTW89_QATAR][47] = 127, ++ [1][1][2][1][RTW89_UK][47] = 127, ++ [1][1][2][1][RTW89_FCC][51] = 66, ++ [1][1][2][1][RTW89_ETSI][51] = 127, ++ [1][1][2][1][RTW89_MKK][51] = 127, ++ [1][1][2][1][RTW89_IC][51] = 127, ++ [1][1][2][1][RTW89_KCC][51] = 127, ++ [1][1][2][1][RTW89_ACMA][51] = 127, ++ [1][1][2][1][RTW89_CHILE][51] = 127, ++ [1][1][2][1][RTW89_UKRAINE][51] = 127, ++ [1][1][2][1][RTW89_MEXICO][51] = 127, ++ [1][1][2][1][RTW89_CN][51] = 127, ++ [1][1][2][1][RTW89_QATAR][51] = 127, ++ [1][1][2][1][RTW89_UK][51] = 127, ++ [2][0][2][0][RTW89_FCC][3] = 64, ++ [2][0][2][0][RTW89_ETSI][3] = 64, ++ [2][0][2][0][RTW89_MKK][3] = 64, ++ [2][0][2][0][RTW89_IC][3] = 62, ++ [2][0][2][0][RTW89_KCC][3] = 68, ++ [2][0][2][0][RTW89_ACMA][3] = 64, ++ [2][0][2][0][RTW89_CHILE][3] = 42, ++ [2][0][2][0][RTW89_UKRAINE][3] = 52, ++ [2][0][2][0][RTW89_MEXICO][3] = 62, ++ [2][0][2][0][RTW89_CN][3] = 62, ++ [2][0][2][0][RTW89_QATAR][3] = 64, ++ [2][0][2][0][RTW89_UK][3] = 64, ++ [2][0][2][0][RTW89_FCC][11] = 66, ++ [2][0][2][0][RTW89_ETSI][11] = 64, ++ [2][0][2][0][RTW89_MKK][11] = 64, ++ [2][0][2][0][RTW89_IC][11] = 64, ++ [2][0][2][0][RTW89_KCC][11] = 70, ++ [2][0][2][0][RTW89_ACMA][11] = 64, ++ [2][0][2][0][RTW89_CHILE][11] = 66, ++ [2][0][2][0][RTW89_UKRAINE][11] = 52, ++ [2][0][2][0][RTW89_MEXICO][11] = 66, ++ [2][0][2][0][RTW89_CN][11] = 62, ++ [2][0][2][0][RTW89_QATAR][11] = 64, ++ [2][0][2][0][RTW89_UK][11] = 64, ++ [2][0][2][0][RTW89_FCC][18] = 62, ++ [2][0][2][0][RTW89_ETSI][18] = 64, ++ [2][0][2][0][RTW89_MKK][18] = 70, ++ [2][0][2][0][RTW89_IC][18] = 62, ++ [2][0][2][0][RTW89_KCC][18] = 64, ++ [2][0][2][0][RTW89_ACMA][18] = 64, ++ [2][0][2][0][RTW89_CHILE][18] = 64, ++ [2][0][2][0][RTW89_UKRAINE][18] = 52, ++ [2][0][2][0][RTW89_MEXICO][18] = 62, ++ [2][0][2][0][RTW89_CN][18] = 127, ++ [2][0][2][0][RTW89_QATAR][18] = 64, ++ [2][0][2][0][RTW89_UK][18] = 64, ++ [2][0][2][0][RTW89_FCC][26] = 74, ++ [2][0][2][0][RTW89_ETSI][26] = 64, ++ [2][0][2][0][RTW89_MKK][26] = 70, ++ [2][0][2][0][RTW89_IC][26] = 127, ++ [2][0][2][0][RTW89_KCC][26] = 70, ++ [2][0][2][0][RTW89_ACMA][26] = 127, ++ [2][0][2][0][RTW89_CHILE][26] = 64, ++ [2][0][2][0][RTW89_UKRAINE][26] = 52, ++ [2][0][2][0][RTW89_MEXICO][26] = 74, ++ [2][0][2][0][RTW89_CN][26] = 127, ++ [2][0][2][0][RTW89_QATAR][26] = 64, ++ [2][0][2][0][RTW89_UK][26] = 64, ++ [2][0][2][0][RTW89_FCC][34] = 74, ++ [2][0][2][0][RTW89_ETSI][34] = 127, ++ [2][0][2][0][RTW89_MKK][34] = 70, ++ [2][0][2][0][RTW89_IC][34] = 74, ++ [2][0][2][0][RTW89_KCC][34] = 70, ++ [2][0][2][0][RTW89_ACMA][34] = 70, ++ [2][0][2][0][RTW89_CHILE][34] = 64, ++ [2][0][2][0][RTW89_UKRAINE][34] = 127, ++ [2][0][2][0][RTW89_MEXICO][34] = 74, ++ [2][0][2][0][RTW89_CN][34] = 127, ++ [2][0][2][0][RTW89_QATAR][34] = 127, ++ [2][0][2][0][RTW89_UK][34] = 70, ++ [2][0][2][0][RTW89_FCC][41] = 74, ++ [2][0][2][0][RTW89_ETSI][41] = 28, ++ [2][0][2][0][RTW89_MKK][41] = 127, ++ [2][0][2][0][RTW89_IC][41] = 74, ++ [2][0][2][0][RTW89_KCC][41] = 66, ++ [2][0][2][0][RTW89_ACMA][41] = 70, ++ [2][0][2][0][RTW89_CHILE][41] = 64, ++ [2][0][2][0][RTW89_UKRAINE][41] = 28, ++ [2][0][2][0][RTW89_MEXICO][41] = 74, ++ [2][0][2][0][RTW89_CN][41] = 70, ++ [2][0][2][0][RTW89_QATAR][41] = 28, ++ [2][0][2][0][RTW89_UK][41] = 64, ++ [2][0][2][0][RTW89_FCC][49] = 64, ++ [2][0][2][0][RTW89_ETSI][49] = 127, ++ [2][0][2][0][RTW89_MKK][49] = 127, ++ [2][0][2][0][RTW89_IC][49] = 127, ++ [2][0][2][0][RTW89_KCC][49] = 127, ++ [2][0][2][0][RTW89_ACMA][49] = 127, ++ [2][0][2][0][RTW89_CHILE][49] = 127, ++ [2][0][2][0][RTW89_UKRAINE][49] = 127, ++ [2][0][2][0][RTW89_MEXICO][49] = 127, ++ [2][0][2][0][RTW89_CN][49] = 127, ++ [2][0][2][0][RTW89_QATAR][49] = 127, ++ [2][0][2][0][RTW89_UK][49] = 127, ++ [2][1][2][0][RTW89_FCC][3] = 56, ++ [2][1][2][0][RTW89_ETSI][3] = 52, ++ [2][1][2][0][RTW89_MKK][3] = 52, ++ [2][1][2][0][RTW89_IC][3] = 52, ++ [2][1][2][0][RTW89_KCC][3] = 54, ++ [2][1][2][0][RTW89_ACMA][3] = 52, ++ [2][1][2][0][RTW89_CHILE][3] = 28, ++ [2][1][2][0][RTW89_UKRAINE][3] = 40, ++ [2][1][2][0][RTW89_MEXICO][3] = 50, ++ [2][1][2][0][RTW89_CN][3] = 50, ++ [2][1][2][0][RTW89_QATAR][3] = 52, ++ [2][1][2][0][RTW89_UK][3] = 52, ++ [2][1][2][0][RTW89_FCC][11] = 62, ++ [2][1][2][0][RTW89_ETSI][11] = 52, ++ [2][1][2][0][RTW89_MKK][11] = 52, ++ [2][1][2][0][RTW89_IC][11] = 52, ++ [2][1][2][0][RTW89_KCC][11] = 56, ++ [2][1][2][0][RTW89_ACMA][11] = 52, ++ [2][1][2][0][RTW89_CHILE][11] = 52, ++ [2][1][2][0][RTW89_UKRAINE][11] = 40, ++ [2][1][2][0][RTW89_MEXICO][11] = 62, ++ [2][1][2][0][RTW89_CN][11] = 50, ++ [2][1][2][0][RTW89_QATAR][11] = 52, ++ [2][1][2][0][RTW89_UK][11] = 52, ++ [2][1][2][0][RTW89_FCC][18] = 56, ++ [2][1][2][0][RTW89_ETSI][18] = 52, ++ [2][1][2][0][RTW89_MKK][18] = 70, ++ [2][1][2][0][RTW89_IC][18] = 56, ++ [2][1][2][0][RTW89_KCC][18] = 58, ++ [2][1][2][0][RTW89_ACMA][18] = 52, ++ [2][1][2][0][RTW89_CHILE][18] = 48, ++ [2][1][2][0][RTW89_UKRAINE][18] = 40, ++ [2][1][2][0][RTW89_MEXICO][18] = 56, ++ [2][1][2][0][RTW89_CN][18] = 127, ++ [2][1][2][0][RTW89_QATAR][18] = 52, ++ [2][1][2][0][RTW89_UK][18] = 52, ++ [2][1][2][0][RTW89_FCC][26] = 70, ++ [2][1][2][0][RTW89_ETSI][26] = 52, ++ [2][1][2][0][RTW89_MKK][26] = 70, ++ [2][1][2][0][RTW89_IC][26] = 127, ++ [2][1][2][0][RTW89_KCC][26] = 56, ++ [2][1][2][0][RTW89_ACMA][26] = 127, ++ [2][1][2][0][RTW89_CHILE][26] = 50, ++ [2][1][2][0][RTW89_UKRAINE][26] = 40, ++ [2][1][2][0][RTW89_MEXICO][26] = 70, ++ [2][1][2][0][RTW89_CN][26] = 127, ++ [2][1][2][0][RTW89_QATAR][26] = 52, ++ [2][1][2][0][RTW89_UK][26] = 52, ++ [2][1][2][0][RTW89_FCC][34] = 74, ++ [2][1][2][0][RTW89_ETSI][34] = 127, ++ [2][1][2][0][RTW89_MKK][34] = 70, ++ [2][1][2][0][RTW89_IC][34] = 74, ++ [2][1][2][0][RTW89_KCC][34] = 56, ++ [2][1][2][0][RTW89_ACMA][34] = 70, ++ [2][1][2][0][RTW89_CHILE][34] = 50, ++ [2][1][2][0][RTW89_UKRAINE][34] = 127, ++ [2][1][2][0][RTW89_MEXICO][34] = 74, ++ [2][1][2][0][RTW89_CN][34] = 127, ++ [2][1][2][0][RTW89_QATAR][34] = 127, ++ [2][1][2][0][RTW89_UK][34] = 68, ++ [2][1][2][0][RTW89_FCC][41] = 74, ++ [2][1][2][0][RTW89_ETSI][41] = 16, ++ [2][1][2][0][RTW89_MKK][41] = 127, ++ [2][1][2][0][RTW89_IC][41] = 74, ++ [2][1][2][0][RTW89_KCC][41] = 56, ++ [2][1][2][0][RTW89_ACMA][41] = 70, ++ [2][1][2][0][RTW89_CHILE][41] = 50, ++ [2][1][2][0][RTW89_UKRAINE][41] = 16, ++ [2][1][2][0][RTW89_MEXICO][41] = 74, ++ [2][1][2][0][RTW89_CN][41] = 70, ++ [2][1][2][0][RTW89_QATAR][41] = 16, ++ [2][1][2][0][RTW89_UK][41] = 52, ++ [2][1][2][0][RTW89_FCC][49] = 58, ++ [2][1][2][0][RTW89_ETSI][49] = 127, ++ [2][1][2][0][RTW89_MKK][49] = 127, ++ [2][1][2][0][RTW89_IC][49] = 127, ++ [2][1][2][0][RTW89_KCC][49] = 127, ++ [2][1][2][0][RTW89_ACMA][49] = 127, ++ [2][1][2][0][RTW89_CHILE][49] = 127, ++ [2][1][2][0][RTW89_UKRAINE][49] = 127, ++ [2][1][2][0][RTW89_MEXICO][49] = 127, ++ [2][1][2][0][RTW89_CN][49] = 127, ++ [2][1][2][0][RTW89_QATAR][49] = 127, ++ [2][1][2][0][RTW89_UK][49] = 127, ++ [2][1][2][1][RTW89_FCC][3] = 56, ++ [2][1][2][1][RTW89_ETSI][3] = 40, ++ [2][1][2][1][RTW89_MKK][3] = 52, ++ [2][1][2][1][RTW89_IC][3] = 40, ++ [2][1][2][1][RTW89_KCC][3] = 54, ++ [2][1][2][1][RTW89_ACMA][3] = 40, ++ [2][1][2][1][RTW89_CHILE][3] = 16, ++ [2][1][2][1][RTW89_UKRAINE][3] = 28, ++ [2][1][2][1][RTW89_MEXICO][3] = 50, ++ [2][1][2][1][RTW89_CN][3] = 38, ++ [2][1][2][1][RTW89_QATAR][3] = 40, ++ [2][1][2][1][RTW89_UK][3] = 40, ++ [2][1][2][1][RTW89_FCC][11] = 62, ++ [2][1][2][1][RTW89_ETSI][11] = 40, ++ [2][1][2][1][RTW89_MKK][11] = 52, ++ [2][1][2][1][RTW89_IC][11] = 40, ++ [2][1][2][1][RTW89_KCC][11] = 56, ++ [2][1][2][1][RTW89_ACMA][11] = 40, ++ [2][1][2][1][RTW89_CHILE][11] = 34, ++ [2][1][2][1][RTW89_UKRAINE][11] = 28, ++ [2][1][2][1][RTW89_MEXICO][11] = 62, ++ [2][1][2][1][RTW89_CN][11] = 38, ++ [2][1][2][1][RTW89_QATAR][11] = 40, ++ [2][1][2][1][RTW89_UK][11] = 40, ++ [2][1][2][1][RTW89_FCC][18] = 56, ++ [2][1][2][1][RTW89_ETSI][18] = 40, ++ [2][1][2][1][RTW89_MKK][18] = 70, ++ [2][1][2][1][RTW89_IC][18] = 56, ++ [2][1][2][1][RTW89_KCC][18] = 58, ++ [2][1][2][1][RTW89_ACMA][18] = 40, ++ [2][1][2][1][RTW89_CHILE][18] = 34, ++ [2][1][2][1][RTW89_UKRAINE][18] = 28, ++ [2][1][2][1][RTW89_MEXICO][18] = 56, ++ [2][1][2][1][RTW89_CN][18] = 127, ++ [2][1][2][1][RTW89_QATAR][18] = 40, ++ [2][1][2][1][RTW89_UK][18] = 40, ++ [2][1][2][1][RTW89_FCC][26] = 68, ++ [2][1][2][1][RTW89_ETSI][26] = 40, ++ [2][1][2][1][RTW89_MKK][26] = 70, ++ [2][1][2][1][RTW89_IC][26] = 127, ++ [2][1][2][1][RTW89_KCC][26] = 56, ++ [2][1][2][1][RTW89_ACMA][26] = 127, ++ [2][1][2][1][RTW89_CHILE][26] = 34, ++ [2][1][2][1][RTW89_UKRAINE][26] = 28, ++ [2][1][2][1][RTW89_MEXICO][26] = 68, ++ [2][1][2][1][RTW89_CN][26] = 127, ++ [2][1][2][1][RTW89_QATAR][26] = 40, ++ [2][1][2][1][RTW89_UK][26] = 40, ++ [2][1][2][1][RTW89_FCC][34] = 68, ++ [2][1][2][1][RTW89_ETSI][34] = 127, ++ [2][1][2][1][RTW89_MKK][34] = 70, ++ [2][1][2][1][RTW89_IC][34] = 68, ++ [2][1][2][1][RTW89_KCC][34] = 56, ++ [2][1][2][1][RTW89_ACMA][34] = 70, ++ [2][1][2][1][RTW89_CHILE][34] = 34, ++ [2][1][2][1][RTW89_UKRAINE][34] = 127, ++ [2][1][2][1][RTW89_MEXICO][34] = 68, ++ [2][1][2][1][RTW89_CN][34] = 127, ++ [2][1][2][1][RTW89_QATAR][34] = 127, ++ [2][1][2][1][RTW89_UK][34] = 56, ++ [2][1][2][1][RTW89_FCC][41] = 74, ++ [2][1][2][1][RTW89_ETSI][41] = 4, ++ [2][1][2][1][RTW89_MKK][41] = 127, ++ [2][1][2][1][RTW89_IC][41] = 74, ++ [2][1][2][1][RTW89_KCC][41] = 56, ++ [2][1][2][1][RTW89_ACMA][41] = 70, ++ [2][1][2][1][RTW89_CHILE][41] = 36, ++ [2][1][2][1][RTW89_UKRAINE][41] = 4, ++ [2][1][2][1][RTW89_MEXICO][41] = 74, ++ [2][1][2][1][RTW89_CN][41] = 70, ++ [2][1][2][1][RTW89_QATAR][41] = 4, ++ [2][1][2][1][RTW89_UK][41] = 38, ++ [2][1][2][1][RTW89_FCC][49] = 58, ++ [2][1][2][1][RTW89_ETSI][49] = 127, ++ [2][1][2][1][RTW89_MKK][49] = 127, ++ [2][1][2][1][RTW89_IC][49] = 127, ++ [2][1][2][1][RTW89_KCC][49] = 127, ++ [2][1][2][1][RTW89_ACMA][49] = 127, ++ [2][1][2][1][RTW89_CHILE][49] = 127, ++ [2][1][2][1][RTW89_UKRAINE][49] = 127, ++ [2][1][2][1][RTW89_MEXICO][49] = 127, ++ [2][1][2][1][RTW89_CN][49] = 127, ++ [2][1][2][1][RTW89_QATAR][49] = 127, ++ [2][1][2][1][RTW89_UK][49] = 127, ++}; ++ ++const s8 rtw89_8852b_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] ++ [RTW89_REGD_NUM][RTW89_2G_CH_NUM] = { ++ [0][0][RTW89_WW][0] = 32, ++ [0][0][RTW89_WW][1] = 32, ++ [0][0][RTW89_WW][2] = 32, ++ [0][0][RTW89_WW][3] = 32, ++ [0][0][RTW89_WW][4] = 32, ++ [0][0][RTW89_WW][5] = 32, ++ [0][0][RTW89_WW][6] = 32, ++ [0][0][RTW89_WW][7] = 32, ++ [0][0][RTW89_WW][8] = 32, ++ [0][0][RTW89_WW][9] = 32, ++ [0][0][RTW89_WW][10] = 32, ++ [0][0][RTW89_WW][11] = 32, ++ [0][0][RTW89_WW][12] = 32, ++ [0][0][RTW89_WW][13] = 0, ++ [0][1][RTW89_WW][0] = 20, ++ [0][1][RTW89_WW][1] = 22, ++ [0][1][RTW89_WW][2] = 22, ++ [0][1][RTW89_WW][3] = 22, ++ [0][1][RTW89_WW][4] = 22, ++ [0][1][RTW89_WW][5] = 22, ++ [0][1][RTW89_WW][6] = 22, ++ [0][1][RTW89_WW][7] = 22, ++ [0][1][RTW89_WW][8] = 22, ++ [0][1][RTW89_WW][9] = 22, ++ [0][1][RTW89_WW][10] = 22, ++ [0][1][RTW89_WW][11] = 22, ++ [0][1][RTW89_WW][12] = 20, ++ [0][1][RTW89_WW][13] = 0, ++ [1][0][RTW89_WW][0] = 42, ++ [1][0][RTW89_WW][1] = 44, ++ [1][0][RTW89_WW][2] = 44, ++ [1][0][RTW89_WW][3] = 44, ++ [1][0][RTW89_WW][4] = 44, ++ [1][0][RTW89_WW][5] = 44, ++ [1][0][RTW89_WW][6] = 44, ++ [1][0][RTW89_WW][7] = 44, ++ [1][0][RTW89_WW][8] = 44, ++ [1][0][RTW89_WW][9] = 44, ++ [1][0][RTW89_WW][10] = 44, ++ [1][0][RTW89_WW][11] = 44, ++ [1][0][RTW89_WW][12] = 38, ++ [1][0][RTW89_WW][13] = 0, ++ [1][1][RTW89_WW][0] = 32, ++ [1][1][RTW89_WW][1] = 32, ++ [1][1][RTW89_WW][2] = 32, ++ [1][1][RTW89_WW][3] = 32, ++ [1][1][RTW89_WW][4] = 32, ++ [1][1][RTW89_WW][5] = 32, ++ [1][1][RTW89_WW][6] = 32, ++ [1][1][RTW89_WW][7] = 32, ++ [1][1][RTW89_WW][8] = 32, ++ [1][1][RTW89_WW][9] = 32, ++ [1][1][RTW89_WW][10] = 32, ++ [1][1][RTW89_WW][11] = 32, ++ [1][1][RTW89_WW][12] = 32, ++ [1][1][RTW89_WW][13] = 0, ++ [2][0][RTW89_WW][0] = 56, ++ [2][0][RTW89_WW][1] = 56, ++ [2][0][RTW89_WW][2] = 56, ++ [2][0][RTW89_WW][3] = 56, ++ [2][0][RTW89_WW][4] = 56, ++ [2][0][RTW89_WW][5] = 56, ++ [2][0][RTW89_WW][6] = 56, ++ [2][0][RTW89_WW][7] = 56, ++ [2][0][RTW89_WW][8] = 56, ++ [2][0][RTW89_WW][9] = 56, ++ [2][0][RTW89_WW][10] = 56, ++ [2][0][RTW89_WW][11] = 50, ++ [2][0][RTW89_WW][12] = 46, ++ [2][0][RTW89_WW][13] = 0, ++ [2][1][RTW89_WW][0] = 44, ++ [2][1][RTW89_WW][1] = 44, ++ [2][1][RTW89_WW][2] = 44, ++ [2][1][RTW89_WW][3] = 44, ++ [2][1][RTW89_WW][4] = 44, ++ [2][1][RTW89_WW][5] = 44, ++ [2][1][RTW89_WW][6] = 44, ++ [2][1][RTW89_WW][7] = 44, ++ [2][1][RTW89_WW][8] = 44, ++ [2][1][RTW89_WW][9] = 44, ++ [2][1][RTW89_WW][10] = 44, ++ [2][1][RTW89_WW][11] = 38, ++ [2][1][RTW89_WW][12] = 34, ++ [2][1][RTW89_WW][13] = 0, ++ [0][0][RTW89_FCC][0] = 68, ++ [0][0][RTW89_ETSI][0] = 32, ++ [0][0][RTW89_MKK][0] = 42, ++ [0][0][RTW89_IC][0] = 68, ++ [0][0][RTW89_KCC][0] = 44, ++ [0][0][RTW89_ACMA][0] = 32, ++ [0][0][RTW89_CHILE][0] = 66, ++ [0][0][RTW89_UKRAINE][0] = 32, ++ [0][0][RTW89_MEXICO][0] = 68, ++ [0][0][RTW89_CN][0] = 32, ++ [0][0][RTW89_QATAR][0] = 32, ++ [0][0][RTW89_UK][0] = 32, ++ [0][0][RTW89_FCC][1] = 68, ++ [0][0][RTW89_ETSI][1] = 32, ++ [0][0][RTW89_MKK][1] = 42, ++ [0][0][RTW89_IC][1] = 68, ++ [0][0][RTW89_KCC][1] = 44, ++ [0][0][RTW89_ACMA][1] = 32, ++ [0][0][RTW89_CHILE][1] = 64, ++ [0][0][RTW89_UKRAINE][1] = 32, ++ [0][0][RTW89_MEXICO][1] = 68, ++ [0][0][RTW89_CN][1] = 32, ++ [0][0][RTW89_QATAR][1] = 32, ++ [0][0][RTW89_UK][1] = 32, ++ [0][0][RTW89_FCC][2] = 72, ++ [0][0][RTW89_ETSI][2] = 32, ++ [0][0][RTW89_MKK][2] = 42, ++ [0][0][RTW89_IC][2] = 72, ++ [0][0][RTW89_KCC][2] = 44, ++ [0][0][RTW89_ACMA][2] = 32, ++ [0][0][RTW89_CHILE][2] = 64, ++ [0][0][RTW89_UKRAINE][2] = 32, ++ [0][0][RTW89_MEXICO][2] = 72, ++ [0][0][RTW89_CN][2] = 32, ++ [0][0][RTW89_QATAR][2] = 32, ++ [0][0][RTW89_UK][2] = 32, ++ [0][0][RTW89_FCC][3] = 76, ++ [0][0][RTW89_ETSI][3] = 32, ++ [0][0][RTW89_MKK][3] = 42, ++ [0][0][RTW89_IC][3] = 76, ++ [0][0][RTW89_KCC][3] = 44, ++ [0][0][RTW89_ACMA][3] = 32, ++ [0][0][RTW89_CHILE][3] = 64, ++ [0][0][RTW89_UKRAINE][3] = 32, ++ [0][0][RTW89_MEXICO][3] = 76, ++ [0][0][RTW89_CN][3] = 32, ++ [0][0][RTW89_QATAR][3] = 32, ++ [0][0][RTW89_UK][3] = 32, ++ [0][0][RTW89_FCC][4] = 76, ++ [0][0][RTW89_ETSI][4] = 32, ++ [0][0][RTW89_MKK][4] = 42, ++ [0][0][RTW89_IC][4] = 76, ++ [0][0][RTW89_KCC][4] = 44, ++ [0][0][RTW89_ACMA][4] = 32, ++ [0][0][RTW89_CHILE][4] = 64, ++ [0][0][RTW89_UKRAINE][4] = 32, ++ [0][0][RTW89_MEXICO][4] = 76, ++ [0][0][RTW89_CN][4] = 32, ++ [0][0][RTW89_QATAR][4] = 32, ++ [0][0][RTW89_UK][4] = 32, ++ [0][0][RTW89_FCC][5] = 84, ++ [0][0][RTW89_ETSI][5] = 32, ++ [0][0][RTW89_MKK][5] = 42, ++ [0][0][RTW89_IC][5] = 84, ++ [0][0][RTW89_KCC][5] = 44, ++ [0][0][RTW89_ACMA][5] = 32, ++ [0][0][RTW89_CHILE][5] = 64, ++ [0][0][RTW89_UKRAINE][5] = 32, ++ [0][0][RTW89_MEXICO][5] = 84, ++ [0][0][RTW89_CN][5] = 32, ++ [0][0][RTW89_QATAR][5] = 32, ++ [0][0][RTW89_UK][5] = 32, ++ [0][0][RTW89_FCC][6] = 74, ++ [0][0][RTW89_ETSI][6] = 32, ++ [0][0][RTW89_MKK][6] = 42, ++ [0][0][RTW89_IC][6] = 74, ++ [0][0][RTW89_KCC][6] = 44, ++ [0][0][RTW89_ACMA][6] = 32, ++ [0][0][RTW89_CHILE][6] = 64, ++ [0][0][RTW89_UKRAINE][6] = 32, ++ [0][0][RTW89_MEXICO][6] = 74, ++ [0][0][RTW89_CN][6] = 32, ++ [0][0][RTW89_QATAR][6] = 32, ++ [0][0][RTW89_UK][6] = 32, ++ [0][0][RTW89_FCC][7] = 74, ++ [0][0][RTW89_ETSI][7] = 32, ++ [0][0][RTW89_MKK][7] = 42, ++ [0][0][RTW89_IC][7] = 74, ++ [0][0][RTW89_KCC][7] = 44, ++ [0][0][RTW89_ACMA][7] = 32, ++ [0][0][RTW89_CHILE][7] = 64, ++ [0][0][RTW89_UKRAINE][7] = 32, ++ [0][0][RTW89_MEXICO][7] = 74, ++ [0][0][RTW89_CN][7] = 32, ++ [0][0][RTW89_QATAR][7] = 32, ++ [0][0][RTW89_UK][7] = 32, ++ [0][0][RTW89_FCC][8] = 70, ++ [0][0][RTW89_ETSI][8] = 32, ++ [0][0][RTW89_MKK][8] = 42, ++ [0][0][RTW89_IC][8] = 70, ++ [0][0][RTW89_KCC][8] = 44, ++ [0][0][RTW89_ACMA][8] = 32, ++ [0][0][RTW89_CHILE][8] = 64, ++ [0][0][RTW89_UKRAINE][8] = 32, ++ [0][0][RTW89_MEXICO][8] = 70, ++ [0][0][RTW89_CN][8] = 32, ++ [0][0][RTW89_QATAR][8] = 32, ++ [0][0][RTW89_UK][8] = 32, ++ [0][0][RTW89_FCC][9] = 66, ++ [0][0][RTW89_ETSI][9] = 32, ++ [0][0][RTW89_MKK][9] = 42, ++ [0][0][RTW89_IC][9] = 66, ++ [0][0][RTW89_KCC][9] = 42, ++ [0][0][RTW89_ACMA][9] = 32, ++ [0][0][RTW89_CHILE][9] = 64, ++ [0][0][RTW89_UKRAINE][9] = 32, ++ [0][0][RTW89_MEXICO][9] = 66, ++ [0][0][RTW89_CN][9] = 32, ++ [0][0][RTW89_QATAR][9] = 32, ++ [0][0][RTW89_UK][9] = 32, ++ [0][0][RTW89_FCC][10] = 66, ++ [0][0][RTW89_ETSI][10] = 32, ++ [0][0][RTW89_MKK][10] = 42, ++ [0][0][RTW89_IC][10] = 66, ++ [0][0][RTW89_KCC][10] = 42, ++ [0][0][RTW89_ACMA][10] = 32, ++ [0][0][RTW89_CHILE][10] = 66, ++ [0][0][RTW89_UKRAINE][10] = 32, ++ [0][0][RTW89_MEXICO][10] = 66, ++ [0][0][RTW89_CN][10] = 32, ++ [0][0][RTW89_QATAR][10] = 32, ++ [0][0][RTW89_UK][10] = 32, ++ [0][0][RTW89_FCC][11] = 50, ++ [0][0][RTW89_ETSI][11] = 32, ++ [0][0][RTW89_MKK][11] = 42, ++ [0][0][RTW89_IC][11] = 50, ++ [0][0][RTW89_KCC][11] = 42, ++ [0][0][RTW89_ACMA][11] = 32, ++ [0][0][RTW89_CHILE][11] = 64, ++ [0][0][RTW89_UKRAINE][11] = 32, ++ [0][0][RTW89_MEXICO][11] = 50, ++ [0][0][RTW89_CN][11] = 32, ++ [0][0][RTW89_QATAR][11] = 32, ++ [0][0][RTW89_UK][11] = 32, ++ [0][0][RTW89_FCC][12] = 32, ++ [0][0][RTW89_ETSI][12] = 32, ++ [0][0][RTW89_MKK][12] = 42, ++ [0][0][RTW89_IC][12] = 32, ++ [0][0][RTW89_KCC][12] = 42, ++ [0][0][RTW89_ACMA][12] = 32, ++ [0][0][RTW89_CHILE][12] = 64, ++ [0][0][RTW89_UKRAINE][12] = 32, ++ [0][0][RTW89_MEXICO][12] = 32, ++ [0][0][RTW89_CN][12] = 32, ++ [0][0][RTW89_QATAR][12] = 32, ++ [0][0][RTW89_UK][12] = 32, ++ [0][0][RTW89_FCC][13] = 127, ++ [0][0][RTW89_ETSI][13] = 127, ++ [0][0][RTW89_MKK][13] = 127, ++ [0][0][RTW89_IC][13] = 127, ++ [0][0][RTW89_KCC][13] = 127, ++ [0][0][RTW89_ACMA][13] = 127, ++ [0][0][RTW89_CHILE][13] = 127, ++ [0][0][RTW89_UKRAINE][13] = 127, ++ [0][0][RTW89_MEXICO][13] = 127, ++ [0][0][RTW89_CN][13] = 127, ++ [0][0][RTW89_QATAR][13] = 127, ++ [0][0][RTW89_UK][13] = 127, ++ [0][1][RTW89_FCC][0] = 54, ++ [0][1][RTW89_ETSI][0] = 20, ++ [0][1][RTW89_MKK][0] = 32, ++ [0][1][RTW89_IC][0] = 54, ++ [0][1][RTW89_KCC][0] = 32, ++ [0][1][RTW89_ACMA][0] = 20, ++ [0][1][RTW89_CHILE][0] = 50, ++ [0][1][RTW89_UKRAINE][0] = 20, ++ [0][1][RTW89_MEXICO][0] = 54, ++ [0][1][RTW89_CN][0] = 20, ++ [0][1][RTW89_QATAR][0] = 20, ++ [0][1][RTW89_UK][0] = 20, ++ [0][1][RTW89_FCC][1] = 54, ++ [0][1][RTW89_ETSI][1] = 22, ++ [0][1][RTW89_MKK][1] = 32, ++ [0][1][RTW89_IC][1] = 54, ++ [0][1][RTW89_KCC][1] = 32, ++ [0][1][RTW89_ACMA][1] = 22, ++ [0][1][RTW89_CHILE][1] = 50, ++ [0][1][RTW89_UKRAINE][1] = 22, ++ [0][1][RTW89_MEXICO][1] = 54, ++ [0][1][RTW89_CN][1] = 22, ++ [0][1][RTW89_QATAR][1] = 22, ++ [0][1][RTW89_UK][1] = 22, ++ [0][1][RTW89_FCC][2] = 58, ++ [0][1][RTW89_ETSI][2] = 22, ++ [0][1][RTW89_MKK][2] = 32, ++ [0][1][RTW89_IC][2] = 58, ++ [0][1][RTW89_KCC][2] = 32, ++ [0][1][RTW89_ACMA][2] = 22, ++ [0][1][RTW89_CHILE][2] = 50, ++ [0][1][RTW89_UKRAINE][2] = 22, ++ [0][1][RTW89_MEXICO][2] = 58, ++ [0][1][RTW89_CN][2] = 22, ++ [0][1][RTW89_QATAR][2] = 22, ++ [0][1][RTW89_UK][2] = 22, ++ [0][1][RTW89_FCC][3] = 62, ++ [0][1][RTW89_ETSI][3] = 22, ++ [0][1][RTW89_MKK][3] = 32, ++ [0][1][RTW89_IC][3] = 62, ++ [0][1][RTW89_KCC][3] = 32, ++ [0][1][RTW89_ACMA][3] = 22, ++ [0][1][RTW89_CHILE][3] = 50, ++ [0][1][RTW89_UKRAINE][3] = 22, ++ [0][1][RTW89_MEXICO][3] = 62, ++ [0][1][RTW89_CN][3] = 22, ++ [0][1][RTW89_QATAR][3] = 22, ++ [0][1][RTW89_UK][3] = 22, ++ [0][1][RTW89_FCC][4] = 66, ++ [0][1][RTW89_ETSI][4] = 22, ++ [0][1][RTW89_MKK][4] = 32, ++ [0][1][RTW89_IC][4] = 66, ++ [0][1][RTW89_KCC][4] = 30, ++ [0][1][RTW89_ACMA][4] = 22, ++ [0][1][RTW89_CHILE][4] = 50, ++ [0][1][RTW89_UKRAINE][4] = 22, ++ [0][1][RTW89_MEXICO][4] = 66, ++ [0][1][RTW89_CN][4] = 22, ++ [0][1][RTW89_QATAR][4] = 22, ++ [0][1][RTW89_UK][4] = 22, ++ [0][1][RTW89_FCC][5] = 74, ++ [0][1][RTW89_ETSI][5] = 22, ++ [0][1][RTW89_MKK][5] = 32, ++ [0][1][RTW89_IC][5] = 74, ++ [0][1][RTW89_KCC][5] = 30, ++ [0][1][RTW89_ACMA][5] = 22, ++ [0][1][RTW89_CHILE][5] = 52, ++ [0][1][RTW89_UKRAINE][5] = 22, ++ [0][1][RTW89_MEXICO][5] = 74, ++ [0][1][RTW89_CN][5] = 22, ++ [0][1][RTW89_QATAR][5] = 22, ++ [0][1][RTW89_UK][5] = 22, ++ [0][1][RTW89_FCC][6] = 66, ++ [0][1][RTW89_ETSI][6] = 22, ++ [0][1][RTW89_MKK][6] = 30, ++ [0][1][RTW89_IC][6] = 66, ++ [0][1][RTW89_KCC][6] = 30, ++ [0][1][RTW89_ACMA][6] = 22, ++ [0][1][RTW89_CHILE][6] = 50, ++ [0][1][RTW89_UKRAINE][6] = 22, ++ [0][1][RTW89_MEXICO][6] = 66, ++ [0][1][RTW89_CN][6] = 22, ++ [0][1][RTW89_QATAR][6] = 22, ++ [0][1][RTW89_UK][6] = 22, ++ [0][1][RTW89_FCC][7] = 62, ++ [0][1][RTW89_ETSI][7] = 22, ++ [0][1][RTW89_MKK][7] = 32, ++ [0][1][RTW89_IC][7] = 62, ++ [0][1][RTW89_KCC][7] = 30, ++ [0][1][RTW89_ACMA][7] = 22, ++ [0][1][RTW89_CHILE][7] = 50, ++ [0][1][RTW89_UKRAINE][7] = 22, ++ [0][1][RTW89_MEXICO][7] = 62, ++ [0][1][RTW89_CN][7] = 22, ++ [0][1][RTW89_QATAR][7] = 22, ++ [0][1][RTW89_UK][7] = 22, ++ [0][1][RTW89_FCC][8] = 58, ++ [0][1][RTW89_ETSI][8] = 22, ++ [0][1][RTW89_MKK][8] = 32, ++ [0][1][RTW89_IC][8] = 58, ++ [0][1][RTW89_KCC][8] = 30, ++ [0][1][RTW89_ACMA][8] = 22, ++ [0][1][RTW89_CHILE][8] = 50, ++ [0][1][RTW89_UKRAINE][8] = 22, ++ [0][1][RTW89_MEXICO][8] = 58, ++ [0][1][RTW89_CN][8] = 22, ++ [0][1][RTW89_QATAR][8] = 22, ++ [0][1][RTW89_UK][8] = 22, ++ [0][1][RTW89_FCC][9] = 54, ++ [0][1][RTW89_ETSI][9] = 22, ++ [0][1][RTW89_MKK][9] = 32, ++ [0][1][RTW89_IC][9] = 54, ++ [0][1][RTW89_KCC][9] = 30, ++ [0][1][RTW89_ACMA][9] = 22, ++ [0][1][RTW89_CHILE][9] = 50, ++ [0][1][RTW89_UKRAINE][9] = 22, ++ [0][1][RTW89_MEXICO][9] = 54, ++ [0][1][RTW89_CN][9] = 22, ++ [0][1][RTW89_QATAR][9] = 22, ++ [0][1][RTW89_UK][9] = 22, ++ [0][1][RTW89_FCC][10] = 54, ++ [0][1][RTW89_ETSI][10] = 22, ++ [0][1][RTW89_MKK][10] = 32, ++ [0][1][RTW89_IC][10] = 54, ++ [0][1][RTW89_KCC][10] = 30, ++ [0][1][RTW89_ACMA][10] = 22, ++ [0][1][RTW89_CHILE][10] = 50, ++ [0][1][RTW89_UKRAINE][10] = 22, ++ [0][1][RTW89_MEXICO][10] = 54, ++ [0][1][RTW89_CN][10] = 22, ++ [0][1][RTW89_QATAR][10] = 22, ++ [0][1][RTW89_UK][10] = 22, ++ [0][1][RTW89_FCC][11] = 38, ++ [0][1][RTW89_ETSI][11] = 22, ++ [0][1][RTW89_MKK][11] = 32, ++ [0][1][RTW89_IC][11] = 38, ++ [0][1][RTW89_KCC][11] = 30, ++ [0][1][RTW89_ACMA][11] = 22, ++ [0][1][RTW89_CHILE][11] = 50, ++ [0][1][RTW89_UKRAINE][11] = 22, ++ [0][1][RTW89_MEXICO][11] = 38, ++ [0][1][RTW89_CN][11] = 22, ++ [0][1][RTW89_QATAR][11] = 22, ++ [0][1][RTW89_UK][11] = 22, ++ [0][1][RTW89_FCC][12] = 30, ++ [0][1][RTW89_ETSI][12] = 20, ++ [0][1][RTW89_MKK][12] = 30, ++ [0][1][RTW89_IC][12] = 30, ++ [0][1][RTW89_KCC][12] = 30, ++ [0][1][RTW89_ACMA][12] = 20, ++ [0][1][RTW89_CHILE][12] = 50, ++ [0][1][RTW89_UKRAINE][12] = 20, ++ [0][1][RTW89_MEXICO][12] = 30, ++ [0][1][RTW89_CN][12] = 20, ++ [0][1][RTW89_QATAR][12] = 20, ++ [0][1][RTW89_UK][12] = 20, ++ [0][1][RTW89_FCC][13] = 127, ++ [0][1][RTW89_ETSI][13] = 127, ++ [0][1][RTW89_MKK][13] = 127, ++ [0][1][RTW89_IC][13] = 127, ++ [0][1][RTW89_KCC][13] = 127, ++ [0][1][RTW89_ACMA][13] = 127, ++ [0][1][RTW89_CHILE][13] = 127, ++ [0][1][RTW89_UKRAINE][13] = 127, ++ [0][1][RTW89_MEXICO][13] = 127, ++ [0][1][RTW89_CN][13] = 127, ++ [0][1][RTW89_QATAR][13] = 127, ++ [0][1][RTW89_UK][13] = 127, ++ [1][0][RTW89_FCC][0] = 72, ++ [1][0][RTW89_ETSI][0] = 42, ++ [1][0][RTW89_MKK][0] = 52, ++ [1][0][RTW89_IC][0] = 72, ++ [1][0][RTW89_KCC][0] = 52, ++ [1][0][RTW89_ACMA][0] = 42, ++ [1][0][RTW89_CHILE][0] = 68, ++ [1][0][RTW89_UKRAINE][0] = 42, ++ [1][0][RTW89_MEXICO][0] = 72, ++ [1][0][RTW89_CN][0] = 42, ++ [1][0][RTW89_QATAR][0] = 42, ++ [1][0][RTW89_UK][0] = 42, ++ [1][0][RTW89_FCC][1] = 72, ++ [1][0][RTW89_ETSI][1] = 44, ++ [1][0][RTW89_MKK][1] = 52, ++ [1][0][RTW89_IC][1] = 72, ++ [1][0][RTW89_KCC][1] = 52, ++ [1][0][RTW89_ACMA][1] = 44, ++ [1][0][RTW89_CHILE][1] = 68, ++ [1][0][RTW89_UKRAINE][1] = 44, ++ [1][0][RTW89_MEXICO][1] = 72, ++ [1][0][RTW89_CN][1] = 44, ++ [1][0][RTW89_QATAR][1] = 44, ++ [1][0][RTW89_UK][1] = 44, ++ [1][0][RTW89_FCC][2] = 76, ++ [1][0][RTW89_ETSI][2] = 44, ++ [1][0][RTW89_MKK][2] = 52, ++ [1][0][RTW89_IC][2] = 76, ++ [1][0][RTW89_KCC][2] = 52, ++ [1][0][RTW89_ACMA][2] = 44, ++ [1][0][RTW89_CHILE][2] = 68, ++ [1][0][RTW89_UKRAINE][2] = 44, ++ [1][0][RTW89_MEXICO][2] = 76, ++ [1][0][RTW89_CN][2] = 44, ++ [1][0][RTW89_QATAR][2] = 44, ++ [1][0][RTW89_UK][2] = 44, ++ [1][0][RTW89_FCC][3] = 78, ++ [1][0][RTW89_ETSI][3] = 44, ++ [1][0][RTW89_MKK][3] = 52, ++ [1][0][RTW89_IC][3] = 78, ++ [1][0][RTW89_KCC][3] = 52, ++ [1][0][RTW89_ACMA][3] = 44, ++ [1][0][RTW89_CHILE][3] = 68, ++ [1][0][RTW89_UKRAINE][3] = 44, ++ [1][0][RTW89_MEXICO][3] = 78, ++ [1][0][RTW89_CN][3] = 44, ++ [1][0][RTW89_QATAR][3] = 44, ++ [1][0][RTW89_UK][3] = 44, ++ [1][0][RTW89_FCC][4] = 78, ++ [1][0][RTW89_ETSI][4] = 44, ++ [1][0][RTW89_MKK][4] = 52, ++ [1][0][RTW89_IC][4] = 78, ++ [1][0][RTW89_KCC][4] = 52, ++ [1][0][RTW89_ACMA][4] = 44, ++ [1][0][RTW89_CHILE][4] = 68, ++ [1][0][RTW89_UKRAINE][4] = 44, ++ [1][0][RTW89_MEXICO][4] = 78, ++ [1][0][RTW89_CN][4] = 44, ++ [1][0][RTW89_QATAR][4] = 44, ++ [1][0][RTW89_UK][4] = 44, ++ [1][0][RTW89_FCC][5] = 84, ++ [1][0][RTW89_ETSI][5] = 44, ++ [1][0][RTW89_MKK][5] = 52, ++ [1][0][RTW89_IC][5] = 84, ++ [1][0][RTW89_KCC][5] = 52, ++ [1][0][RTW89_ACMA][5] = 44, ++ [1][0][RTW89_CHILE][5] = 68, ++ [1][0][RTW89_UKRAINE][5] = 44, ++ [1][0][RTW89_MEXICO][5] = 84, ++ [1][0][RTW89_CN][5] = 44, ++ [1][0][RTW89_QATAR][5] = 44, ++ [1][0][RTW89_UK][5] = 44, ++ [1][0][RTW89_FCC][6] = 72, ++ [1][0][RTW89_ETSI][6] = 44, ++ [1][0][RTW89_MKK][6] = 52, ++ [1][0][RTW89_IC][6] = 72, ++ [1][0][RTW89_KCC][6] = 52, ++ [1][0][RTW89_ACMA][6] = 44, ++ [1][0][RTW89_CHILE][6] = 68, ++ [1][0][RTW89_UKRAINE][6] = 44, ++ [1][0][RTW89_MEXICO][6] = 72, ++ [1][0][RTW89_CN][6] = 44, ++ [1][0][RTW89_QATAR][6] = 44, ++ [1][0][RTW89_UK][6] = 44, ++ [1][0][RTW89_FCC][7] = 72, ++ [1][0][RTW89_ETSI][7] = 44, ++ [1][0][RTW89_MKK][7] = 52, ++ [1][0][RTW89_IC][7] = 72, ++ [1][0][RTW89_KCC][7] = 52, ++ [1][0][RTW89_ACMA][7] = 44, ++ [1][0][RTW89_CHILE][7] = 68, ++ [1][0][RTW89_UKRAINE][7] = 44, ++ [1][0][RTW89_MEXICO][7] = 72, ++ [1][0][RTW89_CN][7] = 44, ++ [1][0][RTW89_QATAR][7] = 44, ++ [1][0][RTW89_UK][7] = 44, ++ [1][0][RTW89_FCC][8] = 72, ++ [1][0][RTW89_ETSI][8] = 44, ++ [1][0][RTW89_MKK][8] = 52, ++ [1][0][RTW89_IC][8] = 72, ++ [1][0][RTW89_KCC][8] = 52, ++ [1][0][RTW89_ACMA][8] = 44, ++ [1][0][RTW89_CHILE][8] = 68, ++ [1][0][RTW89_UKRAINE][8] = 44, ++ [1][0][RTW89_MEXICO][8] = 72, ++ [1][0][RTW89_CN][8] = 44, ++ [1][0][RTW89_QATAR][8] = 44, ++ [1][0][RTW89_UK][8] = 44, ++ [1][0][RTW89_FCC][9] = 68, ++ [1][0][RTW89_ETSI][9] = 44, ++ [1][0][RTW89_MKK][9] = 52, ++ [1][0][RTW89_IC][9] = 68, ++ [1][0][RTW89_KCC][9] = 52, ++ [1][0][RTW89_ACMA][9] = 44, ++ [1][0][RTW89_CHILE][9] = 68, ++ [1][0][RTW89_UKRAINE][9] = 44, ++ [1][0][RTW89_MEXICO][9] = 68, ++ [1][0][RTW89_CN][9] = 44, ++ [1][0][RTW89_QATAR][9] = 44, ++ [1][0][RTW89_UK][9] = 44, ++ [1][0][RTW89_FCC][10] = 68, ++ [1][0][RTW89_ETSI][10] = 44, ++ [1][0][RTW89_MKK][10] = 52, ++ [1][0][RTW89_IC][10] = 68, ++ [1][0][RTW89_KCC][10] = 52, ++ [1][0][RTW89_ACMA][10] = 44, ++ [1][0][RTW89_CHILE][10] = 70, ++ [1][0][RTW89_UKRAINE][10] = 44, ++ [1][0][RTW89_MEXICO][10] = 68, ++ [1][0][RTW89_CN][10] = 44, ++ [1][0][RTW89_QATAR][10] = 44, ++ [1][0][RTW89_UK][10] = 44, ++ [1][0][RTW89_FCC][11] = 50, ++ [1][0][RTW89_ETSI][11] = 44, ++ [1][0][RTW89_MKK][11] = 52, ++ [1][0][RTW89_IC][11] = 50, ++ [1][0][RTW89_KCC][11] = 52, ++ [1][0][RTW89_ACMA][11] = 44, ++ [1][0][RTW89_CHILE][11] = 68, ++ [1][0][RTW89_UKRAINE][11] = 44, ++ [1][0][RTW89_MEXICO][11] = 50, ++ [1][0][RTW89_CN][11] = 44, ++ [1][0][RTW89_QATAR][11] = 44, ++ [1][0][RTW89_UK][11] = 44, ++ [1][0][RTW89_FCC][12] = 38, ++ [1][0][RTW89_ETSI][12] = 42, ++ [1][0][RTW89_MKK][12] = 52, ++ [1][0][RTW89_IC][12] = 38, ++ [1][0][RTW89_KCC][12] = 52, ++ [1][0][RTW89_ACMA][12] = 42, ++ [1][0][RTW89_CHILE][12] = 68, ++ [1][0][RTW89_UKRAINE][12] = 42, ++ [1][0][RTW89_MEXICO][12] = 38, ++ [1][0][RTW89_CN][12] = 42, ++ [1][0][RTW89_QATAR][12] = 42, ++ [1][0][RTW89_UK][12] = 42, ++ [1][0][RTW89_FCC][13] = 127, ++ [1][0][RTW89_ETSI][13] = 127, ++ [1][0][RTW89_MKK][13] = 127, ++ [1][0][RTW89_IC][13] = 127, ++ [1][0][RTW89_KCC][13] = 127, ++ [1][0][RTW89_ACMA][13] = 127, ++ [1][0][RTW89_CHILE][13] = 127, ++ [1][0][RTW89_UKRAINE][13] = 127, ++ [1][0][RTW89_MEXICO][13] = 127, ++ [1][0][RTW89_CN][13] = 127, ++ [1][0][RTW89_QATAR][13] = 127, ++ [1][0][RTW89_UK][13] = 127, ++ [1][1][RTW89_FCC][0] = 54, ++ [1][1][RTW89_ETSI][0] = 32, ++ [1][1][RTW89_MKK][0] = 40, ++ [1][1][RTW89_IC][0] = 54, ++ [1][1][RTW89_KCC][0] = 40, ++ [1][1][RTW89_ACMA][0] = 32, ++ [1][1][RTW89_CHILE][0] = 54, ++ [1][1][RTW89_UKRAINE][0] = 32, ++ [1][1][RTW89_MEXICO][0] = 54, ++ [1][1][RTW89_CN][0] = 32, ++ [1][1][RTW89_QATAR][0] = 32, ++ [1][1][RTW89_UK][0] = 32, ++ [1][1][RTW89_FCC][1] = 54, ++ [1][1][RTW89_ETSI][1] = 32, ++ [1][1][RTW89_MKK][1] = 40, ++ [1][1][RTW89_IC][1] = 54, ++ [1][1][RTW89_KCC][1] = 40, ++ [1][1][RTW89_ACMA][1] = 32, ++ [1][1][RTW89_CHILE][1] = 54, ++ [1][1][RTW89_UKRAINE][1] = 32, ++ [1][1][RTW89_MEXICO][1] = 54, ++ [1][1][RTW89_CN][1] = 32, ++ [1][1][RTW89_QATAR][1] = 32, ++ [1][1][RTW89_UK][1] = 32, ++ [1][1][RTW89_FCC][2] = 58, ++ [1][1][RTW89_ETSI][2] = 32, ++ [1][1][RTW89_MKK][2] = 40, ++ [1][1][RTW89_IC][2] = 58, ++ [1][1][RTW89_KCC][2] = 40, ++ [1][1][RTW89_ACMA][2] = 32, ++ [1][1][RTW89_CHILE][2] = 54, ++ [1][1][RTW89_UKRAINE][2] = 32, ++ [1][1][RTW89_MEXICO][2] = 58, ++ [1][1][RTW89_CN][2] = 32, ++ [1][1][RTW89_QATAR][2] = 32, ++ [1][1][RTW89_UK][2] = 32, ++ [1][1][RTW89_FCC][3] = 62, ++ [1][1][RTW89_ETSI][3] = 32, ++ [1][1][RTW89_MKK][3] = 40, ++ [1][1][RTW89_IC][3] = 62, ++ [1][1][RTW89_KCC][3] = 40, ++ [1][1][RTW89_ACMA][3] = 32, ++ [1][1][RTW89_CHILE][3] = 54, ++ [1][1][RTW89_UKRAINE][3] = 32, ++ [1][1][RTW89_MEXICO][3] = 62, ++ [1][1][RTW89_CN][3] = 32, ++ [1][1][RTW89_QATAR][3] = 32, ++ [1][1][RTW89_UK][3] = 32, ++ [1][1][RTW89_FCC][4] = 66, ++ [1][1][RTW89_ETSI][4] = 32, ++ [1][1][RTW89_MKK][4] = 40, ++ [1][1][RTW89_IC][4] = 66, ++ [1][1][RTW89_KCC][4] = 40, ++ [1][1][RTW89_ACMA][4] = 32, ++ [1][1][RTW89_CHILE][4] = 54, ++ [1][1][RTW89_UKRAINE][4] = 32, ++ [1][1][RTW89_MEXICO][4] = 66, ++ [1][1][RTW89_CN][4] = 32, ++ [1][1][RTW89_QATAR][4] = 32, ++ [1][1][RTW89_UK][4] = 32, ++ [1][1][RTW89_FCC][5] = 74, ++ [1][1][RTW89_ETSI][5] = 32, ++ [1][1][RTW89_MKK][5] = 40, ++ [1][1][RTW89_IC][5] = 74, ++ [1][1][RTW89_KCC][5] = 40, ++ [1][1][RTW89_ACMA][5] = 32, ++ [1][1][RTW89_CHILE][5] = 54, ++ [1][1][RTW89_UKRAINE][5] = 32, ++ [1][1][RTW89_MEXICO][5] = 74, ++ [1][1][RTW89_CN][5] = 32, ++ [1][1][RTW89_QATAR][5] = 32, ++ [1][1][RTW89_UK][5] = 32, ++ [1][1][RTW89_FCC][6] = 66, ++ [1][1][RTW89_ETSI][6] = 32, ++ [1][1][RTW89_MKK][6] = 40, ++ [1][1][RTW89_IC][6] = 66, ++ [1][1][RTW89_KCC][6] = 40, ++ [1][1][RTW89_ACMA][6] = 32, ++ [1][1][RTW89_CHILE][6] = 54, ++ [1][1][RTW89_UKRAINE][6] = 32, ++ [1][1][RTW89_MEXICO][6] = 66, ++ [1][1][RTW89_CN][6] = 32, ++ [1][1][RTW89_QATAR][6] = 32, ++ [1][1][RTW89_UK][6] = 32, ++ [1][1][RTW89_FCC][7] = 62, ++ [1][1][RTW89_ETSI][7] = 32, ++ [1][1][RTW89_MKK][7] = 40, ++ [1][1][RTW89_IC][7] = 62, ++ [1][1][RTW89_KCC][7] = 40, ++ [1][1][RTW89_ACMA][7] = 32, ++ [1][1][RTW89_CHILE][7] = 54, ++ [1][1][RTW89_UKRAINE][7] = 32, ++ [1][1][RTW89_MEXICO][7] = 62, ++ [1][1][RTW89_CN][7] = 32, ++ [1][1][RTW89_QATAR][7] = 32, ++ [1][1][RTW89_UK][7] = 32, ++ [1][1][RTW89_FCC][8] = 58, ++ [1][1][RTW89_ETSI][8] = 32, ++ [1][1][RTW89_MKK][8] = 40, ++ [1][1][RTW89_IC][8] = 58, ++ [1][1][RTW89_KCC][8] = 40, ++ [1][1][RTW89_ACMA][8] = 32, ++ [1][1][RTW89_CHILE][8] = 54, ++ [1][1][RTW89_UKRAINE][8] = 32, ++ [1][1][RTW89_MEXICO][8] = 58, ++ [1][1][RTW89_CN][8] = 32, ++ [1][1][RTW89_QATAR][8] = 32, ++ [1][1][RTW89_UK][8] = 32, ++ [1][1][RTW89_FCC][9] = 54, ++ [1][1][RTW89_ETSI][9] = 32, ++ [1][1][RTW89_MKK][9] = 40, ++ [1][1][RTW89_IC][9] = 54, ++ [1][1][RTW89_KCC][9] = 40, ++ [1][1][RTW89_ACMA][9] = 32, ++ [1][1][RTW89_CHILE][9] = 54, ++ [1][1][RTW89_UKRAINE][9] = 32, ++ [1][1][RTW89_MEXICO][9] = 54, ++ [1][1][RTW89_CN][9] = 32, ++ [1][1][RTW89_QATAR][9] = 32, ++ [1][1][RTW89_UK][9] = 32, ++ [1][1][RTW89_FCC][10] = 54, ++ [1][1][RTW89_ETSI][10] = 32, ++ [1][1][RTW89_MKK][10] = 40, ++ [1][1][RTW89_IC][10] = 54, ++ [1][1][RTW89_KCC][10] = 40, ++ [1][1][RTW89_ACMA][10] = 32, ++ [1][1][RTW89_CHILE][10] = 54, ++ [1][1][RTW89_UKRAINE][10] = 32, ++ [1][1][RTW89_MEXICO][10] = 54, ++ [1][1][RTW89_CN][10] = 32, ++ [1][1][RTW89_QATAR][10] = 32, ++ [1][1][RTW89_UK][10] = 32, ++ [1][1][RTW89_FCC][11] = 38, ++ [1][1][RTW89_ETSI][11] = 32, ++ [1][1][RTW89_MKK][11] = 40, ++ [1][1][RTW89_IC][11] = 38, ++ [1][1][RTW89_KCC][11] = 40, ++ [1][1][RTW89_ACMA][11] = 32, ++ [1][1][RTW89_CHILE][11] = 54, ++ [1][1][RTW89_UKRAINE][11] = 32, ++ [1][1][RTW89_MEXICO][11] = 38, ++ [1][1][RTW89_CN][11] = 32, ++ [1][1][RTW89_QATAR][11] = 32, ++ [1][1][RTW89_UK][11] = 32, ++ [1][1][RTW89_FCC][12] = 32, ++ [1][1][RTW89_ETSI][12] = 32, ++ [1][1][RTW89_MKK][12] = 40, ++ [1][1][RTW89_IC][12] = 32, ++ [1][1][RTW89_KCC][12] = 40, ++ [1][1][RTW89_ACMA][12] = 32, ++ [1][1][RTW89_CHILE][12] = 54, ++ [1][1][RTW89_UKRAINE][12] = 32, ++ [1][1][RTW89_MEXICO][12] = 32, ++ [1][1][RTW89_CN][12] = 32, ++ [1][1][RTW89_QATAR][12] = 32, ++ [1][1][RTW89_UK][12] = 32, ++ [1][1][RTW89_FCC][13] = 127, ++ [1][1][RTW89_ETSI][13] = 127, ++ [1][1][RTW89_MKK][13] = 127, ++ [1][1][RTW89_IC][13] = 127, ++ [1][1][RTW89_KCC][13] = 127, ++ [1][1][RTW89_ACMA][13] = 127, ++ [1][1][RTW89_CHILE][13] = 127, ++ [1][1][RTW89_UKRAINE][13] = 127, ++ [1][1][RTW89_MEXICO][13] = 127, ++ [1][1][RTW89_CN][13] = 127, ++ [1][1][RTW89_QATAR][13] = 127, ++ [1][1][RTW89_UK][13] = 127, ++ [2][0][RTW89_FCC][0] = 72, ++ [2][0][RTW89_ETSI][0] = 56, ++ [2][0][RTW89_MKK][0] = 64, ++ [2][0][RTW89_IC][0] = 72, ++ [2][0][RTW89_KCC][0] = 66, ++ [2][0][RTW89_ACMA][0] = 56, ++ [2][0][RTW89_CHILE][0] = 68, ++ [2][0][RTW89_UKRAINE][0] = 56, ++ [2][0][RTW89_MEXICO][0] = 72, ++ [2][0][RTW89_CN][0] = 56, ++ [2][0][RTW89_QATAR][0] = 56, ++ [2][0][RTW89_UK][0] = 56, ++ [2][0][RTW89_FCC][1] = 72, ++ [2][0][RTW89_ETSI][1] = 56, ++ [2][0][RTW89_MKK][1] = 64, ++ [2][0][RTW89_IC][1] = 72, ++ [2][0][RTW89_KCC][1] = 66, ++ [2][0][RTW89_ACMA][1] = 56, ++ [2][0][RTW89_CHILE][1] = 68, ++ [2][0][RTW89_UKRAINE][1] = 56, ++ [2][0][RTW89_MEXICO][1] = 72, ++ [2][0][RTW89_CN][1] = 56, ++ [2][0][RTW89_QATAR][1] = 56, ++ [2][0][RTW89_UK][1] = 56, ++ [2][0][RTW89_FCC][2] = 74, ++ [2][0][RTW89_ETSI][2] = 56, ++ [2][0][RTW89_MKK][2] = 64, ++ [2][0][RTW89_IC][2] = 74, ++ [2][0][RTW89_KCC][2] = 66, ++ [2][0][RTW89_ACMA][2] = 56, ++ [2][0][RTW89_CHILE][2] = 68, ++ [2][0][RTW89_UKRAINE][2] = 56, ++ [2][0][RTW89_MEXICO][2] = 74, ++ [2][0][RTW89_CN][2] = 56, ++ [2][0][RTW89_QATAR][2] = 56, ++ [2][0][RTW89_UK][2] = 56, ++ [2][0][RTW89_FCC][3] = 74, ++ [2][0][RTW89_ETSI][3] = 56, ++ [2][0][RTW89_MKK][3] = 64, ++ [2][0][RTW89_IC][3] = 74, ++ [2][0][RTW89_KCC][3] = 66, ++ [2][0][RTW89_ACMA][3] = 56, ++ [2][0][RTW89_CHILE][3] = 68, ++ [2][0][RTW89_UKRAINE][3] = 56, ++ [2][0][RTW89_MEXICO][3] = 74, ++ [2][0][RTW89_CN][3] = 56, ++ [2][0][RTW89_QATAR][3] = 56, ++ [2][0][RTW89_UK][3] = 56, ++ [2][0][RTW89_FCC][4] = 74, ++ [2][0][RTW89_ETSI][4] = 56, ++ [2][0][RTW89_MKK][4] = 64, ++ [2][0][RTW89_IC][4] = 74, ++ [2][0][RTW89_KCC][4] = 66, ++ [2][0][RTW89_ACMA][4] = 56, ++ [2][0][RTW89_CHILE][4] = 68, ++ [2][0][RTW89_UKRAINE][4] = 56, ++ [2][0][RTW89_MEXICO][4] = 74, ++ [2][0][RTW89_CN][4] = 56, ++ [2][0][RTW89_QATAR][4] = 56, ++ [2][0][RTW89_UK][4] = 56, ++ [2][0][RTW89_FCC][5] = 84, ++ [2][0][RTW89_ETSI][5] = 56, ++ [2][0][RTW89_MKK][5] = 64, ++ [2][0][RTW89_IC][5] = 84, ++ [2][0][RTW89_KCC][5] = 66, ++ [2][0][RTW89_ACMA][5] = 56, ++ [2][0][RTW89_CHILE][5] = 70, ++ [2][0][RTW89_UKRAINE][5] = 56, ++ [2][0][RTW89_MEXICO][5] = 84, ++ [2][0][RTW89_CN][5] = 56, ++ [2][0][RTW89_QATAR][5] = 56, ++ [2][0][RTW89_UK][5] = 56, ++ [2][0][RTW89_FCC][6] = 70, ++ [2][0][RTW89_ETSI][6] = 56, ++ [2][0][RTW89_MKK][6] = 64, ++ [2][0][RTW89_IC][6] = 70, ++ [2][0][RTW89_KCC][6] = 66, ++ [2][0][RTW89_ACMA][6] = 56, ++ [2][0][RTW89_CHILE][6] = 68, ++ [2][0][RTW89_UKRAINE][6] = 56, ++ [2][0][RTW89_MEXICO][6] = 70, ++ [2][0][RTW89_CN][6] = 56, ++ [2][0][RTW89_QATAR][6] = 56, ++ [2][0][RTW89_UK][6] = 56, ++ [2][0][RTW89_FCC][7] = 70, ++ [2][0][RTW89_ETSI][7] = 56, ++ [2][0][RTW89_MKK][7] = 64, ++ [2][0][RTW89_IC][7] = 70, ++ [2][0][RTW89_KCC][7] = 66, ++ [2][0][RTW89_ACMA][7] = 56, ++ [2][0][RTW89_CHILE][7] = 68, ++ [2][0][RTW89_UKRAINE][7] = 56, ++ [2][0][RTW89_MEXICO][7] = 70, ++ [2][0][RTW89_CN][7] = 56, ++ [2][0][RTW89_QATAR][7] = 56, ++ [2][0][RTW89_UK][7] = 56, ++ [2][0][RTW89_FCC][8] = 70, ++ [2][0][RTW89_ETSI][8] = 56, ++ [2][0][RTW89_MKK][8] = 64, ++ [2][0][RTW89_IC][8] = 70, ++ [2][0][RTW89_KCC][8] = 66, ++ [2][0][RTW89_ACMA][8] = 56, ++ [2][0][RTW89_CHILE][8] = 68, ++ [2][0][RTW89_UKRAINE][8] = 56, ++ [2][0][RTW89_MEXICO][8] = 70, ++ [2][0][RTW89_CN][8] = 56, ++ [2][0][RTW89_QATAR][8] = 56, ++ [2][0][RTW89_UK][8] = 56, ++ [2][0][RTW89_FCC][9] = 68, ++ [2][0][RTW89_ETSI][9] = 56, ++ [2][0][RTW89_MKK][9] = 64, ++ [2][0][RTW89_IC][9] = 68, ++ [2][0][RTW89_KCC][9] = 66, ++ [2][0][RTW89_ACMA][9] = 56, ++ [2][0][RTW89_CHILE][9] = 68, ++ [2][0][RTW89_UKRAINE][9] = 56, ++ [2][0][RTW89_MEXICO][9] = 68, ++ [2][0][RTW89_CN][9] = 56, ++ [2][0][RTW89_QATAR][9] = 56, ++ [2][0][RTW89_UK][9] = 56, ++ [2][0][RTW89_FCC][10] = 68, ++ [2][0][RTW89_ETSI][10] = 56, ++ [2][0][RTW89_MKK][10] = 64, ++ [2][0][RTW89_IC][10] = 68, ++ [2][0][RTW89_KCC][10] = 66, ++ [2][0][RTW89_ACMA][10] = 56, ++ [2][0][RTW89_CHILE][10] = 68, ++ [2][0][RTW89_UKRAINE][10] = 56, ++ [2][0][RTW89_MEXICO][10] = 68, ++ [2][0][RTW89_CN][10] = 56, ++ [2][0][RTW89_QATAR][10] = 56, ++ [2][0][RTW89_UK][10] = 56, ++ [2][0][RTW89_FCC][11] = 50, ++ [2][0][RTW89_ETSI][11] = 56, ++ [2][0][RTW89_MKK][11] = 64, ++ [2][0][RTW89_IC][11] = 50, ++ [2][0][RTW89_KCC][11] = 66, ++ [2][0][RTW89_ACMA][11] = 56, ++ [2][0][RTW89_CHILE][11] = 68, ++ [2][0][RTW89_UKRAINE][11] = 56, ++ [2][0][RTW89_MEXICO][11] = 50, ++ [2][0][RTW89_CN][11] = 56, ++ [2][0][RTW89_QATAR][11] = 56, ++ [2][0][RTW89_UK][11] = 56, ++ [2][0][RTW89_FCC][12] = 46, ++ [2][0][RTW89_ETSI][12] = 56, ++ [2][0][RTW89_MKK][12] = 64, ++ [2][0][RTW89_IC][12] = 46, ++ [2][0][RTW89_KCC][12] = 66, ++ [2][0][RTW89_ACMA][12] = 56, ++ [2][0][RTW89_CHILE][12] = 68, ++ [2][0][RTW89_UKRAINE][12] = 56, ++ [2][0][RTW89_MEXICO][12] = 46, ++ [2][0][RTW89_CN][12] = 56, ++ [2][0][RTW89_QATAR][12] = 56, ++ [2][0][RTW89_UK][12] = 56, ++ [2][0][RTW89_FCC][13] = 127, ++ [2][0][RTW89_ETSI][13] = 127, ++ [2][0][RTW89_MKK][13] = 127, ++ [2][0][RTW89_IC][13] = 127, ++ [2][0][RTW89_KCC][13] = 127, ++ [2][0][RTW89_ACMA][13] = 127, ++ [2][0][RTW89_CHILE][13] = 127, ++ [2][0][RTW89_UKRAINE][13] = 127, ++ [2][0][RTW89_MEXICO][13] = 127, ++ [2][0][RTW89_CN][13] = 127, ++ [2][0][RTW89_QATAR][13] = 127, ++ [2][0][RTW89_UK][13] = 127, ++ [2][1][RTW89_FCC][0] = 54, ++ [2][1][RTW89_ETSI][0] = 44, ++ [2][1][RTW89_MKK][0] = 52, ++ [2][1][RTW89_IC][0] = 54, ++ [2][1][RTW89_KCC][0] = 54, ++ [2][1][RTW89_ACMA][0] = 44, ++ [2][1][RTW89_CHILE][0] = 58, ++ [2][1][RTW89_UKRAINE][0] = 44, ++ [2][1][RTW89_MEXICO][0] = 54, ++ [2][1][RTW89_CN][0] = 44, ++ [2][1][RTW89_QATAR][0] = 44, ++ [2][1][RTW89_UK][0] = 44, ++ [2][1][RTW89_FCC][1] = 54, ++ [2][1][RTW89_ETSI][1] = 44, ++ [2][1][RTW89_MKK][1] = 52, ++ [2][1][RTW89_IC][1] = 54, ++ [2][1][RTW89_KCC][1] = 54, ++ [2][1][RTW89_ACMA][1] = 44, ++ [2][1][RTW89_CHILE][1] = 56, ++ [2][1][RTW89_UKRAINE][1] = 44, ++ [2][1][RTW89_MEXICO][1] = 54, ++ [2][1][RTW89_CN][1] = 44, ++ [2][1][RTW89_QATAR][1] = 44, ++ [2][1][RTW89_UK][1] = 44, ++ [2][1][RTW89_FCC][2] = 58, ++ [2][1][RTW89_ETSI][2] = 44, ++ [2][1][RTW89_MKK][2] = 52, ++ [2][1][RTW89_IC][2] = 58, ++ [2][1][RTW89_KCC][2] = 54, ++ [2][1][RTW89_ACMA][2] = 44, ++ [2][1][RTW89_CHILE][2] = 56, ++ [2][1][RTW89_UKRAINE][2] = 44, ++ [2][1][RTW89_MEXICO][2] = 58, ++ [2][1][RTW89_CN][2] = 44, ++ [2][1][RTW89_QATAR][2] = 44, ++ [2][1][RTW89_UK][2] = 44, ++ [2][1][RTW89_FCC][3] = 62, ++ [2][1][RTW89_ETSI][3] = 44, ++ [2][1][RTW89_MKK][3] = 52, ++ [2][1][RTW89_IC][3] = 62, ++ [2][1][RTW89_KCC][3] = 54, ++ [2][1][RTW89_ACMA][3] = 44, ++ [2][1][RTW89_CHILE][3] = 56, ++ [2][1][RTW89_UKRAINE][3] = 44, ++ [2][1][RTW89_MEXICO][3] = 62, ++ [2][1][RTW89_CN][3] = 44, ++ [2][1][RTW89_QATAR][3] = 44, ++ [2][1][RTW89_UK][3] = 44, ++ [2][1][RTW89_FCC][4] = 64, ++ [2][1][RTW89_ETSI][4] = 44, ++ [2][1][RTW89_MKK][4] = 52, ++ [2][1][RTW89_IC][4] = 64, ++ [2][1][RTW89_KCC][4] = 52, ++ [2][1][RTW89_ACMA][4] = 44, ++ [2][1][RTW89_CHILE][4] = 56, ++ [2][1][RTW89_UKRAINE][4] = 44, ++ [2][1][RTW89_MEXICO][4] = 64, ++ [2][1][RTW89_CN][4] = 44, ++ [2][1][RTW89_QATAR][4] = 44, ++ [2][1][RTW89_UK][4] = 44, ++ [2][1][RTW89_FCC][5] = 80, ++ [2][1][RTW89_ETSI][5] = 44, ++ [2][1][RTW89_MKK][5] = 52, ++ [2][1][RTW89_IC][5] = 80, ++ [2][1][RTW89_KCC][5] = 52, ++ [2][1][RTW89_ACMA][5] = 44, ++ [2][1][RTW89_CHILE][5] = 56, ++ [2][1][RTW89_UKRAINE][5] = 44, ++ [2][1][RTW89_MEXICO][5] = 80, ++ [2][1][RTW89_CN][5] = 44, ++ [2][1][RTW89_QATAR][5] = 44, ++ [2][1][RTW89_UK][5] = 44, ++ [2][1][RTW89_FCC][6] = 62, ++ [2][1][RTW89_ETSI][6] = 44, ++ [2][1][RTW89_MKK][6] = 52, ++ [2][1][RTW89_IC][6] = 62, ++ [2][1][RTW89_KCC][6] = 52, ++ [2][1][RTW89_ACMA][6] = 44, ++ [2][1][RTW89_CHILE][6] = 56, ++ [2][1][RTW89_UKRAINE][6] = 44, ++ [2][1][RTW89_MEXICO][6] = 62, ++ [2][1][RTW89_CN][6] = 44, ++ [2][1][RTW89_QATAR][6] = 44, ++ [2][1][RTW89_UK][6] = 44, ++ [2][1][RTW89_FCC][7] = 62, ++ [2][1][RTW89_ETSI][7] = 44, ++ [2][1][RTW89_MKK][7] = 52, ++ [2][1][RTW89_IC][7] = 62, ++ [2][1][RTW89_KCC][7] = 52, ++ [2][1][RTW89_ACMA][7] = 44, ++ [2][1][RTW89_CHILE][7] = 56, ++ [2][1][RTW89_UKRAINE][7] = 44, ++ [2][1][RTW89_MEXICO][7] = 62, ++ [2][1][RTW89_CN][7] = 44, ++ [2][1][RTW89_QATAR][7] = 44, ++ [2][1][RTW89_UK][7] = 44, ++ [2][1][RTW89_FCC][8] = 58, ++ [2][1][RTW89_ETSI][8] = 44, ++ [2][1][RTW89_MKK][8] = 52, ++ [2][1][RTW89_IC][8] = 58, ++ [2][1][RTW89_KCC][8] = 52, ++ [2][1][RTW89_ACMA][8] = 44, ++ [2][1][RTW89_CHILE][8] = 56, ++ [2][1][RTW89_UKRAINE][8] = 44, ++ [2][1][RTW89_MEXICO][8] = 58, ++ [2][1][RTW89_CN][8] = 44, ++ [2][1][RTW89_QATAR][8] = 44, ++ [2][1][RTW89_UK][8] = 44, ++ [2][1][RTW89_FCC][9] = 54, ++ [2][1][RTW89_ETSI][9] = 44, ++ [2][1][RTW89_MKK][9] = 52, ++ [2][1][RTW89_IC][9] = 54, ++ [2][1][RTW89_KCC][9] = 54, ++ [2][1][RTW89_ACMA][9] = 44, ++ [2][1][RTW89_CHILE][9] = 56, ++ [2][1][RTW89_UKRAINE][9] = 44, ++ [2][1][RTW89_MEXICO][9] = 54, ++ [2][1][RTW89_CN][9] = 44, ++ [2][1][RTW89_QATAR][9] = 44, ++ [2][1][RTW89_UK][9] = 44, ++ [2][1][RTW89_FCC][10] = 54, ++ [2][1][RTW89_ETSI][10] = 44, ++ [2][1][RTW89_MKK][10] = 52, ++ [2][1][RTW89_IC][10] = 54, ++ [2][1][RTW89_KCC][10] = 54, ++ [2][1][RTW89_ACMA][10] = 44, ++ [2][1][RTW89_CHILE][10] = 56, ++ [2][1][RTW89_UKRAINE][10] = 44, ++ [2][1][RTW89_MEXICO][10] = 54, ++ [2][1][RTW89_CN][10] = 44, ++ [2][1][RTW89_QATAR][10] = 44, ++ [2][1][RTW89_UK][10] = 44, ++ [2][1][RTW89_FCC][11] = 38, ++ [2][1][RTW89_ETSI][11] = 44, ++ [2][1][RTW89_MKK][11] = 52, ++ [2][1][RTW89_IC][11] = 38, ++ [2][1][RTW89_KCC][11] = 54, ++ [2][1][RTW89_ACMA][11] = 44, ++ [2][1][RTW89_CHILE][11] = 56, ++ [2][1][RTW89_UKRAINE][11] = 44, ++ [2][1][RTW89_MEXICO][11] = 38, ++ [2][1][RTW89_CN][11] = 44, ++ [2][1][RTW89_QATAR][11] = 44, ++ [2][1][RTW89_UK][11] = 44, ++ [2][1][RTW89_FCC][12] = 34, ++ [2][1][RTW89_ETSI][12] = 42, ++ [2][1][RTW89_MKK][12] = 52, ++ [2][1][RTW89_IC][12] = 34, ++ [2][1][RTW89_KCC][12] = 54, ++ [2][1][RTW89_ACMA][12] = 42, ++ [2][1][RTW89_CHILE][12] = 56, ++ [2][1][RTW89_UKRAINE][12] = 42, ++ [2][1][RTW89_MEXICO][12] = 34, ++ [2][1][RTW89_CN][12] = 42, ++ [2][1][RTW89_QATAR][12] = 42, ++ [2][1][RTW89_UK][12] = 42, ++ [2][1][RTW89_FCC][13] = 127, ++ [2][1][RTW89_ETSI][13] = 127, ++ [2][1][RTW89_MKK][13] = 127, ++ [2][1][RTW89_IC][13] = 127, ++ [2][1][RTW89_KCC][13] = 127, ++ [2][1][RTW89_ACMA][13] = 127, ++ [2][1][RTW89_CHILE][13] = 127, ++ [2][1][RTW89_UKRAINE][13] = 127, ++ [2][1][RTW89_MEXICO][13] = 127, ++ [2][1][RTW89_CN][13] = 127, ++ [2][1][RTW89_QATAR][13] = 127, ++ [2][1][RTW89_UK][13] = 127, ++}; ++ ++const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] ++ [RTW89_REGD_NUM][RTW89_5G_CH_NUM] = { ++ [0][0][RTW89_WW][0] = 24, ++ [0][0][RTW89_WW][2] = 24, ++ [0][0][RTW89_WW][4] = 24, ++ [0][0][RTW89_WW][6] = 12, ++ [0][0][RTW89_WW][8] = 24, ++ [0][0][RTW89_WW][10] = 24, ++ [0][0][RTW89_WW][12] = 24, ++ [0][0][RTW89_WW][14] = 24, ++ [0][0][RTW89_WW][15] = 24, ++ [0][0][RTW89_WW][17] = 24, ++ [0][0][RTW89_WW][19] = 24, ++ [0][0][RTW89_WW][21] = 24, ++ [0][0][RTW89_WW][23] = 24, ++ [0][0][RTW89_WW][25] = 24, ++ [0][0][RTW89_WW][27] = 24, ++ [0][0][RTW89_WW][29] = 24, ++ [0][0][RTW89_WW][31] = 24, ++ [0][0][RTW89_WW][33] = 24, ++ [0][0][RTW89_WW][35] = 24, ++ [0][0][RTW89_WW][37] = 44, ++ [0][0][RTW89_WW][38] = 26, ++ [0][0][RTW89_WW][40] = 26, ++ [0][0][RTW89_WW][42] = 26, ++ [0][0][RTW89_WW][44] = 26, ++ [0][0][RTW89_WW][46] = 26, ++ [0][0][RTW89_WW][48] = 32, ++ [0][0][RTW89_WW][50] = 32, ++ [0][0][RTW89_WW][52] = 32, ++ [0][1][RTW89_WW][0] = 0, ++ [0][1][RTW89_WW][2] = 4, ++ [0][1][RTW89_WW][4] = 0, ++ [0][1][RTW89_WW][6] = 0, ++ [0][1][RTW89_WW][8] = 12, ++ [0][1][RTW89_WW][10] = 12, ++ [0][1][RTW89_WW][12] = 12, ++ [0][1][RTW89_WW][14] = 12, ++ [0][1][RTW89_WW][15] = 12, ++ [0][1][RTW89_WW][17] = 12, ++ [0][1][RTW89_WW][19] = 12, ++ [0][1][RTW89_WW][21] = 12, ++ [0][1][RTW89_WW][23] = 12, ++ [0][1][RTW89_WW][25] = 12, ++ [0][1][RTW89_WW][27] = 12, ++ [0][1][RTW89_WW][29] = 12, ++ [0][1][RTW89_WW][31] = 12, ++ [0][1][RTW89_WW][33] = 12, ++ [0][1][RTW89_WW][35] = 12, ++ [0][1][RTW89_WW][37] = 30, ++ [0][1][RTW89_WW][38] = 14, ++ [0][1][RTW89_WW][40] = 14, ++ [0][1][RTW89_WW][42] = 14, ++ [0][1][RTW89_WW][44] = 14, ++ [0][1][RTW89_WW][46] = 14, ++ [0][1][RTW89_WW][48] = 20, ++ [0][1][RTW89_WW][50] = 20, ++ [0][1][RTW89_WW][52] = 20, ++ [1][0][RTW89_WW][0] = 34, ++ [1][0][RTW89_WW][2] = 34, ++ [1][0][RTW89_WW][4] = 34, ++ [1][0][RTW89_WW][6] = 26, ++ [1][0][RTW89_WW][8] = 34, ++ [1][0][RTW89_WW][10] = 34, ++ [1][0][RTW89_WW][12] = 34, ++ [1][0][RTW89_WW][14] = 34, ++ [1][0][RTW89_WW][15] = 34, ++ [1][0][RTW89_WW][17] = 34, ++ [1][0][RTW89_WW][19] = 34, ++ [1][0][RTW89_WW][21] = 34, ++ [1][0][RTW89_WW][23] = 34, ++ [1][0][RTW89_WW][25] = 34, ++ [1][0][RTW89_WW][27] = 34, ++ [1][0][RTW89_WW][29] = 34, ++ [1][0][RTW89_WW][31] = 34, ++ [1][0][RTW89_WW][33] = 34, ++ [1][0][RTW89_WW][35] = 34, ++ [1][0][RTW89_WW][37] = 52, ++ [1][0][RTW89_WW][38] = 28, ++ [1][0][RTW89_WW][40] = 28, ++ [1][0][RTW89_WW][42] = 28, ++ [1][0][RTW89_WW][44] = 28, ++ [1][0][RTW89_WW][46] = 28, ++ [1][0][RTW89_WW][48] = 44, ++ [1][0][RTW89_WW][50] = 44, ++ [1][0][RTW89_WW][52] = 44, ++ [1][1][RTW89_WW][0] = 10, ++ [1][1][RTW89_WW][2] = 14, ++ [1][1][RTW89_WW][4] = 10, ++ [1][1][RTW89_WW][6] = 10, ++ [1][1][RTW89_WW][8] = 20, ++ [1][1][RTW89_WW][10] = 20, ++ [1][1][RTW89_WW][12] = 22, ++ [1][1][RTW89_WW][14] = 22, ++ [1][1][RTW89_WW][15] = 22, ++ [1][1][RTW89_WW][17] = 22, ++ [1][1][RTW89_WW][19] = 22, ++ [1][1][RTW89_WW][21] = 22, ++ [1][1][RTW89_WW][23] = 22, ++ [1][1][RTW89_WW][25] = 22, ++ [1][1][RTW89_WW][27] = 22, ++ [1][1][RTW89_WW][29] = 22, ++ [1][1][RTW89_WW][31] = 22, ++ [1][1][RTW89_WW][33] = 22, ++ [1][1][RTW89_WW][35] = 22, ++ [1][1][RTW89_WW][37] = 38, ++ [1][1][RTW89_WW][38] = 16, ++ [1][1][RTW89_WW][40] = 16, ++ [1][1][RTW89_WW][42] = 16, ++ [1][1][RTW89_WW][44] = 16, ++ [1][1][RTW89_WW][46] = 16, ++ [1][1][RTW89_WW][48] = 32, ++ [1][1][RTW89_WW][50] = 32, ++ [1][1][RTW89_WW][52] = 32, ++ [2][0][RTW89_WW][0] = 44, ++ [2][0][RTW89_WW][2] = 44, ++ [2][0][RTW89_WW][4] = 44, ++ [2][0][RTW89_WW][6] = 38, ++ [2][0][RTW89_WW][8] = 48, ++ [2][0][RTW89_WW][10] = 48, ++ [2][0][RTW89_WW][12] = 46, ++ [2][0][RTW89_WW][14] = 46, ++ [2][0][RTW89_WW][15] = 48, ++ [2][0][RTW89_WW][17] = 48, ++ [2][0][RTW89_WW][19] = 48, ++ [2][0][RTW89_WW][21] = 48, ++ [2][0][RTW89_WW][23] = 48, ++ [2][0][RTW89_WW][25] = 48, ++ [2][0][RTW89_WW][27] = 48, ++ [2][0][RTW89_WW][29] = 48, ++ [2][0][RTW89_WW][31] = 48, ++ [2][0][RTW89_WW][33] = 48, ++ [2][0][RTW89_WW][35] = 48, ++ [2][0][RTW89_WW][37] = 64, ++ [2][0][RTW89_WW][38] = 28, ++ [2][0][RTW89_WW][40] = 28, ++ [2][0][RTW89_WW][42] = 28, ++ [2][0][RTW89_WW][44] = 28, ++ [2][0][RTW89_WW][46] = 28, ++ [2][0][RTW89_WW][48] = 56, ++ [2][0][RTW89_WW][50] = 56, ++ [2][0][RTW89_WW][52] = 56, ++ [2][1][RTW89_WW][0] = 20, ++ [2][1][RTW89_WW][2] = 18, ++ [2][1][RTW89_WW][4] = 22, ++ [2][1][RTW89_WW][6] = 22, ++ [2][1][RTW89_WW][8] = 34, ++ [2][1][RTW89_WW][10] = 34, ++ [2][1][RTW89_WW][12] = 36, ++ [2][1][RTW89_WW][14] = 36, ++ [2][1][RTW89_WW][15] = 36, ++ [2][1][RTW89_WW][17] = 36, ++ [2][1][RTW89_WW][19] = 36, ++ [2][1][RTW89_WW][21] = 36, ++ [2][1][RTW89_WW][23] = 36, ++ [2][1][RTW89_WW][25] = 36, ++ [2][1][RTW89_WW][27] = 36, ++ [2][1][RTW89_WW][29] = 36, ++ [2][1][RTW89_WW][31] = 36, ++ [2][1][RTW89_WW][33] = 36, ++ [2][1][RTW89_WW][35] = 36, ++ [2][1][RTW89_WW][37] = 48, ++ [2][1][RTW89_WW][38] = 16, ++ [2][1][RTW89_WW][40] = 16, ++ [2][1][RTW89_WW][42] = 16, ++ [2][1][RTW89_WW][44] = 16, ++ [2][1][RTW89_WW][46] = 16, ++ [2][1][RTW89_WW][48] = 44, ++ [2][1][RTW89_WW][50] = 44, ++ [2][1][RTW89_WW][52] = 44, ++ [0][0][RTW89_FCC][0] = 52, ++ [0][0][RTW89_ETSI][0] = 24, ++ [0][0][RTW89_MKK][0] = 26, ++ [0][0][RTW89_IC][0] = 24, ++ [0][0][RTW89_KCC][0] = 44, ++ [0][0][RTW89_ACMA][0] = 24, ++ [0][0][RTW89_CHILE][0] = 40, ++ [0][0][RTW89_UKRAINE][0] = 24, ++ [0][0][RTW89_MEXICO][0] = 52, ++ [0][0][RTW89_CN][0] = 24, ++ [0][0][RTW89_QATAR][0] = 24, ++ [0][0][RTW89_UK][0] = 24, ++ [0][0][RTW89_FCC][2] = 52, ++ [0][0][RTW89_ETSI][2] = 24, ++ [0][0][RTW89_MKK][2] = 26, ++ [0][0][RTW89_IC][2] = 24, ++ [0][0][RTW89_KCC][2] = 44, ++ [0][0][RTW89_ACMA][2] = 24, ++ [0][0][RTW89_CHILE][2] = 38, ++ [0][0][RTW89_UKRAINE][2] = 24, ++ [0][0][RTW89_MEXICO][2] = 52, ++ [0][0][RTW89_CN][2] = 24, ++ [0][0][RTW89_QATAR][2] = 24, ++ [0][0][RTW89_UK][2] = 24, ++ [0][0][RTW89_FCC][4] = 52, ++ [0][0][RTW89_ETSI][4] = 24, ++ [0][0][RTW89_MKK][4] = 26, ++ [0][0][RTW89_IC][4] = 24, ++ [0][0][RTW89_KCC][4] = 44, ++ [0][0][RTW89_ACMA][4] = 24, ++ [0][0][RTW89_CHILE][4] = 38, ++ [0][0][RTW89_UKRAINE][4] = 24, ++ [0][0][RTW89_MEXICO][4] = 52, ++ [0][0][RTW89_CN][4] = 24, ++ [0][0][RTW89_QATAR][4] = 24, ++ [0][0][RTW89_UK][4] = 24, ++ [0][0][RTW89_FCC][6] = 52, ++ [0][0][RTW89_ETSI][6] = 24, ++ [0][0][RTW89_MKK][6] = 26, ++ [0][0][RTW89_IC][6] = 24, ++ [0][0][RTW89_KCC][6] = 12, ++ [0][0][RTW89_ACMA][6] = 24, ++ [0][0][RTW89_CHILE][6] = 40, ++ [0][0][RTW89_UKRAINE][6] = 24, ++ [0][0][RTW89_MEXICO][6] = 52, ++ [0][0][RTW89_CN][6] = 24, ++ [0][0][RTW89_QATAR][6] = 24, ++ [0][0][RTW89_UK][6] = 24, ++ [0][0][RTW89_FCC][8] = 52, ++ [0][0][RTW89_ETSI][8] = 24, ++ [0][0][RTW89_MKK][8] = 26, ++ [0][0][RTW89_IC][8] = 52, ++ [0][0][RTW89_KCC][8] = 46, ++ [0][0][RTW89_ACMA][8] = 24, ++ [0][0][RTW89_CHILE][8] = 64, ++ [0][0][RTW89_UKRAINE][8] = 24, ++ [0][0][RTW89_MEXICO][8] = 52, ++ [0][0][RTW89_CN][8] = 24, ++ [0][0][RTW89_QATAR][8] = 24, ++ [0][0][RTW89_UK][8] = 24, ++ [0][0][RTW89_FCC][10] = 52, ++ [0][0][RTW89_ETSI][10] = 24, ++ [0][0][RTW89_MKK][10] = 26, ++ [0][0][RTW89_IC][10] = 52, ++ [0][0][RTW89_KCC][10] = 46, ++ [0][0][RTW89_ACMA][10] = 24, ++ [0][0][RTW89_CHILE][10] = 64, ++ [0][0][RTW89_UKRAINE][10] = 24, ++ [0][0][RTW89_MEXICO][10] = 52, ++ [0][0][RTW89_CN][10] = 24, ++ [0][0][RTW89_QATAR][10] = 24, ++ [0][0][RTW89_UK][10] = 24, ++ [0][0][RTW89_FCC][12] = 52, ++ [0][0][RTW89_ETSI][12] = 24, ++ [0][0][RTW89_MKK][12] = 24, ++ [0][0][RTW89_IC][12] = 52, ++ [0][0][RTW89_KCC][12] = 42, ++ [0][0][RTW89_ACMA][12] = 24, ++ [0][0][RTW89_CHILE][12] = 64, ++ [0][0][RTW89_UKRAINE][12] = 24, ++ [0][0][RTW89_MEXICO][12] = 52, ++ [0][0][RTW89_CN][12] = 24, ++ [0][0][RTW89_QATAR][12] = 24, ++ [0][0][RTW89_UK][12] = 24, ++ [0][0][RTW89_FCC][14] = 52, ++ [0][0][RTW89_ETSI][14] = 24, ++ [0][0][RTW89_MKK][14] = 24, ++ [0][0][RTW89_IC][14] = 52, ++ [0][0][RTW89_KCC][14] = 42, ++ [0][0][RTW89_ACMA][14] = 24, ++ [0][0][RTW89_CHILE][14] = 64, ++ [0][0][RTW89_UKRAINE][14] = 24, ++ [0][0][RTW89_MEXICO][14] = 52, ++ [0][0][RTW89_CN][14] = 24, ++ [0][0][RTW89_QATAR][14] = 24, ++ [0][0][RTW89_UK][14] = 24, ++ [0][0][RTW89_FCC][15] = 52, ++ [0][0][RTW89_ETSI][15] = 24, ++ [0][0][RTW89_MKK][15] = 46, ++ [0][0][RTW89_IC][15] = 52, ++ [0][0][RTW89_KCC][15] = 44, ++ [0][0][RTW89_ACMA][15] = 24, ++ [0][0][RTW89_CHILE][15] = 60, ++ [0][0][RTW89_UKRAINE][15] = 24, ++ [0][0][RTW89_MEXICO][15] = 52, ++ [0][0][RTW89_CN][15] = 127, ++ [0][0][RTW89_QATAR][15] = 24, ++ [0][0][RTW89_UK][15] = 24, ++ [0][0][RTW89_FCC][17] = 52, ++ [0][0][RTW89_ETSI][17] = 24, ++ [0][0][RTW89_MKK][17] = 48, ++ [0][0][RTW89_IC][17] = 52, ++ [0][0][RTW89_KCC][17] = 44, ++ [0][0][RTW89_ACMA][17] = 24, ++ [0][0][RTW89_CHILE][17] = 60, ++ [0][0][RTW89_UKRAINE][17] = 24, ++ [0][0][RTW89_MEXICO][17] = 52, ++ [0][0][RTW89_CN][17] = 127, ++ [0][0][RTW89_QATAR][17] = 24, ++ [0][0][RTW89_UK][17] = 24, ++ [0][0][RTW89_FCC][19] = 52, ++ [0][0][RTW89_ETSI][19] = 24, ++ [0][0][RTW89_MKK][19] = 48, ++ [0][0][RTW89_IC][19] = 52, ++ [0][0][RTW89_KCC][19] = 44, ++ [0][0][RTW89_ACMA][19] = 24, ++ [0][0][RTW89_CHILE][19] = 60, ++ [0][0][RTW89_UKRAINE][19] = 24, ++ [0][0][RTW89_MEXICO][19] = 52, ++ [0][0][RTW89_CN][19] = 127, ++ [0][0][RTW89_QATAR][19] = 24, ++ [0][0][RTW89_UK][19] = 24, ++ [0][0][RTW89_FCC][21] = 52, ++ [0][0][RTW89_ETSI][21] = 24, ++ [0][0][RTW89_MKK][21] = 48, ++ [0][0][RTW89_IC][21] = 52, ++ [0][0][RTW89_KCC][21] = 44, ++ [0][0][RTW89_ACMA][21] = 24, ++ [0][0][RTW89_CHILE][21] = 62, ++ [0][0][RTW89_UKRAINE][21] = 24, ++ [0][0][RTW89_MEXICO][21] = 52, ++ [0][0][RTW89_CN][21] = 127, ++ [0][0][RTW89_QATAR][21] = 24, ++ [0][0][RTW89_UK][21] = 24, ++ [0][0][RTW89_FCC][23] = 52, ++ [0][0][RTW89_ETSI][23] = 24, ++ [0][0][RTW89_MKK][23] = 48, ++ [0][0][RTW89_IC][23] = 52, ++ [0][0][RTW89_KCC][23] = 44, ++ [0][0][RTW89_ACMA][23] = 24, ++ [0][0][RTW89_CHILE][23] = 62, ++ [0][0][RTW89_UKRAINE][23] = 24, ++ [0][0][RTW89_MEXICO][23] = 52, ++ [0][0][RTW89_CN][23] = 127, ++ [0][0][RTW89_QATAR][23] = 24, ++ [0][0][RTW89_UK][23] = 24, ++ [0][0][RTW89_FCC][25] = 52, ++ [0][0][RTW89_ETSI][25] = 24, ++ [0][0][RTW89_MKK][25] = 48, ++ [0][0][RTW89_IC][25] = 127, ++ [0][0][RTW89_KCC][25] = 44, ++ [0][0][RTW89_ACMA][25] = 127, ++ [0][0][RTW89_CHILE][25] = 62, ++ [0][0][RTW89_UKRAINE][25] = 24, ++ [0][0][RTW89_MEXICO][25] = 52, ++ [0][0][RTW89_CN][25] = 127, ++ [0][0][RTW89_QATAR][25] = 24, ++ [0][0][RTW89_UK][25] = 24, ++ [0][0][RTW89_FCC][27] = 52, ++ [0][0][RTW89_ETSI][27] = 24, ++ [0][0][RTW89_MKK][27] = 48, ++ [0][0][RTW89_IC][27] = 127, ++ [0][0][RTW89_KCC][27] = 44, ++ [0][0][RTW89_ACMA][27] = 127, ++ [0][0][RTW89_CHILE][27] = 62, ++ [0][0][RTW89_UKRAINE][27] = 24, ++ [0][0][RTW89_MEXICO][27] = 52, ++ [0][0][RTW89_CN][27] = 127, ++ [0][0][RTW89_QATAR][27] = 24, ++ [0][0][RTW89_UK][27] = 24, ++ [0][0][RTW89_FCC][29] = 52, ++ [0][0][RTW89_ETSI][29] = 24, ++ [0][0][RTW89_MKK][29] = 48, ++ [0][0][RTW89_IC][29] = 127, ++ [0][0][RTW89_KCC][29] = 44, ++ [0][0][RTW89_ACMA][29] = 127, ++ [0][0][RTW89_CHILE][29] = 60, ++ [0][0][RTW89_UKRAINE][29] = 24, ++ [0][0][RTW89_MEXICO][29] = 52, ++ [0][0][RTW89_CN][29] = 127, ++ [0][0][RTW89_QATAR][29] = 24, ++ [0][0][RTW89_UK][29] = 24, ++ [0][0][RTW89_FCC][31] = 52, ++ [0][0][RTW89_ETSI][31] = 24, ++ [0][0][RTW89_MKK][31] = 48, ++ [0][0][RTW89_IC][31] = 52, ++ [0][0][RTW89_KCC][31] = 44, ++ [0][0][RTW89_ACMA][31] = 24, ++ [0][0][RTW89_CHILE][31] = 60, ++ [0][0][RTW89_UKRAINE][31] = 24, ++ [0][0][RTW89_MEXICO][31] = 52, ++ [0][0][RTW89_CN][31] = 127, ++ [0][0][RTW89_QATAR][31] = 24, ++ [0][0][RTW89_UK][31] = 24, ++ [0][0][RTW89_FCC][33] = 52, ++ [0][0][RTW89_ETSI][33] = 24, ++ [0][0][RTW89_MKK][33] = 48, ++ [0][0][RTW89_IC][33] = 52, ++ [0][0][RTW89_KCC][33] = 44, ++ [0][0][RTW89_ACMA][33] = 24, ++ [0][0][RTW89_CHILE][33] = 60, ++ [0][0][RTW89_UKRAINE][33] = 24, ++ [0][0][RTW89_MEXICO][33] = 52, ++ [0][0][RTW89_CN][33] = 127, ++ [0][0][RTW89_QATAR][33] = 24, ++ [0][0][RTW89_UK][33] = 24, ++ [0][0][RTW89_FCC][35] = 52, ++ [0][0][RTW89_ETSI][35] = 24, ++ [0][0][RTW89_MKK][35] = 48, ++ [0][0][RTW89_IC][35] = 52, ++ [0][0][RTW89_KCC][35] = 44, ++ [0][0][RTW89_ACMA][35] = 24, ++ [0][0][RTW89_CHILE][35] = 60, ++ [0][0][RTW89_UKRAINE][35] = 24, ++ [0][0][RTW89_MEXICO][35] = 52, ++ [0][0][RTW89_CN][35] = 127, ++ [0][0][RTW89_QATAR][35] = 24, ++ [0][0][RTW89_UK][35] = 24, ++ [0][0][RTW89_FCC][37] = 52, ++ [0][0][RTW89_ETSI][37] = 127, ++ [0][0][RTW89_MKK][37] = 44, ++ [0][0][RTW89_IC][37] = 52, ++ [0][0][RTW89_KCC][37] = 44, ++ [0][0][RTW89_ACMA][37] = 52, ++ [0][0][RTW89_CHILE][37] = 62, ++ [0][0][RTW89_UKRAINE][37] = 127, ++ [0][0][RTW89_MEXICO][37] = 52, ++ [0][0][RTW89_CN][37] = 127, ++ [0][0][RTW89_QATAR][37] = 127, ++ [0][0][RTW89_UK][37] = 56, ++ [0][0][RTW89_FCC][38] = 84, ++ [0][0][RTW89_ETSI][38] = 28, ++ [0][0][RTW89_MKK][38] = 127, ++ [0][0][RTW89_IC][38] = 84, ++ [0][0][RTW89_KCC][38] = 44, ++ [0][0][RTW89_ACMA][38] = 84, ++ [0][0][RTW89_CHILE][38] = 60, ++ [0][0][RTW89_UKRAINE][38] = 28, ++ [0][0][RTW89_MEXICO][38] = 84, ++ [0][0][RTW89_CN][38] = 62, ++ [0][0][RTW89_QATAR][38] = 28, ++ [0][0][RTW89_UK][38] = 26, ++ [0][0][RTW89_FCC][40] = 84, ++ [0][0][RTW89_ETSI][40] = 28, ++ [0][0][RTW89_MKK][40] = 127, ++ [0][0][RTW89_IC][40] = 84, ++ [0][0][RTW89_KCC][40] = 44, ++ [0][0][RTW89_ACMA][40] = 84, ++ [0][0][RTW89_CHILE][40] = 60, ++ [0][0][RTW89_UKRAINE][40] = 28, ++ [0][0][RTW89_MEXICO][40] = 84, ++ [0][0][RTW89_CN][40] = 62, ++ [0][0][RTW89_QATAR][40] = 28, ++ [0][0][RTW89_UK][40] = 26, ++ [0][0][RTW89_FCC][42] = 84, ++ [0][0][RTW89_ETSI][42] = 28, ++ [0][0][RTW89_MKK][42] = 127, ++ [0][0][RTW89_IC][42] = 84, ++ [0][0][RTW89_KCC][42] = 44, ++ [0][0][RTW89_ACMA][42] = 84, ++ [0][0][RTW89_CHILE][42] = 64, ++ [0][0][RTW89_UKRAINE][42] = 28, ++ [0][0][RTW89_MEXICO][42] = 84, ++ [0][0][RTW89_CN][42] = 62, ++ [0][0][RTW89_QATAR][42] = 28, ++ [0][0][RTW89_UK][42] = 26, ++ [0][0][RTW89_FCC][44] = 84, ++ [0][0][RTW89_ETSI][44] = 28, ++ [0][0][RTW89_MKK][44] = 127, ++ [0][0][RTW89_IC][44] = 84, ++ [0][0][RTW89_KCC][44] = 44, ++ [0][0][RTW89_ACMA][44] = 84, ++ [0][0][RTW89_CHILE][44] = 60, ++ [0][0][RTW89_UKRAINE][44] = 28, ++ [0][0][RTW89_MEXICO][44] = 84, ++ [0][0][RTW89_CN][44] = 62, ++ [0][0][RTW89_QATAR][44] = 28, ++ [0][0][RTW89_UK][44] = 26, ++ [0][0][RTW89_FCC][46] = 84, ++ [0][0][RTW89_ETSI][46] = 28, ++ [0][0][RTW89_MKK][46] = 127, ++ [0][0][RTW89_IC][46] = 84, ++ [0][0][RTW89_KCC][46] = 44, ++ [0][0][RTW89_ACMA][46] = 84, ++ [0][0][RTW89_CHILE][46] = 60, ++ [0][0][RTW89_UKRAINE][46] = 28, ++ [0][0][RTW89_MEXICO][46] = 84, ++ [0][0][RTW89_CN][46] = 62, ++ [0][0][RTW89_QATAR][46] = 28, ++ [0][0][RTW89_UK][46] = 26, ++ [0][0][RTW89_FCC][48] = 32, ++ [0][0][RTW89_ETSI][48] = 127, ++ [0][0][RTW89_MKK][48] = 127, ++ [0][0][RTW89_IC][48] = 127, ++ [0][0][RTW89_KCC][48] = 127, ++ [0][0][RTW89_ACMA][48] = 127, ++ [0][0][RTW89_CHILE][48] = 127, ++ [0][0][RTW89_UKRAINE][48] = 127, ++ [0][0][RTW89_MEXICO][48] = 127, ++ [0][0][RTW89_CN][48] = 127, ++ [0][0][RTW89_QATAR][48] = 127, ++ [0][0][RTW89_UK][48] = 127, ++ [0][0][RTW89_FCC][50] = 32, ++ [0][0][RTW89_ETSI][50] = 127, ++ [0][0][RTW89_MKK][50] = 127, ++ [0][0][RTW89_IC][50] = 127, ++ [0][0][RTW89_KCC][50] = 127, ++ [0][0][RTW89_ACMA][50] = 127, ++ [0][0][RTW89_CHILE][50] = 127, ++ [0][0][RTW89_UKRAINE][50] = 127, ++ [0][0][RTW89_MEXICO][50] = 127, ++ [0][0][RTW89_CN][50] = 127, ++ [0][0][RTW89_QATAR][50] = 127, ++ [0][0][RTW89_UK][50] = 127, ++ [0][0][RTW89_FCC][52] = 32, ++ [0][0][RTW89_ETSI][52] = 127, ++ [0][0][RTW89_MKK][52] = 127, ++ [0][0][RTW89_IC][52] = 127, ++ [0][0][RTW89_KCC][52] = 127, ++ [0][0][RTW89_ACMA][52] = 127, ++ [0][0][RTW89_CHILE][52] = 127, ++ [0][0][RTW89_UKRAINE][52] = 127, ++ [0][0][RTW89_MEXICO][52] = 127, ++ [0][0][RTW89_CN][52] = 127, ++ [0][0][RTW89_QATAR][52] = 127, ++ [0][0][RTW89_UK][52] = 127, ++ [0][1][RTW89_FCC][0] = 34, ++ [0][1][RTW89_ETSI][0] = 12, ++ [0][1][RTW89_MKK][0] = 12, ++ [0][1][RTW89_IC][0] = 0, ++ [0][1][RTW89_KCC][0] = 28, ++ [0][1][RTW89_ACMA][0] = 12, ++ [0][1][RTW89_CHILE][0] = 14, ++ [0][1][RTW89_UKRAINE][0] = 12, ++ [0][1][RTW89_MEXICO][0] = 34, ++ [0][1][RTW89_CN][0] = 12, ++ [0][1][RTW89_QATAR][0] = 12, ++ [0][1][RTW89_UK][0] = 12, ++ [0][1][RTW89_FCC][2] = 38, ++ [0][1][RTW89_ETSI][2] = 12, ++ [0][1][RTW89_MKK][2] = 12, ++ [0][1][RTW89_IC][2] = 4, ++ [0][1][RTW89_KCC][2] = 28, ++ [0][1][RTW89_ACMA][2] = 12, ++ [0][1][RTW89_CHILE][2] = 12, ++ [0][1][RTW89_UKRAINE][2] = 12, ++ [0][1][RTW89_MEXICO][2] = 38, ++ [0][1][RTW89_CN][2] = 12, ++ [0][1][RTW89_QATAR][2] = 12, ++ [0][1][RTW89_UK][2] = 12, ++ [0][1][RTW89_FCC][4] = 34, ++ [0][1][RTW89_ETSI][4] = 12, ++ [0][1][RTW89_MKK][4] = 14, ++ [0][1][RTW89_IC][4] = 0, ++ [0][1][RTW89_KCC][4] = 28, ++ [0][1][RTW89_ACMA][4] = 12, ++ [0][1][RTW89_CHILE][4] = 12, ++ [0][1][RTW89_UKRAINE][4] = 12, ++ [0][1][RTW89_MEXICO][4] = 34, ++ [0][1][RTW89_CN][4] = 12, ++ [0][1][RTW89_QATAR][4] = 12, ++ [0][1][RTW89_UK][4] = 12, ++ [0][1][RTW89_FCC][6] = 34, ++ [0][1][RTW89_ETSI][6] = 12, ++ [0][1][RTW89_MKK][6] = 14, ++ [0][1][RTW89_IC][6] = 0, ++ [0][1][RTW89_KCC][6] = 2, ++ [0][1][RTW89_ACMA][6] = 12, ++ [0][1][RTW89_CHILE][6] = 12, ++ [0][1][RTW89_UKRAINE][6] = 12, ++ [0][1][RTW89_MEXICO][6] = 34, ++ [0][1][RTW89_CN][6] = 12, ++ [0][1][RTW89_QATAR][6] = 12, ++ [0][1][RTW89_UK][6] = 12, ++ [0][1][RTW89_FCC][8] = 34, ++ [0][1][RTW89_ETSI][8] = 12, ++ [0][1][RTW89_MKK][8] = 14, ++ [0][1][RTW89_IC][8] = 34, ++ [0][1][RTW89_KCC][8] = 30, ++ [0][1][RTW89_ACMA][8] = 12, ++ [0][1][RTW89_CHILE][8] = 50, ++ [0][1][RTW89_UKRAINE][8] = 12, ++ [0][1][RTW89_MEXICO][8] = 34, ++ [0][1][RTW89_CN][8] = 12, ++ [0][1][RTW89_QATAR][8] = 12, ++ [0][1][RTW89_UK][8] = 12, ++ [0][1][RTW89_FCC][10] = 34, ++ [0][1][RTW89_ETSI][10] = 12, ++ [0][1][RTW89_MKK][10] = 14, ++ [0][1][RTW89_IC][10] = 34, ++ [0][1][RTW89_KCC][10] = 30, ++ [0][1][RTW89_ACMA][10] = 12, ++ [0][1][RTW89_CHILE][10] = 50, ++ [0][1][RTW89_UKRAINE][10] = 12, ++ [0][1][RTW89_MEXICO][10] = 34, ++ [0][1][RTW89_CN][10] = 12, ++ [0][1][RTW89_QATAR][10] = 12, ++ [0][1][RTW89_UK][10] = 12, ++ [0][1][RTW89_FCC][12] = 38, ++ [0][1][RTW89_ETSI][12] = 12, ++ [0][1][RTW89_MKK][12] = 12, ++ [0][1][RTW89_IC][12] = 38, ++ [0][1][RTW89_KCC][12] = 30, ++ [0][1][RTW89_ACMA][12] = 12, ++ [0][1][RTW89_CHILE][12] = 50, ++ [0][1][RTW89_UKRAINE][12] = 12, ++ [0][1][RTW89_MEXICO][12] = 38, ++ [0][1][RTW89_CN][12] = 12, ++ [0][1][RTW89_QATAR][12] = 12, ++ [0][1][RTW89_UK][12] = 12, ++ [0][1][RTW89_FCC][14] = 34, ++ [0][1][RTW89_ETSI][14] = 12, ++ [0][1][RTW89_MKK][14] = 12, ++ [0][1][RTW89_IC][14] = 34, ++ [0][1][RTW89_KCC][14] = 30, ++ [0][1][RTW89_ACMA][14] = 12, ++ [0][1][RTW89_CHILE][14] = 48, ++ [0][1][RTW89_UKRAINE][14] = 12, ++ [0][1][RTW89_MEXICO][14] = 34, ++ [0][1][RTW89_CN][14] = 12, ++ [0][1][RTW89_QATAR][14] = 12, ++ [0][1][RTW89_UK][14] = 12, ++ [0][1][RTW89_FCC][15] = 34, ++ [0][1][RTW89_ETSI][15] = 12, ++ [0][1][RTW89_MKK][15] = 32, ++ [0][1][RTW89_IC][15] = 34, ++ [0][1][RTW89_KCC][15] = 30, ++ [0][1][RTW89_ACMA][15] = 12, ++ [0][1][RTW89_CHILE][15] = 52, ++ [0][1][RTW89_UKRAINE][15] = 12, ++ [0][1][RTW89_MEXICO][15] = 34, ++ [0][1][RTW89_CN][15] = 127, ++ [0][1][RTW89_QATAR][15] = 12, ++ [0][1][RTW89_UK][15] = 12, ++ [0][1][RTW89_FCC][17] = 34, ++ [0][1][RTW89_ETSI][17] = 12, ++ [0][1][RTW89_MKK][17] = 34, ++ [0][1][RTW89_IC][17] = 34, ++ [0][1][RTW89_KCC][17] = 30, ++ [0][1][RTW89_ACMA][17] = 12, ++ [0][1][RTW89_CHILE][17] = 52, ++ [0][1][RTW89_UKRAINE][17] = 12, ++ [0][1][RTW89_MEXICO][17] = 34, ++ [0][1][RTW89_CN][17] = 127, ++ [0][1][RTW89_QATAR][17] = 12, ++ [0][1][RTW89_UK][17] = 12, ++ [0][1][RTW89_FCC][19] = 38, ++ [0][1][RTW89_ETSI][19] = 12, ++ [0][1][RTW89_MKK][19] = 34, ++ [0][1][RTW89_IC][19] = 38, ++ [0][1][RTW89_KCC][19] = 30, ++ [0][1][RTW89_ACMA][19] = 12, ++ [0][1][RTW89_CHILE][19] = 52, ++ [0][1][RTW89_UKRAINE][19] = 12, ++ [0][1][RTW89_MEXICO][19] = 38, ++ [0][1][RTW89_CN][19] = 127, ++ [0][1][RTW89_QATAR][19] = 12, ++ [0][1][RTW89_UK][19] = 12, ++ [0][1][RTW89_FCC][21] = 38, ++ [0][1][RTW89_ETSI][21] = 12, ++ [0][1][RTW89_MKK][21] = 34, ++ [0][1][RTW89_IC][21] = 38, ++ [0][1][RTW89_KCC][21] = 30, ++ [0][1][RTW89_ACMA][21] = 12, ++ [0][1][RTW89_CHILE][21] = 52, ++ [0][1][RTW89_UKRAINE][21] = 12, ++ [0][1][RTW89_MEXICO][21] = 38, ++ [0][1][RTW89_CN][21] = 127, ++ [0][1][RTW89_QATAR][21] = 12, ++ [0][1][RTW89_UK][21] = 12, ++ [0][1][RTW89_FCC][23] = 38, ++ [0][1][RTW89_ETSI][23] = 12, ++ [0][1][RTW89_MKK][23] = 34, ++ [0][1][RTW89_IC][23] = 38, ++ [0][1][RTW89_KCC][23] = 30, ++ [0][1][RTW89_ACMA][23] = 12, ++ [0][1][RTW89_CHILE][23] = 52, ++ [0][1][RTW89_UKRAINE][23] = 12, ++ [0][1][RTW89_MEXICO][23] = 38, ++ [0][1][RTW89_CN][23] = 127, ++ [0][1][RTW89_QATAR][23] = 12, ++ [0][1][RTW89_UK][23] = 12, ++ [0][1][RTW89_FCC][25] = 38, ++ [0][1][RTW89_ETSI][25] = 12, ++ [0][1][RTW89_MKK][25] = 34, ++ [0][1][RTW89_IC][25] = 127, ++ [0][1][RTW89_KCC][25] = 30, ++ [0][1][RTW89_ACMA][25] = 127, ++ [0][1][RTW89_CHILE][25] = 52, ++ [0][1][RTW89_UKRAINE][25] = 12, ++ [0][1][RTW89_MEXICO][25] = 38, ++ [0][1][RTW89_CN][25] = 127, ++ [0][1][RTW89_QATAR][25] = 12, ++ [0][1][RTW89_UK][25] = 12, ++ [0][1][RTW89_FCC][27] = 38, ++ [0][1][RTW89_ETSI][27] = 12, ++ [0][1][RTW89_MKK][27] = 34, ++ [0][1][RTW89_IC][27] = 127, ++ [0][1][RTW89_KCC][27] = 30, ++ [0][1][RTW89_ACMA][27] = 127, ++ [0][1][RTW89_CHILE][27] = 52, ++ [0][1][RTW89_UKRAINE][27] = 12, ++ [0][1][RTW89_MEXICO][27] = 38, ++ [0][1][RTW89_CN][27] = 127, ++ [0][1][RTW89_QATAR][27] = 12, ++ [0][1][RTW89_UK][27] = 12, ++ [0][1][RTW89_FCC][29] = 38, ++ [0][1][RTW89_ETSI][29] = 12, ++ [0][1][RTW89_MKK][29] = 34, ++ [0][1][RTW89_IC][29] = 127, ++ [0][1][RTW89_KCC][29] = 30, ++ [0][1][RTW89_ACMA][29] = 127, ++ [0][1][RTW89_CHILE][29] = 52, ++ [0][1][RTW89_UKRAINE][29] = 12, ++ [0][1][RTW89_MEXICO][29] = 38, ++ [0][1][RTW89_CN][29] = 127, ++ [0][1][RTW89_QATAR][29] = 12, ++ [0][1][RTW89_UK][29] = 12, ++ [0][1][RTW89_FCC][31] = 38, ++ [0][1][RTW89_ETSI][31] = 12, ++ [0][1][RTW89_MKK][31] = 34, ++ [0][1][RTW89_IC][31] = 34, ++ [0][1][RTW89_KCC][31] = 30, ++ [0][1][RTW89_ACMA][31] = 12, ++ [0][1][RTW89_CHILE][31] = 52, ++ [0][1][RTW89_UKRAINE][31] = 12, ++ [0][1][RTW89_MEXICO][31] = 38, ++ [0][1][RTW89_CN][31] = 127, ++ [0][1][RTW89_QATAR][31] = 12, ++ [0][1][RTW89_UK][31] = 12, ++ [0][1][RTW89_FCC][33] = 34, ++ [0][1][RTW89_ETSI][33] = 12, ++ [0][1][RTW89_MKK][33] = 34, ++ [0][1][RTW89_IC][33] = 34, ++ [0][1][RTW89_KCC][33] = 30, ++ [0][1][RTW89_ACMA][33] = 12, ++ [0][1][RTW89_CHILE][33] = 52, ++ [0][1][RTW89_UKRAINE][33] = 12, ++ [0][1][RTW89_MEXICO][33] = 34, ++ [0][1][RTW89_CN][33] = 127, ++ [0][1][RTW89_QATAR][33] = 12, ++ [0][1][RTW89_UK][33] = 12, ++ [0][1][RTW89_FCC][35] = 34, ++ [0][1][RTW89_ETSI][35] = 12, ++ [0][1][RTW89_MKK][35] = 34, ++ [0][1][RTW89_IC][35] = 34, ++ [0][1][RTW89_KCC][35] = 30, ++ [0][1][RTW89_ACMA][35] = 12, ++ [0][1][RTW89_CHILE][35] = 52, ++ [0][1][RTW89_UKRAINE][35] = 12, ++ [0][1][RTW89_MEXICO][35] = 34, ++ [0][1][RTW89_CN][35] = 127, ++ [0][1][RTW89_QATAR][35] = 12, ++ [0][1][RTW89_UK][35] = 12, ++ [0][1][RTW89_FCC][37] = 38, ++ [0][1][RTW89_ETSI][37] = 127, ++ [0][1][RTW89_MKK][37] = 34, ++ [0][1][RTW89_IC][37] = 38, ++ [0][1][RTW89_KCC][37] = 30, ++ [0][1][RTW89_ACMA][37] = 38, ++ [0][1][RTW89_CHILE][37] = 52, ++ [0][1][RTW89_UKRAINE][37] = 127, ++ [0][1][RTW89_MEXICO][37] = 38, ++ [0][1][RTW89_CN][37] = 127, ++ [0][1][RTW89_QATAR][37] = 127, ++ [0][1][RTW89_UK][37] = 44, ++ [0][1][RTW89_FCC][38] = 82, ++ [0][1][RTW89_ETSI][38] = 16, ++ [0][1][RTW89_MKK][38] = 127, ++ [0][1][RTW89_IC][38] = 82, ++ [0][1][RTW89_KCC][38] = 30, ++ [0][1][RTW89_ACMA][38] = 84, ++ [0][1][RTW89_CHILE][38] = 52, ++ [0][1][RTW89_UKRAINE][38] = 16, ++ [0][1][RTW89_MEXICO][38] = 82, ++ [0][1][RTW89_CN][38] = 50, ++ [0][1][RTW89_QATAR][38] = 16, ++ [0][1][RTW89_UK][38] = 14, ++ [0][1][RTW89_FCC][40] = 82, ++ [0][1][RTW89_ETSI][40] = 16, ++ [0][1][RTW89_MKK][40] = 127, ++ [0][1][RTW89_IC][40] = 82, ++ [0][1][RTW89_KCC][40] = 30, ++ [0][1][RTW89_ACMA][40] = 84, ++ [0][1][RTW89_CHILE][40] = 52, ++ [0][1][RTW89_UKRAINE][40] = 16, ++ [0][1][RTW89_MEXICO][40] = 82, ++ [0][1][RTW89_CN][40] = 50, ++ [0][1][RTW89_QATAR][40] = 16, ++ [0][1][RTW89_UK][40] = 14, ++ [0][1][RTW89_FCC][42] = 82, ++ [0][1][RTW89_ETSI][42] = 16, ++ [0][1][RTW89_MKK][42] = 127, ++ [0][1][RTW89_IC][42] = 82, ++ [0][1][RTW89_KCC][42] = 30, ++ [0][1][RTW89_ACMA][42] = 84, ++ [0][1][RTW89_CHILE][42] = 54, ++ [0][1][RTW89_UKRAINE][42] = 16, ++ [0][1][RTW89_MEXICO][42] = 82, ++ [0][1][RTW89_CN][42] = 50, ++ [0][1][RTW89_QATAR][42] = 16, ++ [0][1][RTW89_UK][42] = 14, ++ [0][1][RTW89_FCC][44] = 82, ++ [0][1][RTW89_ETSI][44] = 16, ++ [0][1][RTW89_MKK][44] = 127, ++ [0][1][RTW89_IC][44] = 82, ++ [0][1][RTW89_KCC][44] = 30, ++ [0][1][RTW89_ACMA][44] = 84, ++ [0][1][RTW89_CHILE][44] = 54, ++ [0][1][RTW89_UKRAINE][44] = 16, ++ [0][1][RTW89_MEXICO][44] = 82, ++ [0][1][RTW89_CN][44] = 50, ++ [0][1][RTW89_QATAR][44] = 16, ++ [0][1][RTW89_UK][44] = 14, ++ [0][1][RTW89_FCC][46] = 82, ++ [0][1][RTW89_ETSI][46] = 16, ++ [0][1][RTW89_MKK][46] = 127, ++ [0][1][RTW89_IC][46] = 82, ++ [0][1][RTW89_KCC][46] = 30, ++ [0][1][RTW89_ACMA][46] = 84, ++ [0][1][RTW89_CHILE][46] = 54, ++ [0][1][RTW89_UKRAINE][46] = 16, ++ [0][1][RTW89_MEXICO][46] = 82, ++ [0][1][RTW89_CN][46] = 50, ++ [0][1][RTW89_QATAR][46] = 16, ++ [0][1][RTW89_UK][46] = 14, ++ [0][1][RTW89_FCC][48] = 20, ++ [0][1][RTW89_ETSI][48] = 127, ++ [0][1][RTW89_MKK][48] = 127, ++ [0][1][RTW89_IC][48] = 127, ++ [0][1][RTW89_KCC][48] = 127, ++ [0][1][RTW89_ACMA][48] = 127, ++ [0][1][RTW89_CHILE][48] = 127, ++ [0][1][RTW89_UKRAINE][48] = 127, ++ [0][1][RTW89_MEXICO][48] = 127, ++ [0][1][RTW89_CN][48] = 127, ++ [0][1][RTW89_QATAR][48] = 127, ++ [0][1][RTW89_UK][48] = 127, ++ [0][1][RTW89_FCC][50] = 20, ++ [0][1][RTW89_ETSI][50] = 127, ++ [0][1][RTW89_MKK][50] = 127, ++ [0][1][RTW89_IC][50] = 127, ++ [0][1][RTW89_KCC][50] = 127, ++ [0][1][RTW89_ACMA][50] = 127, ++ [0][1][RTW89_CHILE][50] = 127, ++ [0][1][RTW89_UKRAINE][50] = 127, ++ [0][1][RTW89_MEXICO][50] = 127, ++ [0][1][RTW89_CN][50] = 127, ++ [0][1][RTW89_QATAR][50] = 127, ++ [0][1][RTW89_UK][50] = 127, ++ [0][1][RTW89_FCC][52] = 20, ++ [0][1][RTW89_ETSI][52] = 127, ++ [0][1][RTW89_MKK][52] = 127, ++ [0][1][RTW89_IC][52] = 127, ++ [0][1][RTW89_KCC][52] = 127, ++ [0][1][RTW89_ACMA][52] = 127, ++ [0][1][RTW89_CHILE][52] = 127, ++ [0][1][RTW89_UKRAINE][52] = 127, ++ [0][1][RTW89_MEXICO][52] = 127, ++ [0][1][RTW89_CN][52] = 127, ++ [0][1][RTW89_QATAR][52] = 127, ++ [0][1][RTW89_UK][52] = 127, ++ [1][0][RTW89_FCC][0] = 62, ++ [1][0][RTW89_ETSI][0] = 34, ++ [1][0][RTW89_MKK][0] = 36, ++ [1][0][RTW89_IC][0] = 36, ++ [1][0][RTW89_KCC][0] = 52, ++ [1][0][RTW89_ACMA][0] = 34, ++ [1][0][RTW89_CHILE][0] = 40, ++ [1][0][RTW89_UKRAINE][0] = 34, ++ [1][0][RTW89_MEXICO][0] = 62, ++ [1][0][RTW89_CN][0] = 34, ++ [1][0][RTW89_QATAR][0] = 34, ++ [1][0][RTW89_UK][0] = 34, ++ [1][0][RTW89_FCC][2] = 62, ++ [1][0][RTW89_ETSI][2] = 34, ++ [1][0][RTW89_MKK][2] = 36, ++ [1][0][RTW89_IC][2] = 36, ++ [1][0][RTW89_KCC][2] = 52, ++ [1][0][RTW89_ACMA][2] = 34, ++ [1][0][RTW89_CHILE][2] = 42, ++ [1][0][RTW89_UKRAINE][2] = 34, ++ [1][0][RTW89_MEXICO][2] = 62, ++ [1][0][RTW89_CN][2] = 34, ++ [1][0][RTW89_QATAR][2] = 34, ++ [1][0][RTW89_UK][2] = 34, ++ [1][0][RTW89_FCC][4] = 62, ++ [1][0][RTW89_ETSI][4] = 34, ++ [1][0][RTW89_MKK][4] = 34, ++ [1][0][RTW89_IC][4] = 36, ++ [1][0][RTW89_KCC][4] = 52, ++ [1][0][RTW89_ACMA][4] = 34, ++ [1][0][RTW89_CHILE][4] = 42, ++ [1][0][RTW89_UKRAINE][4] = 34, ++ [1][0][RTW89_MEXICO][4] = 62, ++ [1][0][RTW89_CN][4] = 34, ++ [1][0][RTW89_QATAR][4] = 34, ++ [1][0][RTW89_UK][4] = 34, ++ [1][0][RTW89_FCC][6] = 62, ++ [1][0][RTW89_ETSI][6] = 34, ++ [1][0][RTW89_MKK][6] = 34, ++ [1][0][RTW89_IC][6] = 36, ++ [1][0][RTW89_KCC][6] = 26, ++ [1][0][RTW89_ACMA][6] = 34, ++ [1][0][RTW89_CHILE][6] = 42, ++ [1][0][RTW89_UKRAINE][6] = 34, ++ [1][0][RTW89_MEXICO][6] = 62, ++ [1][0][RTW89_CN][6] = 34, ++ [1][0][RTW89_QATAR][6] = 34, ++ [1][0][RTW89_UK][6] = 34, ++ [1][0][RTW89_FCC][8] = 62, ++ [1][0][RTW89_ETSI][8] = 34, ++ [1][0][RTW89_MKK][8] = 36, ++ [1][0][RTW89_IC][8] = 62, ++ [1][0][RTW89_KCC][8] = 54, ++ [1][0][RTW89_ACMA][8] = 34, ++ [1][0][RTW89_CHILE][8] = 64, ++ [1][0][RTW89_UKRAINE][8] = 34, ++ [1][0][RTW89_MEXICO][8] = 62, ++ [1][0][RTW89_CN][8] = 34, ++ [1][0][RTW89_QATAR][8] = 34, ++ [1][0][RTW89_UK][8] = 34, ++ [1][0][RTW89_FCC][10] = 62, ++ [1][0][RTW89_ETSI][10] = 34, ++ [1][0][RTW89_MKK][10] = 36, ++ [1][0][RTW89_IC][10] = 62, ++ [1][0][RTW89_KCC][10] = 54, ++ [1][0][RTW89_ACMA][10] = 34, ++ [1][0][RTW89_CHILE][10] = 64, ++ [1][0][RTW89_UKRAINE][10] = 34, ++ [1][0][RTW89_MEXICO][10] = 62, ++ [1][0][RTW89_CN][10] = 34, ++ [1][0][RTW89_QATAR][10] = 34, ++ [1][0][RTW89_UK][10] = 34, ++ [1][0][RTW89_FCC][12] = 64, ++ [1][0][RTW89_ETSI][12] = 34, ++ [1][0][RTW89_MKK][12] = 36, ++ [1][0][RTW89_IC][12] = 64, ++ [1][0][RTW89_KCC][12] = 54, ++ [1][0][RTW89_ACMA][12] = 34, ++ [1][0][RTW89_CHILE][12] = 64, ++ [1][0][RTW89_UKRAINE][12] = 34, ++ [1][0][RTW89_MEXICO][12] = 64, ++ [1][0][RTW89_CN][12] = 34, ++ [1][0][RTW89_QATAR][12] = 34, ++ [1][0][RTW89_UK][12] = 34, ++ [1][0][RTW89_FCC][14] = 62, ++ [1][0][RTW89_ETSI][14] = 34, ++ [1][0][RTW89_MKK][14] = 36, ++ [1][0][RTW89_IC][14] = 62, ++ [1][0][RTW89_KCC][14] = 54, ++ [1][0][RTW89_ACMA][14] = 34, ++ [1][0][RTW89_CHILE][14] = 64, ++ [1][0][RTW89_UKRAINE][14] = 34, ++ [1][0][RTW89_MEXICO][14] = 62, ++ [1][0][RTW89_CN][14] = 34, ++ [1][0][RTW89_QATAR][14] = 34, ++ [1][0][RTW89_UK][14] = 34, ++ [1][0][RTW89_FCC][15] = 62, ++ [1][0][RTW89_ETSI][15] = 34, ++ [1][0][RTW89_MKK][15] = 54, ++ [1][0][RTW89_IC][15] = 62, ++ [1][0][RTW89_KCC][15] = 54, ++ [1][0][RTW89_ACMA][15] = 34, ++ [1][0][RTW89_CHILE][15] = 62, ++ [1][0][RTW89_UKRAINE][15] = 34, ++ [1][0][RTW89_MEXICO][15] = 62, ++ [1][0][RTW89_CN][15] = 127, ++ [1][0][RTW89_QATAR][15] = 34, ++ [1][0][RTW89_UK][15] = 34, ++ [1][0][RTW89_FCC][17] = 62, ++ [1][0][RTW89_ETSI][17] = 34, ++ [1][0][RTW89_MKK][17] = 58, ++ [1][0][RTW89_IC][17] = 62, ++ [1][0][RTW89_KCC][17] = 54, ++ [1][0][RTW89_ACMA][17] = 34, ++ [1][0][RTW89_CHILE][17] = 62, ++ [1][0][RTW89_UKRAINE][17] = 34, ++ [1][0][RTW89_MEXICO][17] = 62, ++ [1][0][RTW89_CN][17] = 127, ++ [1][0][RTW89_QATAR][17] = 34, ++ [1][0][RTW89_UK][17] = 34, ++ [1][0][RTW89_FCC][19] = 62, ++ [1][0][RTW89_ETSI][19] = 34, ++ [1][0][RTW89_MKK][19] = 58, ++ [1][0][RTW89_IC][19] = 62, ++ [1][0][RTW89_KCC][19] = 54, ++ [1][0][RTW89_ACMA][19] = 34, ++ [1][0][RTW89_CHILE][19] = 62, ++ [1][0][RTW89_UKRAINE][19] = 34, ++ [1][0][RTW89_MEXICO][19] = 62, ++ [1][0][RTW89_CN][19] = 127, ++ [1][0][RTW89_QATAR][19] = 34, ++ [1][0][RTW89_UK][19] = 34, ++ [1][0][RTW89_FCC][21] = 62, ++ [1][0][RTW89_ETSI][21] = 34, ++ [1][0][RTW89_MKK][21] = 58, ++ [1][0][RTW89_IC][21] = 62, ++ [1][0][RTW89_KCC][21] = 54, ++ [1][0][RTW89_ACMA][21] = 34, ++ [1][0][RTW89_CHILE][21] = 64, ++ [1][0][RTW89_UKRAINE][21] = 34, ++ [1][0][RTW89_MEXICO][21] = 62, ++ [1][0][RTW89_CN][21] = 127, ++ [1][0][RTW89_QATAR][21] = 34, ++ [1][0][RTW89_UK][21] = 34, ++ [1][0][RTW89_FCC][23] = 62, ++ [1][0][RTW89_ETSI][23] = 34, ++ [1][0][RTW89_MKK][23] = 58, ++ [1][0][RTW89_IC][23] = 62, ++ [1][0][RTW89_KCC][23] = 54, ++ [1][0][RTW89_ACMA][23] = 34, ++ [1][0][RTW89_CHILE][23] = 64, ++ [1][0][RTW89_UKRAINE][23] = 34, ++ [1][0][RTW89_MEXICO][23] = 62, ++ [1][0][RTW89_CN][23] = 127, ++ [1][0][RTW89_QATAR][23] = 34, ++ [1][0][RTW89_UK][23] = 34, ++ [1][0][RTW89_FCC][25] = 62, ++ [1][0][RTW89_ETSI][25] = 34, ++ [1][0][RTW89_MKK][25] = 58, ++ [1][0][RTW89_IC][25] = 127, ++ [1][0][RTW89_KCC][25] = 54, ++ [1][0][RTW89_ACMA][25] = 127, ++ [1][0][RTW89_CHILE][25] = 64, ++ [1][0][RTW89_UKRAINE][25] = 34, ++ [1][0][RTW89_MEXICO][25] = 62, ++ [1][0][RTW89_CN][25] = 127, ++ [1][0][RTW89_QATAR][25] = 34, ++ [1][0][RTW89_UK][25] = 34, ++ [1][0][RTW89_FCC][27] = 62, ++ [1][0][RTW89_ETSI][27] = 34, ++ [1][0][RTW89_MKK][27] = 58, ++ [1][0][RTW89_IC][27] = 127, ++ [1][0][RTW89_KCC][27] = 54, ++ [1][0][RTW89_ACMA][27] = 127, ++ [1][0][RTW89_CHILE][27] = 64, ++ [1][0][RTW89_UKRAINE][27] = 34, ++ [1][0][RTW89_MEXICO][27] = 62, ++ [1][0][RTW89_CN][27] = 127, ++ [1][0][RTW89_QATAR][27] = 34, ++ [1][0][RTW89_UK][27] = 34, ++ [1][0][RTW89_FCC][29] = 62, ++ [1][0][RTW89_ETSI][29] = 34, ++ [1][0][RTW89_MKK][29] = 58, ++ [1][0][RTW89_IC][29] = 127, ++ [1][0][RTW89_KCC][29] = 54, ++ [1][0][RTW89_ACMA][29] = 127, ++ [1][0][RTW89_CHILE][29] = 66, ++ [1][0][RTW89_UKRAINE][29] = 34, ++ [1][0][RTW89_MEXICO][29] = 62, ++ [1][0][RTW89_CN][29] = 127, ++ [1][0][RTW89_QATAR][29] = 34, ++ [1][0][RTW89_UK][29] = 34, ++ [1][0][RTW89_FCC][31] = 62, ++ [1][0][RTW89_ETSI][31] = 34, ++ [1][0][RTW89_MKK][31] = 58, ++ [1][0][RTW89_IC][31] = 62, ++ [1][0][RTW89_KCC][31] = 54, ++ [1][0][RTW89_ACMA][31] = 34, ++ [1][0][RTW89_CHILE][31] = 66, ++ [1][0][RTW89_UKRAINE][31] = 34, ++ [1][0][RTW89_MEXICO][31] = 62, ++ [1][0][RTW89_CN][31] = 127, ++ [1][0][RTW89_QATAR][31] = 34, ++ [1][0][RTW89_UK][31] = 34, ++ [1][0][RTW89_FCC][33] = 62, ++ [1][0][RTW89_ETSI][33] = 34, ++ [1][0][RTW89_MKK][33] = 58, ++ [1][0][RTW89_IC][33] = 62, ++ [1][0][RTW89_KCC][33] = 54, ++ [1][0][RTW89_ACMA][33] = 34, ++ [1][0][RTW89_CHILE][33] = 66, ++ [1][0][RTW89_UKRAINE][33] = 34, ++ [1][0][RTW89_MEXICO][33] = 62, ++ [1][0][RTW89_CN][33] = 127, ++ [1][0][RTW89_QATAR][33] = 34, ++ [1][0][RTW89_UK][33] = 34, ++ [1][0][RTW89_FCC][35] = 62, ++ [1][0][RTW89_ETSI][35] = 34, ++ [1][0][RTW89_MKK][35] = 58, ++ [1][0][RTW89_IC][35] = 62, ++ [1][0][RTW89_KCC][35] = 54, ++ [1][0][RTW89_ACMA][35] = 34, ++ [1][0][RTW89_CHILE][35] = 66, ++ [1][0][RTW89_UKRAINE][35] = 34, ++ [1][0][RTW89_MEXICO][35] = 62, ++ [1][0][RTW89_CN][35] = 127, ++ [1][0][RTW89_QATAR][35] = 34, ++ [1][0][RTW89_UK][35] = 34, ++ [1][0][RTW89_FCC][37] = 64, ++ [1][0][RTW89_ETSI][37] = 127, ++ [1][0][RTW89_MKK][37] = 52, ++ [1][0][RTW89_IC][37] = 64, ++ [1][0][RTW89_KCC][37] = 54, ++ [1][0][RTW89_ACMA][37] = 64, ++ [1][0][RTW89_CHILE][37] = 64, ++ [1][0][RTW89_UKRAINE][37] = 127, ++ [1][0][RTW89_MEXICO][37] = 64, ++ [1][0][RTW89_CN][37] = 127, ++ [1][0][RTW89_QATAR][37] = 127, ++ [1][0][RTW89_UK][37] = 66, ++ [1][0][RTW89_FCC][38] = 84, ++ [1][0][RTW89_ETSI][38] = 28, ++ [1][0][RTW89_MKK][38] = 127, ++ [1][0][RTW89_IC][38] = 84, ++ [1][0][RTW89_KCC][38] = 56, ++ [1][0][RTW89_ACMA][38] = 84, ++ [1][0][RTW89_CHILE][38] = 64, ++ [1][0][RTW89_UKRAINE][38] = 28, ++ [1][0][RTW89_MEXICO][38] = 84, ++ [1][0][RTW89_CN][38] = 74, ++ [1][0][RTW89_QATAR][38] = 28, ++ [1][0][RTW89_UK][38] = 38, ++ [1][0][RTW89_FCC][40] = 84, ++ [1][0][RTW89_ETSI][40] = 28, ++ [1][0][RTW89_MKK][40] = 127, ++ [1][0][RTW89_IC][40] = 84, ++ [1][0][RTW89_KCC][40] = 56, ++ [1][0][RTW89_ACMA][40] = 84, ++ [1][0][RTW89_CHILE][40] = 64, ++ [1][0][RTW89_UKRAINE][40] = 28, ++ [1][0][RTW89_MEXICO][40] = 84, ++ [1][0][RTW89_CN][40] = 74, ++ [1][0][RTW89_QATAR][40] = 28, ++ [1][0][RTW89_UK][40] = 38, ++ [1][0][RTW89_FCC][42] = 84, ++ [1][0][RTW89_ETSI][42] = 28, ++ [1][0][RTW89_MKK][42] = 127, ++ [1][0][RTW89_IC][42] = 84, ++ [1][0][RTW89_KCC][42] = 56, ++ [1][0][RTW89_ACMA][42] = 84, ++ [1][0][RTW89_CHILE][42] = 64, ++ [1][0][RTW89_UKRAINE][42] = 28, ++ [1][0][RTW89_MEXICO][42] = 84, ++ [1][0][RTW89_CN][42] = 74, ++ [1][0][RTW89_QATAR][42] = 28, ++ [1][0][RTW89_UK][42] = 38, ++ [1][0][RTW89_FCC][44] = 84, ++ [1][0][RTW89_ETSI][44] = 28, ++ [1][0][RTW89_MKK][44] = 127, ++ [1][0][RTW89_IC][44] = 84, ++ [1][0][RTW89_KCC][44] = 56, ++ [1][0][RTW89_ACMA][44] = 84, ++ [1][0][RTW89_CHILE][44] = 64, ++ [1][0][RTW89_UKRAINE][44] = 28, ++ [1][0][RTW89_MEXICO][44] = 84, ++ [1][0][RTW89_CN][44] = 74, ++ [1][0][RTW89_QATAR][44] = 28, ++ [1][0][RTW89_UK][44] = 38, ++ [1][0][RTW89_FCC][46] = 84, ++ [1][0][RTW89_ETSI][46] = 28, ++ [1][0][RTW89_MKK][46] = 127, ++ [1][0][RTW89_IC][46] = 84, ++ [1][0][RTW89_KCC][46] = 56, ++ [1][0][RTW89_ACMA][46] = 84, ++ [1][0][RTW89_CHILE][46] = 64, ++ [1][0][RTW89_UKRAINE][46] = 28, ++ [1][0][RTW89_MEXICO][46] = 84, ++ [1][0][RTW89_CN][46] = 74, ++ [1][0][RTW89_QATAR][46] = 28, ++ [1][0][RTW89_UK][46] = 38, ++ [1][0][RTW89_FCC][48] = 44, ++ [1][0][RTW89_ETSI][48] = 127, ++ [1][0][RTW89_MKK][48] = 127, ++ [1][0][RTW89_IC][48] = 127, ++ [1][0][RTW89_KCC][48] = 127, ++ [1][0][RTW89_ACMA][48] = 127, ++ [1][0][RTW89_CHILE][48] = 127, ++ [1][0][RTW89_UKRAINE][48] = 127, ++ [1][0][RTW89_MEXICO][48] = 127, ++ [1][0][RTW89_CN][48] = 127, ++ [1][0][RTW89_QATAR][48] = 127, ++ [1][0][RTW89_UK][48] = 127, ++ [1][0][RTW89_FCC][50] = 44, ++ [1][0][RTW89_ETSI][50] = 127, ++ [1][0][RTW89_MKK][50] = 127, ++ [1][0][RTW89_IC][50] = 127, ++ [1][0][RTW89_KCC][50] = 127, ++ [1][0][RTW89_ACMA][50] = 127, ++ [1][0][RTW89_CHILE][50] = 127, ++ [1][0][RTW89_UKRAINE][50] = 127, ++ [1][0][RTW89_MEXICO][50] = 127, ++ [1][0][RTW89_CN][50] = 127, ++ [1][0][RTW89_QATAR][50] = 127, ++ [1][0][RTW89_UK][50] = 127, ++ [1][0][RTW89_FCC][52] = 44, ++ [1][0][RTW89_ETSI][52] = 127, ++ [1][0][RTW89_MKK][52] = 127, ++ [1][0][RTW89_IC][52] = 127, ++ [1][0][RTW89_KCC][52] = 127, ++ [1][0][RTW89_ACMA][52] = 127, ++ [1][0][RTW89_CHILE][52] = 127, ++ [1][0][RTW89_UKRAINE][52] = 127, ++ [1][0][RTW89_MEXICO][52] = 127, ++ [1][0][RTW89_CN][52] = 127, ++ [1][0][RTW89_QATAR][52] = 127, ++ [1][0][RTW89_UK][52] = 127, ++ [1][1][RTW89_FCC][0] = 42, ++ [1][1][RTW89_ETSI][0] = 22, ++ [1][1][RTW89_MKK][0] = 22, ++ [1][1][RTW89_IC][0] = 10, ++ [1][1][RTW89_KCC][0] = 36, ++ [1][1][RTW89_ACMA][0] = 22, ++ [1][1][RTW89_CHILE][0] = 22, ++ [1][1][RTW89_UKRAINE][0] = 22, ++ [1][1][RTW89_MEXICO][0] = 42, ++ [1][1][RTW89_CN][0] = 22, ++ [1][1][RTW89_QATAR][0] = 22, ++ [1][1][RTW89_UK][0] = 22, ++ [1][1][RTW89_FCC][2] = 44, ++ [1][1][RTW89_ETSI][2] = 22, ++ [1][1][RTW89_MKK][2] = 22, ++ [1][1][RTW89_IC][2] = 14, ++ [1][1][RTW89_KCC][2] = 36, ++ [1][1][RTW89_ACMA][2] = 22, ++ [1][1][RTW89_CHILE][2] = 22, ++ [1][1][RTW89_UKRAINE][2] = 22, ++ [1][1][RTW89_MEXICO][2] = 44, ++ [1][1][RTW89_CN][2] = 22, ++ [1][1][RTW89_QATAR][2] = 22, ++ [1][1][RTW89_UK][2] = 22, ++ [1][1][RTW89_FCC][4] = 42, ++ [1][1][RTW89_ETSI][4] = 22, ++ [1][1][RTW89_MKK][4] = 20, ++ [1][1][RTW89_IC][4] = 10, ++ [1][1][RTW89_KCC][4] = 36, ++ [1][1][RTW89_ACMA][4] = 22, ++ [1][1][RTW89_CHILE][4] = 20, ++ [1][1][RTW89_UKRAINE][4] = 22, ++ [1][1][RTW89_MEXICO][4] = 42, ++ [1][1][RTW89_CN][4] = 22, ++ [1][1][RTW89_QATAR][4] = 22, ++ [1][1][RTW89_UK][4] = 22, ++ [1][1][RTW89_FCC][6] = 42, ++ [1][1][RTW89_ETSI][6] = 22, ++ [1][1][RTW89_MKK][6] = 20, ++ [1][1][RTW89_IC][6] = 10, ++ [1][1][RTW89_KCC][6] = 10, ++ [1][1][RTW89_ACMA][6] = 22, ++ [1][1][RTW89_CHILE][6] = 20, ++ [1][1][RTW89_UKRAINE][6] = 22, ++ [1][1][RTW89_MEXICO][6] = 42, ++ [1][1][RTW89_CN][6] = 22, ++ [1][1][RTW89_QATAR][6] = 22, ++ [1][1][RTW89_UK][6] = 22, ++ [1][1][RTW89_FCC][8] = 44, ++ [1][1][RTW89_ETSI][8] = 22, ++ [1][1][RTW89_MKK][8] = 20, ++ [1][1][RTW89_IC][8] = 44, ++ [1][1][RTW89_KCC][8] = 36, ++ [1][1][RTW89_ACMA][8] = 22, ++ [1][1][RTW89_CHILE][8] = 54, ++ [1][1][RTW89_UKRAINE][8] = 22, ++ [1][1][RTW89_MEXICO][8] = 44, ++ [1][1][RTW89_CN][8] = 22, ++ [1][1][RTW89_QATAR][8] = 22, ++ [1][1][RTW89_UK][8] = 22, ++ [1][1][RTW89_FCC][10] = 44, ++ [1][1][RTW89_ETSI][10] = 22, ++ [1][1][RTW89_MKK][10] = 20, ++ [1][1][RTW89_IC][10] = 44, ++ [1][1][RTW89_KCC][10] = 36, ++ [1][1][RTW89_ACMA][10] = 22, ++ [1][1][RTW89_CHILE][10] = 54, ++ [1][1][RTW89_UKRAINE][10] = 22, ++ [1][1][RTW89_MEXICO][10] = 44, ++ [1][1][RTW89_CN][10] = 22, ++ [1][1][RTW89_QATAR][10] = 22, ++ [1][1][RTW89_UK][10] = 22, ++ [1][1][RTW89_FCC][12] = 46, ++ [1][1][RTW89_ETSI][12] = 22, ++ [1][1][RTW89_MKK][12] = 22, ++ [1][1][RTW89_IC][12] = 46, ++ [1][1][RTW89_KCC][12] = 40, ++ [1][1][RTW89_ACMA][12] = 22, ++ [1][1][RTW89_CHILE][12] = 52, ++ [1][1][RTW89_UKRAINE][12] = 22, ++ [1][1][RTW89_MEXICO][12] = 46, ++ [1][1][RTW89_CN][12] = 22, ++ [1][1][RTW89_QATAR][12] = 22, ++ [1][1][RTW89_UK][12] = 22, ++ [1][1][RTW89_FCC][14] = 42, ++ [1][1][RTW89_ETSI][14] = 22, ++ [1][1][RTW89_MKK][14] = 22, ++ [1][1][RTW89_IC][14] = 40, ++ [1][1][RTW89_KCC][14] = 40, ++ [1][1][RTW89_ACMA][14] = 22, ++ [1][1][RTW89_CHILE][14] = 54, ++ [1][1][RTW89_UKRAINE][14] = 22, ++ [1][1][RTW89_MEXICO][14] = 42, ++ [1][1][RTW89_CN][14] = 22, ++ [1][1][RTW89_QATAR][14] = 22, ++ [1][1][RTW89_UK][14] = 22, ++ [1][1][RTW89_FCC][15] = 42, ++ [1][1][RTW89_ETSI][15] = 22, ++ [1][1][RTW89_MKK][15] = 42, ++ [1][1][RTW89_IC][15] = 42, ++ [1][1][RTW89_KCC][15] = 38, ++ [1][1][RTW89_ACMA][15] = 22, ++ [1][1][RTW89_CHILE][15] = 54, ++ [1][1][RTW89_UKRAINE][15] = 22, ++ [1][1][RTW89_MEXICO][15] = 42, ++ [1][1][RTW89_CN][15] = 127, ++ [1][1][RTW89_QATAR][15] = 22, ++ [1][1][RTW89_UK][15] = 22, ++ [1][1][RTW89_FCC][17] = 42, ++ [1][1][RTW89_ETSI][17] = 22, ++ [1][1][RTW89_MKK][17] = 44, ++ [1][1][RTW89_IC][17] = 42, ++ [1][1][RTW89_KCC][17] = 38, ++ [1][1][RTW89_ACMA][17] = 22, ++ [1][1][RTW89_CHILE][17] = 54, ++ [1][1][RTW89_UKRAINE][17] = 22, ++ [1][1][RTW89_MEXICO][17] = 42, ++ [1][1][RTW89_CN][17] = 127, ++ [1][1][RTW89_QATAR][17] = 22, ++ [1][1][RTW89_UK][17] = 22, ++ [1][1][RTW89_FCC][19] = 42, ++ [1][1][RTW89_ETSI][19] = 22, ++ [1][1][RTW89_MKK][19] = 44, ++ [1][1][RTW89_IC][19] = 42, ++ [1][1][RTW89_KCC][19] = 38, ++ [1][1][RTW89_ACMA][19] = 22, ++ [1][1][RTW89_CHILE][19] = 54, ++ [1][1][RTW89_UKRAINE][19] = 22, ++ [1][1][RTW89_MEXICO][19] = 42, ++ [1][1][RTW89_CN][19] = 127, ++ [1][1][RTW89_QATAR][19] = 22, ++ [1][1][RTW89_UK][19] = 22, ++ [1][1][RTW89_FCC][21] = 42, ++ [1][1][RTW89_ETSI][21] = 22, ++ [1][1][RTW89_MKK][21] = 44, ++ [1][1][RTW89_IC][21] = 42, ++ [1][1][RTW89_KCC][21] = 38, ++ [1][1][RTW89_ACMA][21] = 22, ++ [1][1][RTW89_CHILE][21] = 54, ++ [1][1][RTW89_UKRAINE][21] = 22, ++ [1][1][RTW89_MEXICO][21] = 42, ++ [1][1][RTW89_CN][21] = 127, ++ [1][1][RTW89_QATAR][21] = 22, ++ [1][1][RTW89_UK][21] = 22, ++ [1][1][RTW89_FCC][23] = 42, ++ [1][1][RTW89_ETSI][23] = 22, ++ [1][1][RTW89_MKK][23] = 44, ++ [1][1][RTW89_IC][23] = 42, ++ [1][1][RTW89_KCC][23] = 38, ++ [1][1][RTW89_ACMA][23] = 22, ++ [1][1][RTW89_CHILE][23] = 54, ++ [1][1][RTW89_UKRAINE][23] = 22, ++ [1][1][RTW89_MEXICO][23] = 42, ++ [1][1][RTW89_CN][23] = 127, ++ [1][1][RTW89_QATAR][23] = 22, ++ [1][1][RTW89_UK][23] = 22, ++ [1][1][RTW89_FCC][25] = 42, ++ [1][1][RTW89_ETSI][25] = 22, ++ [1][1][RTW89_MKK][25] = 44, ++ [1][1][RTW89_IC][25] = 127, ++ [1][1][RTW89_KCC][25] = 38, ++ [1][1][RTW89_ACMA][25] = 127, ++ [1][1][RTW89_CHILE][25] = 54, ++ [1][1][RTW89_UKRAINE][25] = 22, ++ [1][1][RTW89_MEXICO][25] = 42, ++ [1][1][RTW89_CN][25] = 127, ++ [1][1][RTW89_QATAR][25] = 22, ++ [1][1][RTW89_UK][25] = 22, ++ [1][1][RTW89_FCC][27] = 42, ++ [1][1][RTW89_ETSI][27] = 22, ++ [1][1][RTW89_MKK][27] = 44, ++ [1][1][RTW89_IC][27] = 127, ++ [1][1][RTW89_KCC][27] = 38, ++ [1][1][RTW89_ACMA][27] = 127, ++ [1][1][RTW89_CHILE][27] = 54, ++ [1][1][RTW89_UKRAINE][27] = 22, ++ [1][1][RTW89_MEXICO][27] = 42, ++ [1][1][RTW89_CN][27] = 127, ++ [1][1][RTW89_QATAR][27] = 22, ++ [1][1][RTW89_UK][27] = 22, ++ [1][1][RTW89_FCC][29] = 42, ++ [1][1][RTW89_ETSI][29] = 22, ++ [1][1][RTW89_MKK][29] = 44, ++ [1][1][RTW89_IC][29] = 127, ++ [1][1][RTW89_KCC][29] = 38, ++ [1][1][RTW89_ACMA][29] = 127, ++ [1][1][RTW89_CHILE][29] = 54, ++ [1][1][RTW89_UKRAINE][29] = 22, ++ [1][1][RTW89_MEXICO][29] = 42, ++ [1][1][RTW89_CN][29] = 127, ++ [1][1][RTW89_QATAR][29] = 22, ++ [1][1][RTW89_UK][29] = 22, ++ [1][1][RTW89_FCC][31] = 42, ++ [1][1][RTW89_ETSI][31] = 22, ++ [1][1][RTW89_MKK][31] = 44, ++ [1][1][RTW89_IC][31] = 38, ++ [1][1][RTW89_KCC][31] = 38, ++ [1][1][RTW89_ACMA][31] = 22, ++ [1][1][RTW89_CHILE][31] = 54, ++ [1][1][RTW89_UKRAINE][31] = 22, ++ [1][1][RTW89_MEXICO][31] = 42, ++ [1][1][RTW89_CN][31] = 127, ++ [1][1][RTW89_QATAR][31] = 22, ++ [1][1][RTW89_UK][31] = 22, ++ [1][1][RTW89_FCC][33] = 40, ++ [1][1][RTW89_ETSI][33] = 22, ++ [1][1][RTW89_MKK][33] = 44, ++ [1][1][RTW89_IC][33] = 38, ++ [1][1][RTW89_KCC][33] = 38, ++ [1][1][RTW89_ACMA][33] = 22, ++ [1][1][RTW89_CHILE][33] = 54, ++ [1][1][RTW89_UKRAINE][33] = 22, ++ [1][1][RTW89_MEXICO][33] = 40, ++ [1][1][RTW89_CN][33] = 127, ++ [1][1][RTW89_QATAR][33] = 22, ++ [1][1][RTW89_UK][33] = 22, ++ [1][1][RTW89_FCC][35] = 40, ++ [1][1][RTW89_ETSI][35] = 22, ++ [1][1][RTW89_MKK][35] = 44, ++ [1][1][RTW89_IC][35] = 38, ++ [1][1][RTW89_KCC][35] = 38, ++ [1][1][RTW89_ACMA][35] = 22, ++ [1][1][RTW89_CHILE][35] = 54, ++ [1][1][RTW89_UKRAINE][35] = 22, ++ [1][1][RTW89_MEXICO][35] = 40, ++ [1][1][RTW89_CN][35] = 127, ++ [1][1][RTW89_QATAR][35] = 22, ++ [1][1][RTW89_UK][35] = 22, ++ [1][1][RTW89_FCC][37] = 48, ++ [1][1][RTW89_ETSI][37] = 127, ++ [1][1][RTW89_MKK][37] = 42, ++ [1][1][RTW89_IC][37] = 48, ++ [1][1][RTW89_KCC][37] = 38, ++ [1][1][RTW89_ACMA][37] = 48, ++ [1][1][RTW89_CHILE][37] = 54, ++ [1][1][RTW89_UKRAINE][37] = 127, ++ [1][1][RTW89_MEXICO][37] = 48, ++ [1][1][RTW89_CN][37] = 127, ++ [1][1][RTW89_QATAR][37] = 127, ++ [1][1][RTW89_UK][37] = 54, ++ [1][1][RTW89_FCC][38] = 84, ++ [1][1][RTW89_ETSI][38] = 16, ++ [1][1][RTW89_MKK][38] = 127, ++ [1][1][RTW89_IC][38] = 84, ++ [1][1][RTW89_KCC][38] = 38, ++ [1][1][RTW89_ACMA][38] = 82, ++ [1][1][RTW89_CHILE][38] = 54, ++ [1][1][RTW89_UKRAINE][38] = 16, ++ [1][1][RTW89_MEXICO][38] = 84, ++ [1][1][RTW89_CN][38] = 62, ++ [1][1][RTW89_QATAR][38] = 16, ++ [1][1][RTW89_UK][38] = 26, ++ [1][1][RTW89_FCC][40] = 84, ++ [1][1][RTW89_ETSI][40] = 16, ++ [1][1][RTW89_MKK][40] = 127, ++ [1][1][RTW89_IC][40] = 84, ++ [1][1][RTW89_KCC][40] = 38, ++ [1][1][RTW89_ACMA][40] = 82, ++ [1][1][RTW89_CHILE][40] = 54, ++ [1][1][RTW89_UKRAINE][40] = 16, ++ [1][1][RTW89_MEXICO][40] = 84, ++ [1][1][RTW89_CN][40] = 62, ++ [1][1][RTW89_QATAR][40] = 16, ++ [1][1][RTW89_UK][40] = 26, ++ [1][1][RTW89_FCC][42] = 84, ++ [1][1][RTW89_ETSI][42] = 16, ++ [1][1][RTW89_MKK][42] = 127, ++ [1][1][RTW89_IC][42] = 84, ++ [1][1][RTW89_KCC][42] = 38, ++ [1][1][RTW89_ACMA][42] = 84, ++ [1][1][RTW89_CHILE][42] = 54, ++ [1][1][RTW89_UKRAINE][42] = 16, ++ [1][1][RTW89_MEXICO][42] = 84, ++ [1][1][RTW89_CN][42] = 62, ++ [1][1][RTW89_QATAR][42] = 16, ++ [1][1][RTW89_UK][42] = 26, ++ [1][1][RTW89_FCC][44] = 84, ++ [1][1][RTW89_ETSI][44] = 16, ++ [1][1][RTW89_MKK][44] = 127, ++ [1][1][RTW89_IC][44] = 84, ++ [1][1][RTW89_KCC][44] = 38, ++ [1][1][RTW89_ACMA][44] = 84, ++ [1][1][RTW89_CHILE][44] = 56, ++ [1][1][RTW89_UKRAINE][44] = 16, ++ [1][1][RTW89_MEXICO][44] = 84, ++ [1][1][RTW89_CN][44] = 62, ++ [1][1][RTW89_QATAR][44] = 16, ++ [1][1][RTW89_UK][44] = 26, ++ [1][1][RTW89_FCC][46] = 84, ++ [1][1][RTW89_ETSI][46] = 16, ++ [1][1][RTW89_MKK][46] = 127, ++ [1][1][RTW89_IC][46] = 84, ++ [1][1][RTW89_KCC][46] = 38, ++ [1][1][RTW89_ACMA][46] = 84, ++ [1][1][RTW89_CHILE][46] = 56, ++ [1][1][RTW89_UKRAINE][46] = 16, ++ [1][1][RTW89_MEXICO][46] = 84, ++ [1][1][RTW89_CN][46] = 62, ++ [1][1][RTW89_QATAR][46] = 16, ++ [1][1][RTW89_UK][46] = 26, ++ [1][1][RTW89_FCC][48] = 32, ++ [1][1][RTW89_ETSI][48] = 127, ++ [1][1][RTW89_MKK][48] = 127, ++ [1][1][RTW89_IC][48] = 127, ++ [1][1][RTW89_KCC][48] = 127, ++ [1][1][RTW89_ACMA][48] = 127, ++ [1][1][RTW89_CHILE][48] = 127, ++ [1][1][RTW89_UKRAINE][48] = 127, ++ [1][1][RTW89_MEXICO][48] = 127, ++ [1][1][RTW89_CN][48] = 127, ++ [1][1][RTW89_QATAR][48] = 127, ++ [1][1][RTW89_UK][48] = 127, ++ [1][1][RTW89_FCC][50] = 32, ++ [1][1][RTW89_ETSI][50] = 127, ++ [1][1][RTW89_MKK][50] = 127, ++ [1][1][RTW89_IC][50] = 127, ++ [1][1][RTW89_KCC][50] = 127, ++ [1][1][RTW89_ACMA][50] = 127, ++ [1][1][RTW89_CHILE][50] = 127, ++ [1][1][RTW89_UKRAINE][50] = 127, ++ [1][1][RTW89_MEXICO][50] = 127, ++ [1][1][RTW89_CN][50] = 127, ++ [1][1][RTW89_QATAR][50] = 127, ++ [1][1][RTW89_UK][50] = 127, ++ [1][1][RTW89_FCC][52] = 32, ++ [1][1][RTW89_ETSI][52] = 127, ++ [1][1][RTW89_MKK][52] = 127, ++ [1][1][RTW89_IC][52] = 127, ++ [1][1][RTW89_KCC][52] = 127, ++ [1][1][RTW89_ACMA][52] = 127, ++ [1][1][RTW89_CHILE][52] = 127, ++ [1][1][RTW89_UKRAINE][52] = 127, ++ [1][1][RTW89_MEXICO][52] = 127, ++ [1][1][RTW89_CN][52] = 127, ++ [1][1][RTW89_QATAR][52] = 127, ++ [1][1][RTW89_UK][52] = 127, ++ [2][0][RTW89_FCC][0] = 70, ++ [2][0][RTW89_ETSI][0] = 48, ++ [2][0][RTW89_MKK][0] = 48, ++ [2][0][RTW89_IC][0] = 46, ++ [2][0][RTW89_KCC][0] = 66, ++ [2][0][RTW89_ACMA][0] = 48, ++ [2][0][RTW89_CHILE][0] = 44, ++ [2][0][RTW89_UKRAINE][0] = 48, ++ [2][0][RTW89_MEXICO][0] = 64, ++ [2][0][RTW89_CN][0] = 48, ++ [2][0][RTW89_QATAR][0] = 48, ++ [2][0][RTW89_UK][0] = 48, ++ [2][0][RTW89_FCC][2] = 70, ++ [2][0][RTW89_ETSI][2] = 48, ++ [2][0][RTW89_MKK][2] = 48, ++ [2][0][RTW89_IC][2] = 46, ++ [2][0][RTW89_KCC][2] = 66, ++ [2][0][RTW89_ACMA][2] = 48, ++ [2][0][RTW89_CHILE][2] = 44, ++ [2][0][RTW89_UKRAINE][2] = 48, ++ [2][0][RTW89_MEXICO][2] = 64, ++ [2][0][RTW89_CN][2] = 48, ++ [2][0][RTW89_QATAR][2] = 48, ++ [2][0][RTW89_UK][2] = 48, ++ [2][0][RTW89_FCC][4] = 70, ++ [2][0][RTW89_ETSI][4] = 48, ++ [2][0][RTW89_MKK][4] = 48, ++ [2][0][RTW89_IC][4] = 46, ++ [2][0][RTW89_KCC][4] = 66, ++ [2][0][RTW89_ACMA][4] = 48, ++ [2][0][RTW89_CHILE][4] = 44, ++ [2][0][RTW89_UKRAINE][4] = 48, ++ [2][0][RTW89_MEXICO][4] = 64, ++ [2][0][RTW89_CN][4] = 48, ++ [2][0][RTW89_QATAR][4] = 48, ++ [2][0][RTW89_UK][4] = 48, ++ [2][0][RTW89_FCC][6] = 70, ++ [2][0][RTW89_ETSI][6] = 48, ++ [2][0][RTW89_MKK][6] = 48, ++ [2][0][RTW89_IC][6] = 46, ++ [2][0][RTW89_KCC][6] = 38, ++ [2][0][RTW89_ACMA][6] = 48, ++ [2][0][RTW89_CHILE][6] = 44, ++ [2][0][RTW89_UKRAINE][6] = 48, ++ [2][0][RTW89_MEXICO][6] = 64, ++ [2][0][RTW89_CN][6] = 48, ++ [2][0][RTW89_QATAR][6] = 48, ++ [2][0][RTW89_UK][6] = 48, ++ [2][0][RTW89_FCC][8] = 70, ++ [2][0][RTW89_ETSI][8] = 48, ++ [2][0][RTW89_MKK][8] = 48, ++ [2][0][RTW89_IC][8] = 66, ++ [2][0][RTW89_KCC][8] = 64, ++ [2][0][RTW89_ACMA][8] = 48, ++ [2][0][RTW89_CHILE][8] = 66, ++ [2][0][RTW89_UKRAINE][8] = 48, ++ [2][0][RTW89_MEXICO][8] = 70, ++ [2][0][RTW89_CN][8] = 48, ++ [2][0][RTW89_QATAR][8] = 48, ++ [2][0][RTW89_UK][8] = 48, ++ [2][0][RTW89_FCC][10] = 70, ++ [2][0][RTW89_ETSI][10] = 48, ++ [2][0][RTW89_MKK][10] = 48, ++ [2][0][RTW89_IC][10] = 66, ++ [2][0][RTW89_KCC][10] = 64, ++ [2][0][RTW89_ACMA][10] = 48, ++ [2][0][RTW89_CHILE][10] = 66, ++ [2][0][RTW89_UKRAINE][10] = 48, ++ [2][0][RTW89_MEXICO][10] = 70, ++ [2][0][RTW89_CN][10] = 48, ++ [2][0][RTW89_QATAR][10] = 48, ++ [2][0][RTW89_UK][10] = 48, ++ [2][0][RTW89_FCC][12] = 70, ++ [2][0][RTW89_ETSI][12] = 48, ++ [2][0][RTW89_MKK][12] = 46, ++ [2][0][RTW89_IC][12] = 66, ++ [2][0][RTW89_KCC][12] = 64, ++ [2][0][RTW89_ACMA][12] = 48, ++ [2][0][RTW89_CHILE][12] = 66, ++ [2][0][RTW89_UKRAINE][12] = 48, ++ [2][0][RTW89_MEXICO][12] = 70, ++ [2][0][RTW89_CN][12] = 48, ++ [2][0][RTW89_QATAR][12] = 48, ++ [2][0][RTW89_UK][12] = 48, ++ [2][0][RTW89_FCC][14] = 70, ++ [2][0][RTW89_ETSI][14] = 48, ++ [2][0][RTW89_MKK][14] = 46, ++ [2][0][RTW89_IC][14] = 66, ++ [2][0][RTW89_KCC][14] = 64, ++ [2][0][RTW89_ACMA][14] = 48, ++ [2][0][RTW89_CHILE][14] = 66, ++ [2][0][RTW89_UKRAINE][14] = 48, ++ [2][0][RTW89_MEXICO][14] = 70, ++ [2][0][RTW89_CN][14] = 48, ++ [2][0][RTW89_QATAR][14] = 48, ++ [2][0][RTW89_UK][14] = 48, ++ [2][0][RTW89_FCC][15] = 70, ++ [2][0][RTW89_ETSI][15] = 48, ++ [2][0][RTW89_MKK][15] = 68, ++ [2][0][RTW89_IC][15] = 70, ++ [2][0][RTW89_KCC][15] = 64, ++ [2][0][RTW89_ACMA][15] = 48, ++ [2][0][RTW89_CHILE][15] = 62, ++ [2][0][RTW89_UKRAINE][15] = 48, ++ [2][0][RTW89_MEXICO][15] = 70, ++ [2][0][RTW89_CN][15] = 127, ++ [2][0][RTW89_QATAR][15] = 48, ++ [2][0][RTW89_UK][15] = 48, ++ [2][0][RTW89_FCC][17] = 70, ++ [2][0][RTW89_ETSI][17] = 48, ++ [2][0][RTW89_MKK][17] = 70, ++ [2][0][RTW89_IC][17] = 70, ++ [2][0][RTW89_KCC][17] = 64, ++ [2][0][RTW89_ACMA][17] = 48, ++ [2][0][RTW89_CHILE][17] = 62, ++ [2][0][RTW89_UKRAINE][17] = 48, ++ [2][0][RTW89_MEXICO][17] = 70, ++ [2][0][RTW89_CN][17] = 127, ++ [2][0][RTW89_QATAR][17] = 48, ++ [2][0][RTW89_UK][17] = 48, ++ [2][0][RTW89_FCC][19] = 70, ++ [2][0][RTW89_ETSI][19] = 48, ++ [2][0][RTW89_MKK][19] = 70, ++ [2][0][RTW89_IC][19] = 70, ++ [2][0][RTW89_KCC][19] = 64, ++ [2][0][RTW89_ACMA][19] = 48, ++ [2][0][RTW89_CHILE][19] = 62, ++ [2][0][RTW89_UKRAINE][19] = 48, ++ [2][0][RTW89_MEXICO][19] = 70, ++ [2][0][RTW89_CN][19] = 127, ++ [2][0][RTW89_QATAR][19] = 48, ++ [2][0][RTW89_UK][19] = 48, ++ [2][0][RTW89_FCC][21] = 70, ++ [2][0][RTW89_ETSI][21] = 48, ++ [2][0][RTW89_MKK][21] = 70, ++ [2][0][RTW89_IC][21] = 70, ++ [2][0][RTW89_KCC][21] = 64, ++ [2][0][RTW89_ACMA][21] = 48, ++ [2][0][RTW89_CHILE][21] = 64, ++ [2][0][RTW89_UKRAINE][21] = 48, ++ [2][0][RTW89_MEXICO][21] = 70, ++ [2][0][RTW89_CN][21] = 127, ++ [2][0][RTW89_QATAR][21] = 48, ++ [2][0][RTW89_UK][21] = 48, ++ [2][0][RTW89_FCC][23] = 70, ++ [2][0][RTW89_ETSI][23] = 48, ++ [2][0][RTW89_MKK][23] = 70, ++ [2][0][RTW89_IC][23] = 70, ++ [2][0][RTW89_KCC][23] = 64, ++ [2][0][RTW89_ACMA][23] = 48, ++ [2][0][RTW89_CHILE][23] = 64, ++ [2][0][RTW89_UKRAINE][23] = 48, ++ [2][0][RTW89_MEXICO][23] = 70, ++ [2][0][RTW89_CN][23] = 127, ++ [2][0][RTW89_QATAR][23] = 48, ++ [2][0][RTW89_UK][23] = 48, ++ [2][0][RTW89_FCC][25] = 70, ++ [2][0][RTW89_ETSI][25] = 48, ++ [2][0][RTW89_MKK][25] = 70, ++ [2][0][RTW89_IC][25] = 127, ++ [2][0][RTW89_KCC][25] = 64, ++ [2][0][RTW89_ACMA][25] = 127, ++ [2][0][RTW89_CHILE][25] = 64, ++ [2][0][RTW89_UKRAINE][25] = 48, ++ [2][0][RTW89_MEXICO][25] = 70, ++ [2][0][RTW89_CN][25] = 127, ++ [2][0][RTW89_QATAR][25] = 48, ++ [2][0][RTW89_UK][25] = 48, ++ [2][0][RTW89_FCC][27] = 70, ++ [2][0][RTW89_ETSI][27] = 48, ++ [2][0][RTW89_MKK][27] = 70, ++ [2][0][RTW89_IC][27] = 127, ++ [2][0][RTW89_KCC][27] = 64, ++ [2][0][RTW89_ACMA][27] = 127, ++ [2][0][RTW89_CHILE][27] = 64, ++ [2][0][RTW89_UKRAINE][27] = 48, ++ [2][0][RTW89_MEXICO][27] = 70, ++ [2][0][RTW89_CN][27] = 127, ++ [2][0][RTW89_QATAR][27] = 48, ++ [2][0][RTW89_UK][27] = 48, ++ [2][0][RTW89_FCC][29] = 70, ++ [2][0][RTW89_ETSI][29] = 48, ++ [2][0][RTW89_MKK][29] = 70, ++ [2][0][RTW89_IC][29] = 127, ++ [2][0][RTW89_KCC][29] = 64, ++ [2][0][RTW89_ACMA][29] = 127, ++ [2][0][RTW89_CHILE][29] = 66, ++ [2][0][RTW89_UKRAINE][29] = 48, ++ [2][0][RTW89_MEXICO][29] = 70, ++ [2][0][RTW89_CN][29] = 127, ++ [2][0][RTW89_QATAR][29] = 48, ++ [2][0][RTW89_UK][29] = 48, ++ [2][0][RTW89_FCC][31] = 70, ++ [2][0][RTW89_ETSI][31] = 48, ++ [2][0][RTW89_MKK][31] = 70, ++ [2][0][RTW89_IC][31] = 72, ++ [2][0][RTW89_KCC][31] = 64, ++ [2][0][RTW89_ACMA][31] = 48, ++ [2][0][RTW89_CHILE][31] = 66, ++ [2][0][RTW89_UKRAINE][31] = 48, ++ [2][0][RTW89_MEXICO][31] = 70, ++ [2][0][RTW89_CN][31] = 127, ++ [2][0][RTW89_QATAR][31] = 48, ++ [2][0][RTW89_UK][31] = 48, ++ [2][0][RTW89_FCC][33] = 72, ++ [2][0][RTW89_ETSI][33] = 48, ++ [2][0][RTW89_MKK][33] = 70, ++ [2][0][RTW89_IC][33] = 72, ++ [2][0][RTW89_KCC][33] = 64, ++ [2][0][RTW89_ACMA][33] = 48, ++ [2][0][RTW89_CHILE][33] = 66, ++ [2][0][RTW89_UKRAINE][33] = 48, ++ [2][0][RTW89_MEXICO][33] = 72, ++ [2][0][RTW89_CN][33] = 127, ++ [2][0][RTW89_QATAR][33] = 48, ++ [2][0][RTW89_UK][33] = 48, ++ [2][0][RTW89_FCC][35] = 72, ++ [2][0][RTW89_ETSI][35] = 48, ++ [2][0][RTW89_MKK][35] = 70, ++ [2][0][RTW89_IC][35] = 72, ++ [2][0][RTW89_KCC][35] = 64, ++ [2][0][RTW89_ACMA][35] = 48, ++ [2][0][RTW89_CHILE][35] = 66, ++ [2][0][RTW89_UKRAINE][35] = 48, ++ [2][0][RTW89_MEXICO][35] = 72, ++ [2][0][RTW89_CN][35] = 127, ++ [2][0][RTW89_QATAR][35] = 48, ++ [2][0][RTW89_UK][35] = 48, ++ [2][0][RTW89_FCC][37] = 70, ++ [2][0][RTW89_ETSI][37] = 127, ++ [2][0][RTW89_MKK][37] = 66, ++ [2][0][RTW89_IC][37] = 70, ++ [2][0][RTW89_KCC][37] = 64, ++ [2][0][RTW89_ACMA][37] = 76, ++ [2][0][RTW89_CHILE][37] = 66, ++ [2][0][RTW89_UKRAINE][37] = 127, ++ [2][0][RTW89_MEXICO][37] = 70, ++ [2][0][RTW89_CN][37] = 127, ++ [2][0][RTW89_QATAR][37] = 127, ++ [2][0][RTW89_UK][37] = 76, ++ [2][0][RTW89_FCC][38] = 84, ++ [2][0][RTW89_ETSI][38] = 28, ++ [2][0][RTW89_MKK][38] = 127, ++ [2][0][RTW89_IC][38] = 84, ++ [2][0][RTW89_KCC][38] = 66, ++ [2][0][RTW89_ACMA][38] = 84, ++ [2][0][RTW89_CHILE][38] = 64, ++ [2][0][RTW89_UKRAINE][38] = 28, ++ [2][0][RTW89_MEXICO][38] = 84, ++ [2][0][RTW89_CN][38] = 76, ++ [2][0][RTW89_QATAR][38] = 28, ++ [2][0][RTW89_UK][38] = 50, ++ [2][0][RTW89_FCC][40] = 84, ++ [2][0][RTW89_ETSI][40] = 28, ++ [2][0][RTW89_MKK][40] = 127, ++ [2][0][RTW89_IC][40] = 84, ++ [2][0][RTW89_KCC][40] = 66, ++ [2][0][RTW89_ACMA][40] = 84, ++ [2][0][RTW89_CHILE][40] = 64, ++ [2][0][RTW89_UKRAINE][40] = 28, ++ [2][0][RTW89_MEXICO][40] = 84, ++ [2][0][RTW89_CN][40] = 76, ++ [2][0][RTW89_QATAR][40] = 28, ++ [2][0][RTW89_UK][40] = 50, ++ [2][0][RTW89_FCC][42] = 84, ++ [2][0][RTW89_ETSI][42] = 28, ++ [2][0][RTW89_MKK][42] = 127, ++ [2][0][RTW89_IC][42] = 84, ++ [2][0][RTW89_KCC][42] = 66, ++ [2][0][RTW89_ACMA][42] = 84, ++ [2][0][RTW89_CHILE][42] = 66, ++ [2][0][RTW89_UKRAINE][42] = 28, ++ [2][0][RTW89_MEXICO][42] = 84, ++ [2][0][RTW89_CN][42] = 76, ++ [2][0][RTW89_QATAR][42] = 28, ++ [2][0][RTW89_UK][42] = 50, ++ [2][0][RTW89_FCC][44] = 84, ++ [2][0][RTW89_ETSI][44] = 28, ++ [2][0][RTW89_MKK][44] = 127, ++ [2][0][RTW89_IC][44] = 84, ++ [2][0][RTW89_KCC][44] = 66, ++ [2][0][RTW89_ACMA][44] = 84, ++ [2][0][RTW89_CHILE][44] = 64, ++ [2][0][RTW89_UKRAINE][44] = 28, ++ [2][0][RTW89_MEXICO][44] = 84, ++ [2][0][RTW89_CN][44] = 76, ++ [2][0][RTW89_QATAR][44] = 28, ++ [2][0][RTW89_UK][44] = 50, ++ [2][0][RTW89_FCC][46] = 84, ++ [2][0][RTW89_ETSI][46] = 28, ++ [2][0][RTW89_MKK][46] = 127, ++ [2][0][RTW89_IC][46] = 84, ++ [2][0][RTW89_KCC][46] = 66, ++ [2][0][RTW89_ACMA][46] = 84, ++ [2][0][RTW89_CHILE][46] = 64, ++ [2][0][RTW89_UKRAINE][46] = 28, ++ [2][0][RTW89_MEXICO][46] = 84, ++ [2][0][RTW89_CN][46] = 76, ++ [2][0][RTW89_QATAR][46] = 28, ++ [2][0][RTW89_UK][46] = 50, ++ [2][0][RTW89_FCC][48] = 56, ++ [2][0][RTW89_ETSI][48] = 127, ++ [2][0][RTW89_MKK][48] = 127, ++ [2][0][RTW89_IC][48] = 127, ++ [2][0][RTW89_KCC][48] = 127, ++ [2][0][RTW89_ACMA][48] = 127, ++ [2][0][RTW89_CHILE][48] = 127, ++ [2][0][RTW89_UKRAINE][48] = 127, ++ [2][0][RTW89_MEXICO][48] = 127, ++ [2][0][RTW89_CN][48] = 127, ++ [2][0][RTW89_QATAR][48] = 127, ++ [2][0][RTW89_UK][48] = 127, ++ [2][0][RTW89_FCC][50] = 56, ++ [2][0][RTW89_ETSI][50] = 127, ++ [2][0][RTW89_MKK][50] = 127, ++ [2][0][RTW89_IC][50] = 127, ++ [2][0][RTW89_KCC][50] = 127, ++ [2][0][RTW89_ACMA][50] = 127, ++ [2][0][RTW89_CHILE][50] = 127, ++ [2][0][RTW89_UKRAINE][50] = 127, ++ [2][0][RTW89_MEXICO][50] = 127, ++ [2][0][RTW89_CN][50] = 127, ++ [2][0][RTW89_QATAR][50] = 127, ++ [2][0][RTW89_UK][50] = 127, ++ [2][0][RTW89_FCC][52] = 56, ++ [2][0][RTW89_ETSI][52] = 127, ++ [2][0][RTW89_MKK][52] = 127, ++ [2][0][RTW89_IC][52] = 127, ++ [2][0][RTW89_KCC][52] = 127, ++ [2][0][RTW89_ACMA][52] = 127, ++ [2][0][RTW89_CHILE][52] = 127, ++ [2][0][RTW89_UKRAINE][52] = 127, ++ [2][0][RTW89_MEXICO][52] = 127, ++ [2][0][RTW89_CN][52] = 127, ++ [2][0][RTW89_QATAR][52] = 127, ++ [2][0][RTW89_UK][52] = 127, ++ [2][1][RTW89_FCC][0] = 50, ++ [2][1][RTW89_ETSI][0] = 36, ++ [2][1][RTW89_MKK][0] = 36, ++ [2][1][RTW89_IC][0] = 20, ++ [2][1][RTW89_KCC][0] = 46, ++ [2][1][RTW89_ACMA][0] = 36, ++ [2][1][RTW89_CHILE][0] = 32, ++ [2][1][RTW89_UKRAINE][0] = 36, ++ [2][1][RTW89_MEXICO][0] = 52, ++ [2][1][RTW89_CN][0] = 36, ++ [2][1][RTW89_QATAR][0] = 36, ++ [2][1][RTW89_UK][0] = 36, ++ [2][1][RTW89_FCC][2] = 50, ++ [2][1][RTW89_ETSI][2] = 36, ++ [2][1][RTW89_MKK][2] = 36, ++ [2][1][RTW89_IC][2] = 18, ++ [2][1][RTW89_KCC][2] = 46, ++ [2][1][RTW89_ACMA][2] = 36, ++ [2][1][RTW89_CHILE][2] = 32, ++ [2][1][RTW89_UKRAINE][2] = 36, ++ [2][1][RTW89_MEXICO][2] = 52, ++ [2][1][RTW89_CN][2] = 36, ++ [2][1][RTW89_QATAR][2] = 36, ++ [2][1][RTW89_UK][2] = 36, ++ [2][1][RTW89_FCC][4] = 50, ++ [2][1][RTW89_ETSI][4] = 36, ++ [2][1][RTW89_MKK][4] = 36, ++ [2][1][RTW89_IC][4] = 22, ++ [2][1][RTW89_KCC][4] = 46, ++ [2][1][RTW89_ACMA][4] = 36, ++ [2][1][RTW89_CHILE][4] = 30, ++ [2][1][RTW89_UKRAINE][4] = 36, ++ [2][1][RTW89_MEXICO][4] = 52, ++ [2][1][RTW89_CN][4] = 36, ++ [2][1][RTW89_QATAR][4] = 36, ++ [2][1][RTW89_UK][4] = 36, ++ [2][1][RTW89_FCC][6] = 50, ++ [2][1][RTW89_ETSI][6] = 36, ++ [2][1][RTW89_MKK][6] = 36, ++ [2][1][RTW89_IC][6] = 22, ++ [2][1][RTW89_KCC][6] = 22, ++ [2][1][RTW89_ACMA][6] = 36, ++ [2][1][RTW89_CHILE][6] = 30, ++ [2][1][RTW89_UKRAINE][6] = 36, ++ [2][1][RTW89_MEXICO][6] = 52, ++ [2][1][RTW89_CN][6] = 36, ++ [2][1][RTW89_QATAR][6] = 36, ++ [2][1][RTW89_UK][6] = 36, ++ [2][1][RTW89_FCC][8] = 50, ++ [2][1][RTW89_ETSI][8] = 36, ++ [2][1][RTW89_MKK][8] = 34, ++ [2][1][RTW89_IC][8] = 50, ++ [2][1][RTW89_KCC][8] = 48, ++ [2][1][RTW89_ACMA][8] = 36, ++ [2][1][RTW89_CHILE][8] = 54, ++ [2][1][RTW89_UKRAINE][8] = 36, ++ [2][1][RTW89_MEXICO][8] = 50, ++ [2][1][RTW89_CN][8] = 36, ++ [2][1][RTW89_QATAR][8] = 36, ++ [2][1][RTW89_UK][8] = 36, ++ [2][1][RTW89_FCC][10] = 50, ++ [2][1][RTW89_ETSI][10] = 36, ++ [2][1][RTW89_MKK][10] = 34, ++ [2][1][RTW89_IC][10] = 50, ++ [2][1][RTW89_KCC][10] = 48, ++ [2][1][RTW89_ACMA][10] = 36, ++ [2][1][RTW89_CHILE][10] = 54, ++ [2][1][RTW89_UKRAINE][10] = 36, ++ [2][1][RTW89_MEXICO][10] = 50, ++ [2][1][RTW89_CN][10] = 36, ++ [2][1][RTW89_QATAR][10] = 36, ++ [2][1][RTW89_UK][10] = 36, ++ [2][1][RTW89_FCC][12] = 52, ++ [2][1][RTW89_ETSI][12] = 36, ++ [2][1][RTW89_MKK][12] = 36, ++ [2][1][RTW89_IC][12] = 52, ++ [2][1][RTW89_KCC][12] = 48, ++ [2][1][RTW89_ACMA][12] = 36, ++ [2][1][RTW89_CHILE][12] = 54, ++ [2][1][RTW89_UKRAINE][12] = 36, ++ [2][1][RTW89_MEXICO][12] = 52, ++ [2][1][RTW89_CN][12] = 36, ++ [2][1][RTW89_QATAR][12] = 36, ++ [2][1][RTW89_UK][12] = 36, ++ [2][1][RTW89_FCC][14] = 52, ++ [2][1][RTW89_ETSI][14] = 36, ++ [2][1][RTW89_MKK][14] = 36, ++ [2][1][RTW89_IC][14] = 52, ++ [2][1][RTW89_KCC][14] = 48, ++ [2][1][RTW89_ACMA][14] = 36, ++ [2][1][RTW89_CHILE][14] = 54, ++ [2][1][RTW89_UKRAINE][14] = 36, ++ [2][1][RTW89_MEXICO][14] = 52, ++ [2][1][RTW89_CN][14] = 36, ++ [2][1][RTW89_QATAR][14] = 36, ++ [2][1][RTW89_UK][14] = 36, ++ [2][1][RTW89_FCC][15] = 50, ++ [2][1][RTW89_ETSI][15] = 36, ++ [2][1][RTW89_MKK][15] = 54, ++ [2][1][RTW89_IC][15] = 50, ++ [2][1][RTW89_KCC][15] = 48, ++ [2][1][RTW89_ACMA][15] = 36, ++ [2][1][RTW89_CHILE][15] = 56, ++ [2][1][RTW89_UKRAINE][15] = 36, ++ [2][1][RTW89_MEXICO][15] = 50, ++ [2][1][RTW89_CN][15] = 127, ++ [2][1][RTW89_QATAR][15] = 36, ++ [2][1][RTW89_UK][15] = 36, ++ [2][1][RTW89_FCC][17] = 50, ++ [2][1][RTW89_ETSI][17] = 36, ++ [2][1][RTW89_MKK][17] = 56, ++ [2][1][RTW89_IC][17] = 50, ++ [2][1][RTW89_KCC][17] = 48, ++ [2][1][RTW89_ACMA][17] = 36, ++ [2][1][RTW89_CHILE][17] = 56, ++ [2][1][RTW89_UKRAINE][17] = 36, ++ [2][1][RTW89_MEXICO][17] = 50, ++ [2][1][RTW89_CN][17] = 127, ++ [2][1][RTW89_QATAR][17] = 36, ++ [2][1][RTW89_UK][17] = 36, ++ [2][1][RTW89_FCC][19] = 50, ++ [2][1][RTW89_ETSI][19] = 36, ++ [2][1][RTW89_MKK][19] = 56, ++ [2][1][RTW89_IC][19] = 50, ++ [2][1][RTW89_KCC][19] = 48, ++ [2][1][RTW89_ACMA][19] = 36, ++ [2][1][RTW89_CHILE][19] = 56, ++ [2][1][RTW89_UKRAINE][19] = 36, ++ [2][1][RTW89_MEXICO][19] = 50, ++ [2][1][RTW89_CN][19] = 127, ++ [2][1][RTW89_QATAR][19] = 36, ++ [2][1][RTW89_UK][19] = 36, ++ [2][1][RTW89_FCC][21] = 50, ++ [2][1][RTW89_ETSI][21] = 36, ++ [2][1][RTW89_MKK][21] = 56, ++ [2][1][RTW89_IC][21] = 50, ++ [2][1][RTW89_KCC][21] = 48, ++ [2][1][RTW89_ACMA][21] = 36, ++ [2][1][RTW89_CHILE][21] = 58, ++ [2][1][RTW89_UKRAINE][21] = 36, ++ [2][1][RTW89_MEXICO][21] = 50, ++ [2][1][RTW89_CN][21] = 127, ++ [2][1][RTW89_QATAR][21] = 36, ++ [2][1][RTW89_UK][21] = 36, ++ [2][1][RTW89_FCC][23] = 50, ++ [2][1][RTW89_ETSI][23] = 36, ++ [2][1][RTW89_MKK][23] = 56, ++ [2][1][RTW89_IC][23] = 50, ++ [2][1][RTW89_KCC][23] = 48, ++ [2][1][RTW89_ACMA][23] = 36, ++ [2][1][RTW89_CHILE][23] = 58, ++ [2][1][RTW89_UKRAINE][23] = 36, ++ [2][1][RTW89_MEXICO][23] = 50, ++ [2][1][RTW89_CN][23] = 127, ++ [2][1][RTW89_QATAR][23] = 36, ++ [2][1][RTW89_UK][23] = 36, ++ [2][1][RTW89_FCC][25] = 50, ++ [2][1][RTW89_ETSI][25] = 36, ++ [2][1][RTW89_MKK][25] = 56, ++ [2][1][RTW89_IC][25] = 127, ++ [2][1][RTW89_KCC][25] = 48, ++ [2][1][RTW89_ACMA][25] = 127, ++ [2][1][RTW89_CHILE][25] = 58, ++ [2][1][RTW89_UKRAINE][25] = 36, ++ [2][1][RTW89_MEXICO][25] = 50, ++ [2][1][RTW89_CN][25] = 127, ++ [2][1][RTW89_QATAR][25] = 36, ++ [2][1][RTW89_UK][25] = 36, ++ [2][1][RTW89_FCC][27] = 50, ++ [2][1][RTW89_ETSI][27] = 36, ++ [2][1][RTW89_MKK][27] = 56, ++ [2][1][RTW89_IC][27] = 127, ++ [2][1][RTW89_KCC][27] = 48, ++ [2][1][RTW89_ACMA][27] = 127, ++ [2][1][RTW89_CHILE][27] = 58, ++ [2][1][RTW89_UKRAINE][27] = 36, ++ [2][1][RTW89_MEXICO][27] = 50, ++ [2][1][RTW89_CN][27] = 127, ++ [2][1][RTW89_QATAR][27] = 36, ++ [2][1][RTW89_UK][27] = 36, ++ [2][1][RTW89_FCC][29] = 50, ++ [2][1][RTW89_ETSI][29] = 36, ++ [2][1][RTW89_MKK][29] = 56, ++ [2][1][RTW89_IC][29] = 127, ++ [2][1][RTW89_KCC][29] = 48, ++ [2][1][RTW89_ACMA][29] = 127, ++ [2][1][RTW89_CHILE][29] = 56, ++ [2][1][RTW89_UKRAINE][29] = 36, ++ [2][1][RTW89_MEXICO][29] = 50, ++ [2][1][RTW89_CN][29] = 127, ++ [2][1][RTW89_QATAR][29] = 36, ++ [2][1][RTW89_UK][29] = 36, ++ [2][1][RTW89_FCC][31] = 50, ++ [2][1][RTW89_ETSI][31] = 36, ++ [2][1][RTW89_MKK][31] = 56, ++ [2][1][RTW89_IC][31] = 50, ++ [2][1][RTW89_KCC][31] = 48, ++ [2][1][RTW89_ACMA][31] = 36, ++ [2][1][RTW89_CHILE][31] = 56, ++ [2][1][RTW89_UKRAINE][31] = 36, ++ [2][1][RTW89_MEXICO][31] = 50, ++ [2][1][RTW89_CN][31] = 127, ++ [2][1][RTW89_QATAR][31] = 36, ++ [2][1][RTW89_UK][31] = 36, ++ [2][1][RTW89_FCC][33] = 50, ++ [2][1][RTW89_ETSI][33] = 36, ++ [2][1][RTW89_MKK][33] = 56, ++ [2][1][RTW89_IC][33] = 50, ++ [2][1][RTW89_KCC][33] = 48, ++ [2][1][RTW89_ACMA][33] = 36, ++ [2][1][RTW89_CHILE][33] = 56, ++ [2][1][RTW89_UKRAINE][33] = 36, ++ [2][1][RTW89_MEXICO][33] = 50, ++ [2][1][RTW89_CN][33] = 127, ++ [2][1][RTW89_QATAR][33] = 36, ++ [2][1][RTW89_UK][33] = 36, ++ [2][1][RTW89_FCC][35] = 50, ++ [2][1][RTW89_ETSI][35] = 36, ++ [2][1][RTW89_MKK][35] = 56, ++ [2][1][RTW89_IC][35] = 50, ++ [2][1][RTW89_KCC][35] = 48, ++ [2][1][RTW89_ACMA][35] = 36, ++ [2][1][RTW89_CHILE][35] = 56, ++ [2][1][RTW89_UKRAINE][35] = 36, ++ [2][1][RTW89_MEXICO][35] = 50, ++ [2][1][RTW89_CN][35] = 127, ++ [2][1][RTW89_QATAR][35] = 36, ++ [2][1][RTW89_UK][35] = 36, ++ [2][1][RTW89_FCC][37] = 50, ++ [2][1][RTW89_ETSI][37] = 127, ++ [2][1][RTW89_MKK][37] = 54, ++ [2][1][RTW89_IC][37] = 50, ++ [2][1][RTW89_KCC][37] = 48, ++ [2][1][RTW89_ACMA][37] = 60, ++ [2][1][RTW89_CHILE][37] = 56, ++ [2][1][RTW89_UKRAINE][37] = 127, ++ [2][1][RTW89_MEXICO][37] = 50, ++ [2][1][RTW89_CN][37] = 127, ++ [2][1][RTW89_QATAR][37] = 127, ++ [2][1][RTW89_UK][37] = 66, ++ [2][1][RTW89_FCC][38] = 84, ++ [2][1][RTW89_ETSI][38] = 16, ++ [2][1][RTW89_MKK][38] = 127, ++ [2][1][RTW89_IC][38] = 84, ++ [2][1][RTW89_KCC][38] = 48, ++ [2][1][RTW89_ACMA][38] = 84, ++ [2][1][RTW89_CHILE][38] = 58, ++ [2][1][RTW89_UKRAINE][38] = 16, ++ [2][1][RTW89_MEXICO][38] = 84, ++ [2][1][RTW89_CN][38] = 64, ++ [2][1][RTW89_QATAR][38] = 16, ++ [2][1][RTW89_UK][38] = 38, ++ [2][1][RTW89_FCC][40] = 84, ++ [2][1][RTW89_ETSI][40] = 16, ++ [2][1][RTW89_MKK][40] = 127, ++ [2][1][RTW89_IC][40] = 84, ++ [2][1][RTW89_KCC][40] = 48, ++ [2][1][RTW89_ACMA][40] = 84, ++ [2][1][RTW89_CHILE][40] = 58, ++ [2][1][RTW89_UKRAINE][40] = 16, ++ [2][1][RTW89_MEXICO][40] = 84, ++ [2][1][RTW89_CN][40] = 64, ++ [2][1][RTW89_QATAR][40] = 16, ++ [2][1][RTW89_UK][40] = 38, ++ [2][1][RTW89_FCC][42] = 84, ++ [2][1][RTW89_ETSI][42] = 16, ++ [2][1][RTW89_MKK][42] = 127, ++ [2][1][RTW89_IC][42] = 84, ++ [2][1][RTW89_KCC][42] = 48, ++ [2][1][RTW89_ACMA][42] = 84, ++ [2][1][RTW89_CHILE][42] = 58, ++ [2][1][RTW89_UKRAINE][42] = 16, ++ [2][1][RTW89_MEXICO][42] = 84, ++ [2][1][RTW89_CN][42] = 64, ++ [2][1][RTW89_QATAR][42] = 16, ++ [2][1][RTW89_UK][42] = 38, ++ [2][1][RTW89_FCC][44] = 84, ++ [2][1][RTW89_ETSI][44] = 16, ++ [2][1][RTW89_MKK][44] = 127, ++ [2][1][RTW89_IC][44] = 84, ++ [2][1][RTW89_KCC][44] = 48, ++ [2][1][RTW89_ACMA][44] = 84, ++ [2][1][RTW89_CHILE][44] = 58, ++ [2][1][RTW89_UKRAINE][44] = 16, ++ [2][1][RTW89_MEXICO][44] = 84, ++ [2][1][RTW89_CN][44] = 64, ++ [2][1][RTW89_QATAR][44] = 16, ++ [2][1][RTW89_UK][44] = 38, ++ [2][1][RTW89_FCC][46] = 84, ++ [2][1][RTW89_ETSI][46] = 16, ++ [2][1][RTW89_MKK][46] = 127, ++ [2][1][RTW89_IC][46] = 84, ++ [2][1][RTW89_KCC][46] = 48, ++ [2][1][RTW89_ACMA][46] = 84, ++ [2][1][RTW89_CHILE][46] = 58, ++ [2][1][RTW89_UKRAINE][46] = 16, ++ [2][1][RTW89_MEXICO][46] = 84, ++ [2][1][RTW89_CN][46] = 64, ++ [2][1][RTW89_QATAR][46] = 16, ++ [2][1][RTW89_UK][46] = 38, ++ [2][1][RTW89_FCC][48] = 44, ++ [2][1][RTW89_ETSI][48] = 127, ++ [2][1][RTW89_MKK][48] = 127, ++ [2][1][RTW89_IC][48] = 127, ++ [2][1][RTW89_KCC][48] = 127, ++ [2][1][RTW89_ACMA][48] = 127, ++ [2][1][RTW89_CHILE][48] = 127, ++ [2][1][RTW89_UKRAINE][48] = 127, ++ [2][1][RTW89_MEXICO][48] = 127, ++ [2][1][RTW89_CN][48] = 127, ++ [2][1][RTW89_QATAR][48] = 127, ++ [2][1][RTW89_UK][48] = 127, ++ [2][1][RTW89_FCC][50] = 44, ++ [2][1][RTW89_ETSI][50] = 127, ++ [2][1][RTW89_MKK][50] = 127, ++ [2][1][RTW89_IC][50] = 127, ++ [2][1][RTW89_KCC][50] = 127, ++ [2][1][RTW89_ACMA][50] = 127, ++ [2][1][RTW89_CHILE][50] = 127, ++ [2][1][RTW89_UKRAINE][50] = 127, ++ [2][1][RTW89_MEXICO][50] = 127, ++ [2][1][RTW89_CN][50] = 127, ++ [2][1][RTW89_QATAR][50] = 127, ++ [2][1][RTW89_UK][50] = 127, ++ [2][1][RTW89_FCC][52] = 44, ++ [2][1][RTW89_ETSI][52] = 127, ++ [2][1][RTW89_MKK][52] = 127, ++ [2][1][RTW89_IC][52] = 127, ++ [2][1][RTW89_KCC][52] = 127, ++ [2][1][RTW89_ACMA][52] = 127, ++ [2][1][RTW89_CHILE][52] = 127, ++ [2][1][RTW89_UKRAINE][52] = 127, ++ [2][1][RTW89_MEXICO][52] = 127, ++ [2][1][RTW89_CN][52] = 127, ++ [2][1][RTW89_QATAR][52] = 127, ++ [2][1][RTW89_UK][52] = 127, ++}; ++ ++const struct rtw89_phy_table rtw89_8852b_phy_bb_table = { ++ .regs = rtw89_8852b_phy_bb_regs, ++ .n_regs = ARRAY_SIZE(rtw89_8852b_phy_bb_regs), ++ .rf_path = 0, /* don't care */ ++}; ++ ++const struct rtw89_phy_table rtw89_8852b_phy_bb_gain_table = { ++ .regs = rtw89_8852b_phy_bb_reg_gain, ++ .n_regs = ARRAY_SIZE(rtw89_8852b_phy_bb_reg_gain), ++ .rf_path = 0, /* don't care */ ++}; ++ ++const struct rtw89_phy_table rtw89_8852b_phy_radioa_table = { ++ .regs = rtw89_8852b_phy_radioa_regs, ++ .n_regs = ARRAY_SIZE(rtw89_8852b_phy_radioa_regs), ++ .rf_path = RF_PATH_A, ++ .config = rtw89_phy_config_rf_reg_v1, ++}; ++ ++const struct rtw89_phy_table rtw89_8852b_phy_radiob_table = { ++ .regs = rtw89_8852b_phy_radiob_regs, ++ .n_regs = ARRAY_SIZE(rtw89_8852b_phy_radiob_regs), ++ .rf_path = RF_PATH_B, ++ .config = rtw89_phy_config_rf_reg_v1, ++}; ++ ++const struct rtw89_phy_table rtw89_8852b_phy_nctl_table = { ++ .regs = rtw89_8852b_phy_nctl_regs, ++ .n_regs = ARRAY_SIZE(rtw89_8852b_phy_nctl_regs), ++ .rf_path = 0, /* don't care */ ++}; ++ ++const struct rtw89_txpwr_table rtw89_8852b_byr_table = { ++ .data = rtw89_8852b_txpwr_byrate, ++ .size = ARRAY_SIZE(rtw89_8852b_txpwr_byrate), ++ .load = rtw89_phy_load_txpwr_byrate, ++}; ++ ++const struct rtw89_txpwr_track_cfg rtw89_8852b_trk_cfg = { ++ .delta_swingidx_5gb_n = _txpwr_track_delta_swingidx_5gb_n, ++ .delta_swingidx_5gb_p = _txpwr_track_delta_swingidx_5gb_p, ++ .delta_swingidx_5ga_n = _txpwr_track_delta_swingidx_5ga_n, ++ .delta_swingidx_5ga_p = _txpwr_track_delta_swingidx_5ga_p, ++ .delta_swingidx_2gb_n = _txpwr_track_delta_swingidx_2gb_n, ++ .delta_swingidx_2gb_p = _txpwr_track_delta_swingidx_2gb_p, ++ .delta_swingidx_2ga_n = _txpwr_track_delta_swingidx_2ga_n, ++ .delta_swingidx_2ga_p = _txpwr_track_delta_swingidx_2ga_p, ++ .delta_swingidx_2g_cck_b_n = _txpwr_track_delta_swingidx_2g_cck_b_n, ++ .delta_swingidx_2g_cck_b_p = _txpwr_track_delta_swingidx_2g_cck_b_p, ++ .delta_swingidx_2g_cck_a_n = _txpwr_track_delta_swingidx_2g_cck_a_n, ++ .delta_swingidx_2g_cck_a_p = _txpwr_track_delta_swingidx_2g_cck_a_p, ++}; +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_table.h linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_table.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852b_table.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852b_table.h 2022-12-24 00:49:25.785376835 +0200 +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2019-2020 Realtek Corporation ++ */ ++ ++#ifndef __RTW89_8852B_TABLE_H__ ++#define __RTW89_8852B_TABLE_H__ ++ ++#include "core.h" ++ ++extern const struct rtw89_phy_table rtw89_8852b_phy_bb_table; ++extern const struct rtw89_phy_table rtw89_8852b_phy_bb_gain_table; ++extern const struct rtw89_phy_table rtw89_8852b_phy_radioa_table; ++extern const struct rtw89_phy_table rtw89_8852b_phy_radiob_table; ++extern const struct rtw89_phy_table rtw89_8852b_phy_nctl_table; ++extern const struct rtw89_txpwr_table rtw89_8852b_byr_table; ++extern const struct rtw89_txpwr_track_cfg rtw89_8852b_trk_cfg; ++extern const u8 rtw89_8852b_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] ++ [RTW89_REGD_NUM]; ++extern const s8 rtw89_8852b_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] ++ [RTW89_RS_LMT_NUM][RTW89_BF_NUM] ++ [RTW89_REGD_NUM][RTW89_2G_CH_NUM]; ++extern const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] ++ [RTW89_RS_LMT_NUM][RTW89_BF_NUM] ++ [RTW89_REGD_NUM][RTW89_5G_CH_NUM]; ++extern const s8 rtw89_8852b_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] ++ [RTW89_REGD_NUM][RTW89_2G_CH_NUM]; ++extern const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] ++ [RTW89_REGD_NUM][RTW89_5G_CH_NUM]; ++ ++#endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852c.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852c.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852c.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852c.c 2022-12-24 00:49:25.785376835 +0200 +@@ -273,6 +273,9 @@ static int rtw8852c_pwr_on_func(struct r + B_AX_CMAC_DMA_EN | B_AX_PTCLTOP_EN | B_AX_SCHEDULER_EN | + B_AX_TMAC_EN | B_AX_RMAC_EN); + ++ rtw89_write32_mask(rtwdev, R_AX_LED1_FUNC_SEL, B_AX_PINMUX_EESK_FUNC_SEL_V1_MASK, ++ PINMUX_EESK_FUNC_SEL_BT_LOG); ++ + return 0; + } + +@@ -785,40 +788,12 @@ static const struct rtw8852c_bb_gain_op1 + .mask_tia0_lna6 = 0xff000000, + }; + +-static enum rtw89_phy_bb_gain_band +-rtw8852c_mapping_gain_band(enum rtw89_subband subband) +-{ +- switch (subband) { +- default: +- case RTW89_CH_2G: +- return RTW89_BB_GAIN_BAND_2G; +- case RTW89_CH_5G_BAND_1: +- return RTW89_BB_GAIN_BAND_5G_L; +- case RTW89_CH_5G_BAND_3: +- return RTW89_BB_GAIN_BAND_5G_M; +- case RTW89_CH_5G_BAND_4: +- return RTW89_BB_GAIN_BAND_5G_H; +- case RTW89_CH_6G_BAND_IDX0: +- case RTW89_CH_6G_BAND_IDX1: +- return RTW89_BB_GAIN_BAND_6G_L; +- case RTW89_CH_6G_BAND_IDX2: +- case RTW89_CH_6G_BAND_IDX3: +- return RTW89_BB_GAIN_BAND_6G_M; +- case RTW89_CH_6G_BAND_IDX4: +- case RTW89_CH_6G_BAND_IDX5: +- return RTW89_BB_GAIN_BAND_6G_H; +- case RTW89_CH_6G_BAND_IDX6: +- case RTW89_CH_6G_BAND_IDX7: +- return RTW89_BB_GAIN_BAND_6G_UH; +- } +-} +- + static void rtw8852c_set_gain_error(struct rtw89_dev *rtwdev, + enum rtw89_subband subband, + enum rtw89_rf_path path) + { + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; +- u8 gain_band = rtw8852c_mapping_gain_band(subband); ++ u8 gain_band = rtw89_subband_to_bb_gain_band(subband); + s32 val; + u32 reg; + u32 mask; +@@ -976,21 +951,7 @@ static void rtw8852c_set_gain_offset(str + rtw89_phy_write32_mask(rtwdev, R_RPL_OFST, B_RPL_OFST_MASK, tmp & 0x7f); + } + +- switch (chan->subband_type) { +- default: +- case RTW89_CH_2G: +- gain_band = RTW89_GAIN_OFFSET_2G_OFDM; +- break; +- case RTW89_CH_5G_BAND_1: +- gain_band = RTW89_GAIN_OFFSET_5G_LOW; +- break; +- case RTW89_CH_5G_BAND_3: +- gain_band = RTW89_GAIN_OFFSET_5G_MID; +- break; +- case RTW89_CH_5G_BAND_4: +- gain_band = RTW89_GAIN_OFFSET_5G_HIGH; +- break; +- } ++ gain_band = rtw89_subband_to_gain_offset_band_of_ofdm(chan->subband_type); + + offset_q0 = -efuse_gain->offset[path][gain_band]; + offset_base_q4 = efuse_gain->offset_base[phy_idx]; +@@ -1722,12 +1683,12 @@ static void rtw8852c_set_channel_bb(stru + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) + { ++ static const u32 ru_alloc_msk[2] = {B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY0, ++ B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY1}; + struct rtw89_hal *hal = &rtwdev->hal; + bool cck_en = chan->band_type == RTW89_BAND_2G; + u8 pri_ch_idx = chan->pri_ch_idx; + u32 mask, reg; +- u32 ru_alloc_msk[2] = {B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY0, +- B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY1}; + u8 ntx_path; + + if (chan->band_type == RTW89_BAND_2G) +@@ -1871,11 +1832,11 @@ static void rtw8852c_set_channel_help(st + + static void rtw8852c_rfk_init(struct rtw89_dev *rtwdev) + { +- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc; ++ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + + rtwdev->is_tssi_mode[RF_PATH_A] = false; + rtwdev->is_tssi_mode[RF_PATH_B] = false; +- memset(mcc_info, 0, sizeof(*mcc_info)); ++ memset(rfk_mcc, 0, sizeof(*rfk_mcc)); + rtw8852c_lck_init(rtwdev); + + rtw8852c_rck(rtwdev); +@@ -2006,75 +1967,6 @@ static void rtw8852c_set_txpwr_ref(struc + phy_idx); + } + +-static void rtw8852c_set_txpwr_byrate(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- enum rtw89_phy_idx phy_idx) +-{ +- u8 band = chan->band_type; +- u8 ch = chan->channel; +- static const u8 rs[] = { +- RTW89_RS_CCK, +- RTW89_RS_OFDM, +- RTW89_RS_MCS, +- RTW89_RS_HEDCM, +- }; +- s8 tmp; +- u8 i, j; +- u32 val, shf, addr = R_AX_PWR_BY_RATE; +- struct rtw89_rate_desc cur; +- +- rtw89_debug(rtwdev, RTW89_DBG_TXPWR, +- "[TXPWR] set txpwr byrate with ch=%d\n", ch); +- +- for (cur.nss = 0; cur.nss <= RTW89_NSS_2; cur.nss++) { +- for (i = 0; i < ARRAY_SIZE(rs); i++) { +- if (cur.nss >= rtw89_rs_nss_max[rs[i]]) +- continue; +- +- val = 0; +- cur.rs = rs[i]; +- +- for (j = 0; j < rtw89_rs_idx_max[rs[i]]; j++) { +- cur.idx = j; +- shf = (j % 4) * 8; +- tmp = rtw89_phy_read_txpwr_byrate(rtwdev, band, +- &cur); +- val |= (tmp << shf); +- +- if ((j + 1) % 4) +- continue; +- +- rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val); +- val = 0; +- addr += 4; +- } +- } +- } +-} +- +-static void rtw8852c_set_txpwr_offset(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- enum rtw89_phy_idx phy_idx) +-{ +- u8 band = chan->band_type; +- struct rtw89_rate_desc desc = { +- .nss = RTW89_NSS_1, +- .rs = RTW89_RS_OFFSET, +- }; +- u32 val = 0; +- s8 v; +- +- rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr offset\n"); +- +- for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_MAX; desc.idx++) { +- v = rtw89_phy_read_txpwr_byrate(rtwdev, band, &desc); +- val |= ((v & 0xf) << (4 * desc.idx)); +- } +- +- rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_OFST_CTRL, +- GENMASK(19, 0), val); +-} +- + static void rtw8852c_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, + u8 tx_shape_idx, + enum rtw89_phy_idx phy_idx) +@@ -2147,83 +2039,15 @@ static void rtw8852c_set_tx_shape(struct + tx_shape_ofdm); + } + +-static void rtw8852c_set_txpwr_limit(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- enum rtw89_phy_idx phy_idx) +-{ +-#define __MAC_TXPWR_LMT_PAGE_SIZE 40 +- u8 ch = chan->channel; +- u8 bw = chan->band_width; +- struct rtw89_txpwr_limit lmt[NTX_NUM_8852C]; +- u32 addr, val; +- const s8 *ptr; +- u8 i, j; +- +- rtw89_debug(rtwdev, RTW89_DBG_TXPWR, +- "[TXPWR] set txpwr limit with ch=%d bw=%d\n", ch, bw); +- +- for (i = 0; i < NTX_NUM_8852C; i++) { +- rtw89_phy_fill_txpwr_limit(rtwdev, chan, &lmt[i], i); +- +- for (j = 0; j < __MAC_TXPWR_LMT_PAGE_SIZE; j += 4) { +- addr = R_AX_PWR_LMT + j + __MAC_TXPWR_LMT_PAGE_SIZE * i; +- ptr = (s8 *)&lmt[i] + j; +- +- val = FIELD_PREP(GENMASK(7, 0), ptr[0]) | +- FIELD_PREP(GENMASK(15, 8), ptr[1]) | +- FIELD_PREP(GENMASK(23, 16), ptr[2]) | +- FIELD_PREP(GENMASK(31, 24), ptr[3]); +- +- rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val); +- } +- } +-#undef __MAC_TXPWR_LMT_PAGE_SIZE +-} +- +-static void rtw8852c_set_txpwr_limit_ru(struct rtw89_dev *rtwdev, +- const struct rtw89_chan *chan, +- enum rtw89_phy_idx phy_idx) +-{ +-#define __MAC_TXPWR_LMT_RU_PAGE_SIZE 24 +- u8 ch = chan->channel; +- u8 bw = chan->band_width; +- struct rtw89_txpwr_limit_ru lmt_ru[NTX_NUM_8852C]; +- u32 addr, val; +- const s8 *ptr; +- u8 i, j; +- +- rtw89_debug(rtwdev, RTW89_DBG_TXPWR, +- "[TXPWR] set txpwr limit ru with ch=%d bw=%d\n", ch, bw); +- +- for (i = 0; i < NTX_NUM_8852C; i++) { +- rtw89_phy_fill_txpwr_limit_ru(rtwdev, chan, &lmt_ru[i], i); +- +- for (j = 0; j < __MAC_TXPWR_LMT_RU_PAGE_SIZE; j += 4) { +- addr = R_AX_PWR_RU_LMT + j + +- __MAC_TXPWR_LMT_RU_PAGE_SIZE * i; +- ptr = (s8 *)&lmt_ru[i] + j; +- +- val = FIELD_PREP(GENMASK(7, 0), ptr[0]) | +- FIELD_PREP(GENMASK(15, 8), ptr[1]) | +- FIELD_PREP(GENMASK(23, 16), ptr[2]) | +- FIELD_PREP(GENMASK(31, 24), ptr[3]); +- +- rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val); +- } +- } +- +-#undef __MAC_TXPWR_LMT_RU_PAGE_SIZE +-} +- + static void rtw8852c_set_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) + { +- rtw8852c_set_txpwr_byrate(rtwdev, chan, phy_idx); +- rtw8852c_set_txpwr_offset(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx); + rtw8852c_set_tx_shape(rtwdev, chan, phy_idx); +- rtw8852c_set_txpwr_limit(rtwdev, chan, phy_idx); +- rtw8852c_set_txpwr_limit_ru(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx); ++ rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx); + } + + static void rtw8852c_set_txpwr_ctrl(struct rtw89_dev *rtwdev, +@@ -2819,19 +2643,6 @@ static const struct rtw89_btc_fbtc_mreg + }; + + static +-void rtw8852c_btc_bt_aci_imp(struct rtw89_dev *rtwdev) +-{ +- struct rtw89_btc *btc = &rtwdev->btc; +- struct rtw89_btc_dm *dm = &btc->dm; +- struct rtw89_btc_bt_info *bt = &btc->cx.bt; +- struct rtw89_btc_bt_link_info *b = &bt->link_info; +- +- /* fix LNA2 = level-5 for BT ACI issue at BTG */ +- if (btc->dm.wl_btg_rx && b->profile_cnt.now != 0) +- dm->trx_para_level = 1; +-} +- +-static + void rtw8852c_btc_update_bt_cnt(struct rtw89_dev *rtwdev) + { + /* Feature move to firmware */ +@@ -2985,6 +2796,15 @@ static int rtw8852c_mac_disable_bb_rf(st + return 0; + } + ++#ifdef CONFIG_PM ++static const struct wiphy_wowlan_support rtw_wowlan_stub_8852c = { ++ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, ++ .n_patterns = RTW89_MAX_PATTERN_NUM, ++ .pattern_max_len = RTW89_MAX_PATTERN_SIZE, ++ .pattern_min_len = 1, ++}; ++#endif ++ + static const struct rtw89_chip_ops rtw8852c_chip_ops = { + .enable_bb_rf = rtw8852c_mac_enable_bb_rf, + .disable_bb_rf = rtw8852c_mac_disable_bb_rf, +@@ -3027,7 +2847,6 @@ static const struct rtw89_chip_ops rtw88 + .btc_set_wl_pri = rtw8852c_btc_set_wl_pri, + .btc_set_wl_txpwr_ctrl = rtw8852c_btc_set_wl_txpwr_ctrl, + .btc_get_bt_rssi = rtw8852c_btc_get_bt_rssi, +- .btc_bt_aci_imp = rtw8852c_btc_bt_aci_imp, + .btc_update_bt_cnt = rtw8852c_btc_update_bt_cnt, + .btc_wl_s1_standby = rtw8852c_btc_wl_s1_standby, + .btc_set_wl_rx_gain = rtw8852c_btc_set_wl_rx_gain, +@@ -3045,6 +2864,8 @@ const struct rtw89_chip_info rtw8852c_ch + .rsvd_ple_ofst = 0x6f800, + .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, + .dle_mem = rtw8852c_dle_mem_pcie, ++ .wde_qempty_acq_num = 16, ++ .wde_qempty_mgq_sel = 16, + .rf_base_addr = {0xe000, 0xf000}, + .pwr_on_seq = NULL, + .pwr_off_seq = NULL, +@@ -3070,6 +2891,7 @@ const struct rtw89_chip_info rtw8852c_ch + BIT(NL80211_BAND_5GHZ) | + BIT(NL80211_BAND_6GHZ), + .support_bw160 = true, ++ .support_ul_tb_ctrl = false, + .hw_sec_hdr = true, + .rf_path_num = 2, + .tx_nss = 2, +@@ -3132,11 +2954,15 @@ const struct rtw89_chip_info rtw8852c_ch + .c2h_ctrl_reg = R_AX_C2HREG_CTRL_V1, + .c2h_regs = rtw8852c_c2h_regs, + .page_regs = &rtw8852c_page_regs, ++ .cfo_src_fd = false, + .dcfo_comp = &rtw8852c_dcfo_comp, + .dcfo_comp_sft = 5, + .imr_info = &rtw8852c_imr_info, + .rrsr_cfgs = &rtw8852c_rrsr_cfgs, + .dma_ch_mask = 0, ++#ifdef CONFIG_PM ++ .wowlan_stub = &rtw_wowlan_stub_8852c, ++#endif + }; + EXPORT_SYMBOL(rtw8852c_chip_info); + +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852c.h linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852c.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852c.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852c.h 2022-12-24 00:49:25.786376835 +0200 +@@ -9,7 +9,6 @@ + + #define RF_PATH_NUM_8852C 2 + #define BB_PATH_NUM_8852C 2 +-#define NTX_NUM_8852C 2 + + struct rtw8852c_u_efuse { + u8 rsvd[0x38]; +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c 2022-12-24 00:49:25.786376835 +0200 +@@ -22,8 +22,7 @@ static const u32 _tssi_de_mcs_5m[RF_PATH + static const u32 _tssi_de_mcs_10m[RF_PATH_NUM_8852C] = {0x5830, 0x7830}; + + static const u32 rtw8852c_backup_bb_regs[] = { +- 0x813c, 0x8124, 0x8120, 0xc0d4, 0xc0d8, 0xc0e8, 0x823c, 0x8224, 0x8220, +- 0xc1d4, 0xc1d8, 0xc1e8 ++ 0x8120, 0xc0d4, 0xc0d8, 0xc0e8, 0x8220, 0xc1d4, 0xc1d8, 0xc1e8 + }; + + static const u32 rtw8852c_backup_rf_regs[] = { +@@ -1031,9 +1030,9 @@ static bool _iqk_nbtxk(struct rtw89_dev + + static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path) + { +- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc; ++ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; +- u8 idx = mcc_info->table_idx; ++ u8 idx = rfk_mcc->table_idx; + bool is_fail1, is_fail2; + u32 val; + u32 core_i; +@@ -1376,10 +1375,10 @@ static void _iqk_afebb_restore(struct rt + + static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) + { +- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc; ++ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + u8 idx = 0; + +- idx = mcc_info->table_idx; ++ idx = rfk_mcc->table_idx; + rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), B_COEF_SEL_IQC, idx); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_G3, idx); + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); +@@ -1667,7 +1666,7 @@ static u8 _dpk_one_shot(struct rtw89_dev + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x55, + 10, 20000, false, rtwdev, 0xbff8, MASKBYTE0); +- mdelay(10); ++ udelay(10); + rtw89_phy_write32_clr(rtwdev, R_NCTL_N1, MASKBYTE0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, +@@ -3825,20 +3824,20 @@ void rtw8852c_set_channel_rf(struct rtw8 + void rtw8852c_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) + { + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); +- struct rtw89_mcc_info *mcc_info = &rtwdev->mcc; +- u8 idx = mcc_info->table_idx; ++ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; ++ u8 idx = rfk_mcc->table_idx; + int i; + + for (i = 0; i < RTW89_IQK_CHS_NR; i++) { +- if (mcc_info->ch[idx] == 0) ++ if (rfk_mcc->ch[idx] == 0) + break; + if (++idx >= RTW89_IQK_CHS_NR) + idx = 0; + } + +- mcc_info->table_idx = idx; +- mcc_info->ch[idx] = chan->channel; +- mcc_info->band[idx] = chan->band_type; ++ rfk_mcc->table_idx = idx; ++ rfk_mcc->ch[idx] = chan->channel; ++ rfk_mcc->band[idx] = chan->band_type; + } + + void rtw8852c_rck(struct rtw89_dev *rtwdev) +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c 2022-12-24 00:49:25.786376835 +0200 +@@ -10,6 +10,8 @@ static const struct rtw89_reg2_def rtw89 + {0xF0FF0000, 0x00000000}, + {0xF03300FF, 0x00000001}, + {0xF03400FF, 0x00000002}, ++ {0xF03500FF, 0x00000003}, ++ {0xF03600FF, 0x00000004}, + {0x70C, 0x00000020}, + {0x704, 0x601E0100}, + {0x4000, 0x00000000}, +@@ -200,7 +202,7 @@ static const struct rtw89_reg2_def rtw89 + {0x4264, 0x00000000}, + {0x4268, 0x00000000}, + {0x426C, 0x0418317C}, +- {0x46C0, 0x00000001}, ++ {0x46C0, 0x00000000}, + {0x4270, 0x00D6135C}, + {0x46C4, 0x00000033}, + {0x4274, 0x00000000}, +@@ -342,7 +344,7 @@ static const struct rtw89_reg2_def rtw89 + {0x442C, 0x00000000}, + {0x4430, 0x00000000}, + {0x4434, 0x00000000}, +- {0x4438, 0x590642D0}, ++ {0x4438, 0x59096398}, + {0x443C, 0x398668A0}, + {0x4440, 0x6C100808}, + {0x4444, 0x4A145344}, +@@ -566,9 +568,9 @@ static const struct rtw89_reg2_def rtw89 + {0x4BA8, 0x002B6456}, + {0x45E0, 0x00000000}, + {0x45E4, 0x00000000}, +- {0x45E8, 0x00E2E1E1}, ++ {0x45E8, 0x00C8E1E1}, + {0x45EC, 0xCBCBB6B6}, +- {0x45F0, 0x59100FCA}, ++ {0x45F0, 0x5F900FCA}, + {0x4BAC, 0x12CAB6DE}, + {0x4BB0, 0x00001110}, + {0x45F4, 0x08882550}, +@@ -584,9 +586,17 @@ static const struct rtw89_reg2_def rtw89 + {0x4660, 0x41250EF4}, + {0x4664, 0x6750E458}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x45DC, 0xE1CB38E8}, +- {0x4660, 0x4A2E1800}, +- {0x4664, 0x6750E462}, ++ {0x45DC, 0xD1B942F4}, ++ {0x4660, 0x41250EF4}, ++ {0x4664, 0x6750E458}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x45DC, 0xD1B942F4}, ++ {0x4660, 0x41250EF4}, ++ {0x4664, 0x6750E458}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x45DC, 0xD1B942F4}, ++ {0x4660, 0x41250EF4}, ++ {0x4664, 0x6750E458}, + {0xA0000000, 0x00000000}, + {0x45DC, 0xE1CB38E8}, + {0x4660, 0x4A2E1800}, +@@ -603,7 +613,19 @@ static const struct rtw89_reg2_def rtw89 + {0x4688, 0x1A10FF04}, + {0x468C, 0x282A3000}, + {0x4690, 0x2A29292A}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4694, 0x04FA2A2A}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4694, 0x04FA2A2A}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4694, 0x06FA2A2A}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4694, 0x04FA2A2A}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, + {0x4694, 0x04FA2A2A}, ++ {0xA0000000, 0x00000000}, ++ {0x4694, 0x04FA2A2A}, ++ {0xB0000000, 0x00000000}, + {0x4698, 0xEE0F04D1}, + {0x469C, 0x89291436}, + {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, +@@ -612,6 +634,10 @@ static const struct rtw89_reg2_def rtw89 + {0x46A0, 0x0701E79E}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, + {0x46A0, 0x0701E79E}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x46A0, 0x0701E79E}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x46A0, 0x0701E79E}, + {0xA0000000, 0x00000000}, + {0x46A0, 0x0701E79E}, + {0xB0000000, 0x00000000}, +@@ -620,11 +646,17 @@ static const struct rtw89_reg2_def rtw89 + {0x46A8, 0x2212FF14}, + {0x46AC, 0x60423537}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x46A8, 0x649EFF14}, ++ {0x46AC, 0xA1B37C4E}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, + {0x46A8, 0x4D1E7F14}, + {0x46AC, 0x60B37C4E}, +- {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x46A8, 0x2212FF14}, +- {0x46AC, 0x60423537}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x46A8, 0x649EFF14}, ++ {0x46AC, 0xA1B37C4E}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x46A8, 0x649EFF14}, ++ {0x46AC, 0xA1B37C4E}, + {0xA0000000, 0x00000000}, + {0x46A8, 0x2212FF14}, + {0x46AC, 0x60423537}, +@@ -637,11 +669,19 @@ static const struct rtw89_reg2_def rtw89 + {0x4720, 0x3FFFFD63}, + {0x4724, 0xB58D11FF}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x46BC, 0x5107C252}, +- {0x4720, 0x27795843}, ++ {0x46BC, 0x510FC252}, ++ {0x4720, 0x27795303}, + {0x4724, 0xB58D11F5}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x46BC, 0x5107C252}, ++ {0x46BC, 0x510FC252}, ++ {0x4720, 0x27795843}, ++ {0x4724, 0xB58D11F5}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x46BC, 0x510FC252}, ++ {0x4720, 0x27795303}, ++ {0x4724, 0xB58D11F5}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x46BC, 0x510FC252}, + {0x4720, 0x27795303}, + {0x4724, 0xB58D11F5}, + {0xA0000000, 0x00000000}, +@@ -656,11 +696,17 @@ static const struct rtw89_reg2_def rtw89 + {0x4734, 0x00000020}, + {0x4738, 0x8325C500}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x4734, 0x003D4C20}, ++ {0x4734, 0x003D5420}, + {0x4738, 0x8F25C500}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4734, 0x003D4C20}, ++ {0x4738, 0x8F25C500}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4734, 0x003D5420}, ++ {0x4738, 0x8F25C500}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, + {0x4734, 0x003D5420}, +- {0x4738, 0x8725C500}, ++ {0x4738, 0x8F25C500}, + {0xA0000000, 0x00000000}, + {0x4734, 0x00000020}, + {0x4738, 0x8325C500}, +@@ -678,8 +724,14 @@ static const struct rtw89_reg2_def rtw89 + {0x4BB4, 0x05EBC8AF}, + {0x4BB8, 0x99543D24}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x4BB4, 0xFBD5B89F}, +- {0x4BB8, 0x99563918}, ++ {0x4BB4, 0x05EBC8AF}, ++ {0x4BB8, 0x99543D24}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4BB4, 0x05EBC8AF}, ++ {0x4BB8, 0x99543D24}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4BB4, 0x05EBC8AF}, ++ {0x4BB8, 0x99543D24}, + {0xA0000000, 0x00000000}, + {0x4BB4, 0xFBD5B89F}, + {0x4BB8, 0x99563918}, +@@ -729,10 +781,10 @@ static const struct rtw89_reg2_def rtw89 + {0x4C58, 0x00001146}, + {0x4C5C, 0x00000000}, + {0x4C60, 0x00000000}, +- {0x4C64, 0xE2E1E1DE}, ++ {0x4C64, 0xC8E1E1DE}, + {0x4C68, 0xB6B600B6}, + {0x4C6C, 0xCACBCBCA}, +- {0x4C70, 0x8091010F}, ++ {0x4C70, 0x80F9010F}, + {0x4C74, 0x00000B11}, + {0x46C8, 0x08882550}, + {0x46CC, 0x08CC2660}, +@@ -747,9 +799,17 @@ static const struct rtw89_reg2_def rtw89 + {0x4744, 0x412504E8}, + {0x4748, 0x6850E459}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x4740, 0xE4CD38E8}, +- {0x4744, 0x4C321B04}, +- {0x4748, 0x6750E466}, ++ {0x4740, 0xC5AD42F4}, ++ {0x4744, 0x412504E8}, ++ {0x4748, 0x6850E459}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4740, 0xC5AD42F4}, ++ {0x4744, 0x412504E8}, ++ {0x4748, 0x6850E459}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4740, 0xC5AD42F4}, ++ {0x4744, 0x412504E8}, ++ {0x4748, 0x6850E459}, + {0xA0000000, 0x00000000}, + {0x4740, 0xE4CD38E8}, + {0x4744, 0x4C321B04}, +@@ -766,7 +826,19 @@ static const struct rtw89_reg2_def rtw89 + {0x476C, 0x1A10FF04}, + {0x4770, 0x282A3000}, + {0x4774, 0x2A29292A}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x4778, 0x04FA2A2A}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4778, 0x04FA2A2A}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4778, 0x06FA2A2A}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4778, 0x04FA2A2A}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4778, 0x04FA2A2A}, ++ {0xA0000000, 0x00000000}, ++ {0x4778, 0x04FA2A2A}, ++ {0xB0000000, 0x00000000}, + {0x477C, 0xEE0F04D1}, + {0x49F0, 0x89291436}, + {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, +@@ -775,6 +847,10 @@ static const struct rtw89_reg2_def rtw89 + {0x49F4, 0x0701E79E}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, + {0x49F4, 0x0701E79E}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x49F4, 0x0701E79E}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x49F4, 0x0701E79E}, + {0xA0000000, 0x00000000}, + {0x49F4, 0x0701E79E}, + {0xB0000000, 0x00000000}, +@@ -783,11 +859,17 @@ static const struct rtw89_reg2_def rtw89 + {0x4A5C, 0x2212FF14}, + {0x4A60, 0x60423537}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4A5C, 0x649EFF14}, ++ {0x4A60, 0xA1B37C4E}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, + {0x4A5C, 0x4D1E7F14}, + {0x4A60, 0x60B37C4E}, +- {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x4A5C, 0x2212FF14}, +- {0x4A60, 0x60423537}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4A5C, 0x649EFF14}, ++ {0x4A60, 0xA1B37C4E}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4A5C, 0x649EFF14}, ++ {0x4A60, 0xA1B37C4E}, + {0xA0000000, 0x00000000}, + {0x4A5C, 0x2212FF14}, + {0x4A60, 0x60423537}, +@@ -800,11 +882,19 @@ static const struct rtw89_reg2_def rtw89 + {0x4A74, 0x3FFFFD63}, + {0x4A78, 0xB58D11FF}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x4A70, 0x5107C252}, +- {0x4A74, 0x27795843}, ++ {0x4A70, 0x510FC252}, ++ {0x4A74, 0x27795303}, + {0x4A78, 0xB58D11F5}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x4A70, 0x5107C252}, ++ {0x4A70, 0x510FC252}, ++ {0x4A74, 0x27795843}, ++ {0x4A78, 0xB58D11F5}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4A70, 0x510FC252}, ++ {0x4A74, 0x27795303}, ++ {0x4A78, 0xB58D11F5}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4A70, 0x510FC252}, + {0x4A74, 0x27795303}, + {0x4A78, 0xB58D11F5}, + {0xA0000000, 0x00000000}, +@@ -819,11 +909,17 @@ static const struct rtw89_reg2_def rtw89 + {0x4AA0, 0x00000020}, + {0x4AA4, 0x8325C500}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x4AA0, 0x003D4C20}, ++ {0x4AA0, 0x003D5420}, + {0x4AA4, 0x8F25C500}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4AA0, 0x003D4C20}, ++ {0x4AA4, 0x8F25C500}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4AA0, 0x003D5420}, ++ {0x4AA4, 0x8F25C500}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, + {0x4AA0, 0x003D5420}, +- {0x4AA4, 0x8725C500}, ++ {0x4AA4, 0x8F25C500}, + {0xA0000000, 0x00000000}, + {0x4AA0, 0x00000020}, + {0x4AA4, 0x8325C500}, +@@ -841,8 +937,14 @@ static const struct rtw89_reg2_def rtw89 + {0x4C78, 0x07ECC9B0}, + {0x4C7C, 0x995B4126}, + {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x4C78, 0xFBD5B89F}, +- {0x4C7C, 0x99563918}, ++ {0x4C78, 0x07ECC9B0}, ++ {0x4C7C, 0x995B4126}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4C78, 0x07ECC9B0}, ++ {0x4C7C, 0x995B4126}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4C78, 0x07ECC9B0}, ++ {0x4C7C, 0x995B4126}, + {0xA0000000, 0x00000000}, + {0x4C78, 0xFBD5B89F}, + {0x4C7C, 0x99563918}, +@@ -907,17 +1009,46 @@ static const struct rtw89_reg2_def rtw89 + {0x47B4, 0x00000005}, + {0x4D2C, 0x0008C0C1}, + {0x47B8, 0x00001759}, +- {0x47BC, 0x4B702400}, +- {0x47C0, 0x831508BA}, ++ {0x47BC, 0x4B002402}, ++ {0x47C0, 0x831508BC}, + {0x4A14, 0x000000E9}, +- {0x4D30, 0x00000001}, ++ {0x4D30, 0x00000000}, + {0x4E94, 0x000000FC}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x47C4, 0x9ABBCACB}, ++ {0x47C8, 0x56767578}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x47C4, 0x9ABBCACB}, ++ {0x47C8, 0x56767578}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x47C4, 0x9ABBCACB}, ++ {0x47C8, 0x56767578}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x47C4, 0x9ABBCACB}, ++ {0x47C8, 0x56767578}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x47C4, 0x9ABBCACB}, ++ {0x47C8, 0x56767578}, ++ {0xA0000000, 0x00000000}, + {0x47C4, 0x9ABBCACB}, + {0x47C8, 0x56767578}, ++ {0xB0000000, 0x00000000}, + {0x47CC, 0xBBCCBBB3}, + {0x47D0, 0x57889989}, + {0x47D4, 0x00000F45}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4D34, 0x7BB167AB}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4D34, 0x7BB1579A}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4D34, 0x7BB167AB}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4D34, 0x7BB1579A}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4D34, 0x7BB1579A}, ++ {0xA0000000, 0x00000000}, + {0x4D34, 0x7BB167AB}, ++ {0xB0000000, 0x00000000}, + {0x4D38, 0xBBBBBB05}, + {0x4D3C, 0x777777BB}, + {0x4D40, 0x00015277}, +@@ -942,7 +1073,19 @@ static const struct rtw89_reg2_def rtw89 + {0x4D48, 0x8C413016}, + {0x4D4C, 0xA140B028}, + {0x4D50, 0x00150A31}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x481C, 0x576DF814}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x481C, 0x576DF814}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x481C, 0x576BF814}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x481C, 0x576DF814}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x481C, 0x576DF814}, ++ {0xA0000000, 0x00000000}, ++ {0x481C, 0x576DF814}, ++ {0xB0000000, 0x00000000}, + {0x4820, 0xA08877AC}, + {0x4824, 0x0000007A}, + {0x4D54, 0x00001184}, +@@ -967,7 +1110,19 @@ static const struct rtw89_reg2_def rtw89 + {0x4D78, 0x994C1502}, + {0x4D7C, 0x00017912}, + {0x4EDC, 0x00000001}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x484C, 0x0000CA62}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x484C, 0x00008A62}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x484C, 0x0000CA62}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, + {0x484C, 0x00008A62}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x484C, 0x00008A62}, ++ {0xA0000000, 0x00000000}, ++ {0x484C, 0x0000CA62}, ++ {0xB0000000, 0x00000000}, + {0x4D80, 0x00000002}, + {0x4850, 0x00000008}, + {0x4854, 0x009B902A}, +@@ -1014,7 +1169,19 @@ static const struct rtw89_reg2_def rtw89 + {0x4DA0, 0x8C413016}, + {0x4DA4, 0xA140B028}, + {0x4DA8, 0x00150A31}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x48D4, 0x576DF814}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x48D4, 0x576BF814}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x48D4, 0x576BF814}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x48D4, 0x576BF814}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x48D4, 0x576BF814}, ++ {0xA0000000, 0x00000000}, + {0x48D4, 0x576DF814}, ++ {0xB0000000, 0x00000000}, + {0x48D8, 0xA08877AC}, + {0x48DC, 0x0000007A}, + {0x4DAC, 0x00001184}, +@@ -1039,7 +1206,19 @@ static const struct rtw89_reg2_def rtw89 + {0x4DD0, 0x994C1502}, + {0x4DD4, 0x00017912}, + {0x4EE4, 0x00000001}, +- {0x4904, 0x00008A62}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4904, 0x0000CA62}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4904, 0x0000CA62}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4904, 0x0000CA62}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4904, 0x0000CA62}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4904, 0x0000CA62}, ++ {0xA0000000, 0x00000000}, ++ {0x4904, 0x0000CA62}, ++ {0xB0000000, 0x00000000}, + {0x4DD8, 0x00000002}, + {0x4908, 0x00000008}, + {0x490C, 0x80040000}, +@@ -1096,8 +1275,8 @@ static const struct rtw89_reg2_def rtw89 + {0x4988, 0x00000000}, + {0x498C, 0x00000000}, + {0x4E34, 0x00FC0000}, +- {0x4E38, 0x0000F800}, +- {0x4E3C, 0x00000001}, ++ {0x4E38, 0x00000000}, ++ {0x4E3C, 0x00000003}, + {0x4990, 0x00000000}, + {0x4994, 0x00000000}, + {0x4998, 0x00000000}, +@@ -1134,7 +1313,7 @@ static const struct rtw89_reg2_def rtw89 + {0x710, 0xEF810000}, + {0xC54, 0x1AE1436A}, + {0xC58, 0x41000000}, +- {0xC68, 0x10000050}, ++ {0xC68, 0x90000050}, + {0xC6C, 0x20061020}, + {0x704, 0x601E0100}, + {0xC74, 0x00000000}, +@@ -1225,12 +1404,12 @@ static const struct rtw89_reg2_def rtw89 + {0x328, 0xE000E000}, + {0x32C, 0x0041E000}, + {0x35C, 0x000004C4}, +- {0xC0D4, 0xA7C41460}, ++ {0xC0D4, 0xA7441460}, + {0xC0D8, 0xC6BA7F67}, + {0xC0DC, 0x30C52868}, + {0xC0E0, 0x75008128}, + {0xC0E4, 0x0000272B}, +- {0xC1D4, 0xA7C41460}, ++ {0xC1D4, 0xA7441460}, + {0xC1D8, 0xC6BA7F67}, + {0xC1DC, 0x30C52868}, + {0xC1E0, 0x75008128}, +@@ -1290,7 +1469,7 @@ static const struct rtw89_reg2_def rtw89 + {0xC8C, 0x02F2FC08}, + {0xC70, 0x071BFC00}, + {0x980, 0x10002251}, +- {0x988, 0x3C3C4107}, ++ {0x988, 0x3C3C8107}, + {0x904, 0x00000005}, + {0x994, 0x00000010}, + {0x000, 0x0580801F}, +@@ -1359,7 +1538,19 @@ static const struct rtw89_reg2_def rtw89 + {0x2310, 0xBC80536C}, + {0x2314, 0x0363A0F3}, + {0x2318, 0x000000BB}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x724, 0x00111200}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x724, 0x20111100}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x724, 0x20111100}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x724, 0x01100100}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x724, 0x01100100}, ++ {0xA0000000, 0x00000000}, + {0x724, 0x00111200}, ++ {0xB0000000, 0x00000000}, + {0x704, 0x601E0D00}, + {0xC78, 0xBFFFFFFF}, + {0x704, 0x601E0D02}, +@@ -1393,7 +1584,7 @@ static const struct rtw89_reg2_def rtw89 + {0xC60, 0x017FFFF3}, + {0xC70, 0x071BFE00}, + {0xC70, 0x071BFE60}, +- {0xC6C, 0x20061021}, ++ {0xC6C, 0x26061021}, + {0x58AC, 0x08000000}, + {0x78AC, 0x08000000}, + {0x8120, 0x10000000}, +@@ -1452,7 +1643,7 @@ static const struct rtw89_reg2_def rtw89 + {0x12A0, 0x24903056}, + {0x12AC, 0x12333121}, + {0x12B8, 0x30020000}, +- {0x2000, 0x18BBBF84}, ++ {0x2000, 0x20BBBF04}, + {0x2C14, 0x85000005}, + {0x3200, 0x00010142}, + {0x32A0, 0x24903056}, +@@ -1469,7 +1660,21 @@ static const struct rtw89_reg2_def rtw89 + {0x76C8, 0x0E800400}, + {0x984, 0x000000E0}, + {0x2008, 0x000FFFFF}, ++ {0x1210, 0x8049E304}, ++ {0x3210, 0x8049E304}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x58B0, 0x00000800}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x58B0, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x58B0, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x58B0, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x58B0, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x58B0, 0x00000800}, ++ {0xB0000000, 0x00000000}, + {0x5A00, 0x00000000}, + {0x5A04, 0x00000000}, + {0x5A08, 0x00000000}, +@@ -1479,7 +1684,19 @@ static const struct rtw89_reg2_def rtw89 + {0x5A18, 0x00000000}, + {0x5A1C, 0x00000000}, + {0x5A20, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x5A24, 0x00050000}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A24, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A24, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A24, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A24, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x5A24, 0x00050000}, ++ {0xB0000000, 0x00000000}, + {0x5A28, 0x00000000}, + {0x5A2C, 0x00000000}, + {0x5A30, 0x00000000}, +@@ -1487,14 +1704,38 @@ static const struct rtw89_reg2_def rtw89 + {0x5A38, 0x00000000}, + {0x5A3C, 0x00000000}, + {0x5A40, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A44, 0x00000005}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A44, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A44, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A44, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A44, 0x00000000}, ++ {0xA0000000, 0x00000000}, + {0x5A44, 0x00000005}, ++ {0xB0000000, 0x00000000}, + {0x5A48, 0x00000000}, + {0x5A4C, 0x00000000}, + {0x5A50, 0x00000000}, + {0x5A54, 0x00000000}, + {0x5A58, 0x00000000}, + {0x5A5C, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x5A60, 0x00050000}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A60, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A60, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A60, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5A60, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x5A60, 0x00050000}, ++ {0xB0000000, 0x00000000}, + {0x5A64, 0x00000000}, + {0x5A68, 0x00000000}, + {0x5A6C, 0x00000000}, +@@ -1514,12 +1755,49 @@ static const struct rtw89_reg2_def rtw89 + {0x5AA4, 0x00000000}, + {0x5AA8, 0x00000000}, + {0x5AAC, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x5AB0, 0x00050005}, + {0x5AB4, 0x00050005}, + {0x5AB8, 0x00050005}, + {0x5ABC, 0x00050005}, + {0x5AC0, 0x00000005}, + {0x78B0, 0x00000800}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5AB0, 0x00000000}, ++ {0x5AB4, 0x00000000}, ++ {0x5AB8, 0x00000000}, ++ {0x5ABC, 0x00000000}, ++ {0x5AC0, 0x00000000}, ++ {0x78B0, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5AB0, 0x00000000}, ++ {0x5AB4, 0x00000000}, ++ {0x5AB8, 0x00000000}, ++ {0x5ABC, 0x00000000}, ++ {0x5AC0, 0x00000000}, ++ {0x78B0, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5AB0, 0x00000000}, ++ {0x5AB4, 0x00000000}, ++ {0x5AB8, 0x00000000}, ++ {0x5ABC, 0x00000000}, ++ {0x5AC0, 0x00000000}, ++ {0x78B0, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x5AB0, 0x00000000}, ++ {0x5AB4, 0x00000000}, ++ {0x5AB8, 0x00000000}, ++ {0x5ABC, 0x00000000}, ++ {0x5AC0, 0x00000000}, ++ {0x78B0, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x5AB0, 0x00050005}, ++ {0x5AB4, 0x00050005}, ++ {0x5AB8, 0x00050005}, ++ {0x5ABC, 0x00050005}, ++ {0x5AC0, 0x00000005}, ++ {0x78B0, 0x00000800}, ++ {0xB0000000, 0x00000000}, + {0x7A00, 0x00000000}, + {0x7A04, 0x00000000}, + {0x7A08, 0x00000000}, +@@ -1529,7 +1807,19 @@ static const struct rtw89_reg2_def rtw89 + {0x7A18, 0x00000000}, + {0x7A1C, 0x00000000}, + {0x7A20, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x7A24, 0x00050000}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A24, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A24, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A24, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A24, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x7A24, 0x00050000}, ++ {0xB0000000, 0x00000000}, + {0x7A28, 0x00000000}, + {0x7A2C, 0x00000000}, + {0x7A30, 0x00000000}, +@@ -1537,14 +1827,38 @@ static const struct rtw89_reg2_def rtw89 + {0x7A38, 0x00000000}, + {0x7A3C, 0x00000000}, + {0x7A40, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x7A44, 0x00000005}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A44, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A44, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A44, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A44, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x7A44, 0x00000005}, ++ {0xB0000000, 0x00000000}, + {0x7A48, 0x00000000}, + {0x7A4C, 0x00000000}, + {0x7A50, 0x00000000}, + {0x7A54, 0x00000000}, + {0x7A58, 0x00000000}, + {0x7A5C, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A60, 0x00050000}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A60, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A60, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A60, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7A60, 0x00000000}, ++ {0xA0000000, 0x00000000}, + {0x7A60, 0x00050000}, ++ {0xB0000000, 0x00000000}, + {0x7A64, 0x00000000}, + {0x7A68, 0x00000000}, + {0x7A6C, 0x00000000}, +@@ -1564,143 +1878,223 @@ static const struct rtw89_reg2_def rtw89 + {0x7AA4, 0x00000000}, + {0x7AA8, 0x00000000}, + {0x7AAC, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x7AB0, 0x00050005}, + {0x7AB4, 0x00050005}, + {0x7AB8, 0x00050005}, + {0x7ABC, 0x00050005}, + {0x7AC0, 0x00000005}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7AB0, 0x00000000}, ++ {0x7AB4, 0x00000000}, ++ {0x7AB8, 0x00000000}, ++ {0x7ABC, 0x00000000}, ++ {0x7AC0, 0x00000000}, ++ {0x903400ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7AB0, 0x00000000}, ++ {0x7AB4, 0x00000000}, ++ {0x7AB8, 0x00000000}, ++ {0x7ABC, 0x00000000}, ++ {0x7AC0, 0x00000000}, ++ {0x903500ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7AB0, 0x00000000}, ++ {0x7AB4, 0x00000000}, ++ {0x7AB8, 0x00000000}, ++ {0x7ABC, 0x00000000}, ++ {0x7AC0, 0x00000000}, ++ {0x903600ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x7AB0, 0x00000000}, ++ {0x7AB4, 0x00000000}, ++ {0x7AB8, 0x00000000}, ++ {0x7ABC, 0x00000000}, ++ {0x7AC0, 0x00000000}, ++ {0xA0000000, 0x00000000}, ++ {0x7AB0, 0x00050005}, ++ {0x7AB4, 0x00050005}, ++ {0x7AB8, 0x00050005}, ++ {0x7ABC, 0x00050005}, ++ {0x7AC0, 0x00000005}, ++ {0xB0000000, 0x00000000}, + {0x0F0, 0x00010000}, +- {0x0F4, 0x00000018}, +- {0x0F8, 0x20220120}, ++ {0x0F4, 0x00000028}, ++ {0x0F8, 0x20220610}, + }; + + static const struct rtw89_reg2_def rtw89_8852c_phy_bb_reg_gain[] = { + {0xF0FF0000, 0x00000000}, + {0xF03300FF, 0x00000001}, +- {0x000, 0x01E3C39F}, +- {0x001, 0x00694727}, +- {0x002, 0x00005536}, +- {0x100, 0x02E3C39F}, +- {0x101, 0x0069472A}, ++ {0x000, 0x0EEECAA6}, ++ {0x001, 0x006C4B2C}, ++ {0x002, 0x00005636}, ++ {0x100, 0x0DEFCAA9}, ++ {0x101, 0x00694B2C}, + {0x102, 0x00005536}, + {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x10000, 0x1A02E1C9}, + {0x10001, 0x00644A30}, + {0x10002, 0x00006750}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x10000, 0x0EF4D1B9}, +- {0x10001, 0x00584125}, +- {0x10002, 0x00006750}, ++ {0x10000, 0x0BF1CEB6}, ++ {0x10001, 0x00434328}, ++ {0x10002, 0x00005050}, + {0xA0000000, 0x00000000}, +- {0x10000, 0x1A02E1C9}, +- {0x10001, 0x00644A30}, +- {0x10002, 0x00006750}, ++ {0x10000, 0x1D08E8D0}, ++ {0x10001, 0x00644C32}, ++ {0x10002, 0x00006650}, + {0xB0000000, 0x00000000}, + {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x10100, 0x1901E1C8}, + {0x10101, 0x0061482D}, + {0x10102, 0x00006750}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x10100, 0x04E8C5AD}, +- {0x10101, 0x00594125}, +- {0x10102, 0x00006850}, ++ {0x10100, 0x0BF0CEB8}, ++ {0x10101, 0x00424227}, ++ {0x10102, 0x00005050}, + {0xA0000000, 0x00000000}, +- {0x10100, 0x1901E1C8}, +- {0x10101, 0x0061482D}, +- {0x10102, 0x00006750}, ++ {0x10100, 0x1F0AECD5}, ++ {0x10101, 0x00634B31}, ++ {0x10102, 0x00006550}, + {0xB0000000, 0x00000000}, + {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x20000, 0x1601E2CA}, + {0x20001, 0x005D452A}, + {0x20002, 0x00006750}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x20000, 0x0EF4D3BB}, +- {0x20001, 0x00563F25}, +- {0x20002, 0x00006850}, ++ {0x20000, 0x0EF5D3BB}, ++ {0x20001, 0x00454529}, ++ {0x20002, 0x00005050}, + {0xA0000000, 0x00000000}, +- {0x20000, 0x1601E2CA}, +- {0x20001, 0x005D452A}, +- {0x20002, 0x00006750}, ++ {0x20000, 0x1904E6CE}, ++ {0x20001, 0x0060482D}, ++ {0x20002, 0x00006650}, + {0xB0000000, 0x00000000}, + {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x20100, 0x1901E1C8}, + {0x20101, 0x0061482D}, + {0x20102, 0x00006750}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x20100, 0x0BF1CFB7}, +- {0x20101, 0x00574025}, +- {0x20102, 0x00006750}, ++ {0x20100, 0x12F8D7C1}, ++ {0x20101, 0x004A4A2E}, ++ {0x20102, 0x00005050}, + {0xA0000000, 0x00000000}, +- {0x20100, 0x1901E1C8}, ++ {0x20100, 0x1F0AECD5}, + {0x20101, 0x0061482D}, +- {0x20102, 0x00006750}, ++ {0x20102, 0x00006550}, + {0xB0000000, 0x00000000}, + {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x30000, 0x1700E1CA}, + {0x30001, 0x005E472B}, + {0x30002, 0x00006750}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x30000, 0x05EFCEB7}, +- {0x30001, 0x004B351A}, +- {0x30002, 0x00006850}, ++ {0x30000, 0x0DF6D5BE}, ++ {0x30001, 0x00414126}, ++ {0x30002, 0x00005050}, + {0xA0000000, 0x00000000}, +- {0x30000, 0x1700E1CA}, +- {0x30001, 0x005E472B}, +- {0x30002, 0x00006750}, ++ {0x30000, 0x14FEE0CA}, ++ {0x30001, 0x005C4328}, ++ {0x30002, 0x00006650}, + {0xB0000000, 0x00000000}, + {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x30100, 0x14FEE0C9}, + {0x30101, 0x00594428}, + {0x30102, 0x00006650}, + {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, +- {0x30100, 0x0CF2D1B9}, +- {0x30101, 0x00563F24}, +- {0x30102, 0x00006750}, ++ {0x30100, 0x0EF5D5C0}, ++ {0x30101, 0x0045452A}, ++ {0x30102, 0x00005050}, + {0xA0000000, 0x00000000}, +- {0x30100, 0x14FEE0C9}, +- {0x30101, 0x00594428}, ++ {0x30100, 0x1F0AECD8}, ++ {0x30101, 0x00654C31}, + {0x30102, 0x00006650}, + {0xB0000000, 0x00000000}, +- {0x40000, 0x13FCDDC8}, +- {0x40001, 0x005D4328}, +- {0x40002, 0x00006850}, +- {0x40100, 0x14FEE3CF}, +- {0x40101, 0x00583E24}, +- {0x40102, 0x00006850}, +- {0x50000, 0x0DF4D6C6}, +- {0x50001, 0x00604227}, +- {0x50002, 0x00006850}, +- {0x50100, 0x1903E7D5}, +- {0x50101, 0x0061462B}, +- {0x50102, 0x00006850}, +- {0x60000, 0x0FF5D7C6}, +- {0x60001, 0x005D4429}, +- {0x60002, 0x00006850}, +- {0x60100, 0x12FADECF}, +- {0x60101, 0x005B4126}, +- {0x60102, 0x00006850}, +- {0x70000, 0x09F1D2C3}, +- {0x70001, 0x00554026}, +- {0x70002, 0x00006750}, +- {0x70100, 0x0CF5DACC}, +- {0x70101, 0x00563E25}, +- {0x70102, 0x00006750}, ++ {0x40000, 0x15FEE0CB}, ++ {0x40001, 0x0060462B}, ++ {0x40002, 0x00006450}, ++ {0x40100, 0x1902E5D2}, ++ {0x40101, 0x0063482E}, ++ {0x40102, 0x00006450}, ++ {0x50000, 0x1C04E6D3}, ++ {0x50001, 0x006B5034}, ++ {0x50002, 0x00006450}, ++ {0x50100, 0x2009EDDB}, ++ {0x50101, 0x006B5035}, ++ {0x50102, 0x00006450}, ++ {0x60000, 0x16FEE1CF}, ++ {0x60001, 0x00634A2E}, ++ {0x60002, 0x00006550}, ++ {0x60100, 0x14FDE2D2}, ++ {0x60101, 0x005E4429}, ++ {0x60102, 0x00006450}, ++ {0x70000, 0x0BF3D6C6}, ++ {0x70001, 0x00573F24}, ++ {0x70002, 0x00006550}, ++ {0x70100, 0x08F0D6C7}, ++ {0x70101, 0x0052391E}, ++ {0x70102, 0x00006450}, + {0x2000000, 0x02E4C4A0}, + {0x2000001, 0x006A4828}, + {0x2000100, 0x02E4C5A1}, + {0x2000101, 0x00664629}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x2010000, 0x05EBC8AF}, + {0x2010001, 0x00543D24}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x2010000, 0x08EDCAB2}, ++ {0x2010001, 0x00434327}, ++ {0xA0000000, 0x00000000}, ++ {0x2010000, 0x05EBC8AF}, ++ {0x2010001, 0x00543D24}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x2010100, 0x07ECC9B0}, + {0x2010101, 0x005B4126}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x2010100, 0x08ECCBB2}, ++ {0x2010101, 0x003C3C20}, ++ {0xA0000000, 0x00000000}, ++ {0x2010100, 0x07ECC9B0}, ++ {0x2010101, 0x005B4126}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x2020000, 0x05EDCCB2}, + {0x2020001, 0x004D361C}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x2020000, 0x0CF4D2BA}, ++ {0x2020001, 0x00404025}, ++ {0xA0000000, 0x00000000}, ++ {0x2020000, 0x05EDCCB2}, ++ {0x2020001, 0x004D361C}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x2020100, 0x06ECCBB2}, + {0x2020101, 0x00553D22}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x2020100, 0x09EECDB8}, ++ {0x2020101, 0x00444428}, ++ {0xA0000000, 0x00000000}, ++ {0x2020100, 0x06ECCBB2}, ++ {0x2020101, 0x00553D22}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x2030000, 0x02ECCCB3}, + {0x2030001, 0x00483118}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x2030000, 0x0DF8D6BF}, ++ {0x2030001, 0x003F3F24}, ++ {0xA0000000, 0x00000000}, ++ {0x2030000, 0x02ECCCB3}, ++ {0x2030001, 0x00483118}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x2030100, 0x04ECCCB2}, + {0x2030101, 0x004F381C}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x2030100, 0x08EFCDBA}, ++ {0x2030101, 0x00414126}, ++ {0xA0000000, 0x00000000}, ++ {0x2030100, 0x04ECCCB2}, ++ {0x2030101, 0x004F381C}, ++ {0xB0000000, 0x00000000}, + {0x3000000, 0x00000000}, + {0x3000001, 0x00000000}, + {0x3000002, 0x00000000}, +@@ -1709,30 +2103,102 @@ static const struct rtw89_reg2_def rtw89 + {0x3000101, 0x00000000}, + {0x3000102, 0x00000000}, + {0x3000103, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x3010000, 0x0E0CFB0A}, ++ {0x3010001, 0x00100F06}, ++ {0x3010002, 0x34333333}, ++ {0x3010003, 0x3434343C}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x3010000, 0x0E0CFB0A}, ++ {0x3010001, 0x00100F06}, ++ {0x3010002, 0x34333327}, ++ {0x3010003, 0x3434343C}, ++ {0xA0000000, 0x00000000}, + {0x3010000, 0x0E0CFB0A}, + {0x3010001, 0x00100F06}, + {0x3010002, 0x34333333}, + {0x3010003, 0x3434343C}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x3010100, 0x0E0CFB0A}, + {0x3010101, 0x00100F06}, + {0x3010102, 0x34333333}, + {0x3010103, 0x3434343C}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x3010100, 0x0E0CFB0A}, ++ {0x3010101, 0x00100F06}, ++ {0x3010102, 0x34333327}, ++ {0x3010103, 0x3434343C}, ++ {0xA0000000, 0x00000000}, ++ {0x3010100, 0x0E0CFB0A}, ++ {0x3010101, 0x00100F06}, ++ {0x3010102, 0x34333333}, ++ {0x3010103, 0x3434343C}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x3020000, 0x0E0CFB0A}, + {0x3020001, 0x00100F06}, + {0x3020002, 0x34333333}, + {0x3020003, 0x3434343C}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x3020000, 0x0E0CFB0A}, ++ {0x3020001, 0x00100F06}, ++ {0x3020002, 0x34333327}, ++ {0x3020003, 0x3434343C}, ++ {0xA0000000, 0x00000000}, ++ {0x3020000, 0x0E0CFB0A}, ++ {0x3020001, 0x00100F06}, ++ {0x3020002, 0x34333333}, ++ {0x3020003, 0x3434343C}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x3020100, 0x0E0CFB0A}, + {0x3020101, 0x00100F06}, + {0x3020102, 0x34333333}, + {0x3020103, 0x3434343C}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x3020100, 0x0E0CFB0A}, ++ {0x3020101, 0x00100F06}, ++ {0x3020102, 0x34333327}, ++ {0x3020103, 0x3434343C}, ++ {0xA0000000, 0x00000000}, ++ {0x3020100, 0x0E0CFB0A}, ++ {0x3020101, 0x00100F06}, ++ {0x3020102, 0x34333333}, ++ {0x3020103, 0x3434343C}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x3030000, 0x0E0CFB0A}, + {0x3030001, 0x00100F06}, + {0x3030002, 0x34333333}, + {0x3030003, 0x3434343C}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x3030000, 0x0E0CFB0A}, ++ {0x3030001, 0x00100F06}, ++ {0x3030002, 0x34333327}, ++ {0x3030003, 0x3434343C}, ++ {0xA0000000, 0x00000000}, ++ {0x3030000, 0x0E0CFB0A}, ++ {0x3030001, 0x00100F06}, ++ {0x3030002, 0x34333333}, ++ {0x3030003, 0x3434343C}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, + {0x3030100, 0x0E0CFB0A}, + {0x3030101, 0x00100F06}, + {0x3030102, 0x34333333}, + {0x3030103, 0x3434343C}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x3030100, 0x0E0CFB0A}, ++ {0x3030101, 0x00100F06}, ++ {0x3030102, 0x34333327}, ++ {0x3030103, 0x3434343C}, ++ {0xA0000000, 0x00000000}, ++ {0x3030100, 0x0E0CFB0A}, ++ {0x3030101, 0x00100F06}, ++ {0x3030102, 0x34333333}, ++ {0x3030103, 0x3434343C}, ++ {0xB0000000, 0x00000000}, + {0x3040000, 0x0E0CFB0A}, + {0x3040001, 0x00100F06}, + {0x3040002, 0x343B3333}, +@@ -1765,6 +2231,310 @@ static const struct rtw89_reg2_def rtw89 + {0x3070101, 0x00100F06}, + {0x3070102, 0x3C3B3333}, + {0x3070103, 0x34343C3C}, ++ {0x4000000, 0x00000000}, ++ {0x4000001, 0x76543210}, ++ {0x4000002, 0x77777777}, ++ {0x4000003, 0x35374425}, ++ {0x4000004, 0x00000043}, ++ {0x4000005, 0x000038E8}, ++ {0x4000100, 0x00000000}, ++ {0x4000101, 0x76543210}, ++ {0x4000102, 0x77777777}, ++ {0x4000103, 0x35374425}, ++ {0x4000104, 0x00000043}, ++ {0x4000105, 0x000038E8}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4010000, 0x00000000}, ++ {0x4010001, 0x76543210}, ++ {0x4010002, 0x77777777}, ++ {0x4010003, 0x35374425}, ++ {0x4010004, 0x00000042}, ++ {0x4010005, 0x000038E8}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4010000, 0x0000FC50}, ++ {0x4010001, 0x51403210}, ++ {0x4010002, 0x76543276}, ++ {0x4010003, 0x3A4DAA3C}, ++ {0x4010004, 0x00000093}, ++ {0x4010005, 0x000040E4}, ++ {0xA0000000, 0x00000000}, ++ {0x4010000, 0x00000000}, ++ {0x4010001, 0x76543210}, ++ {0x4010002, 0x77777777}, ++ {0x4010003, 0x35374425}, ++ {0x4010004, 0x00000042}, ++ {0x4010005, 0x000038E8}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4010100, 0x00000000}, ++ {0x4010101, 0x76543210}, ++ {0x4010102, 0x77777777}, ++ {0x4010103, 0x35374425}, ++ {0x4010104, 0x00000042}, ++ {0x4010105, 0x000038E8}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4010100, 0x0000FC50}, ++ {0x4010101, 0x51403210}, ++ {0x4010102, 0x76543276}, ++ {0x4010103, 0x3A4DAA3C}, ++ {0x4010104, 0x00000093}, ++ {0x4010105, 0x000040E4}, ++ {0xA0000000, 0x00000000}, ++ {0x4010100, 0x00000000}, ++ {0x4010101, 0x76543210}, ++ {0x4010102, 0x77777777}, ++ {0x4010103, 0x35374425}, ++ {0x4010104, 0x00000042}, ++ {0x4010105, 0x000038E8}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4020000, 0x00000000}, ++ {0x4020001, 0x76543210}, ++ {0x4020002, 0x77777777}, ++ {0x4020003, 0x35374425}, ++ {0x4020004, 0x00000042}, ++ {0x4020005, 0x000038E8}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4020000, 0x0000FC50}, ++ {0x4020001, 0x51403210}, ++ {0x4020002, 0x76543276}, ++ {0x4020003, 0x4B4DAA3C}, ++ {0x4020004, 0x000000A3}, ++ {0x4020005, 0x000040E4}, ++ {0xA0000000, 0x00000000}, ++ {0x4020000, 0x00000000}, ++ {0x4020001, 0x76543210}, ++ {0x4020002, 0x77777777}, ++ {0x4020003, 0x35374425}, ++ {0x4020004, 0x00000042}, ++ {0x4020005, 0x000038E8}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4020100, 0x00000000}, ++ {0x4020101, 0x76543210}, ++ {0x4020102, 0x77777777}, ++ {0x4020103, 0x35374425}, ++ {0x4020104, 0x00000042}, ++ {0x4020105, 0x000038E8}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4020100, 0x0000FC50}, ++ {0x4020101, 0x51403210}, ++ {0x4020102, 0x76543276}, ++ {0x4020103, 0x3A4DAA3C}, ++ {0x4020104, 0x00000093}, ++ {0x4020105, 0x000040E4}, ++ {0xA0000000, 0x00000000}, ++ {0x4020100, 0x00000000}, ++ {0x4020101, 0x76543210}, ++ {0x4020102, 0x77777777}, ++ {0x4020103, 0x35374425}, ++ {0x4020104, 0x00000042}, ++ {0x4020105, 0x000038E8}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4030000, 0x00000000}, ++ {0x4030001, 0x76543210}, ++ {0x4030002, 0x77777777}, ++ {0x4030003, 0x35374425}, ++ {0x4030004, 0x00000042}, ++ {0x4030005, 0x000038E8}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4030000, 0x0000FC50}, ++ {0x4030001, 0x51403210}, ++ {0x4030002, 0x76543276}, ++ {0x4030003, 0x3A4DAA3C}, ++ {0x4030004, 0x00000093}, ++ {0x4030005, 0x000040E4}, ++ {0xA0000000, 0x00000000}, ++ {0x4030000, 0x00000000}, ++ {0x4030001, 0x76543210}, ++ {0x4030002, 0x77777777}, ++ {0x4030003, 0x35374425}, ++ {0x4030004, 0x00000042}, ++ {0x4030005, 0x000038E8}, ++ {0xB0000000, 0x00000000}, ++ {0x80ff0000, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4030100, 0x00000000}, ++ {0x4030101, 0x76543210}, ++ {0x4030102, 0x77777777}, ++ {0x4030103, 0x35374425}, ++ {0x4030104, 0x00000042}, ++ {0x4030105, 0x000038E8}, ++ {0x903300ff, 0x00000000}, {0x40000000, 0x00000000}, ++ {0x4030100, 0x0000FC50}, ++ {0x4030101, 0x51403210}, ++ {0x4030102, 0x76543276}, ++ {0x4030103, 0x3A4DAA3C}, ++ {0x4030104, 0x00000093}, ++ {0x4030105, 0x000040E4}, ++ {0xA0000000, 0x00000000}, ++ {0x4030100, 0x00000000}, ++ {0x4030101, 0x76543210}, ++ {0x4030102, 0x77777777}, ++ {0x4030103, 0x35374425}, ++ {0x4030104, 0x00000042}, ++ {0x4030105, 0x000038E8}, ++ {0xB0000000, 0x00000000}, ++ {0x1000000, 0x00000008}, ++ {0x1000010, 0x00000008}, ++ {0x1000011, 0x00000000}, ++ {0x1000100, 0x00000004}, ++ {0x1000110, 0x00000004}, ++ {0x1000111, 0x00000000}, ++ {0x1010000, 0x00000004}, ++ {0x1010010, 0x00000004}, ++ {0x1010011, 0x00000000}, ++ {0x1010020, 0x00000004}, ++ {0x1010021, 0x00000000}, ++ {0x1010029, 0x00000000}, ++ {0x1010030, 0x00000000}, ++ {0x1010031, 0x00000000}, ++ {0x1010035, 0x00000000}, ++ {0x1010039, 0x00000000}, ++ {0x101003D, 0x00000000}, ++ {0x1010100, 0x00000010}, ++ {0x1010110, 0x00000010}, ++ {0x1010111, 0x00000000}, ++ {0x1010120, 0x00000010}, ++ {0x1010121, 0x00000000}, ++ {0x1010129, 0x00000000}, ++ {0x1010030, 0x00000000}, ++ {0x1010031, 0x00000000}, ++ {0x1010035, 0x00000000}, ++ {0x1010039, 0x00000000}, ++ {0x101003D, 0x00000000}, ++ {0x1020000, 0x000000FA}, ++ {0x1020010, 0x000000FA}, ++ {0x1020011, 0x00000000}, ++ {0x1020020, 0x000000FA}, ++ {0x1020021, 0x00000000}, ++ {0x1020029, 0x00000000}, ++ {0x1020030, 0x00000000}, ++ {0x1020031, 0x00000000}, ++ {0x1020035, 0x00000000}, ++ {0x1020039, 0x00000000}, ++ {0x102003D, 0x00000000}, ++ {0x1020100, 0x0000000D}, ++ {0x1020110, 0x0000000D}, ++ {0x1020111, 0x00000000}, ++ {0x1020120, 0x0000000D}, ++ {0x1020121, 0x00000000}, ++ {0x1020129, 0x00000000}, ++ {0x1020030, 0x00000000}, ++ {0x1020031, 0x00000000}, ++ {0x1020035, 0x00000000}, ++ {0x1020039, 0x00000000}, ++ {0x102003D, 0x00000000}, ++ {0x1030000, 0x000000E4}, ++ {0x1030010, 0x000000E4}, ++ {0x1030011, 0x00000000}, ++ {0x1030020, 0x0000E8E8}, ++ {0x1030021, 0x00000000}, ++ {0x1030029, 0x00000000}, ++ {0x1030030, 0x00000000}, ++ {0x1030031, 0x00000000}, ++ {0x1030035, 0x00000000}, ++ {0x1030039, 0x00000000}, ++ {0x103003D, 0x00000000}, ++ {0x1030100, 0x00000018}, ++ {0x1030110, 0x00000018}, ++ {0x1030111, 0x00000000}, ++ {0x1030120, 0x00000018}, ++ {0x1030121, 0x00000000}, ++ {0x1030129, 0x00000000}, ++ {0x1030030, 0x00000000}, ++ {0x1030031, 0x00000000}, ++ {0x1030035, 0x00000000}, ++ {0x1030039, 0x00000000}, ++ {0x103003D, 0x00000000}, ++ {0x1040000, 0x000000EE}, ++ {0x1040010, 0x000000EE}, ++ {0x1040011, 0x00000000}, ++ {0x1040020, 0x000000EE}, ++ {0x1040021, 0x00000000}, ++ {0x1040029, 0x00000000}, ++ {0x1040030, 0x000000EE}, ++ {0x1040031, 0x00000000}, ++ {0x1040035, 0x00000000}, ++ {0x1040039, 0x00000000}, ++ {0x104003D, 0x00000000}, ++ {0x1040100, 0x00000000}, ++ {0x1040110, 0x00000005}, ++ {0x1040111, 0x00000000}, ++ {0x1040120, 0x00000008}, ++ {0x1040121, 0x00000000}, ++ {0x1040129, 0x00000000}, ++ {0x1040030, 0x00000008}, ++ {0x1040031, 0x00000000}, ++ {0x1040035, 0x00000000}, ++ {0x1040039, 0x00000000}, ++ {0x104003D, 0x00000000}, ++ {0x1050000, 0x00000008}, ++ {0x1050010, 0x0000000B}, ++ {0x1050011, 0x00000000}, ++ {0x1050020, 0x00000015}, ++ {0x1050021, 0x00000000}, ++ {0x1050029, 0x00000000}, ++ {0x1050030, 0x00000010}, ++ {0x1050031, 0x00000000}, ++ {0x1050035, 0x00000000}, ++ {0x1050039, 0x00000000}, ++ {0x105003D, 0x00000000}, ++ {0x1050100, 0x00000016}, ++ {0x1050110, 0x00000016}, ++ {0x1050111, 0x0000F8F8}, ++ {0x1050120, 0x0000001A}, ++ {0x1050121, 0x00000000}, ++ {0x1050129, 0x00000000}, ++ {0x1050030, 0x0000001A}, ++ {0x1050031, 0x00000000}, ++ {0x1050035, 0x00000000}, ++ {0x1050039, 0x00000000}, ++ {0x105003D, 0x00000000}, ++ {0x1060000, 0x000000F8}, ++ {0x1060010, 0x000000F8}, ++ {0x1060011, 0x00000000}, ++ {0x1060020, 0x00000000}, ++ {0x1060021, 0x00000000}, ++ {0x1060029, 0x00000000}, ++ {0x1060030, 0x00000000}, ++ {0x1060031, 0x00000000}, ++ {0x1060035, 0x00000000}, ++ {0x1060039, 0x00000000}, ++ {0x106003D, 0x00000000}, ++ {0x1060100, 0x000000F6}, ++ {0x1060110, 0x000000F6}, ++ {0x1060111, 0x00000000}, ++ {0x1060120, 0x000000F6}, ++ {0x1060121, 0x00000000}, ++ {0x1060129, 0x00000000}, ++ {0x1060030, 0x00000000}, ++ {0x1060031, 0x00000000}, ++ {0x1060035, 0x00000000}, ++ {0x1060039, 0x00000000}, ++ {0x106003D, 0x00000000}, ++ {0x1070000, 0x000000E8}, ++ {0x1070010, 0x000000E8}, ++ {0x1070011, 0x00000000}, ++ {0x1070020, 0x000000E8}, ++ {0x1070021, 0x00000000}, ++ {0x1070029, 0x00000000}, ++ {0x1070030, 0x000000F0}, ++ {0x1070031, 0x00000000}, ++ {0x1070035, 0x00000000}, ++ {0x1070039, 0x00000000}, ++ {0x107003D, 0x00000000}, ++ {0x1070100, 0x000000E4}, ++ {0x1070110, 0x000000E4}, ++ {0x1070111, 0x00000000}, ++ {0x1070120, 0x000000E4}, ++ {0x1070121, 0x00000000}, ++ {0x1070129, 0x00000000}, ++ {0x1070030, 0x000000F0}, ++ {0x1070031, 0x00000000}, ++ {0x1070035, 0x00000000}, ++ {0x1070039, 0x00000000}, ++ {0x107003D, 0x00000000}, + }; + + static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/txrx.h linux-6.2/drivers/net/wireless/realtek/rtw89/txrx.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/txrx.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/txrx.h 2022-12-24 00:49:25.786376835 +0200 +@@ -298,7 +298,9 @@ + le32_get_bits(*((const __le32 *)ie), GENMASK(11, 5)) + #define RTW89_GET_PHY_STS_IE01_CH_IDX(ie) \ + le32_get_bits(*((const __le32 *)ie), GENMASK(23, 16)) +-#define RTW89_GET_PHY_STS_IE01_CFO(ie) \ ++#define RTW89_GET_PHY_STS_IE01_FD_CFO(ie) \ ++ le32_get_bits(*((const __le32 *)(ie) + 1), GENMASK(19, 8)) ++#define RTW89_GET_PHY_STS_IE01_PREMB_CFO(ie) \ + le32_get_bits(*((const __le32 *)(ie) + 1), GENMASK(31, 20)) + + enum rtw89_tx_channel { +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/util.h linux-6.2/drivers/net/wireless/realtek/rtw89/util.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/util.h 2022-12-12 00:15:18.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/util.h 2022-12-24 00:49:25.786376835 +0200 +@@ -44,4 +44,15 @@ static inline s32 s32_div_u32_round_clos + return s32_div_u32_round_down(dividend + divisor / 2, divisor, NULL); + } + ++static inline void ether_addr_copy_mask(u8 *dst, const u8 *src, u8 mask) ++{ ++ int i; ++ ++ eth_zero_addr(dst); ++ for (i = 0; i < ETH_ALEN; i++) { ++ if (mask & BIT(i)) ++ dst[i] = src[i]; ++ } ++} ++ + #endif +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/wow.c linux-6.2/drivers/net/wireless/realtek/rtw89/wow.c +--- linux-6.1/drivers/net/wireless/realtek/rtw89/wow.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/wow.c 2022-12-24 00:49:25.786376835 +0200 +@@ -0,0 +1,859 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause ++/* Copyright(c) 2019-2022 Realtek Corporation ++ */ ++#include "cam.h" ++#include "core.h" ++#include "debug.h" ++#include "fw.h" ++#include "mac.h" ++#include "phy.h" ++#include "ps.h" ++#include "reg.h" ++#include "util.h" ++#include "wow.h" ++ ++static void rtw89_wow_leave_deep_ps(struct rtw89_dev *rtwdev) ++{ ++ __rtw89_leave_ps_mode(rtwdev); ++} ++ ++static void rtw89_wow_enter_deep_ps(struct rtw89_dev *rtwdev) ++{ ++ struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; ++ struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; ++ ++ __rtw89_enter_ps_mode(rtwdev, rtwvif); ++} ++ ++static void rtw89_wow_enter_lps(struct rtw89_dev *rtwdev) ++{ ++ struct ieee80211_vif *wow_vif = rtwdev->wow.wow_vif; ++ struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; ++ ++ rtw89_enter_lps(rtwdev, rtwvif); ++} ++ ++static void rtw89_wow_leave_lps(struct rtw89_dev *rtwdev) ++{ ++ rtw89_leave_lps(rtwdev); ++} ++ ++static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow) ++{ ++ int ret; ++ ++ if (enable_wow) { ++ ret = rtw89_mac_resize_ple_rx_quota(rtwdev, true); ++ if (ret) { ++ rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); ++ return ret; ++ } ++ rtw89_write32_set(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); ++ rtw89_write32_clr(rtwdev, R_AX_RX_FLTR_OPT, B_AX_SNIFFER_MODE); ++ rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); ++ rtw89_write32(rtwdev, R_AX_ACTION_FWD0, 0); ++ rtw89_write32(rtwdev, R_AX_ACTION_FWD1, 0); ++ rtw89_write32(rtwdev, R_AX_TF_FWD, 0); ++ rtw89_write32(rtwdev, R_AX_HW_RPT_FWD, 0); ++ } else { ++ ret = rtw89_mac_resize_ple_rx_quota(rtwdev, false); ++ if (ret) { ++ rtw89_err(rtwdev, "[ERR]patch rx qta %d\n", ret); ++ return ret; ++ } ++ rtw89_write32_clr(rtwdev, R_AX_RX_FUNCTION_STOP, B_AX_HDR_RX_STOP); ++ rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); ++ rtw89_write32(rtwdev, R_AX_ACTION_FWD0, TRXCFG_MPDU_PROC_ACT_FRWD); ++ rtw89_write32(rtwdev, R_AX_TF_FWD, TRXCFG_MPDU_PROC_TF_FRWD); ++ } ++ ++ return 0; ++} ++ ++static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable) ++{ ++ enum rtw89_mac_fwd_target fwd_target = enable ? ++ RTW89_FWD_DONT_CARE : ++ RTW89_FWD_TO_HOST; ++ ++ rtw89_mac_typ_fltr_opt(rtwdev, RTW89_MGNT, fwd_target, RTW89_MAC_0); ++ rtw89_mac_typ_fltr_opt(rtwdev, RTW89_CTRL, fwd_target, RTW89_MAC_0); ++ rtw89_mac_typ_fltr_opt(rtwdev, RTW89_DATA, fwd_target, RTW89_MAC_0); ++} ++ ++static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) ++{ ++ enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; ++ struct cfg80211_wowlan_nd_info nd_info; ++ struct cfg80211_wowlan_wakeup wakeup = { ++ .pattern_idx = -1, ++ }; ++ u32 wow_reason_reg; ++ u8 reason; ++ ++ if (chip_id == RTL8852A || chip_id == RTL8852B) ++ wow_reason_reg = R_AX_C2HREG_DATA3 + 3; ++ else ++ wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3; ++ ++ reason = rtw89_read8(rtwdev, wow_reason_reg); ++ ++ switch (reason) { ++ case RTW89_WOW_RSN_RX_DEAUTH: ++ wakeup.disconnect = true; ++ rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx deauth\n"); ++ break; ++ case RTW89_WOW_RSN_DISCONNECT: ++ wakeup.disconnect = true; ++ rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: AP is off\n"); ++ break; ++ case RTW89_WOW_RSN_RX_MAGIC_PKT: ++ wakeup.magic_pkt = true; ++ rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx magic packet\n"); ++ break; ++ case RTW89_WOW_RSN_RX_GTK_REKEY: ++ wakeup.gtk_rekey_failure = true; ++ rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx gtk rekey\n"); ++ break; ++ case RTW89_WOW_RSN_RX_PATTERN_MATCH: ++ /* Current firmware and driver don't report pattern index ++ * Use pattern_idx to 0 defaultly. ++ */ ++ wakeup.pattern_idx = 0; ++ rtw89_debug(rtwdev, RTW89_DBG_WOW, "WOW: Rx pattern match packet\n"); ++ break; ++ case RTW89_WOW_RSN_RX_NLO: ++ /* Current firmware and driver don't report ssid index. ++ * Use 0 for n_matches based on its comment. ++ */ ++ nd_info.n_matches = 0; ++ wakeup.net_detect = &nd_info; ++ rtw89_debug(rtwdev, RTW89_DBG_WOW, "Rx NLO\n"); ++ break; ++ default: ++ rtw89_warn(rtwdev, "Unknown wakeup reason %x\n", reason); ++ ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, NULL, ++ GFP_KERNEL); ++ return; ++ } ++ ++ ieee80211_report_wowlan_wakeup(rtwdev->wow.wow_vif, &wakeup, ++ GFP_KERNEL); ++} ++ ++static void rtw89_wow_vif_iter(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); ++ ++ /* Current wowlan function support setting of only one STATION vif. ++ * So when one suitable vif is found, stop the iteration. ++ */ ++ if (rtw_wow->wow_vif || vif->type != NL80211_IFTYPE_STATION) ++ return; ++ ++ switch (rtwvif->net_type) { ++ case RTW89_NET_TYPE_INFRA: ++ rtw_wow->wow_vif = vif; ++ break; ++ case RTW89_NET_TYPE_NO_LINK: ++ default: ++ break; ++ } ++} ++ ++static u16 __rtw89_cal_crc16(u8 data, u16 crc) ++{ ++ u8 shift_in, data_bit; ++ u8 crc_bit4, crc_bit11, crc_bit15; ++ u16 crc_result; ++ int index; ++ ++ for (index = 0; index < 8; index++) { ++ crc_bit15 = crc & BIT(15) ? 1 : 0; ++ data_bit = data & BIT(index) ? 1 : 0; ++ shift_in = crc_bit15 ^ data_bit; ++ ++ crc_result = crc << 1; ++ ++ if (shift_in == 0) ++ crc_result &= ~BIT(0); ++ else ++ crc_result |= BIT(0); ++ ++ crc_bit11 = (crc & BIT(11) ? 1 : 0) ^ shift_in; ++ ++ if (crc_bit11 == 0) ++ crc_result &= ~BIT(12); ++ else ++ crc_result |= BIT(12); ++ ++ crc_bit4 = (crc & BIT(4) ? 1 : 0) ^ shift_in; ++ ++ if (crc_bit4 == 0) ++ crc_result &= ~BIT(5); ++ else ++ crc_result |= BIT(5); ++ ++ crc = crc_result; ++ } ++ return crc; ++} ++ ++static u16 rtw89_calc_crc(u8 *pdata, int length) ++{ ++ u16 crc = 0xffff; ++ int i; ++ ++ for (i = 0; i < length; i++) ++ crc = __rtw89_cal_crc16(pdata[i], crc); ++ ++ /* get 1' complement */ ++ return ~crc; ++} ++ ++static int rtw89_wow_pattern_get_type(struct rtw89_vif *rtwvif, ++ struct rtw89_wow_cam_info *rtw_pattern, ++ const u8 *pattern, u8 da_mask) ++{ ++ u8 da[ETH_ALEN]; ++ ++ ether_addr_copy_mask(da, pattern, da_mask); ++ ++ /* Each pattern is divided into different kinds by DA address ++ * a. DA is broadcast address: set bc = 0; ++ * b. DA is multicast address: set mc = 0 ++ * c. DA is unicast address same as dev's mac address: set uc = 0 ++ * d. DA is unmasked. Also called wildcard type: set uc = bc = mc = 0 ++ * e. Others is invalid type. ++ */ ++ ++ if (is_broadcast_ether_addr(da)) ++ rtw_pattern->bc = true; ++ else if (is_multicast_ether_addr(da)) ++ rtw_pattern->mc = true; ++ else if (ether_addr_equal(da, rtwvif->mac_addr) && ++ da_mask == GENMASK(5, 0)) ++ rtw_pattern->uc = true; ++ else if (!da_mask) /*da_mask == 0 mean wildcard*/ ++ return 0; ++ else ++ return -EPERM; ++ ++ return 0; ++} ++ ++static int rtw89_wow_pattern_generate(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, ++ const struct cfg80211_pkt_pattern *pkt_pattern, ++ struct rtw89_wow_cam_info *rtw_pattern) ++{ ++ u8 mask_hw[RTW89_MAX_PATTERN_MASK_SIZE * 4] = {0}; ++ u8 content[RTW89_MAX_PATTERN_SIZE] = {0}; ++ const u8 *mask; ++ const u8 *pattern; ++ u8 mask_len; ++ u16 count; ++ u32 len; ++ int i, ret; ++ ++ pattern = pkt_pattern->pattern; ++ len = pkt_pattern->pattern_len; ++ mask = pkt_pattern->mask; ++ mask_len = DIV_ROUND_UP(len, 8); ++ memset(rtw_pattern, 0, sizeof(*rtw_pattern)); ++ ++ ret = rtw89_wow_pattern_get_type(rtwvif, rtw_pattern, pattern, ++ mask[0] & GENMASK(5, 0)); ++ if (ret) ++ return ret; ++ ++ /* translate mask from os to mask for hw ++ * pattern from OS uses 'ethenet frame', like this: ++ * | 6 | 6 | 2 | 20 | Variable | 4 | ++ * |--------+--------+------+-----------+------------+-----| ++ * | 802.3 Mac Header | IP Header | TCP Packet | FCS | ++ * | DA | SA | Type | ++ * ++ * BUT, packet catched by our HW is in '802.11 frame', begin from LLC ++ * | 24 or 30 | 6 | 2 | 20 | Variable | 4 | ++ * |-------------------+--------+------+-----------+------------+-----| ++ * | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS | ++ * | Others | Tpye | ++ * ++ * Therefore, we need translate mask_from_OS to mask_to_hw. ++ * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, ++ * because new mask[0~5] means 'SA', but our HW packet begins from LLC, ++ * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. ++ */ ++ ++ /* Shift 6 bits */ ++ for (i = 0; i < mask_len - 1; i++) { ++ mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6)) | ++ u8_get_bits(mask[i + 1], GENMASK(5, 0)) << 2; ++ } ++ mask_hw[i] = u8_get_bits(mask[i], GENMASK(7, 6)); ++ ++ /* Set bit 0-5 to zero */ ++ mask_hw[0] &= ~GENMASK(5, 0); ++ ++ memcpy(rtw_pattern->mask, mask_hw, sizeof(rtw_pattern->mask)); ++ ++ /* To get the wake up pattern from the mask. ++ * We do not count first 12 bits which means ++ * DA[6] and SA[6] in the pattern to match HW design. ++ */ ++ count = 0; ++ for (i = 12; i < len; i++) { ++ if ((mask[i / 8] >> (i % 8)) & 0x01) { ++ content[count] = pattern[i]; ++ count++; ++ } ++ } ++ ++ rtw_pattern->crc = rtw89_calc_crc(content, count); ++ ++ return 0; ++} ++ ++static int rtw89_wow_parse_patterns(struct rtw89_dev *rtwdev, ++ struct rtw89_vif *rtwvif, ++ struct cfg80211_wowlan *wowlan) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; ++ int i; ++ int ret; ++ ++ if (!wowlan->n_patterns || !wowlan->patterns) ++ return 0; ++ ++ for (i = 0; i < wowlan->n_patterns; i++) { ++ rtw_pattern = &rtw_wow->patterns[i]; ++ ret = rtw89_wow_pattern_generate(rtwdev, rtwvif, ++ &wowlan->patterns[i], ++ rtw_pattern); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to generate pattern(%d)\n", i); ++ rtw_wow->pattern_cnt = 0; ++ return ret; ++ } ++ ++ rtw_pattern->r_w = true; ++ rtw_pattern->idx = i; ++ rtw_pattern->negative_pattern_match = false; ++ rtw_pattern->skip_mac_hdr = true; ++ rtw_pattern->valid = true; ++ } ++ rtw_wow->pattern_cnt = wowlan->n_patterns; ++ ++ return 0; ++} ++ ++static void rtw89_wow_pattern_clear_cam(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; ++ int i = 0; ++ ++ for (i = 0; i < rtw_wow->pattern_cnt; i++) { ++ rtw_pattern = &rtw_wow->patterns[i]; ++ rtw_pattern->valid = false; ++ rtw89_fw_wow_cam_update(rtwdev, rtw_pattern); ++ } ++} ++ ++static void rtw89_wow_pattern_write(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct rtw89_wow_cam_info *rtw_pattern = rtw_wow->patterns; ++ int i; ++ ++ for (i = 0; i < rtw_wow->pattern_cnt; i++) ++ rtw89_fw_wow_cam_update(rtwdev, rtw_pattern + i); ++} ++ ++static void rtw89_wow_pattern_clear(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ ++ rtw89_wow_pattern_clear_cam(rtwdev); ++ ++ rtw_wow->pattern_cnt = 0; ++ memset(rtw_wow->patterns, 0, sizeof(rtw_wow->patterns)); ++} ++ ++static void rtw89_wow_clear_wakeups(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ ++ rtw_wow->wow_vif = NULL; ++ rtw89_core_release_all_bits_map(rtw_wow->flags, RTW89_WOW_FLAG_NUM); ++ rtw_wow->pattern_cnt = 0; ++} ++ ++static int rtw89_wow_set_wakeups(struct rtw89_dev *rtwdev, ++ struct cfg80211_wowlan *wowlan) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct rtw89_vif *rtwvif; ++ ++ if (wowlan->disconnect) ++ set_bit(RTW89_WOW_FLAG_EN_DISCONNECT, rtw_wow->flags); ++ if (wowlan->magic_pkt) ++ set_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags); ++ ++ rtw89_for_each_rtwvif(rtwdev, rtwvif) ++ rtw89_wow_vif_iter(rtwdev, rtwvif); ++ ++ if (!rtw_wow->wow_vif) ++ return -EPERM; ++ ++ rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; ++ return rtw89_wow_parse_patterns(rtwdev, rtwvif, wowlan); ++} ++ ++static int rtw89_wow_cfg_wake(struct rtw89_dev *rtwdev, bool wow) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; ++ struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; ++ struct ieee80211_sta *wow_sta; ++ struct rtw89_sta *rtwsta = NULL; ++ bool is_conn = true; ++ int ret; ++ ++ wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); ++ if (wow_sta) ++ rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; ++ else ++ is_conn = false; ++ ++ if (wow) { ++ if (rtw_wow->pattern_cnt) ++ rtwvif->wowlan_pattern = true; ++ if (test_bit(RTW89_WOW_FLAG_EN_MAGIC_PKT, rtw_wow->flags)) ++ rtwvif->wowlan_magic = true; ++ } else { ++ rtwvif->wowlan_pattern = false; ++ rtwvif->wowlan_magic = false; ++ } ++ ++ ret = rtw89_fw_h2c_wow_wakeup_ctrl(rtwdev, rtwvif, wow); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to fw wow wakeup ctrl\n"); ++ return ret; ++ } ++ ++ if (wow) { ++ ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to update dctl cam sec entry: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ ++ ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn); ++ if (ret) { ++ rtw89_warn(rtwdev, "failed to send h2c join info\n"); ++ return ret; ++ } ++ ++ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); ++ if (ret) { ++ rtw89_warn(rtwdev, "failed to send h2c cam\n"); ++ return ret; ++ } ++ ++ ret = rtw89_fw_h2c_wow_global(rtwdev, rtwvif, wow); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to fw wow global\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rtw89_wow_check_fw_status(struct rtw89_dev *rtwdev, bool wow_enable) ++{ ++ u8 polling; ++ int ret; ++ ++ ret = read_poll_timeout_atomic(rtw89_read8_mask, polling, ++ wow_enable == !!polling, ++ 50, 50000, false, rtwdev, ++ R_AX_WOW_CTRL, B_AX_WOW_WOWEN); ++ if (ret) ++ rtw89_err(rtwdev, "failed to check wow status %s\n", ++ wow_enable ? "enabled" : "disabled"); ++ return ret; ++} ++ ++static void rtw89_wow_release_pkt_list(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct list_head *pkt_list = &rtw_wow->pkt_list; ++ struct rtw89_pktofld_info *info, *tmp; ++ ++ list_for_each_entry_safe(info, tmp, pkt_list, list) { ++ rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); ++ rtw89_core_release_bit_map(rtwdev->pkt_offload, ++ info->id); ++ list_del(&info->list); ++ kfree(info); ++ } ++} ++ ++static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) ++{ ++ enum rtw89_fw_type fw_type = wow ? RTW89_FW_WOWLAN : RTW89_FW_NORMAL; ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct ieee80211_vif *wow_vif = rtw_wow->wow_vif; ++ struct rtw89_vif *rtwvif = (struct rtw89_vif *)wow_vif->drv_priv; ++ struct ieee80211_sta *wow_sta; ++ struct rtw89_sta *rtwsta = NULL; ++ bool is_conn = true; ++ int ret; ++ ++ rtw89_hci_disable_intr(rtwdev); ++ ++ wow_sta = ieee80211_find_sta(wow_vif, rtwvif->bssid); ++ if (wow_sta) ++ rtwsta = (struct rtw89_sta *)wow_sta->drv_priv; ++ else ++ is_conn = false; ++ ++ ret = rtw89_fw_download(rtwdev, fw_type); ++ if (ret) { ++ rtw89_warn(rtwdev, "download fw failed\n"); ++ return ret; ++ } ++ ++ rtw89_phy_init_rf_reg(rtwdev, true); ++ ++ ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, ++ RTW89_ROLE_FW_RESTORE); ++ if (ret) { ++ rtw89_warn(rtwdev, "failed to send h2c role maintain\n"); ++ return ret; ++ } ++ ++ ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); ++ if (ret) { ++ rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n"); ++ return ret; ++ } ++ ++ if (!is_conn) ++ rtw89_cam_reset_keys(rtwdev); ++ ++ ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, !is_conn); ++ if (ret) { ++ rtw89_warn(rtwdev, "failed to send h2c join info\n"); ++ return ret; ++ } ++ ++ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL); ++ if (ret) { ++ rtw89_warn(rtwdev, "failed to send h2c cam\n"); ++ return ret; ++ } ++ ++ if (is_conn) { ++ rtw89_phy_ra_assoc(rtwdev, wow_sta); ++ rtw89_phy_set_bss_color(rtwdev, wow_vif); ++ rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, wow_vif); ++ } ++ ++ rtw89_mac_hw_mgnt_sec(rtwdev, wow); ++ rtw89_hci_enable_intr(rtwdev); ++ ++ return 0; ++} ++ ++static int rtw89_wow_enable_trx_pre(struct rtw89_dev *rtwdev) ++{ ++ int ret; ++ ++ rtw89_hci_ctrl_txdma_ch(rtwdev, false); ++ rtw89_hci_ctrl_txdma_fw_ch(rtwdev, true); ++ ++ rtw89_mac_ptk_drop_by_band_and_wait(rtwdev, RTW89_MAC_0); ++ ++ ret = rtw89_hci_poll_txdma_ch(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "txdma ch busy\n"); ++ return ret; ++ } ++ rtw89_wow_set_rx_filter(rtwdev, true); ++ ++ ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); ++ if (ret) { ++ rtw89_err(rtwdev, "cfg ppdu status\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rtw89_wow_enable_trx_post(struct rtw89_dev *rtwdev) ++{ ++ int ret; ++ ++ rtw89_hci_disable_intr(rtwdev); ++ rtw89_hci_ctrl_trxhci(rtwdev, false); ++ ++ ret = rtw89_hci_poll_txdma_ch(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to poll txdma ch idle pcie\n"); ++ return ret; ++ } ++ ++ ret = rtw89_wow_config_mac(rtwdev, true); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to config mac\n"); ++ return ret; ++ } ++ ++ rtw89_wow_set_rx_filter(rtwdev, false); ++ rtw89_hci_reset(rtwdev); ++ ++ return 0; ++} ++ ++static int rtw89_wow_disable_trx_pre(struct rtw89_dev *rtwdev) ++{ ++ int ret; ++ ++ rtw89_hci_clr_idx_all(rtwdev); ++ ++ ret = rtw89_hci_rst_bdram(rtwdev); ++ if (ret) { ++ rtw89_warn(rtwdev, "reset bdram busy\n"); ++ return ret; ++ } ++ ++ rtw89_hci_ctrl_trxhci(rtwdev, true); ++ rtw89_hci_ctrl_txdma_ch(rtwdev, true); ++ ++ ret = rtw89_wow_config_mac(rtwdev, false); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to config mac\n"); ++ return ret; ++ } ++ rtw89_hci_enable_intr(rtwdev); ++ ++ return 0; ++} ++ ++static int rtw89_wow_disable_trx_post(struct rtw89_dev *rtwdev) ++{ ++ int ret; ++ ++ ret = rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); ++ if (ret) ++ rtw89_err(rtwdev, "cfg ppdu status\n"); ++ ++ return ret; ++} ++ ++static int rtw89_wow_fw_start(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; ++ int ret; ++ ++ rtw89_wow_pattern_write(rtwdev); ++ ++ ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, true); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to enable keep alive\n"); ++ return ret; ++ } ++ ++ ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, true); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to enable disconnect detect\n"); ++ goto out; ++ } ++ ++ ret = rtw89_wow_cfg_wake(rtwdev, true); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to config wake\n"); ++ goto out; ++ } ++ ++ ret = rtw89_wow_check_fw_status(rtwdev, true); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to check enable fw ready\n"); ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++static int rtw89_wow_fw_stop(struct rtw89_dev *rtwdev) ++{ ++ struct rtw89_wow_param *rtw_wow = &rtwdev->wow; ++ struct rtw89_vif *rtwvif = (struct rtw89_vif *)rtw_wow->wow_vif->drv_priv; ++ int ret; ++ ++ rtw89_wow_pattern_clear(rtwdev); ++ ++ ret = rtw89_fw_h2c_keep_alive(rtwdev, rtwvif, false); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to disable keep alive\n"); ++ goto out; ++ } ++ ++ rtw89_wow_release_pkt_list(rtwdev); ++ ++ ret = rtw89_fw_h2c_disconnect_detect(rtwdev, rtwvif, false); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to disable disconnect detect\n"); ++ goto out; ++ } ++ ++ ret = rtw89_wow_cfg_wake(rtwdev, false); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to disable config wake\n"); ++ goto out; ++ } ++ ++ ret = rtw89_wow_check_fw_status(rtwdev, false); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to check disable fw ready\n"); ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++static int rtw89_wow_enable(struct rtw89_dev *rtwdev) ++{ ++ int ret; ++ ++ set_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); ++ ++ ret = rtw89_wow_enable_trx_pre(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to enable trx_pre\n"); ++ goto out; ++ } ++ ++ ret = rtw89_wow_swap_fw(rtwdev, true); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to swap to wow fw\n"); ++ goto out; ++ } ++ ++ ret = rtw89_wow_fw_start(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to let wow fw start\n"); ++ goto out; ++ } ++ ++ rtw89_wow_enter_lps(rtwdev); ++ ++ ret = rtw89_wow_enable_trx_post(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to enable trx_post\n"); ++ goto out; ++ } ++ ++ return 0; ++ ++out: ++ clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); ++ return ret; ++} ++ ++static int rtw89_wow_disable(struct rtw89_dev *rtwdev) ++{ ++ int ret; ++ ++ ret = rtw89_wow_disable_trx_pre(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to disable trx_pre\n"); ++ goto out; ++ } ++ ++ rtw89_wow_leave_lps(rtwdev); ++ ++ ret = rtw89_wow_fw_stop(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to swap to normal fw\n"); ++ goto out; ++ } ++ ++ ret = rtw89_wow_swap_fw(rtwdev, false); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to disable trx_post\n"); ++ goto out; ++ } ++ ++ ret = rtw89_wow_disable_trx_post(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "wow: failed to disable trx_pre\n"); ++ goto out; ++ } ++ ++out: ++ clear_bit(RTW89_FLAG_WOWLAN, rtwdev->flags); ++ return ret; ++} ++ ++int rtw89_wow_resume(struct rtw89_dev *rtwdev) ++{ ++ int ret; ++ ++ if (!test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) { ++ rtw89_err(rtwdev, "wow is not enabled\n"); ++ ret = -EPERM; ++ goto out; ++ } ++ ++ if (!rtw89_mac_get_power_state(rtwdev)) { ++ rtw89_err(rtwdev, "chip is no power when resume\n"); ++ ret = -EPERM; ++ goto out; ++ } ++ ++ rtw89_wow_leave_deep_ps(rtwdev); ++ ++ rtw89_wow_show_wakeup_reason(rtwdev); ++ ++ ret = rtw89_wow_disable(rtwdev); ++ if (ret) ++ rtw89_err(rtwdev, "failed to disable wow\n"); ++ ++out: ++ rtw89_wow_clear_wakeups(rtwdev); ++ return ret; ++} ++ ++int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan) ++{ ++ int ret; ++ ++ ret = rtw89_wow_set_wakeups(rtwdev, wowlan); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to set wakeup event\n"); ++ return ret; ++ } ++ ++ rtw89_wow_leave_lps(rtwdev); ++ ++ ret = rtw89_wow_enable(rtwdev); ++ if (ret) { ++ rtw89_err(rtwdev, "failed to enable wow\n"); ++ return ret; ++ } ++ ++ rtw89_wow_enter_deep_ps(rtwdev); ++ ++ return 0; ++} +diff -Nurp linux-6.1/drivers/net/wireless/realtek/rtw89/wow.h linux-6.2/drivers/net/wireless/realtek/rtw89/wow.h +--- linux-6.1/drivers/net/wireless/realtek/rtw89/wow.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.2/drivers/net/wireless/realtek/rtw89/wow.h 2022-12-24 00:49:25.786376835 +0200 +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2019-2022 Realtek Corporation ++ */ ++ ++#ifndef __RTW89_WOW_H__ ++#define __RTW89_WOW_H__ ++ ++enum rtw89_wake_reason { ++ RTW89_WOW_RSN_RX_PTK_REKEY = 0x1, ++ RTW89_WOW_RSN_RX_GTK_REKEY = 0x2, ++ RTW89_WOW_RSN_RX_DEAUTH = 0x8, ++ RTW89_WOW_RSN_DISCONNECT = 0x10, ++ RTW89_WOW_RSN_RX_MAGIC_PKT = 0x21, ++ RTW89_WOW_RSN_RX_PATTERN_MATCH = 0x23, ++ RTW89_WOW_RSN_RX_NLO = 0x55, ++}; ++ ++int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan); ++int rtw89_wow_resume(struct rtw89_dev *rtwdev); ++ ++#endif 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 index dfe13ed441..257b0d70b2 100644 --- 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 @@ -6,9 +6,9 @@ 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 +diff -up linux-6.11/Documentation/ABI/testing/sysfs-platform-shuttle-wmi.wmi linux-6.11/Documentation/ABI/testing/sysfs-platform-shuttle-wmi +--- linux-6.11/Documentation/ABI/testing/sysfs-platform-shuttle-wmi.wmi 2024-11-18 10:43:15.072608505 +0100 ++++ linux-6.11/Documentation/ABI/testing/sysfs-platform-shuttle-wmi 2024-11-18 10:43:15.072608505 +0100 @@ -0,0 +1,72 @@ +What: /sys/devices/platform/shuttle_wmi/lcd_auto_adjust +Date: December 2010 @@ -82,10 +82,10 @@ diff -Nurp linux-5.15.1/Documentation/ABI/testing/sysfs-platform-shuttle-wmi lin + 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 +diff -up linux-6.11/drivers/platform/x86/Kconfig.wmi linux-6.11/drivers/platform/x86/Kconfig +--- linux-6.11/drivers/platform/x86/Kconfig.wmi 2024-11-18 00:42:21.841340904 +0100 ++++ linux-6.11/drivers/platform/x86/Kconfig 2024-11-18 10:43:15.072608505 +0100 +@@ -947,6 +947,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. @@ -107,10 +107,10 @@ diff -Nurp linux-5.15.1/drivers/platform/x86/Kconfig linux-5.15.1-shuttle/driver 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 +diff -up linux-6.11/drivers/platform/x86/Makefile.wmi linux-6.11/drivers/platform/x86/Makefile +--- linux-6.11/drivers/platform/x86/Makefile.wmi 2024-09-15 16:57:56.000000000 +0200 ++++ linux-6.11/drivers/platform/x86/Makefile 2024-11-18 10:43:15.072608505 +0100 +@@ -98,6 +98,9 @@ obj-$(CONFIG_BARCO_P50_GPIO) += barco-p5 obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o @@ -120,9 +120,9 @@ diff -Nurp linux-5.15.1/drivers/platform/x86/Makefile linux-5.15.1-shuttle/drive # 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 +diff -up linux-6.11/drivers/platform/x86/shuttle-wmi.c.wmi linux-6.11/drivers/platform/x86/shuttle-wmi.c +--- linux-6.11/drivers/platform/x86/shuttle-wmi.c.wmi 2024-11-18 10:43:15.072608505 +0100 ++++ linux-6.11/drivers/platform/x86/shuttle-wmi.c 2024-11-18 10:43:15.072608505 +0100 @@ -0,0 +1,1297 @@ +/* + * ACPI-WMI driver for Shuttle WMI interface @@ -1421,19 +1421,19 @@ diff -Nurp linux-5.15.1/drivers/platform/x86/shuttle-wmi.c linux-5.15.1-shuttle/ + +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 +diff -up linux-6.11/MAINTAINERS.wmi linux-6.11/MAINTAINERS +--- linux-6.11/MAINTAINERS.wmi 2024-11-18 00:42:21.251332731 +0100 ++++ linux-6.11/MAINTAINERS 2024-11-18 10:43:15.076608549 +0100 +@@ -20958,6 +20958,12 @@ S: Orphan + F: drivers/media/platform/renesas/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 ++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 + S: Orphan diff --git a/kernel/tools/perf/files/patches/mageia/staging-add-r8188eu.patch b/kernel/tools/perf/files/patches/mageia/staging-add-r8188eu.patch new file mode 100644 index 0000000000..d1c75633d8 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/staging-add-r8188eu.patch @@ -0,0 +1,81013 @@ +diff --git a/drivers/staging/r8188eu/Kconfig b/drivers/staging/r8188eu/Kconfig +new file mode 100644 +index 000000000000..dc1719d3f2e4 +--- /dev/null ++++ b/drivers/staging/r8188eu/Kconfig +@@ -0,0 +1,26 @@ ++# SPDX-License-Identifier: GPL-2.0 ++config R8188EU ++ tristate "Realtek RTL8188EU Wireless LAN NIC driver" ++ depends on WLAN && USB && CFG80211 ++ depends on m ++ select WIRELESS_EXT ++ select WEXT_PRIV ++ select LIB80211 ++ select LIB80211_CRYPT_WEP ++ select LIB80211_CRYPT_CCMP ++ help ++ This option adds support for the Realtek RTL8188EU chipset, used in USB ++ devices such as the ASUS USB-N10 Nano. This newer driver is based on GitHub ++ sources for version v4.1.4_6773.20130222, and contains modifications for ++ newer kernel features. If built as a module, it will be called r8188eu. ++ ++if R8188EU ++ ++config 88EU_AP_MODE ++ bool "Realtek RTL8188EU AP mode" ++ help ++ This option enables Access Point mode. Unless you know that your system ++ will never be used as an AP, or the target system has limited memory, ++ "Y" should be selected. ++ ++endif +diff --git a/drivers/staging/r8188eu/Makefile b/drivers/staging/r8188eu/Makefile +new file mode 100644 +index 000000000000..aebaf29990fd +--- /dev/null ++++ b/drivers/staging/r8188eu/Makefile +@@ -0,0 +1,105 @@ ++SHELL := /bin/bash ++EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) ++EXTRA_CFLAGS += -O1 ++ ++ccflags-y += -D__CHECK_ENDIAN__ ++ ++CONFIG_BT_COEXIST = n ++CONFIG_WOWLAN = n ++ ++OUTSRC_FILES := \ ++ hal/HalHWImg8188E_MAC.o \ ++ hal/HalHWImg8188E_BB.o \ ++ hal/HalHWImg8188E_RF.o \ ++ hal/HalPhyRf_8188e.o \ ++ hal/HalPwrSeqCmd.o \ ++ hal/Hal8188EPwrSeq.o \ ++ hal/Hal8188ERateAdaptive.o\ ++ hal/hal_intf.o \ ++ hal/hal_com.o \ ++ hal/odm.o \ ++ hal/odm_debug.o \ ++ hal/odm_interface.o \ ++ hal/odm_HWConfig.o \ ++ hal/odm_RegConfig8188E.o\ ++ hal/odm_RTL8188E.o \ ++ hal/rtl8188e_cmd.o \ ++ hal/rtl8188e_dm.o \ ++ hal/rtl8188e_hal_init.o \ ++ hal/rtl8188e_mp.o \ ++ hal/rtl8188e_phycfg.o \ ++ hal/rtl8188e_rf6052.o \ ++ hal/rtl8188e_rxdesc.o \ ++ hal/rtl8188e_sreset.o \ ++ hal/rtl8188e_xmit.o \ ++ hal/rtl8188eu_led.o \ ++ hal/rtl8188eu_recv.o \ ++ hal/rtl8188eu_xmit.o \ ++ hal/usb_halinit.o \ ++ hal/usb_ops_linux.o ++ ++RTL871X = rtl8188e ++ ++HCI_NAME = usb ++ ++_OS_INTFS_FILES := \ ++ os_dep/ioctl_linux.o \ ++ os_dep/mlme_linux.o \ ++ os_dep/os_intfs.o \ ++ os_dep/osdep_service.o \ ++ os_dep/recv_linux.o \ ++ os_dep/usb_intf.o \ ++ os_dep/usb_ops_linux.o \ ++ os_dep/xmit_linux.o ++ ++_HAL_INTFS_FILES += $(OUTSRC_FILES) ++ ++ifeq ($(CONFIG_BT_COEXIST), y) ++EXTRA_CFLAGS += -DCONFIG_BT_COEXIST ++endif ++ ++ifeq ($(CONFIG_WOWLAN), y) ++EXTRA_CFLAGS += -DCONFIG_WOWLAN ++endif ++ ++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 ?= $(if $(KERNELRELEASE),$(KERNELRELEASE),$(shell uname -r)) ++KSRC ?= $(if $(KERNEL_SRC),$(KERNEL_SRC),/lib/modules/$(KVER)/build) ++MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless ++INSTALL_PREFIX := ++ ++rtk_core := \ ++ core/rtw_ap.o \ ++ core/rtw_br_ext.o \ ++ core/rtw_cmd.o \ ++ core/rtw_debug.o \ ++ core/rtw_efuse.o \ ++ core/rtw_ieee80211.o \ ++ core/rtw_io.o \ ++ core/rtw_ioctl_set.o \ ++ core/rtw_iol.o \ ++ core/rtw_led.o \ ++ core/rtw_mlme.o \ ++ core/rtw_mlme_ext.o \ ++ core/rtw_mp.o \ ++ core/rtw_mp_ioctl.o \ ++ core/rtw_pwrctrl.o \ ++ core/rtw_p2p.o \ ++ core/rtw_recv.o \ ++ core/rtw_rf.o \ ++ core/rtw_security.o \ ++ core/rtw_sreset.o \ ++ core/rtw_sta_mgt.o \ ++ core/rtw_wlan_util.o \ ++ core/rtw_xmit.o ++ ++r8188eu-y += $(rtk_core) ++ ++r8188eu-y += $(_HAL_INTFS_FILES) ++ ++r8188eu-y += $(_OS_INTFS_FILES) ++ ++obj-$(CONFIG_R8188EU) := r8188eu.o +diff --git a/drivers/staging/r8188eu/TODO b/drivers/staging/r8188eu/TODO +new file mode 100644 +index 000000000000..ab9d5d145b3b +--- /dev/null ++++ b/drivers/staging/r8188eu/TODO +@@ -0,0 +1,16 @@ ++To-do list: ++ ++* Correct the coding style according to Linux guidelines; please read the document ++ at https://www.kernel.org/doc/html/latest/process/coding-style.html. ++* Remove unnecessary debugging/printing macros; for those that are still needed ++ use the proper kernel API (pr_debug(), dev_dbg(), netdev_dbg()). ++* Remove dead code such as unusued functions, variables, fields, etc.. ++* Use in-kernel API and remove unnecessary wrappers where possible. ++* Fix bugs due to code that sleeps in atomic context. ++* Remove the HAL layer and migrate its functionality into the relevant parts of ++ the driver. ++* Switch to use LIB80211. ++* Switch to use MAC80211. ++* Switch to use CFG80211. ++* Improve the error handling of various functions, particularly those that use ++ existing kernel APIs. +diff --git a/drivers/staging/r8188eu/core/rtw_ap.c b/drivers/staging/r8188eu/core/rtw_ap.c +new file mode 100644 +index 000000000000..1c07ad28b242 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_ap.c +@@ -0,0 +1,1850 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_AP_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/wifi.h" ++#include "../include/ieee80211.h" ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++void init_mlme_ap_info(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ spin_lock_init(&pmlmepriv->bcn_update_lock); ++ ++ /* for ACL */ ++ _rtw_init_queue(&pacl_list->acl_node_q); ++ ++ start_ap_mode(padapter); ++} ++ ++void free_mlme_ap_info(struct adapter *padapter) ++{ ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ pmlmepriv->update_bcn = false; ++ pmlmeext->bstart_bss = false; ++ ++ rtw_sta_flush(padapter); ++ ++ pmlmeinfo->state = _HW_STATE_NOLINK_; ++ ++ /* free_assoc_sta_resources */ ++ rtw_free_all_stainfo(padapter); ++ ++ /* free bc/mc sta_info */ ++ psta = rtw_get_bcmc_stainfo(padapter); ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ rtw_free_stainfo(padapter, psta); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++} ++ ++static void update_BCNTIM(struct adapter *padapter) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network; ++ unsigned char *pie = pnetwork_mlmeext->IEs; ++ ++ /* update TIM IE */ ++ if (true) { ++ u8 *p, *dst_ie, *premainder_ie = NULL; ++ u8 *pbackup_remainder_ie = NULL; ++ __le16 tim_bitmap_le; ++ uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen; ++ ++ tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap); ++ ++ p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_); ++ if (p && tim_ielen > 0) { ++ tim_ielen += 2; ++ premainder_ie = p + tim_ielen; ++ tim_ie_offset = (int)(p - pie); ++ remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen; ++ /* append TIM IE from dst_ie offset */ ++ dst_ie = p; ++ } else { ++ tim_ielen = 0; ++ ++ /* calculate head_len */ ++ offset = _FIXED_IE_LENGTH_; ++ offset += pnetwork_mlmeext->Ssid.SsidLength + 2; ++ ++ /* get supported rates len */ ++ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); ++ if (p) ++ offset += tmp_len + 2; ++ ++ /* DS Parameter Set IE, len = 3 */ ++ offset += 3; ++ ++ premainder_ie = pie + offset; ++ ++ remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen; ++ ++ /* append TIM IE from offset */ ++ dst_ie = pie + offset; ++ } ++ ++ if (remainder_ielen > 0) { ++ pbackup_remainder_ie = kmalloc(remainder_ielen, GFP_ATOMIC); ++ if (pbackup_remainder_ie && premainder_ie) ++ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); ++ } ++ *dst_ie++ = _TIM_IE_; ++ ++ if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fc)) ++ tim_ielen = 5; ++ else ++ tim_ielen = 4; ++ ++ *dst_ie++ = tim_ielen; ++ ++ *dst_ie++ = 0;/* DTIM count */ ++ *dst_ie++ = 1;/* DTIM period */ ++ ++ if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */ ++ *dst_ie++ = BIT(0);/* bitmap ctrl */ ++ else ++ *dst_ie++ = 0; ++ ++ if (tim_ielen == 4) { ++ *dst_ie++ = *(u8 *)&tim_bitmap_le; ++ } else if (tim_ielen == 5) { ++ memcpy(dst_ie, &tim_bitmap_le, 2); ++ dst_ie += 2; ++ } ++ ++ /* copy remainder IE */ ++ if (pbackup_remainder_ie) { ++ memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); ++ ++ kfree(pbackup_remainder_ie); ++ } ++ offset = (uint)(dst_ie - pie); ++ pnetwork_mlmeext->IELength = offset + remainder_ielen; ++ } ++ ++ set_tx_beacon_cmd(padapter); ++} ++ ++static u8 chk_sta_is_alive(struct sta_info *psta) ++{ ++ u8 ret = false; ++ ++ if ((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) == ++ (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts)) ++ ; ++ else ++ ret = true; ++ ++ sta_update_last_rx_pkts(psta); ++ ++ return ret; ++} ++ ++void expire_timeout_chk(struct adapter *padapter) ++{ ++ struct list_head *phead, *plist; ++ u8 updated = 0; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 chk_alive_num = 0; ++ char chk_alive_list[NUM_STA]; ++ int i; ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ ++ phead = &pstapriv->auth_list; ++ plist = phead->next; ++ ++ /* check auth_queue */ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, auth_list); ++ plist = plist->next; ++ ++ if (psta->expire_to > 0) { ++ psta->expire_to--; ++ if (psta->expire_to == 0) { ++ list_del_init(&psta->auth_list); ++ pstapriv->auth_list_cnt--; ++ ++ DBG_88E("auth expire %6ph\n", ++ psta->hwaddr); ++ ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ rtw_free_stainfo(padapter, psta); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ } ++ } ++ ++ } ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ psta = NULL; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ ++ phead = &pstapriv->asoc_list; ++ plist = phead->next; ++ ++ /* check asoc_queue */ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, asoc_list); ++ plist = plist->next; ++ ++ if (chk_sta_is_alive(psta) || !psta->expire_to) { ++ psta->expire_to = pstapriv->expire_to; ++ psta->keep_alive_trycnt = 0; ++ psta->under_exist_checking = 0; ++ } else { ++ psta->expire_to--; ++ } ++ ++ if (psta->expire_to <= 0) { ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (padapter->registrypriv.wifi_spec == 1) { ++ psta->expire_to = pstapriv->expire_to; ++ continue; ++ } ++ ++ if (psta->state & WIFI_SLEEP_STATE) { ++ if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { ++ /* to check if alive by another methods if station is at ps mode. */ ++ psta->expire_to = pstapriv->expire_to; ++ psta->state |= WIFI_STA_ALIVE_CHK_STATE; ++ ++ /* to update bcn with tim_bitmap for this station */ ++ pstapriv->tim_bitmap |= BIT(psta->aid); ++ update_beacon(padapter, _TIM_IE_, NULL, false); ++ ++ if (!pmlmeext->active_keep_alive_check) ++ continue; ++ } ++ } ++ if (pmlmeext->active_keep_alive_check) { ++ int stainfo_offset; ++ ++ stainfo_offset = rtw_stainfo_offset(pstapriv, psta); ++ if (stainfo_offset_valid(stainfo_offset)) ++ chk_alive_list[chk_alive_num++] = stainfo_offset; ++ continue; ++ } ++ ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ ++ DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state); ++ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); ++ } else { ++ /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */ ++ if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt) && ++ padapter->xmitpriv.free_xmitframe_cnt < (NR_XMITFRAME / pstapriv->asoc_list_cnt / 2)) { ++ DBG_88E("%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__, ++ (psta->hwaddr), psta->sleepq_len, ++ padapter->xmitpriv.free_xmitframe_cnt, ++ pstapriv->asoc_list_cnt); ++ wakeup_sta_to_xmit(padapter, psta); ++ } ++ } ++ } ++ ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ if (chk_alive_num) { ++ u8 backup_oper_channel = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ /* switch to correct channel of current network before issue keep-alive frames */ ++ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { ++ backup_oper_channel = rtw_get_oper_ch(padapter); ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ } ++ ++ /* issue null data to check sta alive*/ ++ for (i = 0; i < chk_alive_num; i++) { ++ int ret = _FAIL; ++ ++ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); ++ ++ if (psta->state & WIFI_SLEEP_STATE) ++ ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50); ++ else ++ ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50); ++ ++ psta->keep_alive_trycnt++; ++ if (ret == _SUCCESS) { ++ DBG_88E("asoc check, sta(%pM) is alive\n", (psta->hwaddr)); ++ psta->expire_to = pstapriv->expire_to; ++ psta->keep_alive_trycnt = 0; ++ continue; ++ } else if (psta->keep_alive_trycnt <= 3) { ++ DBG_88E("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt); ++ psta->expire_to = 1; ++ continue; ++ } ++ ++ psta->keep_alive_trycnt = 0; ++ ++ DBG_88E("asoc expire %pM, state = 0x%x\n", (psta->hwaddr), psta->state); ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ } ++ ++ if (backup_oper_channel > 0) /* back to the original operation channel */ ++ SelectChannel(padapter, backup_oper_channel); ++ } ++ ++ associated_clients_update(padapter, updated); ++} ++ ++void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level) ++{ ++ int i; ++ u8 rf_type; ++ u32 init_rate = 0; ++ unsigned char sta_band = 0, raid, shortGIrate = false; ++ unsigned char limit; ++ unsigned int tx_ra_bitmap = 0; ++ struct ht_priv *psta_ht = NULL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ ++ if (psta) ++ psta_ht = &psta->htpriv; ++ else ++ return; ++ ++ if (!(psta->state & _FW_LINKED)) ++ return; ++ ++ /* b/g mode ra_bitmap */ ++ for (i = 0; i < sizeof(psta->bssrateset); i++) { ++ if (psta->bssrateset[i]) ++ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i] & 0x7f); ++ } ++ /* n mode ra_bitmap */ ++ if (psta_ht->ht_option) { ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if (rf_type == RF_2T2R) ++ limit = 16;/* 2R */ ++ else ++ limit = 8;/* 1R */ ++ ++ for (i = 0; i < limit; i++) { ++ if (psta_ht->ht_cap.mcs.rx_mask[i / 8] & BIT(i % 8)) ++ tx_ra_bitmap |= BIT(i + 12); ++ } ++ ++ /* max short GI rate */ ++ shortGIrate = psta_ht->sgi; ++ } ++ ++ if (pcur_network->Configuration.DSConfig > 14) { ++ sta_band |= WIRELESS_INVALID; ++ } else { ++ if (tx_ra_bitmap & 0xffff000) ++ sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B; ++ else if (tx_ra_bitmap & 0xff0) ++ sta_band |= WIRELESS_11G | WIRELESS_11B; ++ else ++ sta_band |= WIRELESS_11B; ++ } ++ ++ psta->wireless_mode = sta_band; ++ ++ raid = networktype_to_raid(sta_band); ++ init_rate = get_highest_rate_idx(tx_ra_bitmap & 0x0fffffff) & 0x3f; ++ ++ if (psta->aid < NUM_STA) { ++ u8 arg = 0; ++ ++ arg = psta->mac_id & 0x1f; ++ ++ arg |= BIT(7);/* support entry 2~31 */ ++ ++ if (shortGIrate) ++ arg |= BIT(5); ++ ++ tx_ra_bitmap |= ((raid << 28) & 0xf0000000); ++ ++ DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n", ++ __func__, psta->mac_id, raid, tx_ra_bitmap, arg); ++ ++ /* bitmap[0:27] = tx_rate_bitmap */ ++ /* bitmap[28:31]= Rate Adaptive id */ ++ /* arg[0:4] = macid */ ++ /* arg[5] = Short GI */ ++ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, rssi_level); ++ ++ if (shortGIrate) ++ init_rate |= BIT(6); ++ ++ /* set ra_id, init_rate */ ++ psta->raid = raid; ++ psta->init_rate = init_rate; ++ ++ } else { ++ DBG_88E("station aid %d exceed the max number\n", psta->aid); ++ } ++} ++ ++void update_bmc_sta(struct adapter *padapter) ++{ ++ u32 init_rate = 0; ++ unsigned char network_type, raid; ++ int i, supportRateNum = 0; ++ unsigned int tx_ra_bitmap = 0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ struct sta_info *psta = rtw_get_bcmc_stainfo(padapter); ++ ++ if (psta) { ++ psta->aid = 0;/* default set to 0 */ ++ psta->mac_id = psta->aid + 1; ++ ++ psta->qos_option = 0; ++ psta->htpriv.ht_option = false; ++ ++ psta->ieee8021x_blocked = 0; ++ ++ memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); ++ ++ /* prepare for add_RATid */ ++ supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates); ++ network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, 1); ++ ++ memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum); ++ psta->bssratelen = supportRateNum; ++ ++ /* b/g mode ra_bitmap */ ++ for (i = 0; i < supportRateNum; i++) { ++ if (psta->bssrateset[i]) ++ tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i] & 0x7f); ++ } ++ ++ if (pcur_network->Configuration.DSConfig > 14) { ++ network_type = WIRELESS_INVALID; ++ } else { ++ /* force to b mode */ ++ network_type = WIRELESS_11B; ++ tx_ra_bitmap = 0xf; ++ } ++ ++ raid = networktype_to_raid(network_type); ++ init_rate = get_highest_rate_idx(tx_ra_bitmap & 0x0fffffff) & 0x3f; ++ ++ /* ap mode */ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); ++ ++ { ++ u8 arg = 0; ++ ++ arg = psta->mac_id & 0x1f; ++ arg |= BIT(7); ++ tx_ra_bitmap |= ((raid << 28) & 0xf0000000); ++ DBG_88E("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg); ++ ++ /* bitmap[0:27] = tx_rate_bitmap */ ++ /* bitmap[28:31]= Rate Adaptive id */ ++ /* arg[0:4] = macid */ ++ /* arg[5] = Short GI */ ++ rtw_hal_add_ra_tid(padapter, tx_ra_bitmap, arg, 0); ++ } ++ /* set ra_id, init_rate */ ++ psta->raid = raid; ++ psta->init_rate = init_rate; ++ ++ rtw_sta_media_status_rpt(padapter, psta, 1); ++ ++ spin_lock_bh(&psta->lock); ++ psta->state = _FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++ ++ } else { ++ DBG_88E("add_RATid_bmc_sta error!\n"); ++ } ++} ++ ++/* notes: */ ++/* AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */ ++/* MAC_ID = AID+1 for sta in ap/adhoc mode */ ++/* MAC_ID = 1 for bc/mc for sta/ap/adhoc */ ++/* MAC_ID = 0 for bssid for sta/ap/adhoc */ ++/* CAM_ID = 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */ ++ ++void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; ++ struct ht_priv *phtpriv_sta = &psta->htpriv; ++ u16 sta_cap_info; ++ u16 ap_cap_info; ++ ++ psta->mac_id = psta->aid + 1; ++ DBG_88E("%s\n", __func__); ++ ++ /* ap mode */ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); ++ ++ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ++ psta->ieee8021x_blocked = true; ++ else ++ psta->ieee8021x_blocked = false; ++ ++ /* update sta's cap */ ++ ++ /* ERP */ ++ VCS_update(padapter, psta); ++ /* HT related cap */ ++ if (phtpriv_sta->ht_option) { ++ /* check if sta supports rx ampdu */ ++ phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable; ++ sta_cap_info = le16_to_cpu(phtpriv_sta->ht_cap.cap_info); ++ ap_cap_info = le16_to_cpu(phtpriv_ap->ht_cap.cap_info); ++ ++ /* check if sta support s Short GI */ ++ if ((sta_cap_info & ap_cap_info) & ++ (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) ++ phtpriv_sta->sgi = true; ++ ++ /* bwmode */ ++ if ((sta_cap_info & ap_cap_info) & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { ++ phtpriv_sta->bwmode = pmlmeext->cur_bwmode; ++ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; ++ } ++ psta->qos_option = true; ++ } else { ++ phtpriv_sta->ampdu_enable = false; ++ phtpriv_sta->sgi = false; ++ phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; ++ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ /* Rx AMPDU */ ++ send_delba(padapter, 0, psta->hwaddr);/* recipient */ ++ ++ /* TX AMPDU */ ++ send_delba(padapter, 1, psta->hwaddr);/* originator */ ++ phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */ ++ phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */ ++ ++ /* todo: init other variables */ ++ ++ memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); ++ ++ spin_lock_bh(&psta->lock); ++ psta->state |= _FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++} ++ ++static void update_hw_ht_param(struct adapter *padapter) ++{ ++ unsigned char max_AMPDU_len; ++ unsigned char min_MPDU_spacing; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ DBG_88E("%s\n", __func__); ++ ++ /* handle A-MPDU parameter field */ ++ /* ++ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k ++ AMPDU_para [4:2]:Min MPDU Start Spacing ++ */ ++ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; ++ ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); ++ ++ /* */ ++ /* Config SM Power Save setting */ ++ /* */ ++ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2; ++ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) ++ DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); ++} ++ ++static void start_bss_network(struct adapter *padapter, u8 *pbuf) ++{ ++ u8 *p; ++ u8 val8, cur_channel, cur_bwmode, cur_ch_offset; ++ u16 bcn_interval; ++ u32 acparm; ++ int ie_len; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network; ++ struct HT_info_element *pht_info = NULL; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; ++ cur_channel = pnetwork->Configuration.DSConfig; ++ cur_bwmode = HT_CHANNEL_WIDTH_20; ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ /* check if there is wps ie, */ ++ /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */ ++ /* and at first time the security ie (RSN/WPA IE) will not include in beacon. */ ++ if (!rtw_get_wps_ie(pnetwork->IEs + _FIXED_IE_LENGTH_, pnetwork->IELength - _FIXED_IE_LENGTH_, NULL, NULL)) ++ pmlmeext->bstart_bss = true; ++ ++ /* todo: update wmm, ht cap */ ++ if (pmlmepriv->qospriv.qos_option) ++ pmlmeinfo->WMM_enable = true; ++ if (pmlmepriv->htpriv.ht_option) { ++ pmlmeinfo->WMM_enable = true; ++ pmlmeinfo->HT_enable = true; ++ ++ update_hw_ht_param(padapter); ++ } ++ ++ if (pmlmepriv->cur_network.join_res != true) { /* setting only at first time */ ++ /* WEP Key will be set before this function, do not clear CAM. */ ++ if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && ++ (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)) ++ flush_all_cam_entry(padapter); /* clear CAM */ ++ } ++ ++ /* set MSR to AP_Mode */ ++ Set_MSR(padapter, _HW_STATE_AP_); ++ ++ /* Set BSSID REG */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress); ++ ++ /* Set EDCA param reg */ ++ acparm = 0x002F3217; /* VO */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); ++ acparm = 0x005E4317; /* VI */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); ++ acparm = 0x005ea42b; ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); ++ acparm = 0x0000A444; /* BK */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); ++ ++ /* Set Security */ ++ val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ /* Beacon Control related register */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval)); ++ ++ UpdateBrateTbl(padapter, pnetwork->SupportedRates); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates); ++ ++ if (!pmlmepriv->cur_network.join_res) { /* setting only at first time */ ++ /* turn on all dynamic functions */ ++ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); ++ } ++ /* set channel, bwmode */ ++ p = rtw_get_ie((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - sizeof(struct ndis_802_11_fixed_ie))); ++ if (p && ie_len) { ++ pht_info = (struct HT_info_element *)(p + 2); ++ ++ if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) { ++ /* switch to the 40M Hz mode */ ++ cur_bwmode = HT_CHANNEL_WIDTH_40; ++ switch (pht_info->infos[0] & 0x3) { ++ case 1: ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ case 3: ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ default: ++ cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ } ++ } ++ /* TODO: need to judge the phy parameters on concurrent mode for single phy */ ++ set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); ++ ++ DBG_88E("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode, cur_ch_offset); ++ ++ /* */ ++ pmlmeext->cur_channel = cur_channel; ++ pmlmeext->cur_bwmode = cur_bwmode; ++ pmlmeext->cur_ch_offset = cur_ch_offset; ++ pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type; ++ ++ /* update cur_wireless_mode */ ++ update_wireless_mode(padapter); ++ ++ /* udpate capability after cur_wireless_mode updated */ ++ update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork)); ++ ++ /* let pnetwork_mlmeext == pnetwork_mlme. */ ++ memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length); ++ ++#ifdef CONFIG_88EU_P2P ++ memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.Ssid, pnetwork->Ssid.SsidLength); ++ pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.SsidLength; ++#endif /* CONFIG_88EU_P2P */ ++ ++ if (pmlmeext->bstart_bss) { ++ update_beacon(padapter, _TIM_IE_, NULL, false); ++ ++ /* issue beacon frame */ ++ if (send_beacon(padapter) == _FAIL) ++ DBG_88E("issue_beacon, fail!\n"); ++ } ++ ++ /* update bc/mc sta_info */ ++ update_bmc_sta(padapter); ++} ++ ++int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) ++{ ++ int ret = _SUCCESS; ++ u8 *p; ++ u8 *pHT_caps_ie = NULL; ++ u8 *pHT_info_ie = NULL; ++ struct sta_info *psta = NULL; ++ u16 cap, ht_cap = false; ++ uint ie_len = 0; ++ int group_cipher, pairwise_cipher; ++ u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX]; ++ int supportRateNum = 0; ++ u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01}; ++ u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network; ++ u8 *ie = pbss_network->IEs; ++ ++ /* SSID */ ++ /* Supported rates */ ++ /* DS Params */ ++ /* WLAN_EID_COUNTRY */ ++ /* ERP Information element */ ++ /* Extended supported rates */ ++ /* WPA/WPA2 */ ++ /* Wi-Fi Wireless Multimedia Extensions */ ++ /* ht_capab, ht_oper */ ++ /* WPS IE */ ++ ++ DBG_88E("%s, len =%d\n", __func__, len); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true) ++ return _FAIL; ++ ++ if (len > MAX_IE_SZ) ++ return _FAIL; ++ ++ pbss_network->IELength = len; ++ ++ memset(ie, 0, MAX_IE_SZ); ++ ++ memcpy(ie, pbuf, pbss_network->IELength); ++ ++ if (pbss_network->InfrastructureMode != Ndis802_11APMode) ++ return _FAIL; ++ ++ pbss_network->Rssi = 0; ++ ++ memcpy(pbss_network->MacAddress, myid(&padapter->eeprompriv), ETH_ALEN); ++ ++ /* beacon interval */ ++ p = rtw_get_beacon_interval_from_ie(ie);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */ ++ pbss_network->Configuration.BeaconPeriod = get_unaligned_le16(p); ++ ++ /* capability */ ++ cap = get_unaligned_le16(ie); ++ ++ /* SSID */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len > 0) { ++ memset(&pbss_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len); ++ pbss_network->Ssid.SsidLength = ie_len; ++ } ++ ++ /* channel */ ++ channel = 0; ++ pbss_network->Configuration.Length = 0; ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len > 0) ++ channel = *(p + 2); ++ ++ pbss_network->Configuration.DSConfig = channel; ++ ++ memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX); ++ /* get supported rates */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p) { ++ memcpy(supportRate, p + 2, ie_len); ++ supportRateNum = ie_len; ++ } ++ ++ /* get ext_supported rates */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_); ++ if (p) { ++ memcpy(supportRate + supportRateNum, p + 2, ie_len); ++ supportRateNum += ie_len; ++ } ++ ++ network_type = rtw_check_network_type(supportRate, supportRateNum, channel); ++ ++ rtw_set_supported_rate(pbss_network->SupportedRates, network_type); ++ ++ /* parsing ERP_IE */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len > 0) ++ ERP_IE_handler(padapter, (struct ndis_802_11_var_ie *)p); ++ ++ /* update privacy/security */ ++ if (cap & BIT(4)) ++ pbss_network->Privacy = 1; ++ else ++ pbss_network->Privacy = 0; ++ ++ psecuritypriv->wpa_psk = 0; ++ ++ /* wpa2 */ ++ group_cipher = 0; ++ pairwise_cipher = 0; ++ psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; ++ psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len > 0) { ++ if (rtw_parse_wpa2_ie(p, ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ ++ psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ ++ psecuritypriv->wpa_psk |= BIT(1); ++ ++ psecuritypriv->wpa2_group_cipher = group_cipher; ++ psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher; ++ } ++ } ++ /* wpa */ ++ ie_len = 0; ++ group_cipher = 0; ++ pairwise_cipher = 0; ++ psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; ++ psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; ++ for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) { ++ p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, ++ (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if ((p) && (!memcmp(p + 2, OUI1, 4))) { ++ if (rtw_parse_wpa_ie(p, ie_len + 2, &group_cipher, ++ &pairwise_cipher, NULL) == _SUCCESS) { ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ ++ psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ ++ ++ psecuritypriv->wpa_psk |= BIT(0); ++ ++ psecuritypriv->wpa_group_cipher = group_cipher; ++ psecuritypriv->wpa_pairwise_cipher = pairwise_cipher; ++ } ++ break; ++ } ++ if (!p || ie_len == 0) ++ break; ++ } ++ ++ /* wmm */ ++ ie_len = 0; ++ pmlmepriv->qospriv.qos_option = 0; ++ if (pregistrypriv->wmm_enable) { ++ for (p = ie + _BEACON_IE_OFFSET_;; p += (ie_len + 2)) { ++ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, ++ (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if ((p) && !memcmp(p + 2, WMM_PARA_IE, 6)) { ++ pmlmepriv->qospriv.qos_option = 1; ++ ++ *(p + 8) |= BIT(7);/* QoS Info, support U-APSD */ ++ ++ /* disable all ACM bits since the WMM admission control is not supported */ ++ *(p + 10) &= ~BIT(4); /* BE */ ++ *(p + 14) &= ~BIT(4); /* BK */ ++ *(p + 18) &= ~BIT(4); /* VI */ ++ *(p + 22) &= ~BIT(4); /* VO */ ++ break; ++ } ++ ++ if (!p || ie_len == 0) ++ break; ++ } ++ } ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, ++ (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len > 0) { ++ u8 rf_type; ++ struct ieee80211_ht_cap *pht_cap = (struct ieee80211_ht_cap *)(p + 2); ++ ++ pHT_caps_ie = p; ++ ht_cap = true; ++ network_type |= WIRELESS_11_24N; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) || ++ (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & (0x07 << 2)); ++ else ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & 0x00); ++ ++ /* set Max Rx AMPDU size to 64K */ ++ pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_FACTOR & 0x03); ++ ++ if (rf_type == RF_1T1R) { ++ pht_cap->mcs.rx_mask[0] = 0xff; ++ pht_cap->mcs.rx_mask[1] = 0x0; ++ } ++ memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len); ++ } ++ ++ /* parsing HT_INFO_IE */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, ++ (pbss_network->IELength - _BEACON_IE_OFFSET_)); ++ if (p && ie_len > 0) ++ pHT_info_ie = p; ++ switch (network_type) { ++ case WIRELESS_11B: ++ pbss_network->NetworkTypeInUse = Ndis802_11DS; ++ break; ++ case WIRELESS_11G: ++ case WIRELESS_11BG: ++ case WIRELESS_11G_24N: ++ case WIRELESS_11BG_24N: ++ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; ++ break; ++ default: ++ pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; ++ break; ++ } ++ ++ pmlmepriv->cur_network.network_type = network_type; ++ ++ pmlmepriv->htpriv.ht_option = false; ++ ++ if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) || ++ (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) { ++ /* todo: */ ++ /* ht_cap = false; */ ++ } ++ ++ /* ht_cap */ ++ if (pregistrypriv->ht_enable && ht_cap) { ++ pmlmepriv->htpriv.ht_option = true; ++ pmlmepriv->qospriv.qos_option = 1; ++ ++ if (pregistrypriv->ampdu_enable == 1) ++ pmlmepriv->htpriv.ampdu_enable = true; ++ HT_caps_handler(padapter, (struct ndis_802_11_var_ie *)pHT_caps_ie); ++ ++ HT_info_handler(padapter, (struct ndis_802_11_var_ie *)pHT_info_ie); ++ } ++ ++ pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pbss_network); ++ ++ /* issue beacon to start bss network */ ++ start_bss_network(padapter, (u8 *)pbss_network); ++ ++ /* alloc sta_info for ap itself */ ++ psta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress); ++ if (!psta) { ++ psta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress); ++ if (!psta) ++ return _FAIL; ++ } ++ ++ /* fix bug of flush_cam_entry at STOP AP mode */ ++ psta->state |= WIFI_AP_STATE; ++ rtw_indicate_connect(padapter); ++ pmlmepriv->cur_network.join_res = true;/* for check if already set beacon */ ++ return ret; ++} ++ ++void rtw_set_macaddr_acl(struct adapter *padapter, int mode) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ DBG_88E("%s, mode =%d\n", __func__, mode); ++ ++ pacl_list->mode = mode; ++} ++ ++int rtw_acl_add_sta(struct adapter *padapter, u8 *addr) ++{ ++ struct list_head *plist, *phead; ++ u8 added = false; ++ int i, ret = 0; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ struct __queue *pacl_node_q = &pacl_list->acl_node_q; ++ ++ DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr)); ++ ++ if ((NUM_ACL - 1) < pacl_list->num) ++ return -1; ++ ++ spin_lock_bh(&pacl_node_q->lock); ++ ++ phead = get_list_head(pacl_node_q); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ paclnode = container_of(plist, struct rtw_wlan_acl_node, list); ++ plist = plist->next; ++ ++ if (!memcmp(paclnode->addr, addr, ETH_ALEN)) { ++ if (paclnode->valid) { ++ added = true; ++ DBG_88E("%s, sta has been added\n", __func__); ++ break; ++ } ++ } ++ } ++ ++ spin_unlock_bh(&pacl_node_q->lock); ++ ++ if (added) ++ return ret; ++ ++ spin_lock_bh(&pacl_node_q->lock); ++ ++ for (i = 0; i < NUM_ACL; i++) { ++ paclnode = &pacl_list->aclnode[i]; ++ ++ if (!paclnode->valid) { ++ INIT_LIST_HEAD(&paclnode->list); ++ ++ memcpy(paclnode->addr, addr, ETH_ALEN); ++ ++ paclnode->valid = true; ++ ++ list_add_tail(&paclnode->list, get_list_head(pacl_node_q)); ++ ++ pacl_list->num++; ++ ++ break; ++ } ++ } ++ ++ DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num); ++ ++ spin_unlock_bh(&pacl_node_q->lock); ++ ++ return ret; ++} ++ ++int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr) ++{ ++ struct list_head *plist, *phead; ++ int ret = 0; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ struct __queue *pacl_node_q = &pacl_list->acl_node_q; ++ ++ DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr)); ++ ++ spin_lock_bh(&pacl_node_q->lock); ++ ++ phead = get_list_head(pacl_node_q); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ paclnode = container_of(plist, struct rtw_wlan_acl_node, list); ++ plist = plist->next; ++ ++ if (!memcmp(paclnode->addr, addr, ETH_ALEN)) { ++ if (paclnode->valid) { ++ paclnode->valid = false; ++ ++ list_del_init(&paclnode->list); ++ ++ pacl_list->num--; ++ } ++ } ++ } ++ ++ spin_unlock_bh(&pacl_node_q->lock); ++ ++ DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num); ++ return ret; ++} ++ ++static void update_bcn_fixed_ie(struct adapter *padapter) ++{ ++ DBG_88E("%s\n", __func__); ++} ++ ++static void update_bcn_erpinfo_ie(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; ++ unsigned char *p, *ie = pnetwork->IEs; ++ u32 len = 0; ++ ++ DBG_88E("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable); ++ ++ if (!pmlmeinfo->ERP_enable) ++ return; ++ ++ /* parsing ERP_IE */ ++ p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, ++ (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if (p && len > 0) { ++ struct ndis_802_11_var_ie *pIE = (struct ndis_802_11_var_ie *)p; ++ ++ if (pmlmepriv->num_sta_non_erp == 1) ++ pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION; ++ else ++ pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION); ++ ++ if (pmlmepriv->num_sta_no_short_preamble > 0) ++ pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE; ++ else ++ pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE); ++ ++ ERP_IE_handler(padapter, pIE); ++ } ++} ++ ++static void update_bcn_htcap_ie(struct adapter *padapter) ++{ ++ DBG_88E("%s\n", __func__); ++} ++ ++static void update_bcn_htinfo_ie(struct adapter *padapter) ++{ ++ DBG_88E("%s\n", __func__); ++} ++ ++static void update_bcn_rsn_ie(struct adapter *padapter) ++{ ++ DBG_88E("%s\n", __func__); ++} ++ ++static void update_bcn_wpa_ie(struct adapter *padapter) ++{ ++ DBG_88E("%s\n", __func__); ++} ++ ++static void update_bcn_wmm_ie(struct adapter *padapter) ++{ ++ DBG_88E("%s\n", __func__); ++} ++ ++static void update_bcn_wps_ie(struct adapter *padapter) ++{ ++ u8 *pwps_ie = NULL, *pwps_ie_src; ++ u8 *premainder_ie, *pbackup_remainder_ie = NULL; ++ uint wps_ielen = 0, wps_offset, remainder_ielen; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; ++ unsigned char *ie = pnetwork->IEs; ++ u32 ielen = pnetwork->IELength; ++ ++ DBG_88E("%s\n", __func__); ++ ++ pwps_ie = rtw_get_wps_ie(ie + _FIXED_IE_LENGTH_, ielen - _FIXED_IE_LENGTH_, NULL, &wps_ielen); ++ ++ if (!pwps_ie || wps_ielen == 0) ++ return; ++ ++ wps_offset = (uint)(pwps_ie - ie); ++ ++ premainder_ie = pwps_ie + wps_ielen; ++ ++ remainder_ielen = ielen - wps_offset - wps_ielen; ++ ++ if (remainder_ielen > 0) { ++ pbackup_remainder_ie = kmalloc(remainder_ielen, GFP_ATOMIC); ++ if (pbackup_remainder_ie) ++ memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); ++ } ++ ++ pwps_ie_src = pmlmepriv->wps_beacon_ie; ++ if (!pwps_ie_src) ++ goto exit; ++ ++ wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */ ++ if ((wps_offset + wps_ielen + 2 + remainder_ielen) <= MAX_IE_SZ) { ++ memcpy(pwps_ie, pwps_ie_src, wps_ielen + 2); ++ pwps_ie += (wps_ielen + 2); ++ ++ if (pbackup_remainder_ie) ++ memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen); ++ ++ /* update IELength */ ++ pnetwork->IELength = wps_offset + (wps_ielen + 2) + remainder_ielen; ++ } ++ ++exit: ++ kfree(pbackup_remainder_ie); ++} ++ ++static void update_bcn_p2p_ie(struct adapter *padapter) ++{ ++} ++ ++static void update_bcn_vendor_spec_ie(struct adapter *padapter, u8 *oui) ++{ ++ DBG_88E("%s\n", __func__); ++ ++ if (!memcmp(RTW_WPA_OUI, oui, 4)) ++ update_bcn_wpa_ie(padapter); ++ else if (!memcmp(WMM_OUI, oui, 4)) ++ update_bcn_wmm_ie(padapter); ++ else if (!memcmp(WPS_OUI, oui, 4)) ++ update_bcn_wps_ie(padapter); ++ else if (!memcmp(P2P_OUI, oui, 4)) ++ update_bcn_p2p_ie(padapter); ++ else ++ DBG_88E("unknown OUI type!\n"); ++} ++ ++void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx) ++{ ++ struct mlme_priv *pmlmepriv; ++ struct mlme_ext_priv *pmlmeext; ++ ++ if (!padapter) ++ return; ++ ++ pmlmepriv = &padapter->mlmepriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ ++ if (!pmlmeext->bstart_bss) ++ return; ++ ++ spin_lock_bh(&pmlmepriv->bcn_update_lock); ++ ++ switch (ie_id) { ++ case 0xFF: ++ update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */ ++ break; ++ case _TIM_IE_: ++ update_BCNTIM(padapter); ++ break; ++ case _ERPINFO_IE_: ++ update_bcn_erpinfo_ie(padapter); ++ break; ++ case _HT_CAPABILITY_IE_: ++ update_bcn_htcap_ie(padapter); ++ break; ++ case _RSN_IE_2_: ++ update_bcn_rsn_ie(padapter); ++ break; ++ case _HT_ADD_INFO_IE_: ++ update_bcn_htinfo_ie(padapter); ++ break; ++ case _VENDOR_SPECIFIC_IE_: ++ update_bcn_vendor_spec_ie(padapter, oui); ++ break; ++ default: ++ break; ++ } ++ ++ pmlmepriv->update_bcn = true; ++ ++ spin_unlock_bh(&pmlmepriv->bcn_update_lock); ++ ++ if (tx) ++ set_tx_beacon_cmd(padapter); ++} ++ ++/* ++op_mode ++Set to 0 (HT pure) under the followign conditions ++ - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or ++ - all STAs in the BSS are 20 MHz HT in 20 MHz BSS ++Set to 1 (HT non-member protection) if there may be non-HT STAs ++ in both the primary and the secondary channel ++Set to 2 if only HT STAs are associated in BSS, ++ however and at least one 20 MHz HT STA is associated ++Set to 3 (HT mixed mode) when one or more non-HT STAs are associated ++ (currently non-GF HT station is considered as non-HT STA also) ++*/ ++static int rtw_ht_operation_update(struct adapter *padapter) ++{ ++ u16 cur_op_mode, new_op_mode; ++ int op_mode_changes = 0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; ++ ++ if (pmlmepriv->htpriv.ht_option) ++ return 0; ++ ++ DBG_88E("%s current operation mode = 0x%X\n", ++ __func__, pmlmepriv->ht_op_mode); ++ ++ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && ++ pmlmepriv->num_sta_ht_no_gf) { ++ pmlmepriv->ht_op_mode |= ++ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; ++ op_mode_changes++; ++ } else if ((pmlmepriv->ht_op_mode & ++ HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && ++ pmlmepriv->num_sta_ht_no_gf == 0) { ++ pmlmepriv->ht_op_mode &= ++ ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; ++ op_mode_changes++; ++ } ++ ++ if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && ++ (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) { ++ pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; ++ op_mode_changes++; ++ } else if ((pmlmepriv->ht_op_mode & ++ HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && ++ (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) { ++ pmlmepriv->ht_op_mode &= ++ ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; ++ op_mode_changes++; ++ } ++ ++ /* Note: currently we switch to the MIXED op mode if HT non-greenfield ++ * station is associated. Probably it's a theoretical case, since ++ * it looks like all known HT STAs support greenfield. ++ */ ++ new_op_mode = 0; ++ if (pmlmepriv->num_sta_no_ht || ++ (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)) ++ new_op_mode = OP_MODE_MIXED; ++ else if ((le16_to_cpu(phtpriv_ap->ht_cap.cap_info) & ++ IEEE80211_HT_CAP_SUP_WIDTH_20_40) && ++ pmlmepriv->num_sta_ht_20mhz) ++ new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; ++ else if (pmlmepriv->olbc_ht) ++ new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; ++ else ++ new_op_mode = OP_MODE_PURE; ++ ++ cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; ++ if (cur_op_mode != new_op_mode) { ++ pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK; ++ pmlmepriv->ht_op_mode |= new_op_mode; ++ op_mode_changes++; ++ } ++ ++ DBG_88E("%s new operation mode = 0x%X changes =%d\n", ++ __func__, pmlmepriv->ht_op_mode, op_mode_changes); ++ ++ return op_mode_changes; ++} ++ ++void associated_clients_update(struct adapter *padapter, u8 updated) ++{ ++ /* update associcated stations cap. */ ++ if (updated) { ++ struct list_head *phead, *plist; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ ++ phead = &pstapriv->asoc_list; ++ plist = phead->next; ++ ++ /* check asoc_queue */ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, asoc_list); ++ ++ plist = plist->next; ++ ++ VCS_update(padapter, psta); ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ } ++} ++ ++/* called > TSR LEVEL for USB or SDIO Interface*/ ++void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 beacon_updated = false; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) { ++ if (!psta->no_short_preamble_set) { ++ psta->no_short_preamble_set = 1; ++ ++ pmlmepriv->num_sta_no_short_preamble++; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_preamble == 1)) { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ } else { ++ if (psta->no_short_preamble_set) { ++ psta->no_short_preamble_set = 0; ++ ++ pmlmepriv->num_sta_no_short_preamble--; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_preamble == 0)) { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ } ++ ++ if (psta->flags & WLAN_STA_NONERP) { ++ if (!psta->nonerp_set) { ++ psta->nonerp_set = 1; ++ ++ pmlmepriv->num_sta_non_erp++; ++ ++ if (pmlmepriv->num_sta_non_erp == 1) { ++ beacon_updated = true; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, true); ++ } ++ } ++ } else { ++ if (psta->nonerp_set) { ++ psta->nonerp_set = 0; ++ ++ pmlmepriv->num_sta_non_erp--; ++ ++ if (pmlmepriv->num_sta_non_erp == 0) { ++ beacon_updated = true; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, true); ++ } ++ } ++ } ++ ++ if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) { ++ if (!psta->no_short_slot_time_set) { ++ psta->no_short_slot_time_set = 1; ++ ++ pmlmepriv->num_sta_no_short_slot_time++; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_slot_time == 1)) { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ } else { ++ if (psta->no_short_slot_time_set) { ++ psta->no_short_slot_time_set = 0; ++ ++ pmlmepriv->num_sta_no_short_slot_time--; ++ ++ if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && ++ (pmlmepriv->num_sta_no_short_slot_time == 0)) { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ } ++ ++ if (psta->flags & WLAN_STA_HT) { ++ u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info); ++ ++ DBG_88E("HT: STA %pM HT Capabilities Info: 0x%04x\n", ++ (psta->hwaddr), ht_capab); ++ ++ if (psta->no_ht_set) { ++ psta->no_ht_set = 0; ++ pmlmepriv->num_sta_no_ht--; ++ } ++ ++ if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) { ++ if (!psta->no_ht_gf_set) { ++ psta->no_ht_gf_set = 1; ++ pmlmepriv->num_sta_ht_no_gf++; ++ } ++ DBG_88E("%s STA %pM - no greenfield, num of non-gf stations %d\n", ++ __func__, (psta->hwaddr), ++ pmlmepriv->num_sta_ht_no_gf); ++ } ++ ++ if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH_20_40) == 0) { ++ if (!psta->ht_20mhz_set) { ++ psta->ht_20mhz_set = 1; ++ pmlmepriv->num_sta_ht_20mhz++; ++ } ++ DBG_88E("%s STA %pM - 20 MHz HT, num of 20MHz HT STAs %d\n", ++ __func__, (psta->hwaddr), ++ pmlmepriv->num_sta_ht_20mhz); ++ } ++ } else { ++ if (!psta->no_ht_set) { ++ psta->no_ht_set = 1; ++ pmlmepriv->num_sta_no_ht++; ++ } ++ if (pmlmepriv->htpriv.ht_option) { ++ DBG_88E("%s STA %pM - no HT, num of non-HT stations %d\n", ++ __func__, (psta->hwaddr), ++ pmlmepriv->num_sta_no_ht); ++ } ++ } ++ ++ if (rtw_ht_operation_update(padapter) > 0) { ++ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false); ++ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true); ++ } ++ ++ /* update associcated stations cap. */ ++ associated_clients_update(padapter, beacon_updated); ++ ++ DBG_88E("%s, updated =%d\n", __func__, beacon_updated); ++} ++ ++u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 beacon_updated = false; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (!psta) ++ return beacon_updated; ++ ++ if (psta->no_short_preamble_set) { ++ psta->no_short_preamble_set = 0; ++ pmlmepriv->num_sta_no_short_preamble--; ++ if (pmlmeext->cur_wireless_mode > WIRELESS_11B && ++ pmlmepriv->num_sta_no_short_preamble == 0) { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ ++ if (psta->nonerp_set) { ++ psta->nonerp_set = 0; ++ pmlmepriv->num_sta_non_erp--; ++ if (pmlmepriv->num_sta_non_erp == 0) { ++ beacon_updated = true; ++ update_beacon(padapter, _ERPINFO_IE_, NULL, true); ++ } ++ } ++ ++ if (psta->no_short_slot_time_set) { ++ psta->no_short_slot_time_set = 0; ++ pmlmepriv->num_sta_no_short_slot_time--; ++ if (pmlmeext->cur_wireless_mode > WIRELESS_11B && ++ pmlmepriv->num_sta_no_short_slot_time == 0) { ++ beacon_updated = true; ++ update_beacon(padapter, 0xFF, NULL, true); ++ } ++ } ++ ++ if (psta->no_ht_gf_set) { ++ psta->no_ht_gf_set = 0; ++ pmlmepriv->num_sta_ht_no_gf--; ++ } ++ ++ if (psta->no_ht_set) { ++ psta->no_ht_set = 0; ++ pmlmepriv->num_sta_no_ht--; ++ } ++ ++ if (psta->ht_20mhz_set) { ++ psta->ht_20mhz_set = 0; ++ pmlmepriv->num_sta_ht_20mhz--; ++ } ++ ++ if (rtw_ht_operation_update(padapter) > 0) { ++ update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, false); ++ update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true); ++ } ++ ++ /* update associcated stations cap. */ ++ ++ DBG_88E("%s, updated =%d\n", __func__, beacon_updated); ++ ++ return beacon_updated; ++} ++ ++u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta, ++ bool active, u16 reason) ++{ ++ u8 beacon_updated = false; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if (!psta) ++ return beacon_updated; ++ ++ /* tear down Rx AMPDU */ ++ send_delba(padapter, 0, psta->hwaddr);/* recipient */ ++ ++ /* tear down TX AMPDU */ ++ send_delba(padapter, 1, psta->hwaddr);/* originator */ ++ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ ++ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ ++ ++ if (active) ++ issue_deauth(padapter, psta->hwaddr, reason); ++ ++ /* clear cam entry / key */ ++ rtw_clearstakey_cmd(padapter, (u8 *)psta, (u8)(psta->mac_id + 3), true); ++ ++ spin_lock_bh(&psta->lock); ++ psta->state &= ~_FW_LINKED; ++ spin_unlock_bh(&psta->lock); ++ ++ rtw_indicate_sta_disassoc_event(padapter, psta); ++ ++ report_del_sta_event(padapter, psta->hwaddr, reason); ++ ++ beacon_updated = bss_cap_update_on_sta_leave(padapter, psta); ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ rtw_free_stainfo(padapter, psta); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ return beacon_updated; ++} ++ ++int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset) ++{ ++ struct list_head *phead, *plist; ++ int ret = 0; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) ++ return ret; ++ ++ DBG_88E(FUNC_NDEV_FMT" with ch:%u, offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset); ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ phead = &pstapriv->asoc_list; ++ plist = phead->next; ++ ++ /* for each sta in asoc_queue */ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, asoc_list); ++ plist = plist->next; ++ ++ issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset); ++ psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2); ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset); ++ ++ return ret; ++} ++ ++int rtw_sta_flush(struct adapter *padapter) ++{ ++ struct list_head *phead, *plist; ++ int ret = 0; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); ++ ++ if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) ++ return ret; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ phead = &pstapriv->asoc_list; ++ plist = phead->next; ++ ++ /* free sta asoc_queue */ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, asoc_list); ++ ++ plist = plist->next; ++ ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ ++ ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING); ++ ++ associated_clients_update(padapter, true); ++ ++ return ret; ++} ++ ++/* called > TSR LEVEL for USB or SDIO Interface*/ ++void sta_info_update(struct adapter *padapter, struct sta_info *psta) ++{ ++ int flags = psta->flags; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ /* update wmm cap. */ ++ if (WLAN_STA_WME & flags) ++ psta->qos_option = 1; ++ else ++ psta->qos_option = 0; ++ ++ if (pmlmepriv->qospriv.qos_option == 0) ++ psta->qos_option = 0; ++ ++ /* update 802.11n ht cap. */ ++ if (WLAN_STA_HT & flags) { ++ psta->htpriv.ht_option = true; ++ psta->qos_option = 1; ++ } else { ++ psta->htpriv.ht_option = false; ++ } ++ ++ if (!pmlmepriv->htpriv.ht_option) ++ psta->htpriv.ht_option = false; ++ ++ update_sta_info_apmode(padapter, psta); ++} ++ ++/* called >= TSR LEVEL for USB or SDIO Interface*/ ++void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta) ++{ ++ if (psta->state & _FW_LINKED) { ++ /* add ratid */ ++ add_RATid(padapter, psta, 0);/* DM_RATR_STA_INIT */ ++ } ++} ++ ++void start_ap_mode(struct adapter *padapter) ++{ ++ int i; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ ++ pmlmepriv->update_bcn = false; ++ ++ pmlmeext->bstart_bss = false; ++ ++ pmlmepriv->num_sta_non_erp = 0; ++ ++ pmlmepriv->num_sta_no_short_slot_time = 0; ++ ++ pmlmepriv->num_sta_no_short_preamble = 0; ++ ++ pmlmepriv->num_sta_ht_no_gf = 0; ++ pmlmepriv->num_sta_no_ht = 0; ++ pmlmepriv->num_sta_ht_20mhz = 0; ++ ++ pmlmepriv->olbc = false; ++ ++ pmlmepriv->olbc_ht = false; ++ ++ pmlmepriv->ht_op_mode = 0; ++ ++ for (i = 0; i < NUM_STA; i++) ++ pstapriv->sta_aid[i] = NULL; ++ ++ pmlmepriv->wps_beacon_ie = NULL; ++ pmlmepriv->wps_probe_resp_ie = NULL; ++ pmlmepriv->wps_assoc_resp_ie = NULL; ++ ++ pmlmepriv->p2p_beacon_ie = NULL; ++ pmlmepriv->p2p_probe_resp_ie = NULL; ++ ++ /* for ACL */ ++ INIT_LIST_HEAD(&pacl_list->acl_node_q.queue); ++ pacl_list->num = 0; ++ pacl_list->mode = 0; ++ for (i = 0; i < NUM_ACL; i++) { ++ INIT_LIST_HEAD(&pacl_list->aclnode[i].list); ++ pacl_list->aclnode[i].valid = false; ++ } ++} ++ ++void stop_ap_mode(struct adapter *padapter) ++{ ++ struct list_head *phead, *plist; ++ struct rtw_wlan_acl_node *paclnode; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ struct __queue *pacl_node_q = &pacl_list->acl_node_q; ++ ++ pmlmepriv->update_bcn = false; ++ pmlmeext->bstart_bss = false; ++ ++ /* reset and init security priv , this can refine with rtw_reset_securitypriv */ ++ memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv)); ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; ++ ++ /* for ACL */ ++ spin_lock_bh(&pacl_node_q->lock); ++ phead = get_list_head(pacl_node_q); ++ plist = phead->next; ++ while (phead != plist) { ++ paclnode = container_of(plist, struct rtw_wlan_acl_node, list); ++ plist = plist->next; ++ ++ if (paclnode->valid) { ++ paclnode->valid = false; ++ ++ list_del_init(&paclnode->list); ++ ++ pacl_list->num--; ++ } ++ } ++ spin_unlock_bh(&pacl_node_q->lock); ++ ++ DBG_88E("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num); ++ ++ rtw_sta_flush(padapter); ++ ++ /* free_assoc_sta_resources */ ++ rtw_free_all_stainfo(padapter); ++ ++ psta = rtw_get_bcmc_stainfo(padapter); ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ rtw_free_stainfo(padapter, psta); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ rtw_init_bcmc_stainfo(padapter); ++ ++ rtw_free_mlme_priv_ie_data(pmlmepriv); ++} ++ ++#endif /* CONFIG_88EU_AP_MODE */ +diff --git a/drivers/staging/r8188eu/core/rtw_br_ext.c b/drivers/staging/r8188eu/core/rtw_br_ext.c +new file mode 100644 +index 000000000000..62a672243696 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_br_ext.c +@@ -0,0 +1,717 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. i*/ ++ ++#define _RTW_BR_EXT_C_ ++ ++#include "../include/linux/if_arp.h" ++#include "../include/net/ip.h" ++#include "../include/linux/atalk.h" ++#include "../include/linux/udp.h" ++#include "../include/linux/if_pppox.h" ++ ++#include "../include/drv_types.h" ++#include "../include/rtw_br_ext.h" ++#include "../include/usb_osintf.h" ++#include "../include/recv_osdep.h" ++ ++#ifndef csum_ipv6_magic ++#include "../include/net/ip6_checksum.h" ++#endif ++ ++#include "../include/linux/ipv6.h" ++#include "../include/linux/icmpv6.h" ++#include "../include/net/ndisc.h" ++#include "../include/net/checksum.h" ++ ++#define NAT25_IPV4 01 ++#define NAT25_IPV6 02 ++#define NAT25_IPX 03 ++#define NAT25_APPLE 04 ++#define NAT25_PPPOE 05 ++ ++#define RTL_RELAY_TAG_LEN (ETH_ALEN) ++#define TAG_HDR_LEN 4 ++ ++#define MAGIC_CODE 0x8186 ++#define MAGIC_CODE_LEN 2 ++#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */ ++ ++/*----------------------------------------------------------------- ++ How database records network address: ++ 0 1 2 3 4 5 6 7 8 9 10 ++ |----|----|----|----|----|----|----|----|----|----|----| ++ IPv4 |type| | IP addr | ++ IPX |type| Net addr | Node addr | ++ IPX |type| Net addr |Sckt addr| ++ Apple |type| Network |node| ++ PPPoE |type| SID | AC MAC | ++-----------------------------------------------------------------*/ ++ ++/* Find a tag in pppoe frame and return the pointer */ ++static unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type) ++{ ++ unsigned char *cur_ptr, *start_ptr; ++ unsigned short tagLen, tagType; ++ ++ start_ptr = cur_ptr = (unsigned char *)ph->tag; ++ while ((cur_ptr - start_ptr) < ntohs(ph->length)) { ++ /* prevent un-alignment access */ ++ tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]); ++ tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]); ++ if (tagType == type) ++ return cur_ptr; ++ cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen; ++ } ++ return NULL; ++} ++ ++static int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag) ++{ ++ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); ++ int data_len; ++ ++ data_len = tag->tag_len + TAG_HDR_LEN; ++ if (skb_tailroom(skb) < data_len) { ++ _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n"); ++ return -1; ++ } ++ ++ skb_put(skb, data_len); ++ /* have a room for new tag */ ++ memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length)); ++ ph->length = htons(ntohs(ph->length) + data_len); ++ memcpy((unsigned char *)ph->tag, tag, data_len); ++ return data_len; ++} ++ ++static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len) ++{ ++ int tail_len; ++ unsigned long end, tail; ++ ++ if ((src+len) > skb_tail_pointer(skb) || skb->len < len) ++ return -1; ++ ++ tail = (unsigned long)skb_tail_pointer(skb); ++ end = (unsigned long)src+len; ++ if (tail < end) ++ return -1; ++ ++ tail_len = (int)(tail-end); ++ if (tail_len > 0) ++ memmove(src, src+len, tail_len); ++ ++ skb_trim(skb, skb->len-len); ++ return 0; ++} ++ ++static unsigned long __nat25_timeout(struct adapter *priv) ++{ ++ unsigned long timeout; ++ ++ timeout = jiffies - NAT25_AGEING_TIME*HZ; ++ ++ return timeout; ++} ++ ++static int __nat25_has_expired(struct adapter *priv, ++ struct nat25_network_db_entry *fdb) ++{ ++ if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv))) ++ return 1; ++ ++ return 0; ++} ++ ++static void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr, ++ unsigned int *ipAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPV4; ++ memcpy(networkAddr+7, (unsigned char *)ipAddr, 4); ++} ++ ++static void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr, ++ unsigned char *ac_mac, __be16 *sid) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_PPPOE; ++ memcpy(networkAddr+1, (unsigned char *)sid, 2); ++ memcpy(networkAddr+3, (unsigned char *)ac_mac, 6); ++} ++ ++static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr, ++ unsigned int *ipAddr) ++{ ++ memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); ++ ++ networkAddr[0] = NAT25_IPV6; ++ memcpy(networkAddr+1, (unsigned char *)ipAddr, 16); ++} ++ ++static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b) ++{ ++ while (len > 0) { ++ if (*data == tag && *(data+1) == len8b && len >= len8b*8) ++ return data+2; ++ ++ len -= (*(data+1))*8; ++ data += (*(data+1))*8; ++ } ++ return NULL; ++} ++ ++static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac) ++{ ++ struct icmp6hdr *icmphdr = (struct icmp6hdr *)data; ++ unsigned char *mac; ++ ++ if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) { ++ if (len >= 8) { ++ mac = scan_tlv(&data[8], len-8, 1, 1); ++ if (mac) { ++ _DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ++ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) { ++ if (len >= 16) { ++ mac = scan_tlv(&data[16], len-16, 1, 1); ++ if (mac) { ++ _DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ++ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { ++ if (len >= 24) { ++ mac = scan_tlv(&data[24], len-24, 1, 1); ++ if (mac) { ++ _DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ++ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { ++ if (len >= 24) { ++ mac = scan_tlv(&data[24], len-24, 2, 1); ++ if (mac) { ++ _DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ++ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } else if (icmphdr->icmp6_type == NDISC_REDIRECT) { ++ if (len >= 40) { ++ mac = scan_tlv(&data[40], len-40, 2, 1); ++ if (mac) { ++ _DEBUG_INFO("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", ++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ++ replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); ++ memcpy(mac, replace_mac, 6); ++ return 1; ++ } ++ } ++ } ++ return 0; ++} ++ ++static int __nat25_network_hash(unsigned char *networkAddr) ++{ ++ if (networkAddr[0] == NAT25_IPV4) { ++ unsigned long x; ++ ++ x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } else if (networkAddr[0] == NAT25_IPX) { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ ++ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } else if (networkAddr[0] == NAT25_APPLE) { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } else if (networkAddr[0] == NAT25_PPPOE) { ++ unsigned long x; ++ ++ x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } else if (networkAddr[0] == NAT25_IPV6) { ++ unsigned long x; ++ ++ x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ ++ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^ ++ networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^ ++ networkAddr[16]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } else { ++ unsigned long x = 0; ++ int i; ++ ++ for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++) ++ x ^= networkAddr[i]; ++ ++ return x & (NAT25_HASH_SIZE - 1); ++ } ++} ++ ++static void __network_hash_link(struct adapter *priv, ++ struct nat25_network_db_entry *ent, int hash) ++{ ++ /* Caller must spin_lock already! */ ++ ent->next_hash = priv->nethash[hash]; ++ if (ent->next_hash) ++ ent->next_hash->pprev_hash = &ent->next_hash; ++ priv->nethash[hash] = ent; ++ ent->pprev_hash = &priv->nethash[hash]; ++} ++ ++static void __network_hash_unlink(struct nat25_network_db_entry *ent) ++{ ++ /* Caller must spin_lock already! */ ++ *ent->pprev_hash = ent->next_hash; ++ if (ent->next_hash) ++ ent->next_hash->pprev_hash = ent->pprev_hash; ++ ent->next_hash = NULL; ++ ent->pprev_hash = NULL; ++} ++ ++static void __nat25_db_network_insert(struct adapter *priv, ++ unsigned char *macAddr, unsigned char *networkAddr) ++{ ++ struct nat25_network_db_entry *db; ++ int hash; ++ ++ spin_lock_bh(&priv->br_ext_lock); ++ hash = __nat25_network_hash(networkAddr); ++ db = priv->nethash[hash]; ++ while (db) { ++ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { ++ memcpy(db->macAddr, macAddr, ETH_ALEN); ++ db->ageing_timer = jiffies; ++ spin_unlock_bh(&priv->br_ext_lock); ++ return; ++ } ++ db = db->next_hash; ++ } ++ db = kmalloc(sizeof(*db), GFP_ATOMIC); ++ if (!db) { ++ spin_unlock_bh(&priv->br_ext_lock); ++ return; ++ } ++ memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN); ++ memcpy(db->macAddr, macAddr, ETH_ALEN); ++ atomic_set(&db->use_count, 1); ++ db->ageing_timer = jiffies; ++ ++ __network_hash_link(priv, db, hash); ++ ++ spin_unlock_bh(&priv->br_ext_lock); ++} ++ ++static void __nat25_db_print(struct adapter *priv) ++{ ++} ++ ++/* ++ * NAT2.5 interface ++ */ ++ ++void nat25_db_cleanup(struct adapter *priv) ++{ ++ int i; ++ ++ spin_lock_bh(&priv->br_ext_lock); ++ ++ for (i = 0; i < NAT25_HASH_SIZE; i++) { ++ struct nat25_network_db_entry *f; ++ f = priv->nethash[i]; ++ while (f) { ++ struct nat25_network_db_entry *g; ++ ++ g = f->next_hash; ++ if (priv->scdb_entry == f) { ++ memset(priv->scdb_mac, 0, ETH_ALEN); ++ memset(priv->scdb_ip, 0, 4); ++ priv->scdb_entry = NULL; ++ } ++ __network_hash_unlink(f); ++ kfree(f); ++ f = g; ++ } ++ } ++ spin_unlock_bh(&priv->br_ext_lock); ++} ++ ++void nat25_db_expire(struct adapter *priv) ++{ ++ int i; ++ ++ spin_lock_bh(&priv->br_ext_lock); ++ ++ for (i = 0; i < NAT25_HASH_SIZE; i++) { ++ struct nat25_network_db_entry *f; ++ f = priv->nethash[i]; ++ ++ while (f) { ++ struct nat25_network_db_entry *g; ++ g = f->next_hash; ++ ++ if (__nat25_has_expired(priv, f)) { ++ if (atomic_dec_and_test(&f->use_count)) { ++ if (priv->scdb_entry == f) { ++ memset(priv->scdb_mac, 0, ETH_ALEN); ++ memset(priv->scdb_ip, 0, 4); ++ priv->scdb_entry = NULL; ++ } ++ __network_hash_unlink(f); ++ kfree(f); ++ } ++ } ++ f = g; ++ } ++ } ++ spin_unlock_bh(&priv->br_ext_lock); ++} ++ ++int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method) ++{ ++ unsigned short protocol; ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++ unsigned int tmp; ++ ++ if (!skb) ++ return -1; ++ ++ if ((method <= NAT25_MIN) || (method >= NAT25_MAX)) ++ return -1; ++ ++ protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN))); ++ ++ /*---------------------------------------------------*/ ++ /* Handle IP frame */ ++ /*---------------------------------------------------*/ ++ if (protocol == ETH_P_IP) { ++ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); ++ ++ if (((unsigned char *)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) { ++ DEBUG_WARN("NAT25: malformed IP packet !\n"); ++ return -1; ++ } ++ ++ switch (method) { ++ case NAT25_CHECK: ++ return -1; ++ case NAT25_INSERT: ++ /* some multicast with source IP is all zero, maybe other case is illegal */ ++ /* in class A, B, C, host address is all zero or all one is illegal */ ++ if (iph->saddr == 0) ++ return 0; ++ tmp = be32_to_cpu(iph->saddr); ++ DEBUG_INFO("NAT25: Insert IP, SA =%08x, DA =%08x\n", tmp, iph->daddr); ++ __nat25_generate_ipv4_network_addr(networkAddr, &tmp); ++ /* record source IP address and , source mac address into db */ ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(priv); ++ return 0; ++ default: ++ return -1; ++ } ++ } else if (protocol == ETH_P_ARP) { ++ /*---------------------------------------------------*/ ++ /* Handle ARP frame */ ++ /*---------------------------------------------------*/ ++ struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN); ++ unsigned char *arp_ptr = (unsigned char *)(arp + 1); ++ unsigned int *sender; ++ ++ if (arp->ar_pro != __constant_htons(ETH_P_IP)) { ++ DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", be16_to_cpu(arp->ar_pro)); ++ return -1; ++ } ++ ++ switch (method) { ++ case NAT25_CHECK: ++ return 0; /* skb_copy for all ARP frame */ ++ case NAT25_INSERT: ++ DEBUG_INFO("NAT25: Insert ARP, MAC =%02x%02x%02x%02x%02x%02x\n", arp_ptr[0], ++ arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]); ++ ++ /* change to ARP sender mac address to wlan STA address */ ++ memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN); ++ arp_ptr += arp->ar_hln; ++ sender = (unsigned int *)arp_ptr; ++ __nat25_generate_ipv4_network_addr(networkAddr, sender); ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ __nat25_db_print(priv); ++ return 0; ++ default: ++ return -1; ++ } ++ } else if ((protocol == ETH_P_PPP_DISC) || ++ (protocol == ETH_P_PPP_SES)) { ++ /*---------------------------------------------------*/ ++ /* Handle PPPoE frame */ ++ /*---------------------------------------------------*/ ++ struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); ++ unsigned short *pMagic; ++ ++ switch (method) { ++ case NAT25_CHECK: ++ if (ph->sid == 0) ++ return 0; ++ return 1; ++ case NAT25_INSERT: ++ if (ph->sid == 0) { /* Discovery phase according to tag */ ++ if (ph->code == PADI_CODE || ph->code == PADR_CODE) { ++ if (priv->ethBrExtInfo.addPPPoETag) { ++ struct pppoe_tag *tag, *pOldTag; ++ unsigned char tag_buf[40]; ++ int old_tag_len = 0; ++ ++ tag = (struct pppoe_tag *)tag_buf; ++ pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); ++ if (pOldTag) { /* if SID existed, copy old value and delete it */ ++ old_tag_len = ntohs(pOldTag->tag_len); ++ if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) { ++ DEBUG_ERR("SID tag length too long!\n"); ++ return -1; ++ } ++ ++ memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN, ++ pOldTag->tag_data, old_tag_len); ++ ++ if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) { ++ DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n"); ++ return -1; ++ } ++ ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len); ++ } ++ ++ tag->tag_type = PTT_RELAY_SID; ++ tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len); ++ ++ /* insert the magic_code+client mac in relay tag */ ++ pMagic = (unsigned short *)tag->tag_data; ++ *pMagic = htons(MAGIC_CODE); ++ memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN); ++ ++ /* Add relay tag */ ++ if (__nat25_add_pppoe_tag(skb, tag) < 0) ++ return -1; ++ ++ DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n", ++ (ph->code == PADI_CODE ? "PADI" : "PADR")); ++ } else { /* not add relay tag */ ++ if (priv->pppoe_connection_in_progress && ++ memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) { ++ DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n"); ++ return -2; ++ } ++ ++ if (priv->pppoe_connection_in_progress == 0) ++ memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN); ++ ++ priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; ++ } ++ } else { ++ return -1; ++ } ++ } else { /* session phase */ ++ DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name); ++ ++ __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &ph->sid); ++ ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ ++ __nat25_db_print(priv); ++ ++ if (!priv->ethBrExtInfo.addPPPoETag && ++ priv->pppoe_connection_in_progress && ++ !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) ++ priv->pppoe_connection_in_progress = 0; ++ } ++ return 0; ++ default: ++ return -1; ++ } ++ } else if (protocol == 0x888e) { ++ /*---------------------------------------------------*/ ++ /* Handle EAP frame */ ++ /*---------------------------------------------------*/ ++ switch (method) { ++ case NAT25_CHECK: ++ return -1; ++ case NAT25_INSERT: ++ return 0; ++ default: ++ return -1; ++ } ++ } else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) { ++ /*---------------------------------------------------*/ ++ /* Handle C-Media proprietary frame */ ++ /*---------------------------------------------------*/ ++ switch (method) { ++ case NAT25_CHECK: ++ return -1; ++ case NAT25_INSERT: ++ return 0; ++ default: ++ return -1; ++ } ++ } else if (protocol == ETH_P_IPV6) { ++ /*------------------------------------------------*/ ++ /* Handle IPV6 frame */ ++ /*------------------------------------------------*/ ++ struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); ++ ++ if (sizeof(*iph) >= (skb->len - ETH_HLEN)) { ++ DEBUG_WARN("NAT25: malformed IPv6 packet !\n"); ++ return -1; ++ } ++ ++ switch (method) { ++ case NAT25_CHECK: ++ if (skb->data[0] & 1) ++ return 0; ++ return -1; ++ case NAT25_INSERT: ++ DEBUG_INFO("NAT25: Insert IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," ++ " DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", ++ iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], ++ iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], ++ iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], ++ iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); ++ ++ if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) { ++ __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr); ++ __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr); ++ __nat25_db_print(priv); ++ ++ if (iph->nexthdr == IPPROTO_ICMPV6 && ++ skb->len > (ETH_HLEN + sizeof(*iph) + 4)) { ++ if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph), ++ skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) { ++ struct icmp6hdr *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph)); ++ hdr->icmp6_cksum = 0; ++ hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr, ++ iph->payload_len, ++ IPPROTO_ICMPV6, ++ csum_partial((__u8 *)hdr, iph->payload_len, 0)); ++ } ++ } ++ } ++ return 0; ++ default: ++ return -1; ++ } ++ } ++ return -1; ++} ++ ++#define SERVER_PORT 67 ++#define CLIENT_PORT 68 ++#define DHCP_MAGIC 0x63825363 ++#define BROADCAST_FLAG 0x8000 ++ ++struct dhcpMessage { ++ u_int8_t op; ++ u_int8_t htype; ++ u_int8_t hlen; ++ u_int8_t hops; ++ u_int32_t xid; ++ __be16 secs; ++ __be16 flags; ++ __be32 ciaddr; ++ __be32 yiaddr; ++ __be32 siaddr; ++ __be32 giaddr; ++ u_int8_t chaddr[16]; ++ u_int8_t sname[64]; ++ u_int8_t file[128]; ++ __be32 cookie; ++ u_int8_t options[308]; /* 312 - cookie */ ++}; ++ ++void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb) ++{ ++ if (!skb) ++ return; ++ ++ if (!priv->ethBrExtInfo.dhcp_bcst_disable) { ++ __be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN)); ++ ++ if (protocol == __constant_htons(ETH_P_IP)) { /* IP */ ++ struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); ++ ++ if (iph->protocol == IPPROTO_UDP) { /* UDP */ ++ struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2)); ++ ++ if ((udph->source == __constant_htons(CLIENT_PORT)) && ++ (udph->dest == __constant_htons(SERVER_PORT))) { /* DHCP request */ ++ struct dhcpMessage *dhcph = ++ (struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr)); ++ u32 cookie = be32_to_cpu((__be32)dhcph->cookie); ++ ++ if (cookie == DHCP_MAGIC) { /* match magic word */ ++ if (!(dhcph->flags & htons(BROADCAST_FLAG))) { ++ /* if not broadcast */ ++ register int sum = 0; ++ ++ DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n"); ++ /* or BROADCAST flag */ ++ dhcph->flags |= htons(BROADCAST_FLAG); ++ /* recalculate checksum */ ++ sum = ~(udph->check) & 0xffff; ++ sum += be16_to_cpu(dhcph->flags); ++ while (sum >> 16) ++ sum = (sum & 0xffff) + (sum >> 16); ++ udph->check = ~sum; ++ } ++ } ++ } ++ } ++ } ++ } ++} ++ ++void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr, ++ unsigned char *ipAddr) ++{ ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++ struct nat25_network_db_entry *db; ++ int hash; ++ ++ __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr); ++ hash = __nat25_network_hash(networkAddr); ++ db = priv->nethash[hash]; ++ while (db) { ++ if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { ++ return (void *)db; ++ } ++ ++ db = db->next_hash; ++ } ++ ++ return NULL; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_cmd.c b/drivers/staging/r8188eu/core/rtw_cmd.c +new file mode 100644 +index 000000000000..ce73ac7cf973 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_cmd.c +@@ -0,0 +1,2128 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_CMD_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/mlme_osdep.h" ++#include "../include/rtw_br_ext.h" ++#include "../include/rtw_mlme_ext.h" ++ ++/* ++Caller and the rtw_cmd_thread can protect cmd_q by spin_lock. ++No irqsave is necessary. ++*/ ++ ++static int _rtw_init_cmd_priv(struct cmd_priv *pcmdpriv) ++{ ++ int res = _SUCCESS; ++ ++ sema_init(&pcmdpriv->cmd_queue_sema, 0); ++ /* sema_init(&(pcmdpriv->cmd_done_sema), 0); */ ++ sema_init(&pcmdpriv->terminate_cmdthread_sema, 0); ++ ++ _rtw_init_queue(&pcmdpriv->cmd_queue); ++ ++ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ ++ ++ pcmdpriv->cmd_seq = 1; ++ ++ pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ, ++ GFP_KERNEL); ++ ++ if (!pcmdpriv->cmd_allocated_buf) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ((size_t)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ - 1)); ++ ++ pcmdpriv->rsp_allocated_buf = kzalloc(MAX_RSPSZ + 4, GFP_KERNEL); ++ ++ if (!pcmdpriv->rsp_allocated_buf) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ((size_t)(pcmdpriv->rsp_allocated_buf) & 3); ++ ++ pcmdpriv->cmd_issued_cnt = 0; ++ pcmdpriv->cmd_done_cnt = 0; ++ pcmdpriv->rsp_cnt = 0; ++exit: ++ ++ return res; ++} ++ ++static void c2h_wk_callback(struct work_struct *work); ++ ++static int _rtw_init_evt_priv(struct evt_priv *pevtpriv) ++{ ++ int res = _SUCCESS; ++ ++ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ ++ atomic_set(&pevtpriv->event_seq, 0); ++ pevtpriv->evt_done_cnt = 0; ++ ++ _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); ++ pevtpriv->c2h_wk_alive = false; ++ pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN + 1); ++ ++ return res; ++} ++ ++void rtw_free_evt_priv(struct evt_priv *pevtpriv) ++{ ++ _cancel_workitem_sync(&pevtpriv->c2h_wk); ++ while (pevtpriv->c2h_wk_alive) ++ msleep(10); ++ ++ while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) { ++ void *c2h = rtw_cbuf_pop(pevtpriv->c2h_queue); ++ if (c2h && c2h != (void *)pevtpriv) ++ kfree(c2h); ++ } ++} ++ ++static void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) ++{ ++ if (pcmdpriv) { ++ kfree(pcmdpriv->cmd_allocated_buf); ++ kfree(pcmdpriv->rsp_allocated_buf); ++ } ++} ++ ++/* ++Calling Context: ++ ++rtw_enqueue_cmd can only be called between kernel thread, ++since only spin_lock is used. ++ ++ISR/Call-Back functions can't call this sub-function. ++ ++*/ ++ ++static int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj) ++{ ++ unsigned long flags; ++ ++ if (!obj) ++ goto exit; ++ ++ spin_lock_irqsave(&queue->lock, flags); ++ ++ list_add_tail(&obj->list, &queue->queue); ++ ++ spin_unlock_irqrestore(&queue->lock, flags); ++ ++exit: ++ ++ return _SUCCESS; ++} ++ ++static struct cmd_obj *_rtw_dequeue_cmd(struct __queue *queue) ++{ ++ struct cmd_obj *obj; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&queue->lock, flags); ++ if (list_empty(&queue->queue)) { ++ obj = NULL; ++ } else { ++ obj = container_of((&queue->queue)->next, struct cmd_obj, list); ++ rtw_list_delete(&obj->list); ++ } ++ ++ spin_unlock_irqrestore(&queue->lock, flags); ++ ++ return obj; ++} ++ ++u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv) ++{ ++ u32 res; ++ ++ res = _rtw_init_cmd_priv(pcmdpriv); ++ ++ return res; ++} ++ ++u32 rtw_init_evt_priv(struct evt_priv *pevtpriv) ++{ ++ int res; ++ ++ res = _rtw_init_evt_priv(pevtpriv); ++ ++ return res; ++} ++ ++void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) ++{ ++ _rtw_free_cmd_priv(pcmdpriv); ++} ++ ++static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) ++{ ++ u8 bAllow = false; /* set to true to allow enqueuing cmd when hw_init_completed is false */ ++ ++ /* To decide allow or not */ ++ if ((pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect) && ++ (!pcmdpriv->padapter->registrypriv.usbss_enable)) { ++ if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf; ++ if (pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID) ++ bAllow = true; ++ } ++ } ++ ++ if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan)) ++ bAllow = true; ++ ++ if ((!pcmdpriv->padapter->hw_init_completed && !bAllow) || ++ !pcmdpriv->cmdthd_running) /* com_thread not running */ ++ return _FAIL; ++ return _SUCCESS; ++} ++ ++u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) ++{ ++ int res = _FAIL; ++ struct adapter *padapter = pcmdpriv->padapter; ++ ++ if (!cmd_obj) ++ goto exit; ++ ++ cmd_obj->padapter = padapter; ++ ++ res = rtw_cmd_filter(pcmdpriv, cmd_obj); ++ if (_FAIL == res) { ++ rtw_free_cmd_obj(cmd_obj); ++ goto exit; ++ } ++ ++ res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj); ++ ++ if (res == _SUCCESS) ++ up(&pcmdpriv->cmd_queue_sema); ++ ++exit: ++ ++ return res; ++} ++ ++struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv) ++{ ++ struct cmd_obj *cmd_obj; ++ ++ cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue); ++ ++ return cmd_obj; ++} ++ ++void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv) ++{ ++ ++ pcmdpriv->cmd_done_cnt++; ++ /* up(&(pcmdpriv->cmd_done_sema)); */ ++ ++} ++ ++void rtw_free_cmd_obj(struct cmd_obj *pcmd) ++{ ++ ++ if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) { ++ /* free parmbuf in cmd_obj */ ++ kfree(pcmd->parmbuf); ++ } ++ ++ if (pcmd->rsp) { ++ if (pcmd->rspsz != 0) { ++ /* free rsp in cmd_obj */ ++ kfree(pcmd->rsp); ++ } ++ } ++ ++ /* free cmd_obj */ ++ kfree(pcmd); ++ ++} ++ ++int rtw_cmd_thread(void *context) ++{ ++ u8 ret; ++ struct cmd_obj *pcmd; ++ u8 *pcmdbuf; ++ u8 (*cmd_hdl)(struct adapter *padapter, u8 *pbuf); ++ void (*pcmd_callback)(struct adapter *dev, struct cmd_obj *pcmd); ++ struct adapter *padapter = (struct adapter *)context; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ thread_enter("RTW_CMD_THREAD"); ++ ++ pcmdbuf = pcmdpriv->cmd_buf; ++ ++ pcmdpriv->cmdthd_running = true; ++ up(&pcmdpriv->terminate_cmdthread_sema); ++ ++ while (1) { ++ if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL) ++ break; ++ ++ if (padapter->bDriverStopped || ++ padapter->bSurpriseRemoved) { ++ DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", ++ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); ++ break; ++ } ++_next: ++ if (padapter->bDriverStopped || ++ padapter->bSurpriseRemoved) { ++ DBG_88E("%s: DriverStopped(%d) SurpriseRemoved(%d) break at line %d\n", ++ __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, __LINE__); ++ break; ++ } ++ ++ pcmd = rtw_dequeue_cmd(pcmdpriv); ++ if (!pcmd) ++ continue; ++ ++ if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) { ++ pcmd->res = H2C_DROPPED; ++ goto post_process; ++ } ++ ++ pcmdpriv->cmd_issued_cnt++; ++ ++ pcmd->cmdsz = _RND4((pcmd->cmdsz));/* _RND4 */ ++ ++ memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); ++ ++ if (pcmd->cmdcode < ARRAY_SIZE(wlancmds)) { ++ cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; ++ ++ if (cmd_hdl) { ++ ret = cmd_hdl(pcmd->padapter, pcmdbuf); ++ pcmd->res = ret; ++ } ++ ++ pcmdpriv->cmd_seq++; ++ } else { ++ pcmd->res = H2C_PARAMETERS_ERROR; ++ } ++ ++ cmd_hdl = NULL; ++ ++post_process: ++ ++ /* call callback function for post-processed */ ++ if (pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) { ++ pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; ++ if (!pcmd_callback) ++ rtw_free_cmd_obj(pcmd); ++ else ++ /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */ ++ pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */ ++ } else { ++ rtw_free_cmd_obj(pcmd); ++ } ++ ++ flush_signals_thread(); ++ ++ goto _next; ++ } ++ pcmdpriv->cmdthd_running = false; ++ ++ /* free all cmd_obj resources */ ++ do { ++ pcmd = rtw_dequeue_cmd(pcmdpriv); ++ if (!pcmd) ++ break; ++ ++ /* DBG_88E("%s: leaving... drop cmdcode:%u\n", __func__, pcmd->cmdcode); */ ++ ++ rtw_free_cmd_obj(pcmd); ++ } while (1); ++ ++ up(&pcmdpriv->terminate_cmdthread_sema); ++ ++ thread_exit(); ++} ++ ++u8 rtw_setstandby_cmd(struct adapter *padapter, uint action) ++{ ++ struct cmd_obj *ph2c; ++ struct usb_suspend_parm *psetusbsuspend; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 ret = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ psetusbsuspend = kzalloc(sizeof(struct usb_suspend_parm), GFP_ATOMIC); ++ if (!psetusbsuspend) { ++ kfree(ph2c); ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ psetusbsuspend->action = action; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend)); ++ ++ ret = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return ret; ++} ++ ++/* ++rtw_sitesurvey_cmd(~) ++ ### NOTE:#### (!!!!) ++ MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock ++*/ ++u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, int ssid_num, ++ struct rtw_ieee80211_channel *ch, int ch_num) ++{ ++ u8 res = _FAIL; ++ struct cmd_obj *ph2c; ++ struct sitesurvey_parm *psurveyPara; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1); ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1); ++ } ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) ++ return _FAIL; ++ ++ psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC); ++ if (!psurveyPara) { ++ kfree(ph2c); ++ return _FAIL; ++ } ++ ++ rtw_free_network_queue(padapter, false); ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); ++ ++ /* psurveyPara->bsslimit = 48; */ ++ psurveyPara->scan_mode = pmlmepriv->scan_mode; ++ ++ /* prepare ssid list */ ++ if (ssid) { ++ int i; ++ for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) { ++ if (ssid[i].SsidLength) { ++ memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(struct ndis_802_11_ssid)); ++ psurveyPara->ssid_num++; ++ } ++ } ++ } ++ ++ /* prepare channel list */ ++ if (ch) { ++ int i; ++ for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) { ++ if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) { ++ memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel)); ++ psurveyPara->ch_num++; ++ } ++ } ++ } ++ ++ set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++ if (res == _SUCCESS) { ++ pmlmepriv->scan_start_time = jiffies; ++ ++ _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT); ++ ++ rtw_led_control(padapter, LED_CTL_SITE_SURVEY); ++ ++ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ ++ } else { ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++ ++ return res; ++} ++ ++u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset) ++{ ++ struct cmd_obj *ph2c; ++ struct setdatarate_parm *pbsetdataratepara; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pbsetdataratepara = kzalloc(sizeof(struct setdatarate_parm), GFP_ATOMIC); ++ if (!pbsetdataratepara) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate)); ++ pbsetdataratepara->mac_id = 5; ++ memcpy(pbsetdataratepara->datarates, rateset, NumRates); ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset) ++{ ++ struct cmd_obj *ph2c; ++ struct setbasicrate_parm *pssetbasicratepara; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ pssetbasicratepara = kzalloc(sizeof(struct setbasicrate_parm), GFP_ATOMIC); ++ ++ if (!pssetbasicratepara) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_); ++ ++ memcpy(pssetbasicratepara->basicrates, rateset, NumRates); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++/* ++unsigned char rtw_setphy_cmd(unsigned char *adapter) ++ ++1. be called only after rtw_update_registrypriv_dev_network(~) or mp testing program ++2. for AdHoc/Ap mode or mp mode? ++ ++*/ ++u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch) ++{ ++ struct cmd_obj *ph2c; ++ struct setphy_parm *psetphypara; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ psetphypara = kzalloc(sizeof(struct setphy_parm), GFP_ATOMIC); ++ ++ if (!psetphypara) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_); ++ ++ psetphypara->modem = modem; ++ psetphypara->rfchannel = ch; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_setbbreg_cmd(struct adapter *padapter, u8 offset, u8 val) ++{ ++ struct cmd_obj *ph2c; ++ struct writeBB_parm *pwritebbparm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ pwritebbparm = kzalloc(sizeof(struct writeBB_parm), GFP_ATOMIC); ++ ++ if (!pwritebbparm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg)); ++ ++ pwritebbparm->offset = offset; ++ pwritebbparm->value = val; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_getbbreg_cmd(struct adapter *padapter, u8 offset, u8 *pval) ++{ ++ struct cmd_obj *ph2c; ++ struct readBB_parm *prdbbparm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ prdbbparm = kzalloc(sizeof(struct readBB_parm), GFP_ATOMIC); ++ ++ if (!prdbbparm) { ++ kfree(ph2c); ++ return _FAIL; ++ } ++ ++ INIT_LIST_HEAD(&ph2c->list); ++ ph2c->cmdcode = GEN_CMD_CODE(_GetBBReg); ++ ph2c->parmbuf = (unsigned char *)prdbbparm; ++ ph2c->cmdsz = sizeof(struct readBB_parm); ++ ph2c->rsp = pval; ++ ph2c->rspsz = sizeof(struct readBB_rsp); ++ ++ prdbbparm->offset = offset; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_setrfreg_cmd(struct adapter *padapter, u8 offset, u32 val) ++{ ++ struct cmd_obj *ph2c; ++ struct writeRF_parm *pwriterfparm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ pwriterfparm = kzalloc(sizeof(struct writeRF_parm), GFP_ATOMIC); ++ ++ if (!pwriterfparm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg)); ++ ++ pwriterfparm->offset = offset; ++ pwriterfparm->value = val; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_getrfreg_cmd(struct adapter *padapter, u8 offset, u8 *pval) ++{ ++ struct cmd_obj *ph2c; ++ struct readRF_parm *prdrfparm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ prdrfparm = kzalloc(sizeof(struct readRF_parm), GFP_ATOMIC); ++ if (!prdrfparm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ INIT_LIST_HEAD(&ph2c->list); ++ ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg); ++ ph2c->parmbuf = (unsigned char *)prdrfparm; ++ ph2c->cmdsz = sizeof(struct readRF_parm); ++ ph2c->rsp = pval; ++ ph2c->rspsz = sizeof(struct readRF_rsp); ++ ++ prdrfparm->offset = offset; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++} ++ ++void rtw_getbbrfreg_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ ++ ++ kfree(pcmd->parmbuf); ++ kfree(pcmd); ++ ++ if (padapter->registrypriv.mp_mode == 1) ++ padapter->mppriv.workparam.bcompleted = true; ++ ++} ++ ++void rtw_readtssi_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ ++ ++ kfree(pcmd->parmbuf); ++ kfree(pcmd); ++ ++ if (padapter->registrypriv.mp_mode == 1) ++ padapter->mppriv.workparam.bcompleted = true; ++ ++} ++ ++u8 rtw_createbss_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *pcmd; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network; ++ u8 res = _SUCCESS; ++ ++ rtw_led_control(padapter, LED_CTL_START_TO_LINK); ++ ++ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!pcmd) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ pcmd->cmdcode = _CreateBss_CMD_; ++ pcmd->parmbuf = (unsigned char *)pdev_network; ++ pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ pdev_network->Length = pcmd->cmdsz; ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_createbss_cmd_ex(struct adapter *padapter, unsigned char *pbss, unsigned int sz) ++{ ++ struct cmd_obj *pcmd; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!pcmd) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ pcmd->cmdcode = GEN_CMD_CODE(_CreateBss); ++ pcmd->parmbuf = pbss; ++ pcmd->cmdsz = sz; ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) ++{ ++ u8 res = _SUCCESS; ++ uint t_len = 0; ++ struct wlan_bssid_ex *psecnetwork; ++ struct cmd_obj *pcmd; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ enum ndis_802_11_network_infra ndis_network_mode = pnetwork->network.InfrastructureMode; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ rtw_led_control(padapter, LED_CTL_START_TO_LINK); ++ ++ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!pcmd) { ++ res = _FAIL; ++ goto exit; ++ } ++ /* for IEs is fix buf size */ ++ t_len = sizeof(struct wlan_bssid_ex); ++ ++ /* for hidden ap to set fw_state here */ ++ if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) { ++ switch (ndis_network_mode) { ++ case Ndis802_11IBSS: ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ break; ++ case Ndis802_11Infrastructure: ++ set_fwstate(pmlmepriv, WIFI_STATION_STATE); ++ break; ++ case Ndis802_11APMode: ++ case Ndis802_11AutoUnknown: ++ case Ndis802_11InfrastructureMax: ++ break; ++ } ++ } ++ ++ psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss; ++ if (!psecnetwork) { ++ kfree(pcmd); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ memset(psecnetwork, 0, t_len); ++ ++ memcpy(psecnetwork, &pnetwork->network, get_wlan_bssid_ex_sz(&pnetwork->network)); ++ ++ psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength; ++ ++ if (psecnetwork->IELength - 12 < 255) { ++ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength - 12); ++ } else { ++ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], 255); ++ } ++ ++ psecnetwork->IELength = 0; ++ /* Added by Albert 2009/02/18 */ ++ /* If the the driver wants to use the bssid to create the connection. */ ++ /* If not, we have to copy the connecting AP's MAC address to it so that */ ++ /* the driver just has the bssid information for PMKIDList searching. */ ++ ++ if (!pmlmepriv->assoc_by_bssid) ++ memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN); ++ ++ psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength); ++ ++ pqospriv->qos_option = 0; ++ ++ if (pregistrypriv->wmm_enable) { ++ u32 tmp_len; ++ ++ tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength); ++ ++ if (psecnetwork->IELength != tmp_len) { ++ psecnetwork->IELength = tmp_len; ++ pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */ ++ } else { ++ pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */ ++ } ++ } ++ ++ phtpriv->ht_option = false; ++ if (pregistrypriv->ht_enable) { ++ /* Added by Albert 2010/06/23 */ ++ /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */ ++ /* Especially for Realtek 8192u SoftAP. */ ++ if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) && ++ (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) && ++ (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) { ++ /* rtw_restructure_ht_ie */ ++ rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], ++ pnetwork->network.IELength, &psecnetwork->IELength); ++ } ++ } ++ ++ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength); ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA) ++ padapter->pwrctrlpriv.smart_ps = 0; ++ else ++ padapter->pwrctrlpriv.smart_ps = padapter->registrypriv.smart_ps; ++ ++ DBG_88E("%s: smart_ps =%d\n", __func__, padapter->pwrctrlpriv.smart_ps); ++ ++ pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);/* get cmdsz before endian conversion */ ++ ++ INIT_LIST_HEAD(&pcmd->list); ++ pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */ ++ pcmd->parmbuf = (unsigned char *)psecnetwork; ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */ ++{ ++ struct cmd_obj *cmdobj = NULL; ++ struct disconnect_parm *param = NULL; ++ struct cmd_priv *cmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ /* prepare cmd parameter */ ++ param = kzalloc(sizeof(*param), GFP_ATOMIC); ++ if (!param) { ++ res = _FAIL; ++ goto exit; ++ } ++ param->deauth_timeout_ms = deauth_timeout_ms; ++ ++ if (enqueue) { ++ /* need enqueue, prepare cmd_obj and enqueue */ ++ cmdobj = kzalloc(sizeof(*cmdobj), GFP_ATOMIC); ++ if (!cmdobj) { ++ res = _FAIL; ++ kfree(param); ++ goto exit; ++ } ++ init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_); ++ res = rtw_enqueue_cmd(cmdpriv, cmdobj); ++ } else { ++ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ ++ if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param)) ++ res = _FAIL; ++ kfree(param); ++ } ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra networktype) ++{ ++ struct cmd_obj *ph2c; ++ struct setopmode_parm *psetop; ++ ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!ph2c) { ++ res = false; ++ goto exit; ++ } ++ psetop = kzalloc(sizeof(struct setopmode_parm), GFP_KERNEL); ++ ++ if (!psetop) { ++ kfree(ph2c); ++ res = false; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); ++ psetop->mode = (u8)networktype; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key) ++{ ++ struct cmd_obj *ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct set_stakey_rsp *psetstakey_rsp = NULL; ++ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct sta_info *sta = (struct sta_info *)psta; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL); ++ if (!psetstakey_para) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_KERNEL); ++ if (!psetstakey_rsp) { ++ kfree(ph2c); ++ kfree(psetstakey_para); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ph2c->rsp = (u8 *)psetstakey_rsp; ++ ph2c->rspsz = sizeof(struct set_stakey_rsp); ++ ++ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ psetstakey_para->algorithm = (unsigned char)psecuritypriv->dot11PrivacyAlgrthm; ++ else ++ GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false); ++ ++ if (unicast_key) ++ memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16); ++ else ++ memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16); ++ ++ /* jeff: set this because at least sw key is ready */ ++ padapter->securitypriv.busetkipkey = true; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue) ++{ ++ struct cmd_obj *ph2c; ++ struct set_stakey_parm *psetstakey_para; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct set_stakey_rsp *psetstakey_rsp = NULL; ++ struct sta_info *sta = (struct sta_info *)psta; ++ u8 res = _SUCCESS; ++ ++ if (!enqueue) { ++ clear_cam_entry(padapter, entry); ++ } else { ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), ++ GFP_ATOMIC); ++ if (!psetstakey_para) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), ++ GFP_ATOMIC); ++ if (!psetstakey_rsp) { ++ kfree(ph2c); ++ kfree(psetstakey_para); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); ++ ph2c->rsp = (u8 *)psetstakey_rsp; ++ ph2c->rspsz = sizeof(struct set_stakey_rsp); ++ ++ memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); ++ ++ psetstakey_para->algorithm = _NO_PRIVACY_; ++ ++ psetstakey_para->id = entry; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++exit: ++ ++ return res; ++} ++ ++u8 rtw_setrttbl_cmd(struct adapter *padapter, struct setratable_parm *prate_table) ++{ ++ struct cmd_obj *ph2c; ++ struct setratable_parm *psetrttblparm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ psetrttblparm = kzalloc(sizeof(struct setratable_parm), GFP_KERNEL); ++ ++ if (!psetrttblparm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); ++ ++ memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_getrttbl_cmd(struct adapter *padapter, struct getratable_rsp *pval) ++{ ++ struct cmd_obj *ph2c; ++ struct getratable_parm *pgetrttblparm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ pgetrttblparm = kzalloc(sizeof(struct getratable_parm), GFP_KERNEL); ++ ++ if (!pgetrttblparm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++/* init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); */ ++ ++ INIT_LIST_HEAD(&ph2c->list); ++ ph2c->cmdcode = GEN_CMD_CODE(_GetRaTable); ++ ph2c->parmbuf = (unsigned char *)pgetrttblparm; ++ ph2c->cmdsz = sizeof(struct getratable_parm); ++ ph2c->rsp = (u8 *)pval; ++ ph2c->rspsz = sizeof(struct getratable_rsp); ++ ++ pgetrttblparm->rsvd = 0x0; ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_setassocsta_cmd(struct adapter *padapter, u8 *mac_addr) ++{ ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct cmd_obj *ph2c; ++ struct set_assocsta_parm *psetassocsta_para; ++ struct set_stakey_rsp *psetassocsta_rsp = NULL; ++ ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetassocsta_para = kzalloc(sizeof(struct set_assocsta_parm), GFP_ATOMIC); ++ if (!psetassocsta_para) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ psetassocsta_rsp = kzalloc(sizeof(struct set_assocsta_rsp), GFP_ATOMIC); ++ if (!psetassocsta_rsp) { ++ kfree(ph2c); ++ kfree(psetassocsta_para); ++ return _FAIL; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_); ++ ph2c->rsp = (u8 *)psetassocsta_rsp; ++ ph2c->rspsz = sizeof(struct set_assocsta_rsp); ++ ++ memcpy(psetassocsta_para->addr, mac_addr, ETH_ALEN); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++ } ++ ++u8 rtw_addbareq_cmd(struct adapter *padapter, u8 tid, u8 *addr) ++{ ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct cmd_obj *ph2c; ++ struct addBaReq_parm *paddbareq_parm; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_ATOMIC); ++ if (!paddbareq_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ paddbareq_parm->tid = tid; ++ memcpy(paddbareq_parm->addr, addr, ETH_ALEN); ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq)); ++ ++ /* DBG_88E("rtw_addbareq_cmd, tid =%d\n", tid); */ ++ ++ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID; ++ pdrvextra_cmd_parm->type_size = 0; ++ pdrvextra_cmd_parm->pbuf = (u8 *)padapter; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++exit: ++ ++ return res; ++} ++ ++u8 rtw_set_ch_cmd(struct adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue) ++{ ++ struct cmd_obj *pcmdobj; ++ struct set_ch_parm *set_ch_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++ ++ DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset); ++ ++ /* check input parameter */ ++ ++ /* prepare cmd parameter */ ++ set_ch_parm = kzalloc(sizeof(*set_ch_parm), GFP_ATOMIC); ++ if (!set_ch_parm) { ++ res = _FAIL; ++ goto exit; ++ } ++ set_ch_parm->ch = ch; ++ set_ch_parm->bw = bw; ++ set_ch_parm->ch_offset = ch_offset; ++ ++ if (enqueue) { ++ /* need enqueue, prepare cmd_obj and enqueue */ ++ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!pcmdobj) { ++ kfree(set_ch_parm); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ } else { ++ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ ++ if (H2C_SUCCESS != set_ch_hdl(padapter, (u8 *)set_ch_parm)) ++ res = _FAIL; ++ ++ kfree(set_ch_parm); ++ } ++ ++ /* do something based on res... */ ++ ++exit: ++ ++ DBG_88E(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res); ++ ++ return res; ++} ++ ++u8 rtw_set_chplan_cmd(struct adapter *padapter, u8 chplan, u8 enqueue) ++{ ++ struct cmd_obj *pcmdobj; ++ struct SetChannelPlan_param *setChannelPlan_param; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++ ++ /* check input parameter */ ++ if (!rtw_is_channel_plan_valid(chplan)) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ /* prepare cmd parameter */ ++ setChannelPlan_param = kzalloc(sizeof(struct SetChannelPlan_param), ++ GFP_KERNEL); ++ if (!setChannelPlan_param) { ++ res = _FAIL; ++ goto exit; ++ } ++ setChannelPlan_param->channel_plan = chplan; ++ ++ if (enqueue) { ++ /* need enqueue, prepare cmd_obj and enqueue */ ++ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!pcmdobj) { ++ kfree(setChannelPlan_param); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelPlan_param, GEN_CMD_CODE(_SetChannelPlan)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ } else { ++ /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ ++ if (H2C_SUCCESS != set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param)) ++ res = _FAIL; ++ ++ kfree(setChannelPlan_param); ++ } ++ ++ /* do something based on res... */ ++ if (res == _SUCCESS) ++ padapter->mlmepriv.ChannelPlan = chplan; ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_led_blink_cmd(struct adapter *padapter, struct LED_871x *pLed) ++{ ++ struct cmd_obj *pcmdobj; ++ struct LedBlink_param *ledBlink_param; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++ ++ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!pcmdobj) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ ledBlink_param = kzalloc(sizeof(struct LedBlink_param), GFP_ATOMIC); ++ if (!ledBlink_param) { ++ kfree(pcmdobj); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ ledBlink_param->pLed = pLed; ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_set_csa_cmd(struct adapter *padapter, u8 new_ch_no) ++{ ++ struct cmd_obj *pcmdobj; ++ struct SetChannelSwitch_param *setChannelSwitch_param; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++ ++ pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!pcmdobj) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ setChannelSwitch_param = kzalloc(sizeof(struct SetChannelSwitch_param), ++ GFP_ATOMIC); ++ if (!setChannelSwitch_param) { ++ kfree(pcmdobj); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ setChannelSwitch_param->new_ch_no = new_ch_no; ++ ++ init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch)); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); ++ ++exit: ++ ++ return res; ++} ++ ++u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option) ++{ ++ return _SUCCESS; ++} ++ ++static void traffic_status_watchdog(struct adapter *padapter) ++{ ++ u8 bEnterPS; ++ u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false; ++ u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false, bHigherBusyTxTraffic = false; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ /* */ ++ /* Determine if our traffic is busy now */ ++ /* */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 100 || ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 100) { ++ bBusyTraffic = true; ++ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) ++ bRxBusyTraffic = true; ++ else ++ bTxBusyTraffic = true; ++ } ++ ++ /* Higher Tx/Rx data. */ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 || ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) { ++ bHigherBusyTraffic = true; ++ ++ if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) ++ bHigherBusyRxTraffic = true; ++ else ++ bHigherBusyTxTraffic = true; ++ } ++ ++ /* check traffic for powersaving. */ ++ if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) || ++ (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2)) ++ bEnterPS = false; ++ else ++ bEnterPS = true; ++ ++ /* LeisurePS only work in infra mode. */ ++ if (bEnterPS) ++ LPS_Enter(padapter); ++ else ++ LPS_Leave(padapter); ++ } else { ++ LPS_Leave(padapter); ++ } ++ ++ pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic; ++ pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; ++} ++ ++static void dynamic_chk_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz) ++{ ++ struct mlme_priv *pmlmepriv; ++ ++ padapter = (struct adapter *)pbuf; ++ pmlmepriv = &padapter->mlmepriv; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ expire_timeout_chk(padapter); ++#endif ++ ++ rtw_hal_sreset_xmit_status_check(padapter); ++ ++ linked_status_chk(padapter); ++ traffic_status_watchdog(padapter); ++ ++ rtw_hal_dm_watchdog(padapter); ++} ++ ++static void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 mstatus; ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) ++ return; ++ ++ switch (lps_ctrl_type) { ++ case LPS_CTRL_SCAN: ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ /* connect */ ++ LPS_Leave(padapter); ++ } ++ break; ++ case LPS_CTRL_JOINBSS: ++ LPS_Leave(padapter); ++ break; ++ case LPS_CTRL_CONNECT: ++ mstatus = 1;/* connect */ ++ /* Reset LPS Setting */ ++ padapter->pwrctrlpriv.LpsIdleCount = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); ++ break; ++ case LPS_CTRL_DISCONNECT: ++ mstatus = 0;/* disconnect */ ++ LPS_Leave(padapter); ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); ++ break; ++ case LPS_CTRL_SPECIAL_PACKET: ++ /* DBG_88E("LPS_CTRL_SPECIAL_PACKET\n"); */ ++ pwrpriv->DelayLPSLastTimeStamp = jiffies; ++ LPS_Leave(padapter); ++ break; ++ case LPS_CTRL_LEAVE: ++ LPS_Leave(padapter); ++ break; ++ default: ++ break; ++ } ++ ++} ++ ++u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ /* struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; */ ++ u8 res = _SUCCESS; ++ ++ /* if (!pwrctrlpriv->bLeisurePs) */ ++ /* return res; */ ++ ++ if (enqueue) { ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), ++ GFP_ATOMIC); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID; ++ pdrvextra_cmd_parm->type_size = lps_ctrl_type; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } else { ++ lps_ctrl_wk_hdl(padapter, lps_ctrl_type); ++ } ++ ++exit: ++ ++ return res; ++} ++ ++static void rpt_timer_setting_wk_hdl(struct adapter *padapter, u16 min_time) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&min_time)); ++} ++ ++u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), ++ GFP_ATOMIC); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID; ++ pdrvextra_cmd_parm->type_size = min_time; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ 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; ++} ++ ++static void antenna_select_wk_hdl(struct adapter *padapter, u8 antenna) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_ANTENNA_DIVERSITY_SELECT, (u8 *)(&antenna)); ++} ++ ++u8 rtw_antenna_select_cmd(struct adapter *padapter, u8 antenna, u8 enqueue) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 support_ant_div; ++ u8 res = _SUCCESS; ++ ++ rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &support_ant_div); ++ if (!support_ant_div) ++ return res; ++ ++ if (enqueue) { ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), ++ GFP_KERNEL); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID; ++ pdrvextra_cmd_parm->type_size = antenna; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } else { ++ antenna_select_wk_hdl(padapter, antenna); ++ } ++exit: ++ ++ return res; ++} ++ ++static void power_saving_wk_hdl(struct adapter *padapter, u8 *pbuf, int sz) ++{ ++ rtw_ps_processor(padapter); ++} ++ ++#ifdef CONFIG_88EU_P2P ++u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return res; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID; ++ pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */ ++ pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */ ++ ++ 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; ++} ++#endif /* CONFIG_88EU_P2P */ ++ ++u8 rtw_ps_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ppscmd; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ u8 res = _SUCCESS; ++ ++ ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ppscmd) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ppscmd); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ppscmd); ++ ++exit: ++ ++ return res; ++} ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++static void rtw_chk_hi_queue_hdl(struct adapter *padapter) ++{ ++ int cnt = 0; ++ struct sta_info *psta_bmc; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if (!psta_bmc) ++ return; ++ ++ if (psta_bmc->sleepq_len == 0) { ++ u8 val = 0; ++ ++ /* while ((rtw_read32(padapter, 0x414)&0x00ffff00)!= 0) */ ++ /* while ((rtw_read32(padapter, 0x414)&0x0000ff00)!= 0) */ ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val); ++ ++ while (!val) { ++ msleep(100); ++ ++ cnt++; ++ ++ if (cnt > 10) ++ break; ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val); ++ } ++ ++ if (cnt <= 10) { ++ pstapriv->tim_bitmap &= ~BIT(0); ++ pstapriv->sta_dz_bitmap &= ~BIT(0); ++ ++ update_beacon(padapter, _TIM_IE_, NULL, false); ++ } else { /* re check again */ ++ rtw_chk_hi_queue_cmd(padapter); ++ } ++ } ++} ++ ++u8 rtw_chk_hi_queue_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID; ++ pdrvextra_cmd_parm->type_size = 0; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ 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; ++} ++#endif ++ ++u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = C2H_WK_CID; ++ pdrvextra_cmd_parm->type_size = c2h_evt ? 16 : 0; ++ pdrvextra_cmd_parm->pbuf = c2h_evt; ++ ++ 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; ++} ++ ++static s32 c2h_evt_hdl(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter) ++{ ++ s32 ret = _FAIL; ++ u8 buf[16]; ++ ++ if (!c2h_evt) { ++ /* No c2h event in cmd_obj, read c2h event before handling*/ ++ if (c2h_evt_read(adapter, buf) == _SUCCESS) { ++ c2h_evt = (struct c2h_evt_hdr *)buf; ++ ++ if (filter && !filter(c2h_evt->id)) ++ goto exit; ++ ++ ret = rtw_hal_c2h_handler(adapter, c2h_evt); ++ } ++ } else { ++ if (filter && !filter(c2h_evt->id)) ++ goto exit; ++ ++ ret = rtw_hal_c2h_handler(adapter, c2h_evt); ++ } ++exit: ++ return ret; ++} ++ ++static void c2h_wk_callback(struct work_struct *work) ++{ ++ struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk); ++ struct adapter *adapter = container_of(evtpriv, struct adapter, evtpriv); ++ struct c2h_evt_hdr *c2h_evt; ++ c2h_id_filter ccx_id_filter = rtw_hal_c2h_id_filter_ccx(adapter); ++ ++ evtpriv->c2h_wk_alive = true; ++ ++ while (!rtw_cbuf_empty(evtpriv->c2h_queue)) { ++ if ((c2h_evt = (struct c2h_evt_hdr *)rtw_cbuf_pop(evtpriv->c2h_queue)) != NULL) { ++ /* This C2H event is read, clear it */ ++ c2h_evt_clear(adapter); ++ } else { ++ c2h_evt = kmalloc(16, GFP_KERNEL); ++ if (c2h_evt) { ++ /* This C2H event is not read, read & clear now */ ++ if (c2h_evt_read(adapter, (u8 *)c2h_evt) != _SUCCESS) { ++ kfree(c2h_evt); ++ continue; ++ } ++ } else { ++ return; ++ } ++ } ++ ++ /* Special pointer to trigger c2h_evt_clear only */ ++ if ((void *)c2h_evt == (void *)evtpriv) ++ continue; ++ ++ if (!c2h_evt_exist(c2h_evt)) { ++ kfree(c2h_evt); ++ continue; ++ } ++ ++ if (ccx_id_filter(c2h_evt->id)) { ++ /* Handle CCX report here */ ++ rtw_hal_c2h_handler(adapter, c2h_evt); ++ kfree(c2h_evt); ++ } else { ++#ifdef CONFIG_88EU_P2P ++ /* Enqueue into cmd_thread for others */ ++ rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt); ++#endif ++ } ++ } ++ ++ evtpriv->c2h_wk_alive = false; ++} ++ ++u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct drvextra_cmd_parm *pdrvextra_cmd; ++ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf; ++ ++ switch (pdrvextra_cmd->ec_id) { ++ case DYNAMIC_CHK_WK_CID: ++ dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); ++ break; ++ case POWER_SAVING_CTRL_WK_CID: ++ power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type_size); ++ break; ++ case LPS_CTRL_WK_CID: ++ lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size); ++ break; ++ case RTP_TIMER_CFG_WK_CID: ++ rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type_size); ++ break; ++ case ANT_SELECT_WK_CID: ++ antenna_select_wk_hdl(padapter, pdrvextra_cmd->type_size); ++ break; ++#ifdef CONFIG_88EU_P2P ++ case P2P_PS_WK_CID: ++ p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type_size); ++ break; ++ case P2P_PROTO_WK_CID: ++ /* Commented by Albert 2011/07/01 */ ++ /* I used the type_size as the type command */ ++ p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type_size); ++ break; ++#endif ++#ifdef CONFIG_88EU_AP_MODE ++ case CHECK_HIQ_WK_CID: ++ rtw_chk_hi_queue_hdl(padapter); ++ break; ++#endif /* CONFIG_88EU_AP_MODE */ ++ case C2H_WK_CID: ++ c2h_evt_hdl(padapter, (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL); ++ break; ++ default: ++ break; ++ } ++ ++ if (pdrvextra_cmd->pbuf && pdrvextra_cmd->type_size > 0) ++ kfree(pdrvextra_cmd->pbuf); ++ ++ return H2C_SUCCESS; ++} ++ ++void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (pcmd->res == H2C_DROPPED) { ++ /* TODO: cancel timer and do timeout handler directly... */ ++ /* need to make timeout handlerOS independent */ ++ _set_timer(&pmlmepriv->scan_to_timer, 1); ++ } else if (pcmd->res != H2C_SUCCESS) { ++ _set_timer(&pmlmepriv->scan_to_timer, 1); ++ } ++ ++ /* free cmd */ ++ rtw_free_cmd_obj(pcmd); ++ ++} ++void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (pcmd->res != H2C_SUCCESS) { ++ spin_lock_bh(&pmlmepriv->lock); ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ return; ++ } else /* clear bridge database */ ++ nat25_db_cleanup(padapter); ++ ++ /* free cmd */ ++ rtw_free_cmd_obj(pcmd); ++} ++ ++void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (pcmd->res == H2C_DROPPED) { ++ /* TODO: cancel timer and do timeout handler directly... */ ++ /* need to make timeout handlerOS independent */ ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ } else if (pcmd->res != H2C_SUCCESS) { ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ } ++ ++ rtw_free_cmd_obj(pcmd); ++} ++ ++void rtw_createbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ u8 timer_cancelled; ++ struct sta_info *psta = NULL; ++ struct wlan_network *pwlan = NULL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ ++ if (pcmd->res != H2C_SUCCESS) ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ ++ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ psta = rtw_get_stainfo(&padapter->stapriv, pnetwork->MacAddress); ++ if (!psta) { ++ psta = rtw_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress); ++ if (!psta) ++ goto createbss_cmd_fail; ++ } ++ ++ rtw_indicate_connect(padapter); ++ } else { ++ ++ pwlan = _rtw_alloc_network(pmlmepriv); ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ if (!pwlan) { ++ pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue); ++ if (!pwlan) { ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ goto createbss_cmd_fail; ++ } ++ pwlan->last_scanned = jiffies; ++ } else { ++ list_add_tail(&pwlan->list, &pmlmepriv->scanned_queue.queue); ++ } ++ ++ pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork); ++ memcpy(&pwlan->network, pnetwork, pnetwork->Length); ++ ++ memcpy(&tgt_network->network, pnetwork, (get_wlan_bssid_ex_sz(pnetwork))); ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ /* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */ ++ } ++ ++createbss_cmd_fail: ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ rtw_free_cmd_obj(pcmd); ++ ++} ++ ++void rtw_setstaKey_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp); ++ struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr); ++ ++ if (!psta) ++ goto exit; ++exit: ++ rtw_free_cmd_obj(pcmd); ++ ++} ++ ++void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter, struct cmd_obj *pcmd) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf); ++ struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp); ++ struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr); ++ ++ if (!psta) ++ goto exit; ++ ++ psta->aid = passocsta_rsp->cam_id; ++ psta->mac_id = passocsta_rsp->cam_id; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++exit: ++ rtw_free_cmd_obj(pcmd); ++ ++} +diff --git a/drivers/staging/r8188eu/core/rtw_debug.c b/drivers/staging/r8188eu/core/rtw_debug.c +new file mode 100644 +index 000000000000..2ee64cef73f7 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_debug.c +@@ -0,0 +1,904 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_DEBUG_C_ ++ ++#include "../include/rtw_debug.h" ++#include "../include/drv_types.h" ++ ++int proc_get_drv_version(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "%s\n", DRIVERVERSION); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_write_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ *eof = 1; ++ return 0; ++} ++ ++int proc_set_write_reg(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 addr, val, len; ++ ++ if (count < 3) { ++ DBG_88E("argument size is less than 3\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ int num = sscanf(tmp, "%x %x %x", &addr, &val, &len); ++ ++ if (num != 3) { ++ DBG_88E("invalid write_reg parameter!\n"); ++ return count; ++ } ++ switch (len) { ++ case 1: ++ rtw_write8(padapter, addr, (u8)val); ++ break; ++ case 2: ++ rtw_write16(padapter, addr, (u16)val); ++ break; ++ case 4: ++ rtw_write32(padapter, addr, val); ++ break; ++ default: ++ DBG_88E("error write length =%d", len); ++ break; ++ } ++ } ++ return count; ++} ++ ++static u32 proc_get_read_addr = 0xeeeeeeee; ++static u32 proc_get_read_len = 0x4; ++ ++int proc_get_read_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ int len = 0; ++ ++ if (proc_get_read_addr == 0xeeeeeeee) { ++ *eof = 1; ++ return len; ++ } ++ ++ switch (proc_get_read_len) { ++ case 1: ++ len += snprintf(page + len, count - len, "rtw_read8(0x%x)=0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr)); ++ break; ++ case 2: ++ len += snprintf(page + len, count - len, "rtw_read16(0x%x)=0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr)); ++ break; ++ case 4: ++ len += snprintf(page + len, count - len, "rtw_read32(0x%x)=0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr)); ++ break; ++ default: ++ len += snprintf(page + len, count - len, "error read length=%d\n", proc_get_read_len); ++ break; ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_read_reg(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ char tmp[16]; ++ u32 addr, len; ++ ++ if (count < 2) { ++ DBG_88E("argument size is less than 2\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ int num = sscanf(tmp, "%x %x", &addr, &len); ++ ++ if (num != 2) { ++ DBG_88E("invalid read_reg parameter!\n"); ++ return count; ++ } ++ ++ proc_get_read_addr = addr; ++ ++ proc_get_read_len = len; ++ } ++ ++ return count; ++} ++ ++int proc_get_fwstate(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "fwstate=0x%x\n", get_fwstate(pmlmepriv)); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_sec_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n", ++ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, ++ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_mlmext_state(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "pmlmeinfo->state=0x%x\n", pmlmeinfo->state); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_qos_option(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "qos_option=%d\n", pmlmepriv->qospriv.qos_option); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_ht_option(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ int len = 0; ++ len += snprintf(page + len, count - len, "ht_option=%d\n", pmlmepriv->htpriv.ht_option); ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rf_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n", ++ pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_ap_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct sta_info *psta; ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ int len = 0; ++ ++ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if (psta) { ++ int i; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ len += snprintf(page + len, count - len, "SSID=%s\n", cur_network->network.Ssid.Ssid); ++ len += snprintf(page + len, count - len, "sta's macaddr:%pM\n", psta->hwaddr); ++ len += snprintf(page + len, count - len, "cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); ++ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); ++ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++ ++ for (i = 0; i < 16; i++) { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ if (preorder_ctrl->enable) ++ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", i, preorder_ctrl->indicate_seq); ++ } ++ } else { ++ len += snprintf(page + len, count - len, "can't get sta's macaddr, cur_network's macaddr: %pM\n", cur_network->network.MacAddress); ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_adapter_state(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n", ++ padapter->bSurpriseRemoved, padapter->bDriverStopped); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_trx_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d, free_ext_xmitbuf_cnt=%d, free_recvframe_cnt=%d\n", ++ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmit_extbuf_cnt, precvpriv->free_recvframe_cnt); ++ len += snprintf(page + len, count - len, "rx_urb_pending_cn=%d\n", precvpriv->rx_pending_cnt); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_mac_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1; ++ ++ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); ++ ++ for (i = 0x0; i < 0x300; i += 4) { ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_mac_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1; ++ ++ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); ++ memset(page, 0, count); ++ for (i = 0x300; i < 0x600; i += 4) { ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_mac_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1; ++ ++ len += snprintf(page + len, count - len, "\n======= MAC REG =======\n"); ++ ++ for (i = 0x600; i < 0x800; i += 4) { ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_bb_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1; ++ ++ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); ++ for (i = 0x800; i < 0xB00; i += 4) { ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_bb_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1; ++ ++ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); ++ for (i = 0xB00; i < 0xE00; i += 4) { ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_bb_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1; ++ ++ len += snprintf(page + len, count - len, "\n======= BB REG =======\n"); ++ for (i = 0xE00; i < 0x1000; i += 4) { ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rf_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1, path; ++ u32 value; ++ ++ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); ++ path = 1; ++ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path); ++ for (i = 0; i < 0xC0; i++) { ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x ", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", value); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rf_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1, path; ++ u32 value; ++ ++ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); ++ path = 1; ++ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path); ++ for (i = 0xC0; i < 0x100; i++) { ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x ", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", value); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rf_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1, path; ++ u32 value; ++ ++ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); ++ path = 2; ++ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path); ++ for (i = 0; i < 0xC0; i++) { ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x ", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", value); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rf_reg_dump4(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ int i, j = 1, path; ++ u32 value; ++ ++ len += snprintf(page + len, count - len, "\n======= RF REG =======\n"); ++ path = 2; ++ len += snprintf(page + len, count - len, "\nRF_Path(%x)\n", path); ++ for (i = 0xC0; i < 0x100; i++) { ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if (j % 4 == 1) ++ len += snprintf(page + len, count - len, "0x%02x ", i); ++ len += snprintf(page + len, count - len, " 0x%08x ", value); ++ if ((j++) % 4 == 0) ++ len += snprintf(page + len, count - len, "\n"); ++ } ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rx_signal(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int len = 0; ++ ++ len = snprintf(page + len, count, ++ "rssi:%d\n" ++ "rxpwdb:%d\n" ++ "signal_strength:%u\n" ++ "signal_qual:%u\n" ++ "noise:%u\n", ++ padapter->recvpriv.rssi, ++ padapter->recvpriv.rxpwdb, ++ padapter->recvpriv.signal_strength, ++ padapter->recvpriv.signal_qual, ++ padapter->recvpriv.noise ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_rx_signal(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 is_signal_dbg; ++ s32 signal_strength; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength); ++ is_signal_dbg = is_signal_dbg == 0 ? 0 : 1; ++ if (is_signal_dbg && num != 2) ++ return count; ++ ++ signal_strength = signal_strength > 100 ? 100 : signal_strength; ++ signal_strength = signal_strength < 0 ? 0 : signal_strength; ++ ++ padapter->recvpriv.is_signal_dbg = is_signal_dbg; ++ padapter->recvpriv.signal_strength_dbg = signal_strength; ++ ++ if (is_signal_dbg) ++ DBG_88E("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength); ++ else ++ DBG_88E("set %s\n", "HW_SIGNAL_STRENGTH"); ++ } ++ return count; ++} ++ ++int proc_get_ht_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ int len = 0; ++ ++ if (pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ pregpriv->ht_enable ++ ); ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_ht_enable(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ s32 mode = 0; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ if (pregpriv) { ++ pregpriv->ht_enable = mode; ++ pr_info("ht_enable=%d\n", pregpriv->ht_enable); ++ } ++ } ++ ++ return count; ++} ++ ++int proc_get_cbw40_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ int len = 0; ++ ++ if (pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ pregpriv->cbw40_enable ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_cbw40_enable(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ s32 mode = 0; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ if (pregpriv) { ++ pregpriv->cbw40_enable = mode; ++ pr_info("cbw40_enable=%d\n", mode); ++ } ++ } ++ return count; ++} ++ ++int proc_get_ampdu_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ int len = 0; ++ ++ if (pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ pregpriv->ampdu_enable ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_ampdu_enable(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ s32 mode = 0; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ if (pregpriv) { ++ pregpriv->ampdu_enable = mode; ++ pr_info("ampdu_enable=%d\n", mode); ++ } ++ } ++ return count; ++} ++ ++int proc_get_two_path_rssi(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ int len = 0; ++ ++ if (padapter) ++ len += snprintf(page + len, count - len, ++ "%d %d\n", ++ padapter->recvpriv.RxRssi[0], ++ padapter->recvpriv.RxRssi[1] ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_get_rx_stbc(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ int len = 0; ++ ++ if (pregpriv) ++ len += snprintf(page + len, count - len, ++ "%d\n", ++ pregpriv->rx_stbc ++ ); ++ ++ *eof = 1; ++ return len; ++} ++ ++int proc_set_rx_stbc(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ char tmp[32]; ++ u32 mode = 0; ++ ++ if (count < 1) ++ return -EFAULT; ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ if (pregpriv) { ++ pregpriv->rx_stbc = mode; ++ printk("rx_stbc=%d\n", mode); ++ } ++ } ++ return count; ++} ++ ++int proc_get_rssi_disp(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ *eof = 1; ++ return 0; ++} ++ ++int proc_set_rssi_disp(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ char tmp[32]; ++ u32 enable = 0; ++ ++ if (count < 1) { ++ DBG_88E("argument size is less than 1\n"); ++ return -EFAULT; ++ } ++ ++ if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { ++ int num = sscanf(tmp, "%x", &enable); ++ ++ if (num != 1) { ++ DBG_88E("invalid set_rssi_disp parameter!\n"); ++ return count; ++ } ++ ++ if (enable) { ++ DBG_88E("Turn On Rx RSSI Display Function\n"); ++ padapter->bRxRSSIDisplay = enable; ++ } else { ++ DBG_88E("Turn Off Rx RSSI Display Function\n"); ++ padapter->bRxRSSIDisplay = 0; ++ } ++ } ++ return count; ++} ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++int proc_get_all_sta_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct sta_info *psta; ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ int i, j; ++ struct list_head *plist, *phead; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ int len = 0; ++ ++ len += snprintf(page + len, count - len, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ for (i = 0; i < NUM_STA; i++) { ++ phead = &pstapriv->sta_hash[i]; ++ plist = phead->next; ++ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, hash_list); ++ ++ plist = plist->next; ++ ++ len += snprintf(page + len, count - len, "sta's macaddr: %pM\n", psta->hwaddr); ++ len += snprintf(page + len, count - len, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); ++ len += snprintf(page + len, count - len, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++ len += snprintf(page + len, count - len, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ len += snprintf(page + len, count - len, "bwmode=%d, ch_offset=%d, sgi=%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); ++ len += snprintf(page + len, count - len, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ len += snprintf(page + len, count - len, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++ len += snprintf(page + len, count - len, "sleepq_len=%d\n", psta->sleepq_len); ++ len += snprintf(page + len, count - len, "capability=0x%x\n", psta->capability); ++ len += snprintf(page + len, count - len, "flags=0x%x\n", psta->flags); ++ len += snprintf(page + len, count - len, "wpa_psk=0x%x\n", psta->wpa_psk); ++ len += snprintf(page + len, count - len, "wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher); ++ len += snprintf(page + len, count - len, "wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher); ++ len += snprintf(page + len, count - len, "qos_info=0x%x\n", psta->qos_info); ++ len += snprintf(page + len, count - len, "dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy); ++ ++ for (j = 0; j < 16; j++) { ++ preorder_ctrl = &psta->recvreorder_ctrl[j]; ++ if (preorder_ctrl->enable) ++ len += snprintf(page + len, count - len, "tid=%d, indicate_seq=%d\n", j, preorder_ctrl->indicate_seq); ++ } ++ } ++ } ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ *eof = 1; ++ return len; ++} ++#endif ++ ++int proc_get_best_channel(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data) ++{ ++ struct net_device *dev = data; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ int len = 0; ++ u32 i, best_channel_24G = 1, index_24G = 0; ++ ++ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) { ++ if (pmlmeext->channel_set[i].ChannelNum == 1) ++ index_24G = i; ++ } ++ ++ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) { ++ /* 2.4G */ ++ if (pmlmeext->channel_set[i].ChannelNum == 6) { ++ if (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count) { ++ index_24G = i; ++ best_channel_24G = pmlmeext->channel_set[i].ChannelNum; ++ } ++ } ++ ++ /* debug */ ++ len += snprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n", ++ pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count); ++ } ++ ++ len += snprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G); ++ ++ *eof = 1; ++ return len; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_efuse.c b/drivers/staging/r8188eu/core/rtw_efuse.c +new file mode 100644 +index 000000000000..c1c70648f5bc +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_efuse.c +@@ -0,0 +1,848 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTW_EFUSE_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtw_efuse.h" ++ ++/*------------------------Define local variable------------------------------*/ ++u8 fakeEfuseBank; ++u32 fakeEfuseUsedBytes; ++u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0}; ++u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0}; ++u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0}; ++ ++u32 BTEfuseUsedBytes; ++u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; ++u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; ++ ++u32 fakeBTEfuseUsedBytes; ++u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; ++u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; ++/*------------------------Define local variable------------------------------*/ ++ ++/* */ ++#define REG_EFUSE_CTRL 0x0030 ++#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ ++/* */ ++static bool Efuse_Read1ByteFromFakeContent(struct adapter *pAdapter, ++ u16 Offset, ++ u8 *Value) ++{ ++ if (Offset >= EFUSE_MAX_HW_SIZE) ++ return false; ++ if (fakeEfuseBank == 0) ++ *Value = fakeEfuseContent[Offset]; ++ else ++ *Value = fakeBTEfuseContent[fakeEfuseBank - 1][Offset]; ++ return true; ++} ++ ++static bool ++Efuse_Write1ByteToFakeContent( ++ struct adapter *pAdapter, ++ u16 Offset, ++ u8 Value) ++{ ++ if (Offset >= EFUSE_MAX_HW_SIZE) ++ return false; ++ if (fakeEfuseBank == 0) { ++ fakeEfuseContent[Offset] = Value; ++ } else { ++ fakeBTEfuseContent[fakeEfuseBank - 1][Offset] = Value; ++ } ++ return true; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: Efuse_PowerSwitch ++ * ++ * Overview: When we want to enable write operation, we should change to ++ * pwr on state. When we stop write, we should switch to 500k mode ++ * and disable LDO 2.5V. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/17/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++Efuse_PowerSwitch( ++ struct adapter *pAdapter, ++ u8 write, ++ u8 PwrState) ++{ ++ pAdapter->HalFunc.EfusePowerSwitch(pAdapter, write, PwrState); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: efuse_GetCurrentSize ++ * ++ * Overview: Get current efuse size!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/16/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++u16 ++Efuse_GetCurrentSize( ++ struct adapter *pAdapter, ++ u8 efuseType, ++ bool pseudo) ++{ ++ u16 ret = 0; ++ ++ ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType, pseudo); ++ ++ return ret; ++} ++ ++/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ ++u8 ++Efuse_CalculateWordCnts(u8 word_en) ++{ ++ u8 word_cnts = 0; ++ if (!(word_en & BIT(0))) ++ word_cnts++; /* 0 : write enable */ ++ if (!(word_en & BIT(1))) ++ word_cnts++; ++ if (!(word_en & BIT(2))) ++ word_cnts++; ++ if (!(word_en & BIT(3))) ++ word_cnts++; ++ return word_cnts; ++} ++ ++/* */ ++/* Description: */ ++/* Execute E-Fuse read byte operation. */ ++/* Referred from SD1 Richard. */ ++/* */ ++/* Assumption: */ ++/* 1. Boot from E-Fuse and successfully auto-load. */ ++/* 2. PASSIVE_LEVEL (USB interface) */ ++/* */ ++/* Created by Roger, 2008.10.21. */ ++/* */ ++void ++ReadEFuseByte( ++ struct adapter *Adapter, ++ u16 _offset, ++ u8 *pbuf, ++ bool pseudo) ++{ ++ u32 value32; ++ u8 readbyte; ++ u16 retry; ++ ++ if (pseudo) { ++ Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf); ++ return; ++ } ++ ++ /* Write Address */ ++ rtw_write8(Adapter, EFUSE_CTRL + 1, (_offset & 0xff)); ++ readbyte = rtw_read8(Adapter, EFUSE_CTRL + 2); ++ rtw_write8(Adapter, EFUSE_CTRL + 2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); ++ ++ /* Write bit 32 0 */ ++ readbyte = rtw_read8(Adapter, EFUSE_CTRL + 3); ++ rtw_write8(Adapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); ++ ++ /* Check bit 32 read-ready */ ++ retry = 0; ++ value32 = rtw_read32(Adapter, EFUSE_CTRL); ++ while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { ++ value32 = rtw_read32(Adapter, EFUSE_CTRL); ++ retry++; ++ } ++ ++ /* 20100205 Joseph: Add delay suggested by SD1 Victor. */ ++ /* This fix the problem that Efuse read error in high temperature condition. */ ++ /* Designer says that there shall be some delay after ready bit is set, or the */ ++ /* result will always stay on last data we read. */ ++ udelay(50); ++ value32 = rtw_read32(Adapter, EFUSE_CTRL); ++ ++ *pbuf = (u8)(value32 & 0xff); ++} ++ ++/* */ ++/* Description: */ ++/* 1. Execute E-Fuse read byte operation according as map offset and */ ++/* save to E-Fuse table. */ ++/* 2. Referred from SD1 Richard. */ ++/* */ ++/* Assumption: */ ++/* 1. Boot from E-Fuse and successfully auto-load. */ ++/* 2. PASSIVE_LEVEL (USB interface) */ ++/* */ ++/* Created by Roger, 2008.10.21. */ ++/* */ ++/* 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. */ ++/* 2. Add efuse utilization collect. */ ++/* 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 */ ++/* write addr must be after sec5. */ ++/* */ ++ ++static void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool pseudo) ++{ ++ Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, pseudo); ++} ++ ++void EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool pseudo ++ ) ++{ ++ pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, pseudo); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_Read1Byte ++ * ++ * Overview: Copy from WMAC fot EFUSE read 1 byte. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 09/23/2008 MHC Copy from WMAC. ++ * ++ *---------------------------------------------------------------------------*/ ++u8 EFUSE_Read1Byte(struct adapter *Adapter, u16 Address) ++{ ++ u8 data; ++ u8 Bytetemp = {0x00}; ++ u8 temp = {0x00}; ++ u32 k = 0; ++ u16 contentLen = 0; ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); ++ ++ if (Address < contentLen) { /* E-fuse 512Byte */ ++ /* Write E-fuse Register address bit0~7 */ ++ temp = Address & 0xFF; ++ rtw_write8(Adapter, EFUSE_CTRL + 1, temp); ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL + 2); ++ /* Write E-fuse Register address bit8~9 */ ++ temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); ++ rtw_write8(Adapter, EFUSE_CTRL + 2, temp); ++ ++ /* Write 0x30[31]= 0 */ ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL + 3); ++ temp = Bytetemp & 0x7F; ++ rtw_write8(Adapter, EFUSE_CTRL + 3, temp); ++ ++ /* Wait Write-ready (0x30[31]= 1) */ ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL + 3); ++ while (!(Bytetemp & 0x80)) { ++ Bytetemp = rtw_read8(Adapter, EFUSE_CTRL + 3); ++ k++; ++ if (k == 1000) { ++ k = 0; ++ break; ++ } ++ } ++ data = rtw_read8(Adapter, EFUSE_CTRL); ++ return data; ++ } else { ++ return 0xFF; ++ } ++ ++} /* EFUSE_Read1Byte */ ++ ++/* 11/16/2008 MH Read one byte from real Efuse. */ ++u8 efuse_OneByteRead(struct adapter *pAdapter, u16 addr, u8 *data, bool pseudo) ++{ ++ u8 tmpidx = 0; ++ u8 result; ++ ++ if (pseudo) { ++ result = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data); ++ return result; ++ } ++ /* -----------------e-fuse reg ctrl --------------------------------- */ ++ /* address */ ++ rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff)); ++ rtw_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | ++ (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC)); ++ ++ rtw_write8(pAdapter, EFUSE_CTRL + 3, 0x72);/* read cmd */ ++ ++ while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100)) ++ tmpidx++; ++ if (tmpidx < 100) { ++ *data = rtw_read8(pAdapter, EFUSE_CTRL); ++ result = true; ++ } else { ++ *data = 0xff; ++ result = false; ++ } ++ return result; ++} ++ ++/* 11/16/2008 MH Write one byte to reald Efuse. */ ++u8 efuse_OneByteWrite(struct adapter *pAdapter, u16 addr, u8 data, bool pseudo) ++{ ++ u8 tmpidx = 0; ++ u8 result; ++ ++ if (pseudo) { ++ result = Efuse_Write1ByteToFakeContent(pAdapter, addr, data); ++ return result; ++ } ++ ++ /* -----------------e-fuse reg ctrl --------------------------------- */ ++ /* address */ ++ rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff)); ++ rtw_write8(pAdapter, EFUSE_CTRL + 2, ++ (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC) | ++ (u8)((addr >> 8) & 0x03)); ++ rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */ ++ ++ rtw_write8(pAdapter, EFUSE_CTRL + 3, 0xF2);/* write cmd */ ++ ++ while ((0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100)) ++ tmpidx++; ++ ++ if (tmpidx < 100) ++ result = true; ++ else ++ result = false; ++ ++ return result; ++} ++ ++int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool pseudo) ++{ ++ int ret = 0; ++ ++ ret = pAdapter->HalFunc.Efuse_PgPacketRead(pAdapter, offset, data, pseudo); ++ ++ return ret; ++} ++ ++int Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo) ++{ ++ int ret; ++ ++ ret = pAdapter->HalFunc.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, pseudo); ++ ++ return ret; ++} ++ ++static int Efuse_PgPacketWrite_BT(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool pseudo) ++{ ++ int ret; ++ ++ ret = pAdapter->HalFunc.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, pseudo); ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: efuse_WordEnableDataRead ++ * ++ * Overview: Read allowed word in current efuse section data. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/16/2008 MHC Create Version 0. ++ * 11/21/2008 MHC Fix Write bug when we only enable late word. ++ * ++ *---------------------------------------------------------------------------*/ ++void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata) ++{ ++ if (!(word_en & BIT(0))) { ++ targetdata[0] = sourdata[0]; ++ targetdata[1] = sourdata[1]; ++ } ++ if (!(word_en & BIT(1))) { ++ targetdata[2] = sourdata[2]; ++ targetdata[3] = sourdata[3]; ++ } ++ if (!(word_en & BIT(2))) { ++ targetdata[4] = sourdata[4]; ++ targetdata[5] = sourdata[5]; ++ } ++ if (!(word_en & BIT(3))) { ++ targetdata[6] = sourdata[6]; ++ targetdata[7] = sourdata[7]; ++ } ++} ++ ++u8 Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool pseudo) ++{ ++ u8 ret = 0; ++ ++ ret = pAdapter->HalFunc.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, pseudo); ++ ++ return ret; ++} ++ ++static u8 efuse_read8(struct adapter *padapter, u16 address, u8 *value) ++{ ++ return efuse_OneByteRead(padapter, address, value, false); ++} ++ ++static u8 efuse_write8(struct adapter *padapter, u16 address, u8 *value) ++{ ++ return efuse_OneByteWrite(padapter, address, *value, false); ++} ++ ++/* ++ * read/wirte raw efuse data ++ */ ++u8 rtw_efuse_access(struct adapter *padapter, u8 write, u16 start_addr, u16 cnts, u8 *data) ++{ ++ int i = 0; ++ u16 real_content_len = 0, max_available_size = 0; ++ u8 res = _FAIL; ++ u8 (*rw8)(struct adapter *, u16, u8*); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&real_content_len, false); ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ ++ if (start_addr > real_content_len) ++ return _FAIL; ++ ++ if (write) { ++ if ((start_addr + cnts) > max_available_size) ++ return _FAIL; ++ rw8 = &efuse_write8; ++ } else { ++ rw8 = &efuse_read8; ++ } ++ ++ Efuse_PowerSwitch(padapter, write, true); ++ ++ /* e-fuse one byte read / write */ ++ for (i = 0; i < cnts; i++) { ++ if (start_addr >= real_content_len) { ++ res = _FAIL; ++ break; ++ } ++ ++ res = rw8(padapter, start_addr++, data++); ++ if (_FAIL == res) ++ break; ++ } ++ ++ Efuse_PowerSwitch(padapter, write, false); ++ ++ return res; ++} ++/* */ ++u16 efuse_GetMaxSize(struct adapter *padapter) ++{ ++ u16 max_size; ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_size, false); ++ return max_size; ++} ++/* */ ++u8 efuse_GetCurrentSize(struct adapter *padapter, u16 *size) ++{ ++ Efuse_PowerSwitch(padapter, false, true); ++ *size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, false); ++ Efuse_PowerSwitch(padapter, false, false); ++ ++ return _SUCCESS; ++} ++/* */ ++u8 rtw_efuse_map_read(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) ++{ ++ u16 mapLen = 0; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); ++ ++ if ((addr + cnts) > mapLen) ++ return _FAIL; ++ ++ Efuse_PowerSwitch(padapter, false, true); ++ ++ efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, false); ++ ++ Efuse_PowerSwitch(padapter, false, false); ++ ++ return _SUCCESS; ++} ++ ++u8 rtw_BT_efuse_map_read(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) ++{ ++ u16 mapLen = 0; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); ++ ++ if ((addr + cnts) > mapLen) ++ return _FAIL; ++ ++ Efuse_PowerSwitch(padapter, false, true); ++ ++ efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, false); ++ ++ Efuse_PowerSwitch(padapter, false, false); ++ ++ return _SUCCESS; ++} ++/* */ ++u8 rtw_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) ++{ ++ u8 offset, word_en; ++ u8 *map; ++ u8 newdata[PGPKT_DATA_SIZE + 1]; ++ s32 i, idx; ++ u8 ret = _SUCCESS; ++ u16 mapLen = 0; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); ++ ++ if ((addr + cnts) > mapLen) ++ return _FAIL; ++ ++ map = kzalloc(mapLen, GFP_KERNEL); ++ if (!map) ++ return _FAIL; ++ ++ ret = rtw_efuse_map_read(padapter, 0, mapLen, map); ++ if (ret == _FAIL) ++ goto exit; ++ ++ Efuse_PowerSwitch(padapter, true, true); ++ ++ offset = (addr >> 3); ++ word_en = 0xF; ++ memset(newdata, 0xFF, PGPKT_DATA_SIZE + 1); ++ i = addr & 0x7; /* index of one package */ ++ idx = 0; /* data index */ ++ ++ if (i & 0x1) { ++ /* odd start */ ++ if (data[idx] != map[addr + idx]) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i - 1] = map[addr + idx - 1]; ++ newdata[i] = data[idx]; ++ } ++ i++; ++ idx++; ++ } ++ do { ++ for (; i < PGPKT_DATA_SIZE; i += 2) { ++ if (cnts == idx) ++ break; ++ if ((cnts - idx) == 1) { ++ if (data[idx] != map[addr + idx]) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i] = data[idx]; ++ newdata[i + 1] = map[addr + idx + 1]; ++ } ++ idx++; ++ break; ++ } else { ++ if ((data[idx] != map[addr + idx]) || ++ (data[idx + 1] != map[addr + idx + 1])) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i] = data[idx]; ++ newdata[i + 1] = data[idx + 1]; ++ } ++ idx += 2; ++ } ++ if (idx == cnts) ++ break; ++ } ++ ++ if (word_en != 0xF) { ++ ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, false); ++ DBG_88E("offset=%x\n", offset); ++ DBG_88E("word_en=%x\n", word_en); ++ ++ for (i = 0; i < PGPKT_DATA_SIZE; i++) ++ DBG_88E("data=%x \t", newdata[i]); ++ if (ret == _FAIL) ++ break; ++ } ++ ++ if (idx == cnts) ++ break; ++ ++ offset++; ++ i = 0; ++ word_en = 0xF; ++ memset(newdata, 0xFF, PGPKT_DATA_SIZE); ++ } while (1); ++ ++ Efuse_PowerSwitch(padapter, true, false); ++exit: ++ kfree(map); ++ return ret; ++} ++ ++/* */ ++u8 rtw_BT_efuse_map_write(struct adapter *padapter, u16 addr, u16 cnts, u8 *data) ++{ ++ u8 offset, word_en; ++ u8 *map; ++ u8 newdata[PGPKT_DATA_SIZE + 1]; ++ s32 i, idx; ++ u8 ret = _SUCCESS; ++ u16 mapLen = 0; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); ++ ++ if ((addr + cnts) > mapLen) ++ return _FAIL; ++ ++ map = kzalloc(mapLen, GFP_KERNEL); ++ if (!map) ++ return _FAIL; ++ ++ ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map); ++ if (ret == _FAIL) ++ goto exit; ++ ++ Efuse_PowerSwitch(padapter, true, true); ++ ++ offset = (addr >> 3); ++ word_en = 0xF; ++ memset(newdata, 0xFF, PGPKT_DATA_SIZE + 1); ++ i = addr & 0x7; /* index of one package */ ++ idx = 0; /* data index */ ++ ++ if (i & 0x1) { ++ /* odd start */ ++ if (data[idx] != map[addr + idx]) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i - 1] = map[addr + idx - 1]; ++ newdata[i] = data[idx]; ++ } ++ i++; ++ idx++; ++ } ++ do { ++ for (; i < PGPKT_DATA_SIZE; i += 2) { ++ if (cnts == idx) ++ break; ++ if ((cnts - idx) == 1) { ++ if (data[idx] != map[addr + idx]) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i] = data[idx]; ++ newdata[i + 1] = map[addr + idx + 1]; ++ } ++ idx++; ++ break; ++ } else { ++ if ((data[idx] != map[addr + idx]) || ++ (data[idx + 1] != map[addr + idx + 1])) { ++ word_en &= ~BIT(i >> 1); ++ newdata[i] = data[idx]; ++ newdata[i + 1] = data[idx + 1]; ++ } ++ idx += 2; ++ } ++ if (idx == cnts) ++ break; ++ } ++ ++ if (word_en != 0xF) { ++ DBG_88E("%s: offset=%#X\n", __func__, offset); ++ DBG_88E("%s: word_en=%#X\n", __func__, word_en); ++ DBG_88E("%s: data=", __func__); ++ for (i = 0; i < PGPKT_DATA_SIZE; i++) ++ DBG_88E("0x%02X ", newdata[i]); ++ DBG_88E("\n"); ++ ++ ret = Efuse_PgPacketWrite_BT(padapter, offset, word_en, newdata, false); ++ if (ret == _FAIL) ++ break; ++ } ++ ++ if (idx == cnts) ++ break; ++ ++ offset++; ++ i = 0; ++ word_en = 0xF; ++ memset(newdata, 0xFF, PGPKT_DATA_SIZE); ++ } while (1); ++ ++ Efuse_PowerSwitch(padapter, true, false); ++ ++exit: ++ ++ kfree(map); ++ ++ return ret; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: efuse_ShadowRead1Byte ++ * efuse_ShadowRead2Byte ++ * efuse_ShadowRead4Byte ++ * ++ * Overview: Read from efuse init map by one/two/four bytes !!!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++efuse_ShadowRead1Byte( ++ struct adapter *pAdapter, ++ u16 Offset, ++ u8 *Value) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ ++ *Value = pEEPROM->efuse_eeprom_data[Offset]; ++ ++} /* EFUSE_ShadowRead1Byte */ ++ ++/* Read Two Bytes */ ++static void ++efuse_ShadowRead2Byte( ++ struct adapter *pAdapter, ++ u16 Offset, ++ u16 *Value) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ ++ *Value = pEEPROM->efuse_eeprom_data[Offset]; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset + 1] << 8; ++ ++} /* EFUSE_ShadowRead2Byte */ ++ ++/* Read Four Bytes */ ++static void ++efuse_ShadowRead4Byte( ++ struct adapter *pAdapter, ++ u16 Offset, ++ u32 *Value) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ ++ *Value = pEEPROM->efuse_eeprom_data[Offset]; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset + 1] << 8; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset + 2] << 16; ++ *Value |= pEEPROM->efuse_eeprom_data[Offset + 3] << 24; ++ ++} /* efuse_ShadowRead4Byte */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: Efuse_ReadAllMap ++ * ++ * Overview: Read All Efuse content ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/11/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++static void Efuse_ReadAllMap(struct adapter *pAdapter, u8 efuseType, u8 *Efuse, bool pseudo) ++{ ++ u16 mapLen = 0; ++ ++ Efuse_PowerSwitch(pAdapter, false, true); ++ ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo); ++ ++ efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, pseudo); ++ ++ Efuse_PowerSwitch(pAdapter, false, false); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_ShadowMapUpdate ++ * ++ * Overview: Transfer current EFUSE content to shadow init and modify map. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/13/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void EFUSE_ShadowMapUpdate( ++ struct adapter *pAdapter, ++ u8 efuseType, ++ bool pseudo) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter); ++ u16 mapLen = 0; ++ ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, pseudo); ++ ++ if (pEEPROM->bautoload_fail_flag) ++ memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen); ++ else ++ Efuse_ReadAllMap(pAdapter, efuseType, pEEPROM->efuse_eeprom_data, pseudo); ++} /* EFUSE_ShadowMapUpdate */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: EFUSE_ShadowRead ++ * ++ * Overview: Read from efuse init map !!!!! ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void EFUSE_ShadowRead(struct adapter *pAdapter, u8 Type, u16 Offset, u32 *Value) ++{ ++ if (Type == 1) ++ efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value); ++ else if (Type == 2) ++ efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value); ++ else if (Type == 4) ++ efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value); ++ ++} /* EFUSE_ShadowRead */ +diff --git a/drivers/staging/r8188eu/core/rtw_ieee80211.c b/drivers/staging/r8188eu/core/rtw_ieee80211.c +new file mode 100644 +index 000000000000..b3a74198596a +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_ieee80211.c +@@ -0,0 +1,1539 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _IEEE80211_C ++ ++#include "../include/drv_types.h" ++#include "../include/ieee80211.h" ++#include "../include/wifi.h" ++#include "../include/osdep_service.h" ++#include "../include/wlan_bssdef.h" ++#include "../include/usb_osintf.h" ++ ++u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 }; ++u16 RTW_WPA_VERSION = 1; ++u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 }; ++u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 }; ++u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 }; ++u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 }; ++u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 }; ++u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 }; ++u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 }; ++u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 }; ++u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 }; ++ ++u16 RSN_VERSION_BSD = 1; ++u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 }; ++u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 }; ++u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 }; ++u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 }; ++u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 }; ++u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 }; ++u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 }; ++u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 }; ++/* */ ++/* for adhoc-master to generate ie and provide supported-rate to fw */ ++/* */ ++ ++static u8 WIFI_CCKRATES[] = { ++ (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), ++ (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK) ++ }; ++ ++static u8 WIFI_OFDMRATES[] = { ++ (IEEE80211_OFDM_RATE_6MB), ++ (IEEE80211_OFDM_RATE_9MB), ++ (IEEE80211_OFDM_RATE_12MB), ++ (IEEE80211_OFDM_RATE_18MB), ++ (IEEE80211_OFDM_RATE_24MB), ++ IEEE80211_OFDM_RATE_36MB, ++ IEEE80211_OFDM_RATE_48MB, ++ IEEE80211_OFDM_RATE_54MB ++ }; ++ ++int rtw_get_bit_value_from_ieee_value(u8 val) ++{ ++ unsigned char dot11_rate_table[] = { ++ 2, 4, 11, 22, 12, 18, 24, 36, 48, ++ 72, 96, 108, 0}; /* last element must be zero!! */ ++ ++ int i = 0; ++ while (dot11_rate_table[i] != 0) { ++ if (dot11_rate_table[i] == val) ++ return BIT(i); ++ i++; ++ } ++ return 0; ++} ++ ++uint rtw_is_cckrates_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ while (rate[i] != 0) { ++ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || ++ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) ++ return true; ++ i++; ++ } ++ return false; ++} ++ ++uint rtw_is_cckratesonly_included(u8 *rate) ++{ ++ u32 i = 0; ++ ++ while (rate[i] != 0) { ++ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && ++ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) ++ return false; ++ i++; ++ } ++ ++ return true; ++} ++ ++int rtw_check_network_type(unsigned char *rate, int ratelen, int channel) ++{ ++ if (channel > 14) { ++ return WIRELESS_INVALID; ++ } else { /* could be pure B, pure G, or B/G */ ++ if (rtw_is_cckratesonly_included(rate)) ++ return WIRELESS_11B; ++ else if (rtw_is_cckrates_included(rate)) ++ return WIRELESS_11BG; ++ else ++ return WIRELESS_11G; ++ } ++} ++ ++u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source, ++ unsigned int *frlen) ++{ ++ memcpy((void *)pbuf, (void *)source, len); ++ *frlen = *frlen + len; ++ return pbuf + len; ++} ++ ++/* rtw_set_ie will update frame length */ ++u8 *rtw_set_ie ++( ++ u8 *pbuf, ++ int index, ++ uint len, ++ u8 *source, ++ uint *frlen /* frame length */ ++) ++{ ++ ++ *pbuf = (u8)index; ++ ++ *(pbuf + 1) = (u8)len; ++ ++ if (len > 0) ++ memcpy((void *)(pbuf + 2), (void *)source, len); ++ ++ *frlen = *frlen + (len + 2); ++ ++ return pbuf + len + 2; ++} ++ ++inline u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode, ++ u8 new_ch, u8 ch_switch_cnt) ++{ ++ u8 ie_data[3]; ++ ++ ie_data[0] = ch_switch_mode; ++ ie_data[1] = new_ch; ++ ie_data[2] = ch_switch_cnt; ++ return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH, 3, ie_data, buf_len); ++} ++ ++inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset) ++{ ++ if (ch_offset == SCN) ++ return HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ else if (ch_offset == SCA) ++ return HAL_PRIME_CHNL_OFFSET_UPPER; ++ else if (ch_offset == SCB) ++ return HAL_PRIME_CHNL_OFFSET_LOWER; ++ ++ return HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++} ++ ++inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset) ++{ ++ if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ++ return SCN; ++ else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ++ return SCB; ++ else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) ++ return SCA; ++ ++ return SCN; ++} ++ ++inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset) ++{ ++ return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET, 1, &secondary_ch_offset, buf_len); ++} ++ ++inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, ++ u8 flags, u16 reason, u16 precedence) ++{ ++ u8 ie_data[6]; ++ ++ ie_data[0] = ttl; ++ ie_data[1] = flags; ++ *(u16 *)(ie_data + 2) = cpu_to_le16(reason); ++ *(u16 *)(ie_data + 4) = cpu_to_le16(precedence); ++ ++ return rtw_set_ie(buf, 0x118, 6, ie_data, buf_len); ++} ++ ++/*---------------------------------------------------------------------------- ++index: the information element id index, limit is the limit for search ++-----------------------------------------------------------------------------*/ ++u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit) ++{ ++ int tmp, i; ++ u8 *p; ++ ++ if (limit < 1) { ++ ++ return NULL; ++ } ++ ++ p = pbuf; ++ i = 0; ++ *len = 0; ++ while (1) { ++ if (*p == index) { ++ *len = *(p + 1); ++ return p; ++ } else { ++ tmp = *(p + 1); ++ p += (tmp + 2); ++ i += (tmp + 2); ++ } ++ if (i >= limit) ++ break; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * rtw_get_ie_ex - Search specific IE from a series of IEs ++ * @in_ie: Address of IEs to search ++ * @in_len: Length limit from in_ie ++ * @eid: Element ID to match ++ * @oui: OUI to match ++ * @oui_len: OUI length ++ * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE ++ * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE ++ * ++ * Returns: The address of the specific IE found, or NULL ++ */ ++u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen) ++{ ++ uint cnt; ++ u8 *target_ie = NULL; ++ ++ if (ielen) ++ *ielen = 0; ++ ++ if (!in_ie || in_len <= 0) ++ return target_ie; ++ ++ cnt = 0; ++ ++ while (cnt < in_len) { ++ if (eid == in_ie[cnt] && (!oui || !memcmp(&in_ie[cnt + 2], oui, oui_len))) { ++ target_ie = &in_ie[cnt]; ++ ++ if (ie) ++ memcpy(ie, &in_ie[cnt], in_ie[cnt + 1] + 2); ++ ++ if (ielen) ++ *ielen = in_ie[cnt + 1] + 2; ++ ++ break; ++ } else { ++ cnt += in_ie[cnt + 1] + 2; /* goto next */ ++ } ++ } ++ return target_ie; ++} ++ ++/** ++ * rtw_ies_remove_ie - Find matching IEs and remove ++ * @ies: Address of IEs to search ++ * @ies_len: Pointer of length of ies, will update to new length ++ * @offset: The offset to start scarch ++ * @eid: Element ID to match ++ * @oui: OUI to match ++ * @oui_len: OUI length ++ * ++ * Returns: _SUCCESS: ies is updated, _FAIL: not updated ++ */ ++int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len) ++{ ++ int ret = _FAIL; ++ u8 *target_ie; ++ u32 target_ielen; ++ u8 *start; ++ uint search_len; ++ ++ if (!ies || !ies_len || *ies_len <= offset) ++ goto exit; ++ ++ start = ies + offset; ++ search_len = *ies_len - offset; ++ ++ while (1) { ++ target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen); ++ if (target_ie && target_ielen) { ++ u8 buf[MAX_IE_SZ] = {0}; ++ u8 *remain_ies = target_ie + target_ielen; ++ uint remain_len = search_len - (remain_ies - start); ++ ++ memcpy(buf, remain_ies, remain_len); ++ memcpy(target_ie, buf, remain_len); ++ *ies_len = *ies_len - target_ielen; ++ ret = _SUCCESS; ++ ++ start = target_ie; ++ search_len = remain_len; ++ } else { ++ break; ++ } ++ } ++exit: ++ return ret; ++} ++ ++void rtw_set_supported_rate(u8 *SupportedRates, uint mode) ++{ ++ ++ memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); ++ ++ switch (mode) { ++ case WIRELESS_11B: ++ memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); ++ break; ++ case WIRELESS_11G: ++ memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); ++ break; ++ case WIRELESS_11BG: ++ case WIRELESS_11G_24N: ++ case WIRELESS_11_24N: ++ case WIRELESS_11BG_24N: ++ memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); ++ memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); ++ break; ++ } ++ ++} ++ ++uint rtw_get_rateset_len(u8 *rateset) ++{ ++ uint i = 0; ++ ++ while (1) { ++ if ((rateset[i]) == 0) ++ break; ++ if (i > 12) ++ break; ++ i++; ++ } ++ ++ return i; ++} ++ ++int rtw_generate_ie(struct registry_priv *pregistrypriv) ++{ ++ u8 wireless_mode; ++ int sz = 0, rateLen; ++ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; ++ u8 *ie = pdev_network->IEs; ++ ++ /* timestamp will be inserted by hardware */ ++ sz += 8; ++ ie += sz; ++ ++ /* beacon interval : 2bytes */ ++ *(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);/* BCN_INTERVAL; */ ++ sz += 2; ++ ie += 2; ++ ++ /* capability info */ ++ *(u16 *)ie = 0; ++ ++ *(__le16 *)ie |= cpu_to_le16(cap_IBSS); ++ ++ if (pregistrypriv->preamble == PREAMBLE_SHORT) ++ *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble); ++ ++ if (pdev_network->Privacy) ++ *(__le16 *)ie |= cpu_to_le16(cap_Privacy); ++ ++ sz += 2; ++ ie += 2; ++ ++ /* SSID */ ++ ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz); ++ ++ /* supported rates */ ++ wireless_mode = pregistrypriv->wireless_mode; ++ ++ rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode); ++ ++ rateLen = rtw_get_rateset_len(pdev_network->SupportedRates); ++ ++ if (rateLen > 8) { ++ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz); ++ /* ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */ ++ } else { ++ ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz); ++ } ++ ++ /* DS parameter set */ ++ ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&pdev_network->Configuration.DSConfig, &sz); ++ ++ /* IBSS Parameter Set */ ++ ++ ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&pdev_network->Configuration.ATIMWindow, &sz); ++ ++ if (rateLen > 8) ++ ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); ++ ++ return sz; ++} ++ ++unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) ++{ ++ int len; ++ u16 val16; ++ __le16 le_tmp; ++ unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; ++ u8 *pbuf = pie; ++ int limit_new = limit; ++ ++ while (1) { ++ pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new); ++ ++ if (pbuf) { ++ /* check if oui matches... */ ++ if (memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type))) ++ goto check_next_ie; ++ ++ /* check version... */ ++ memcpy((u8 *)&le_tmp, (pbuf + 6), sizeof(val16)); ++ ++ val16 = le16_to_cpu(le_tmp); ++ if (val16 != 0x0001) ++ goto check_next_ie; ++ *wpa_ie_len = *(pbuf + 1); ++ return pbuf; ++ } else { ++ *wpa_ie_len = 0; ++ return NULL; ++ } ++ ++check_next_ie: ++ limit_new = limit - (pbuf - pie) - 2 - len; ++ if (limit_new <= 0) ++ break; ++ pbuf += (2 + len); ++ } ++ *wpa_ie_len = 0; ++ return NULL; ++} ++ ++unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) ++{ ++ ++ return rtw_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); ++} ++ ++int rtw_get_wpa_cipher_suite(u8 *s) ++{ ++ if (!memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_NONE; ++ if (!memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_WEP40; ++ if (!memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_TKIP; ++ if (!memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_CCMP; ++ if (!memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN)) ++ return WPA_CIPHER_WEP104; ++ ++ return 0; ++} ++ ++int rtw_get_wpa2_cipher_suite(u8 *s) ++{ ++ if (!memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_NONE; ++ if (!memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_WEP40; ++ if (!memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_TKIP; ++ if (!memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_CCMP; ++ if (!memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN)) ++ return WPA_CIPHER_WEP104; ++ ++ return 0; ++} ++ ++int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) ++{ ++ int i, ret = _SUCCESS; ++ int left, count; ++ u8 *pos; ++ u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1}; ++ ++ if (wpa_ie_len <= 0) { ++ /* No WPA IE - fail silently */ ++ return _FAIL; ++ } ++ ++ if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) || ++ (memcmp(wpa_ie + 2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN))) ++ return _FAIL; ++ ++ pos = wpa_ie; ++ ++ pos += 8; ++ left = wpa_ie_len - 8; ++ ++ /* group_cipher */ ++ if (left >= WPA_SELECTOR_LEN) { ++ *group_cipher = rtw_get_wpa_cipher_suite(pos); ++ pos += WPA_SELECTOR_LEN; ++ left -= WPA_SELECTOR_LEN; ++ } else if (left > 0) { ++ return _FAIL; ++ } ++ ++ /* pairwise_cipher */ ++ if (left >= 2) { ++ count = get_unaligned_le16(pos); ++ pos += 2; ++ left -= 2; ++ ++ if (count == 0 || left < count * WPA_SELECTOR_LEN) ++ return _FAIL; ++ ++ for (i = 0; i < count; i++) { ++ *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos); ++ ++ pos += WPA_SELECTOR_LEN; ++ left -= WPA_SELECTOR_LEN; ++ } ++ } else if (left == 1) { ++ return _FAIL; ++ } ++ ++ if (is_8021x) { ++ if (left >= 6) { ++ pos += 2; ++ if (!memcmp(pos, SUITE_1X, 4)) ++ *is_8021x = 1; ++ } ++ } ++ ++ return ret; ++} ++ ++int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) ++{ ++ int i, ret = _SUCCESS; ++ int left, count; ++ u8 *pos; ++ u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01}; ++ ++ if (rsn_ie_len <= 0) { ++ /* No RSN IE - fail silently */ ++ return _FAIL; ++ } ++ ++ if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2))) ++ return _FAIL; ++ ++ pos = rsn_ie; ++ pos += 4; ++ left = rsn_ie_len - 4; ++ ++ /* group_cipher */ ++ if (left >= RSN_SELECTOR_LEN) { ++ *group_cipher = rtw_get_wpa2_cipher_suite(pos); ++ ++ pos += RSN_SELECTOR_LEN; ++ left -= RSN_SELECTOR_LEN; ++ ++ } else if (left > 0) { ++ return _FAIL; ++ } ++ ++ /* pairwise_cipher */ ++ if (left >= 2) { ++ count = get_unaligned_le16(pos); ++ pos += 2; ++ left -= 2; ++ ++ if (count == 0 || left < count * RSN_SELECTOR_LEN) ++ return _FAIL; ++ ++ for (i = 0; i < count; i++) { ++ *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos); ++ ++ pos += RSN_SELECTOR_LEN; ++ left -= RSN_SELECTOR_LEN; ++ } ++ ++ } else if (left == 1) { ++ return _FAIL; ++ } ++ ++ if (is_8021x) { ++ if (left >= 6) { ++ pos += 2; ++ if (!memcmp(pos, SUITE_1X, 4)) ++ *is_8021x = 1; ++ } ++ } ++ return ret; ++} ++ ++int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len) ++{ ++ u8 authmode; ++ u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; ++ uint cnt; ++ ++ /* Search required WPA or WPA2 IE and copy to sec_ie[] */ ++ ++ cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); ++ ++ while (cnt < in_len) { ++ authmode = in_ie[cnt]; ++ ++ if ((authmode == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4))) { ++ if (wpa_ie) ++ memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); ++ ++ *wpa_len = in_ie[cnt + 1] + 2; ++ cnt += in_ie[cnt + 1] + 2; /* get next */ ++ } else { ++ if (authmode == _WPA2_IE_ID_) { ++ if (rsn_ie) ++ memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); ++ ++ *rsn_len = in_ie[cnt + 1] + 2; ++ cnt += in_ie[cnt + 1] + 2; /* get next */ ++ } else { ++ cnt += in_ie[cnt + 1] + 2; /* get next */ ++ } ++ } ++ } ++ ++ return *rsn_len + *wpa_len; ++} ++ ++u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen) ++{ ++ u8 match = false; ++ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; ++ ++ if (!ie_ptr) ++ return match; ++ ++ eid = ie_ptr[0]; ++ ++ if ((eid == _WPA_IE_ID_) && (!memcmp(&ie_ptr[2], wps_oui, 4))) { ++ *wps_ielen = ie_ptr[1] + 2; ++ match = true; ++ } ++ return match; ++} ++ ++/** ++ * rtw_get_wps_ie - Search WPS IE from a series of IEs ++ * @in_ie: Address of IEs to search ++ * @in_len: Length limit from in_ie ++ * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie ++ * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE ++ * ++ * Returns: The address of the WPS IE found, or NULL ++ */ ++u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) ++{ ++ uint cnt; ++ u8 *wpsie_ptr = NULL; ++ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; ++ ++ if (wps_ielen) ++ *wps_ielen = 0; ++ ++ if (!in_ie || in_len <= 0) ++ return wpsie_ptr; ++ ++ cnt = 0; ++ ++ while (cnt < in_len) { ++ eid = in_ie[cnt]; ++ ++ if ((eid == _WPA_IE_ID_) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) { ++ wpsie_ptr = &in_ie[cnt]; ++ ++ if (wps_ie) ++ memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); ++ ++ if (wps_ielen) ++ *wps_ielen = in_ie[cnt + 1] + 2; ++ ++ cnt += in_ie[cnt + 1] + 2; ++ ++ break; ++ } else { ++ cnt += in_ie[cnt + 1] + 2; /* goto next */ ++ } ++ } ++ return wpsie_ptr; ++} ++ ++/** ++ * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE ++ * @wps_ie: Address of WPS IE to search ++ * @wps_ielen: Length limit from wps_ie ++ * @target_attr_id: The attribute ID of WPS attribute to search ++ * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr ++ * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute ++ * ++ * Returns: the address of the specific WPS attribute found, or NULL ++ */ ++u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_attr, u32 *len_attr) ++{ ++ u8 *attr_ptr = NULL; ++ u8 *target_attr_ptr = NULL; ++ u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04}; ++ ++ if (len_attr) ++ *len_attr = 0; ++ ++ if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) || ++ (memcmp(wps_ie + 2, wps_oui, 4))) ++ return attr_ptr; ++ ++ /* 6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */ ++ attr_ptr = wps_ie + 6; /* goto first attr */ ++ ++ while (attr_ptr - wps_ie < wps_ielen) { ++ /* 4 = 2(Attribute ID) + 2(Length) */ ++ u16 attr_id = RTW_GET_BE16(attr_ptr); ++ u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2); ++ u16 attr_len = attr_data_len + 4; ++ ++ if (attr_id == target_attr_id) { ++ target_attr_ptr = attr_ptr; ++ if (buf_attr) ++ memcpy(buf_attr, attr_ptr, attr_len); ++ if (len_attr) ++ *len_attr = attr_len; ++ break; ++ } else { ++ attr_ptr += attr_len; /* goto next */ ++ } ++ } ++ return target_attr_ptr; ++} ++ ++/** ++ * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE ++ * @wps_ie: Address of WPS IE to search ++ * @wps_ielen: Length limit from wps_ie ++ * @target_attr_id: The attribute ID of WPS attribute to search ++ * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content ++ * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content ++ * ++ * Returns: the address of the specific WPS attribute content found, or NULL ++ */ ++u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_content, uint *len_content) ++{ ++ u8 *attr_ptr; ++ u32 attr_len; ++ ++ if (len_content) ++ *len_content = 0; ++ ++ attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len); ++ ++ if (attr_ptr && attr_len) { ++ if (buf_content) ++ memcpy(buf_content, attr_ptr + 4, attr_len - 4); ++ ++ if (len_content) ++ *len_content = attr_len - 4; ++ ++ return attr_ptr + 4; ++ } ++ ++ return NULL; ++} ++ ++static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, ++ struct rtw_ieee802_11_elems *elems, ++ int show_errors) ++{ ++ unsigned int oui; ++ ++ /* first 3 bytes in vendor specific information element are the IEEE ++ * OUI of the vendor. The following byte is used a vendor specific ++ * sub-type. */ ++ if (elen < 4) { ++ if (show_errors) { ++ DBG_88E("short vendor specific information element ignored (len=%lu)\n", ++ (unsigned long)elen); ++ } ++ return -1; ++ } ++ ++ oui = RTW_GET_BE24(pos); ++ switch (oui) { ++ case OUI_MICROSOFT: ++ /* Microsoft/Wi-Fi information elements are further typed and ++ * subtyped */ ++ switch (pos[3]) { ++ case 1: ++ /* Microsoft OUI (00:50:F2) with OUI Type 1: ++ * real WPA information element */ ++ elems->wpa_ie = pos; ++ elems->wpa_ie_len = elen; ++ break; ++ case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ ++ if (elen < 5) { ++ DBG_88E("short WME information element ignored (len=%lu)\n", ++ (unsigned long)elen); ++ return -1; ++ } ++ switch (pos[4]) { ++ case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: ++ case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: ++ elems->wme = pos; ++ elems->wme_len = elen; ++ break; ++ case WME_OUI_SUBTYPE_TSPEC_ELEMENT: ++ elems->wme_tspec = pos; ++ elems->wme_tspec_len = elen; ++ break; ++ default: ++ DBG_88E("unknown WME information element ignored (subtype=%d len=%lu)\n", ++ pos[4], (unsigned long)elen); ++ return -1; ++ } ++ break; ++ case 4: ++ /* Wi-Fi Protected Setup (WPS) IE */ ++ elems->wps_ie = pos; ++ elems->wps_ie_len = elen; ++ break; ++ default: ++ DBG_88E("Unknown Microsoft information element ignored (type=%d len=%lu)\n", ++ pos[3], (unsigned long)elen); ++ return -1; ++ } ++ break; ++ ++ case OUI_BROADCOM: ++ switch (pos[3]) { ++ case VENDOR_HT_CAPAB_OUI_TYPE: ++ elems->vendor_ht_cap = pos; ++ elems->vendor_ht_cap_len = elen; ++ break; ++ default: ++ DBG_88E("Unknown Broadcom information element ignored (type=%d len=%lu)\n", ++ pos[3], (unsigned long)elen); ++ return -1; ++ } ++ break; ++ default: ++ DBG_88E("unknown vendor specific information element ignored (vendor OUI %02x:%02x:%02x len=%lu)\n", ++ pos[0], pos[1], pos[2], (unsigned long)elen); ++ return -1; ++ } ++ return 0; ++} ++ ++/** ++ * ieee802_11_parse_elems - Parse information elements in management frames ++ * @start: Pointer to the start of IEs ++ * @len: Length of IE buffer in octets ++ * @elems: Data structure for parsed elements ++ * @show_errors: Whether to show parsing errors in debug log ++ * Returns: Parsing result ++ */ ++enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len, ++ struct rtw_ieee802_11_elems *elems, ++ int show_errors) ++{ ++ uint left = len; ++ u8 *pos = start; ++ int unknown = 0; ++ ++ memset(elems, 0, sizeof(*elems)); ++ ++ while (left >= 2) { ++ u8 id, elen; ++ ++ id = *pos++; ++ elen = *pos++; ++ left -= 2; ++ ++ if (elen > left) { ++ if (show_errors) { ++ DBG_88E("IEEE 802.11 element parse failed (id=%d elen=%d left=%lu)\n", ++ id, elen, (unsigned long)left); ++ } ++ return ParseFailed; ++ } ++ ++ switch (id) { ++ case WLAN_EID_SSID: ++ elems->ssid = pos; ++ elems->ssid_len = elen; ++ break; ++ case WLAN_EID_SUPP_RATES: ++ elems->supp_rates = pos; ++ elems->supp_rates_len = elen; ++ break; ++ case WLAN_EID_FH_PARAMS: ++ elems->fh_params = pos; ++ elems->fh_params_len = elen; ++ break; ++ case WLAN_EID_DS_PARAMS: ++ elems->ds_params = pos; ++ elems->ds_params_len = elen; ++ break; ++ case WLAN_EID_CF_PARAMS: ++ elems->cf_params = pos; ++ elems->cf_params_len = elen; ++ break; ++ case WLAN_EID_TIM: ++ elems->tim = pos; ++ elems->tim_len = elen; ++ break; ++ case WLAN_EID_IBSS_PARAMS: ++ elems->ibss_params = pos; ++ elems->ibss_params_len = elen; ++ break; ++ case WLAN_EID_CHALLENGE: ++ elems->challenge = pos; ++ elems->challenge_len = elen; ++ break; ++ case WLAN_EID_ERP_INFO: ++ elems->erp_info = pos; ++ elems->erp_info_len = elen; ++ break; ++ case WLAN_EID_EXT_SUPP_RATES: ++ elems->ext_supp_rates = pos; ++ elems->ext_supp_rates_len = elen; ++ break; ++ case WLAN_EID_VENDOR_SPECIFIC: ++ if (rtw_ieee802_11_parse_vendor_specific(pos, elen, elems, show_errors)) ++ unknown++; ++ break; ++ case WLAN_EID_RSN: ++ elems->rsn_ie = pos; ++ elems->rsn_ie_len = elen; ++ break; ++ case WLAN_EID_PWR_CAPABILITY: ++ elems->power_cap = pos; ++ elems->power_cap_len = elen; ++ break; ++ case WLAN_EID_SUPPORTED_CHANNELS: ++ elems->supp_channels = pos; ++ elems->supp_channels_len = elen; ++ break; ++ case WLAN_EID_MOBILITY_DOMAIN: ++ elems->mdie = pos; ++ elems->mdie_len = elen; ++ break; ++ case WLAN_EID_FAST_BSS_TRANSITION: ++ elems->ftie = pos; ++ elems->ftie_len = elen; ++ break; ++ case WLAN_EID_TIMEOUT_INTERVAL: ++ elems->timeout_int = pos; ++ elems->timeout_int_len = elen; ++ break; ++ case WLAN_EID_HT_CAP: ++ elems->ht_capabilities = pos; ++ elems->ht_capabilities_len = elen; ++ break; ++ case WLAN_EID_HT_OPERATION: ++ elems->ht_operation = pos; ++ elems->ht_operation_len = elen; ++ break; ++ default: ++ unknown++; ++ if (!show_errors) ++ break; ++ DBG_88E("IEEE 802.11 element parse ignored unknown element (id=%d elen=%d)\n", ++ id, elen); ++ break; ++ } ++ left -= elen; ++ pos += elen; ++ } ++ if (left) ++ return ParseFailed; ++ return unknown ? ParseUnknown : ParseOK; ++} ++ ++u8 key_char2num(u8 ch) ++{ ++ if ((ch >= '0') && (ch <= '9')) ++ return ch - '0'; ++ else if ((ch >= 'a') && (ch <= 'f')) ++ return ch - 'a' + 10; ++ else if ((ch >= 'A') && (ch <= 'F')) ++ return ch - 'A' + 10; ++ else ++ return 0xff; ++} ++ ++u8 str_2char2num(u8 hch, u8 lch) ++{ ++ return (key_char2num(hch) * 10) + key_char2num(lch); ++} ++ ++u8 key_2char2num(u8 hch, u8 lch) ++{ ++ return (key_char2num(hch) << 4) | key_char2num(lch); ++} ++ ++void rtw_macaddr_cfg(u8 *mac_addr) ++{ ++ u8 mac[ETH_ALEN]; ++ if (!mac_addr) ++ return; ++ ++ if (rtw_initmac) { /* Users specify the mac address */ ++ int jj, kk; ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk + 1]); ++ memcpy(mac_addr, mac, ETH_ALEN); ++ } else { /* Use the mac address stored in the Efuse */ ++ memcpy(mac, mac_addr, ETH_ALEN); ++ } ++ ++ if (((mac[0] == 0xff) && (mac[1] == 0xff) && (mac[2] == 0xff) && ++ (mac[3] == 0xff) && (mac[4] == 0xff) && (mac[5] == 0xff)) || ++ ((mac[0] == 0x0) && (mac[1] == 0x0) && (mac[2] == 0x0) && ++ (mac[3] == 0x0) && (mac[4] == 0x0) && (mac[5] == 0x0))) { ++ mac[0] = 0x00; ++ mac[1] = 0xe0; ++ mac[2] = 0x4c; ++ mac[3] = 0x87; ++ mac[4] = 0x00; ++ mac[5] = 0x00; ++ /* use default mac addresss */ ++ memcpy(mac_addr, mac, ETH_ALEN); ++ DBG_88E("MAC Address from efuse error, assign default one !!!\n"); ++ } ++ ++ DBG_88E("rtw_macaddr_cfg MAC Address = %pM\n", (mac_addr)); ++} ++ ++void dump_ies(u8 *buf, u32 buf_len) ++{ ++ u8 *pos = (u8 *)buf; ++ u8 id, len; ++ ++ while (pos - buf <= buf_len) { ++ id = *pos; ++ len = *(pos + 1); ++ ++ DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len); ++ #ifdef CONFIG_88EU_P2P ++ dump_p2p_ie(pos, len); ++ #endif ++ dump_wps_ie(pos, len); ++ ++ pos += (2 + len); ++ } ++} ++ ++void dump_wps_ie(u8 *ie, u32 ie_len) ++{ ++ u8 *pos = (u8 *)ie; ++ u16 id; ++ u16 len; ++ u8 *wps_ie; ++ uint wps_ielen; ++ ++ wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen); ++ if (wps_ie != ie || wps_ielen == 0) ++ return; ++ ++ pos += 6; ++ while (pos - ie < ie_len) { ++ id = RTW_GET_BE16(pos); ++ len = RTW_GET_BE16(pos + 2); ++ DBG_88E("%s ID:0x%04x, LEN:%u\n", __func__, id, len); ++ pos += (4 + len); ++ } ++} ++ ++#ifdef CONFIG_88EU_P2P ++void dump_p2p_ie(u8 *ie, u32 ie_len) ++{ ++ u8 *pos = (u8 *)ie; ++ u8 id; ++ u16 len; ++ u8 *p2p_ie; ++ uint p2p_ielen; ++ ++ p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen); ++ if (p2p_ie != ie || p2p_ielen == 0) ++ return; ++ ++ pos += 6; ++ while (pos - ie < ie_len) { ++ id = *pos; ++ len = get_unaligned_le16(pos + 1); ++ DBG_88E("%s ID:%u, LEN:%u\n", __func__, id, len); ++ pos += (3 + len); ++ } ++} ++ ++/** ++ * rtw_get_p2p_ie - Search P2P IE from a series of IEs ++ * @in_ie: Address of IEs to search ++ * @in_len: Length limit from in_ie ++ * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the buf starting from p2p_ie ++ * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of the entire P2P IE ++ * ++ * Returns: The address of the P2P IE found, or NULL ++ */ ++u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen) ++{ ++ uint cnt = 0; ++ u8 *p2p_ie_ptr; ++ u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09}; ++ ++ if (p2p_ielen) ++ *p2p_ielen = 0; ++ ++ while (cnt < in_len) { ++ eid = in_ie[cnt]; ++ if ((in_len < 0) || (cnt > MAX_IE_SZ)) { ++ dump_stack(); ++ return NULL; ++ } ++ if ((eid == _VENDOR_SPECIFIC_IE_) && !memcmp(&in_ie[cnt + 2], p2p_oui, 4)) { ++ p2p_ie_ptr = in_ie + cnt; ++ ++ if (p2p_ie) ++ memcpy(p2p_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); ++ if (p2p_ielen) ++ *p2p_ielen = in_ie[cnt + 1] + 2; ++ return p2p_ie_ptr; ++ } else { ++ cnt += in_ie[cnt + 1] + 2; /* goto next */ ++ } ++ } ++ return NULL; ++} ++ ++/** ++ * rtw_get_p2p_attr - Search a specific P2P attribute from a given P2P IE ++ * @p2p_ie: Address of P2P IE to search ++ * @p2p_ielen: Length limit from p2p_ie ++ * @target_attr_id: The attribute ID of P2P attribute to search ++ * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will be copied to the buf starting from buf_attr ++ * @len_attr: If not NULL and the P2P attribute is found, will set to the length of the entire P2P attribute ++ * ++ * Returns: the address of the specific WPS attribute found, or NULL ++ */ ++u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, u8 *buf_attr, u32 *len_attr) ++{ ++ u8 *attr_ptr = NULL; ++ u8 *target_attr_ptr = NULL; ++ u8 p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09}; ++ ++ if (len_attr) ++ *len_attr = 0; ++ ++ if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) || ++ memcmp(p2p_ie + 2, p2p_oui, 4)) ++ return attr_ptr; ++ ++ /* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */ ++ attr_ptr = p2p_ie + 6; /* goto first attr */ ++ ++ while (attr_ptr - p2p_ie < p2p_ielen) { ++ /* 3 = 1(Attribute ID) + 2(Length) */ ++ u8 attr_id = *attr_ptr; ++ u16 attr_data_len = get_unaligned_le16(attr_ptr + 1); ++ u16 attr_len = attr_data_len + 3; ++ ++ if (attr_id == target_attr_id) { ++ target_attr_ptr = attr_ptr; ++ ++ if (buf_attr) ++ memcpy(buf_attr, attr_ptr, attr_len); ++ if (len_attr) ++ *len_attr = attr_len; ++ break; ++ } else { ++ attr_ptr += attr_len; /* goto next */ ++ } ++ } ++ return target_attr_ptr; ++} ++ ++/** ++ * rtw_get_p2p_attr_content - Search a specific P2P attribute content from a given P2P IE ++ * @p2p_ie: Address of P2P IE to search ++ * @p2p_ielen: Length limit from p2p_ie ++ * @target_attr_id: The attribute ID of P2P attribute to search ++ * @buf_content: If not NULL and the P2P attribute is found, P2P attribute content will be copied to the buf starting from buf_content ++ * @len_content: If not NULL and the P2P attribute is found, will set to the length of the P2P attribute content ++ * ++ * Returns: the address of the specific P2P attribute content found, or NULL ++ */ ++u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, u8 *buf_content, uint *len_content) ++{ ++ u8 *attr_ptr; ++ u32 attr_len; ++ ++ if (len_content) ++ *len_content = 0; ++ ++ attr_ptr = rtw_get_p2p_attr(p2p_ie, p2p_ielen, target_attr_id, NULL, &attr_len); ++ ++ if (attr_ptr && attr_len) { ++ if (buf_content) ++ memcpy(buf_content, attr_ptr + 3, attr_len - 3); ++ ++ if (len_content) ++ *len_content = attr_len - 3; ++ ++ return attr_ptr + 3; ++ } ++ ++ return NULL; ++} ++ ++u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr) ++{ ++ u32 a_len; ++ ++ *pbuf = attr_id; ++ ++ /* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */ ++ RTW_PUT_LE16(pbuf + 1, attr_len); ++ ++ if (pdata_attr) ++ memcpy(pbuf + 3, pdata_attr, attr_len); ++ ++ a_len = attr_len + 3; ++ ++ return a_len; ++} ++ ++static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id) ++{ ++ u8 *target_attr; ++ u32 target_attr_len; ++ uint ielen = ielen_ori; ++ ++ while (1) { ++ target_attr = rtw_get_p2p_attr(ie, ielen, attr_id, NULL, &target_attr_len); ++ if (target_attr && target_attr_len) { ++ u8 *next_attr = target_attr + target_attr_len; ++ uint remain_len = ielen - (next_attr - ie); ++ ++ memset(target_attr, 0, target_attr_len); ++ memcpy(target_attr, next_attr, remain_len); ++ memset(target_attr + remain_len, 0, target_attr_len); ++ *(ie + 1) -= target_attr_len; ++ ielen -= target_attr_len; ++ } else { ++ break; ++ } ++ } ++ return ielen; ++} ++ ++void rtw_wlan_bssid_ex_remove_p2p_attr(struct wlan_bssid_ex *bss_ex, u8 attr_id) ++{ ++ u8 *p2p_ie; ++ uint p2p_ielen, p2p_ielen_ori; ++ ++ p2p_ie = rtw_get_p2p_ie(bss_ex->IEs + _FIXED_IE_LENGTH_, bss_ex->IELength - _FIXED_IE_LENGTH_, NULL, &p2p_ielen_ori); ++ if (p2p_ie) { ++ p2p_ielen = rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id); ++ if (p2p_ielen != p2p_ielen_ori) { ++ u8 *next_ie_ori = p2p_ie + p2p_ielen_ori; ++ u8 *next_ie = p2p_ie + p2p_ielen; ++ uint remain_len = bss_ex->IELength - (next_ie_ori - bss_ex->IEs); ++ ++ memcpy(next_ie, next_ie_ori, remain_len); ++ memset(next_ie + remain_len, 0, p2p_ielen_ori - p2p_ielen); ++ bss_ex->IELength -= p2p_ielen_ori - p2p_ielen; ++ } ++ } ++} ++ ++#endif /* CONFIG_88EU_P2P */ ++ ++/* Baron adds to avoid FreeBSD warning */ ++int ieee80211_is_empty_essid(const char *essid, int essid_len) ++{ ++ /* Single white space is for Linksys APs */ ++ if (essid_len == 1 && essid[0] == ' ') ++ return 1; ++ ++ /* Otherwise, if the entire essid is 0, we assume it is hidden */ ++ while (essid_len) { ++ essid_len--; ++ if (essid[essid_len] != '\0') ++ return 0; ++ } ++ ++ return 1; ++} ++ ++int ieee80211_get_hdrlen(u16 fc) ++{ ++ int hdrlen = 24; ++ ++ switch (WLAN_FC_GET_TYPE(fc)) { ++ case RTW_IEEE80211_FTYPE_DATA: ++ if (fc & RTW_IEEE80211_STYPE_QOS_DATA) ++ hdrlen += 2; ++ if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS)) ++ hdrlen += 6; /* Addr4 */ ++ break; ++ case RTW_IEEE80211_FTYPE_CTL: ++ switch (WLAN_FC_GET_STYPE(fc)) { ++ case RTW_IEEE80211_STYPE_CTS: ++ case RTW_IEEE80211_STYPE_ACK: ++ hdrlen = 10; ++ break; ++ default: ++ hdrlen = 16; ++ break; ++ } ++ break; ++ } ++ ++ return hdrlen; ++} ++ ++static int rtw_get_cipher_info(struct wlan_network *pnetwork) ++{ ++ u32 wpa_ielen; ++ unsigned char *pbuf; ++ int group_cipher = 0, pairwise_cipher = 0, is8021x = 0; ++ int ret = _FAIL; ++ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12); ++ ++ if (pbuf && (wpa_ielen > 0)) { ++ if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) { ++ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; ++ pnetwork->BcnInfo.group_cipher = group_cipher; ++ pnetwork->BcnInfo.is_8021x = is8021x; ++ ret = _SUCCESS; ++ } ++ } else { ++ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12); ++ ++ if (pbuf && (wpa_ielen > 0)) { ++ if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) { ++ pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; ++ pnetwork->BcnInfo.group_cipher = group_cipher; ++ pnetwork->BcnInfo.is_8021x = is8021x; ++ ret = _SUCCESS; ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++void rtw_get_bcn_info(struct wlan_network *pnetwork) ++{ ++ unsigned short cap = 0; ++ u8 bencrypt = 0; ++ __le16 le_tmp; ++ u16 wpa_len = 0, rsn_len = 0; ++ struct HT_info_element *pht_info = NULL; ++ struct ieee80211_ht_cap *pht_cap = NULL; ++ unsigned int len; ++ unsigned char *p; ++ ++ memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2); ++ cap = le16_to_cpu(le_tmp); ++ if (cap & WLAN_CAPABILITY_PRIVACY) { ++ bencrypt = 1; ++ pnetwork->network.Privacy = 1; ++ } else { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; ++ } ++ rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len); ++ ++ if (rsn_len > 0) { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2; ++ } else if (wpa_len > 0) { ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA; ++ } else { ++ if (bencrypt) ++ pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP; ++ } ++ rtw_get_cipher_info(pnetwork); ++ ++ /* get bwmode and ch_offset */ ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); ++ if (p && len > 0) { ++ pht_cap = (struct ieee80211_ht_cap *)(p + 2); ++ pnetwork->BcnInfo.ht_cap_info = le16_to_cpu(pht_cap->cap_info); ++ } else { ++ pnetwork->BcnInfo.ht_cap_info = 0; ++ } ++ /* parsing HT_INFO_IE */ ++ p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); ++ if (p && len > 0) { ++ pht_info = (struct HT_info_element *)(p + 2); ++ pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0]; ++ } else { ++ pnetwork->BcnInfo.ht_info_infos_0 = 0; ++ } ++} ++ ++/* show MCS rate, unit: 100Kbps */ ++u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char *MCS_rate) ++{ ++ u16 max_rate = 0; ++ ++ if (rf_type == RF_1T1R) { ++ if (MCS_rate[0] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650); ++ else if (MCS_rate[0] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585); ++ else if (MCS_rate[0] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520); ++ else if (MCS_rate[0] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390); ++ else if (MCS_rate[0] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260); ++ else if (MCS_rate[0] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195); ++ else if (MCS_rate[0] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130); ++ else if (MCS_rate[0] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65); ++ } else { ++ if (MCS_rate[1]) { ++ if (MCS_rate[1] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 3000 : 2700) : ((short_GI_20) ? 1444 : 1300); ++ else if (MCS_rate[1] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 2700 : 2430) : ((short_GI_20) ? 1300 : 1170); ++ else if (MCS_rate[1] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 2400 : 2160) : ((short_GI_20) ? 1156 : 1040); ++ else if (MCS_rate[1] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1800 : 1620) : ((short_GI_20) ? 867 : 780); ++ else if (MCS_rate[1] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520); ++ else if (MCS_rate[1] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390); ++ else if (MCS_rate[1] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260); ++ else if (MCS_rate[1] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130); ++ } else { ++ if (MCS_rate[0] & BIT(7)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1500 : 1350) : ((short_GI_20) ? 722 : 650); ++ else if (MCS_rate[0] & BIT(6)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1350 : 1215) : ((short_GI_20) ? 650 : 585); ++ else if (MCS_rate[0] & BIT(5)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 1200 : 1080) : ((short_GI_20) ? 578 : 520); ++ else if (MCS_rate[0] & BIT(4)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 900 : 810) : ((short_GI_20) ? 433 : 390); ++ else if (MCS_rate[0] & BIT(3)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 600 : 540) : ((short_GI_20) ? 289 : 260); ++ else if (MCS_rate[0] & BIT(2)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 450 : 405) : ((short_GI_20) ? 217 : 195); ++ else if (MCS_rate[0] & BIT(1)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 300 : 270) : ((short_GI_20) ? 144 : 130); ++ else if (MCS_rate[0] & BIT(0)) ++ max_rate = (bw_40MHz) ? ((short_GI_40) ? 150 : 135) : ((short_GI_20) ? 72 : 65); ++ } ++ } ++ return max_rate; ++} ++ ++int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action) ++{ ++ const u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr); ++ u16 fc; ++ u8 c, a = 0; ++ ++ fc = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)frame)->frame_ctl); ++ ++ if ((fc & (RTW_IEEE80211_FCTL_FTYPE | RTW_IEEE80211_FCTL_STYPE)) != ++ (RTW_IEEE80211_FTYPE_MGMT | RTW_IEEE80211_STYPE_ACTION)) ++ return false; ++ ++ c = frame_body[0]; ++ ++ switch (c) { ++ case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */ ++ break; ++ default: ++ a = frame_body[1]; ++ } ++ ++ if (category) ++ *category = c; ++ if (action) ++ *action = a; ++ ++ return true; ++} ++ ++static const char *_action_public_str[] = { ++ "ACT_PUB_BSSCOEXIST", ++ "ACT_PUB_DSE_ENABLE", ++ "ACT_PUB_DSE_DEENABLE", ++ "ACT_PUB_DSE_REG_LOCATION", ++ "ACT_PUB_EXT_CHL_SWITCH", ++ "ACT_PUB_DSE_MSR_REQ", ++ "ACT_PUB_DSE_MSR_RPRT", ++ "ACT_PUB_MP", ++ "ACT_PUB_DSE_PWR_CONSTRAINT", ++ "ACT_PUB_VENDOR", ++ "ACT_PUB_GAS_INITIAL_REQ", ++ "ACT_PUB_GAS_INITIAL_RSP", ++ "ACT_PUB_GAS_COMEBACK_REQ", ++ "ACT_PUB_GAS_COMEBACK_RSP", ++ "ACT_PUB_TDLS_DISCOVERY_RSP", ++ "ACT_PUB_LOCATION_TRACK", ++ "ACT_PUB_RSVD", ++}; ++ ++const char *action_public_str(u8 action) ++{ ++ action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action; ++ return _action_public_str[action]; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_io.c b/drivers/staging/r8188eu/core/rtw_io.c +new file mode 100644 +index 000000000000..cde0205816b1 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_io.c +@@ -0,0 +1,299 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++/* ++ ++The purpose of rtw_io.c ++ ++a. provides the API ++ ++b. provides the protocol engine ++ ++c. provides the software interface between caller and the hardware interface ++ ++Compiler Flag Option: ++ ++USB: ++ a. USE_ASYNC_IRP: Both sync/async operations are provided. ++ ++Only sync read/rtw_write_mem operations are provided. ++ ++jackson@realtek.com.tw ++ ++*/ ++ ++#define _RTW_IO_C_ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtw_io.h" ++#include "../include/osdep_intf.h" ++#include "../include/usb_ops.h" ++ ++#define rtw_le16_to_cpu(val) le16_to_cpu(val) ++#define rtw_le32_to_cpu(val) le32_to_cpu(val) ++#define rtw_cpu_to_le16(val) cpu_to_le16(val) ++#define rtw_cpu_to_le32(val) cpu_to_le32(val) ++ ++u8 _rtw_read8(struct adapter *adapter, u32 addr) ++{ ++ u8 r_val; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ ++ _read8 = pintfhdl->io_ops._read8; ++ r_val = _read8(pintfhdl, addr); ++ ++ return r_val; ++} ++ ++u16 _rtw_read16(struct adapter *adapter, u32 addr) ++{ ++ u16 r_val; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ _read16 = pintfhdl->io_ops._read16; ++ ++ r_val = _read16(pintfhdl, addr); ++ ++ return r_val; ++} ++ ++u32 _rtw_read32(struct adapter *adapter, u32 addr) ++{ ++ u32 r_val; ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); ++ ++ _read32 = pintfhdl->io_ops._read32; ++ ++ r_val = _read32(pintfhdl, addr); ++ ++ return r_val; ++} ++ ++int _rtw_write8(struct adapter *adapter, u32 addr, u8 val) ++{ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int ret; ++ ++ _write8 = pintfhdl->io_ops._write8; ++ ++ ret = _write8(pintfhdl, addr, val); ++ ++ ++ return RTW_STATUS_CODE(ret); ++} ++ ++int _rtw_write16(struct adapter *adapter, u32 addr, u16 val) ++{ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int ret; ++ ++ _write16 = pintfhdl->io_ops._write16; ++ ++ ret = _write16(pintfhdl, addr, val); ++ ++ ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write32(struct adapter *adapter, u32 addr, u32 val) ++{ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ int ret; ++ ++ _write32 = pintfhdl->io_ops._write32; ++ ++ ret = _write32(pintfhdl, addr, val); ++ ++ ++ return RTW_STATUS_CODE(ret); ++} ++ ++int _rtw_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata) ++{ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = (struct intf_hdl *)(&pio_priv->intf); ++ int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata); ++ int ret; ++ ++ _writeN = pintfhdl->io_ops._writeN; ++ ++ ret = _writeN(pintfhdl, addr, length, pdata); ++ ++ ++ return RTW_STATUS_CODE(ret); ++} ++int _rtw_write8_async(struct adapter *adapter, u32 addr, u8 val) ++{ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int ret; ++ ++ _write8_async = pintfhdl->io_ops._write8_async; ++ ++ ret = _write8_async(pintfhdl, addr, val); ++ ++ ++ return RTW_STATUS_CODE(ret); ++} ++ ++int _rtw_write16_async(struct adapter *adapter, u32 addr, u16 val) ++{ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int ret; ++ ++ _write16_async = pintfhdl->io_ops._write16_async; ++ ret = _write16_async(pintfhdl, addr, val); ++ ++ return RTW_STATUS_CODE(ret); ++} ++ ++int _rtw_write32_async(struct adapter *adapter, u32 addr, u32 val) ++{ ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ int ret; ++ ++ _write32_async = pintfhdl->io_ops._write32_async; ++ ret = _write32_async(pintfhdl, addr, val); ++ ++ return RTW_STATUS_CODE(ret); ++} ++ ++void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ ++ ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) ++ return; ++ _read_mem = pintfhdl->io_ops._read_mem; ++ _read_mem(pintfhdl, addr, cnt, pmem); ++ ++} ++ ++void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ ++ ++ ++ _write_mem = pintfhdl->io_ops._write_mem; ++ ++ _write_mem(pintfhdl, addr, cnt, pmem); ++ ++ ++} ++ ++void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ ++ ++ ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) ++ return; ++ ++ _read_port = pintfhdl->io_ops._read_port; ++ ++ _read_port(pintfhdl, addr, cnt, pmem); ++ ++ ++} ++ ++void _rtw_read_port_cancel(struct adapter *adapter) ++{ ++ void (*_read_port_cancel)(struct intf_hdl *pintfhdl); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ ++ _read_port_cancel = pintfhdl->io_ops._read_port_cancel; ++ ++ if (_read_port_cancel) ++ _read_port_cancel(pintfhdl); ++} ++ ++u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem) ++{ ++ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ u32 ret = _SUCCESS; ++ ++ ++ ++ _write_port = pintfhdl->io_ops._write_port; ++ ++ ret = _write_port(pintfhdl, addr, cnt, pmem); ++ ++ ++ ++ return ret; ++} ++ ++u32 _rtw_write_port_and_wait(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem, int timeout_ms) ++{ ++ int ret = _SUCCESS; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pmem; ++ struct submit_ctx sctx; ++ ++ rtw_sctx_init(&sctx, timeout_ms); ++ pxmitbuf->sctx = &sctx; ++ ++ ret = _rtw_write_port(adapter, addr, cnt, pmem); ++ ++ if (ret == _SUCCESS) ++ ret = rtw_sctx_wait(&sctx); ++ ++ return ret; ++} ++ ++void _rtw_write_port_cancel(struct adapter *adapter) ++{ ++ void (*_write_port_cancel)(struct intf_hdl *pintfhdl); ++ struct io_priv *pio_priv = &adapter->iopriv; ++ struct intf_hdl *pintfhdl = &pio_priv->intf; ++ ++ _write_port_cancel = pintfhdl->io_ops._write_port_cancel; ++ ++ if (_write_port_cancel) ++ _write_port_cancel(pintfhdl); ++} ++ ++int rtw_init_io_priv(struct adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops)) ++{ ++ struct io_priv *piopriv = &padapter->iopriv; ++ struct intf_hdl *pintf = &piopriv->intf; ++ ++ if (!set_intf_ops) ++ return _FAIL; ++ ++ piopriv->padapter = padapter; ++ pintf->padapter = padapter; ++ pintf->pintf_dev = adapter_to_dvobj(padapter); ++ ++ set_intf_ops(&pintf->io_ops); ++ ++ return _SUCCESS; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_ioctl_set.c b/drivers/staging/r8188eu/core/rtw_ioctl_set.c +new file mode 100644 +index 000000000000..c187de78b4ac +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_ioctl_set.c +@@ -0,0 +1,891 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_IOCTL_SET_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtw_ioctl_set.h" ++#include "../include/hal_intf.h" ++ ++#include "../include/usb_osintf.h" ++#include "../include/usb_ops.h" ++ ++extern void indicate_wx_scan_complete_event(struct adapter *padapter); ++ ++u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid) ++{ ++ u8 i; ++ u8 ret = true; ++ ++ if (ssid->SsidLength > 32) { ++ ret = false; ++ goto exit; ++ } ++ ++ for (i = 0; i < ssid->SsidLength; i++) { ++ /* wifi, printable ascii code must be supported */ ++ if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) { ++ ret = false; ++ break; ++ } ++ } ++ ++exit: ++ ++ return ret; ++} ++ ++u8 rtw_do_join(struct adapter *padapter) ++{ ++ struct list_head *plist, *phead; ++ u8 *pibss = NULL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ u8 ret = _SUCCESS; ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ pmlmepriv->cur_network.join_res = -2; ++ ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ++ pmlmepriv->pscanned = plist; ++ ++ pmlmepriv->to_join = true; ++ ++ if (list_empty(&queue->queue)) { ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ /* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */ ++ /* we try to issue sitesurvey firstly */ ++ ++ if (!pmlmepriv->LinkDetectInfo.bBusyTraffic || ++ pmlmepriv->to_roaming > 0) { ++ /* submit site_survey_cmd */ ++ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); ++ if (_SUCCESS != ret) ++ pmlmepriv->to_join = false; ++ } else { ++ pmlmepriv->to_join = false; ++ ret = _FAIL; ++ } ++ ++ goto exit; ++ } else { ++ int select_ret; ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv); ++ if (select_ret == _SUCCESS) { ++ pmlmepriv->to_join = false; ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ } else { ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { ++ /* submit createbss_cmd to change to a ADHOC_MASTER */ ++ ++ /* pmlmepriv->lock has been acquired by caller... */ ++ struct wlan_bssid_ex *pdev_network = &padapter->registrypriv.dev_network; ++ ++ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; ++ ++ pibss = padapter->registrypriv.dev_network.MacAddress; ++ ++ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ rtw_update_registrypriv_dev_network(padapter); ++ ++ rtw_generate_random_ibss(pibss); ++ ++ if (rtw_createbss_cmd(padapter) != _SUCCESS) { ++ ret = false; ++ goto exit; ++ } ++ pmlmepriv->to_join = false; ++ } else { ++ /* can't associate ; reset under-linking */ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++ /* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */ ++ /* we try to issue sitesurvey firstly */ ++ if (!pmlmepriv->LinkDetectInfo.bBusyTraffic || ++ pmlmepriv->to_roaming > 0) { ++ ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); ++ if (_SUCCESS != ret) ++ pmlmepriv->to_join = false; ++ } else { ++ ret = _FAIL; ++ pmlmepriv->to_join = false; ++ } ++ } ++ } ++ } ++ ++exit: ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid) ++{ ++ u8 status = _SUCCESS; ++ u32 cur_time = 0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ DBG_88E_LEVEL(_drv_info_, "set bssid:%pM\n", bssid); ++ ++ if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 && ++ bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) || ++ (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF && ++ bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) { ++ status = _FAIL; ++ goto exit; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ DBG_88E("Set BSSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ goto handle_tkip_countermeasure; ++ else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ goto release_mlme_lock; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) { ++ if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN)) { ++ if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ ++ } else { ++ rtw_disassoc_cmd(padapter, 0, true); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } ++ } ++ ++handle_tkip_countermeasure: ++ /* should we add something here...? */ ++ ++ if (padapter->securitypriv.btkip_countermeasure) { ++ cur_time = jiffies; ++ ++ if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) { ++ padapter->securitypriv.btkip_countermeasure = false; ++ padapter->securitypriv.btkip_countermeasure_time = 0; ++ } else { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ } ++ ++ memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); ++ pmlmepriv->assoc_by_bssid = true; ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ pmlmepriv->to_join = true; ++ else ++ status = rtw_do_join(padapter); ++ ++release_mlme_lock: ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++exit: ++ return status; ++} ++ ++u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) ++{ ++ u8 status = _SUCCESS; ++ u32 cur_time = 0; ++ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *pnetwork = &pmlmepriv->cur_network; ++ ++ DBG_88E_LEVEL(_drv_info_, "set ssid [%s] fw_state=0x%08x\n", ++ ssid->Ssid, get_fwstate(pmlmepriv)); ++ ++ if (!padapter->hw_init_completed) { ++ status = _FAIL; ++ goto exit; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ DBG_88E("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv)); ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { ++ goto handle_tkip_countermeasure; ++ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { ++ goto release_mlme_lock; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) { ++ if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && ++ (!memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength))) { ++ if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ if (!rtw_is_same_ibss(padapter, pnetwork)) { ++ /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */ ++ rtw_disassoc_cmd(padapter, 0, true); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } else { ++ goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ ++ } ++ } else { ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1); ++ } ++ } else { ++ rtw_disassoc_cmd(padapter, 0, true); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_indicate_disconnect(padapter); ++ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ } ++ } ++ ++handle_tkip_countermeasure: ++ ++ if (padapter->securitypriv.btkip_countermeasure) { ++ cur_time = jiffies; ++ ++ if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ) { ++ padapter->securitypriv.btkip_countermeasure = false; ++ padapter->securitypriv.btkip_countermeasure_time = 0; ++ } else { ++ status = _FAIL; ++ goto release_mlme_lock; ++ } ++ } ++ ++ memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct ndis_802_11_ssid)); ++ pmlmepriv->assoc_by_bssid = false; ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { ++ pmlmepriv->to_join = true; ++ } else { ++ status = rtw_do_join(padapter); ++ } ++ ++release_mlme_lock: ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++exit: ++ return status; ++} ++ ++u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, ++ enum ndis_802_11_network_infra networktype) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ enum ndis_802_11_network_infra *pold_state = &cur_network->network.InfrastructureMode; ++ ++ if (*pold_state != networktype) { ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ /* DBG_88E("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */ ++ ++ if (*pold_state == Ndis802_11APMode) { ++ /* change to other mode from Ndis802_11APMode */ ++ cur_network->join_res = -1; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ stop_ap_mode(padapter); ++#endif ++ } ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED)) || ++ (*pold_state == Ndis802_11IBSS)) ++ rtw_disassoc_cmd(padapter, 0, true); ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED)) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) ++ rtw_free_assoc_resources(padapter, 1); ++ ++ if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) { ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */ ++ } ++ ++ *pold_state = networktype; ++ ++ _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE); ++ ++ switch (networktype) { ++ case Ndis802_11IBSS: ++ set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); ++ break; ++ case Ndis802_11Infrastructure: ++ set_fwstate(pmlmepriv, WIFI_STATION_STATE); ++ break; ++ case Ndis802_11APMode: ++ set_fwstate(pmlmepriv, WIFI_AP_STATE); ++#ifdef CONFIG_88EU_AP_MODE ++ start_ap_mode(padapter); ++#endif ++ break; ++ case Ndis802_11AutoUnknown: ++ case Ndis802_11InfrastructureMax: ++ break; ++ } ++ spin_unlock_bh(&pmlmepriv->lock); ++ } ++ ++ return true; ++} ++ ++u8 rtw_set_802_11_disassociate(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ rtw_disassoc_cmd(padapter, 0, true); ++ rtw_indicate_disconnect(padapter); ++ rtw_free_assoc_resources(padapter, 1); ++ rtw_pwr_wakeup(padapter); ++ } ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ return true; ++} ++ ++u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int ssid_max_num) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 res = true; ++ ++ if (!padapter) { ++ res = false; ++ goto exit; ++ } ++ if (!padapter->hw_init_completed) { ++ res = false; ++ goto exit; ++ } ++ ++ if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) || ++ (pmlmepriv->LinkDetectInfo.bBusyTraffic)) { ++ /* Scan or linking is in progress, do nothing. */ ++ res = true; ++ } else { ++ if (rtw_is_scan_deny(padapter)) { ++ DBG_88E(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter)); ++ indicate_wx_scan_complete_event(padapter); ++ return _SUCCESS; ++ } ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0); ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ } ++exit: ++ ++ return res; ++} ++ ++u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11_auth_mode authmode) ++{ ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ int res; ++ u8 ret; ++ ++ psecuritypriv->ndisauthtype = authmode; ++ ++ if (psecuritypriv->ndisauthtype > 3) ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ ++ res = rtw_set_auth(padapter, psecuritypriv); ++ ++ if (res == _SUCCESS) ++ ret = true; ++ else ++ ret = false; ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep) ++{ ++ int keyid, res; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u8 ret = _SUCCESS; ++ ++ keyid = wep->KeyIndex & 0x3fffffff; ++ ++ if (keyid >= 4) { ++ ret = false; ++ goto exit; ++ } ++ ++ switch (wep->KeyLength) { ++ case 5: ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; ++ break; ++ case 13: ++ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; ++ break; ++ default: ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ break; ++ } ++ ++ memcpy(&psecuritypriv->dot11DefKey[keyid].skey[0], &wep->KeyMaterial, wep->KeyLength); ++ ++ psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength; ++ ++ psecuritypriv->dot11PrivacyKeyIndex = keyid; ++ ++ res = rtw_set_key(padapter, psecuritypriv, keyid, 1); ++ ++ if (res == _FAIL) ++ ret = false; ++exit: ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_remove_wep(struct adapter *padapter, u32 keyindex) ++{ ++ u8 ret = _SUCCESS; ++ ++ if (keyindex >= 0x80000000 || !padapter) { ++ ret = false; ++ goto exit; ++ } else { ++ int res; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ if (keyindex < 4) { ++ memset(&psecuritypriv->dot11DefKey[keyindex], 0, 16); ++ res = rtw_set_key(padapter, psecuritypriv, keyindex, 0); ++ psecuritypriv->dot11DefKeylen[keyindex] = 0; ++ if (res == _FAIL) ++ ret = _FAIL; ++ } else { ++ ret = _FAIL; ++ } ++ } ++exit: ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_add_key(struct adapter *padapter, struct ndis_802_11_key *key) ++{ ++ uint encryptionalgo; ++ u8 *pbssid; ++ struct sta_info *stainfo; ++ u8 bgroup = false; ++ u8 bgrouptkey = false;/* can be removed later */ ++ u8 ret = _SUCCESS; ++ ++ if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)) { ++ /* It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, */ ++ /* it must fail the request and return NDIS_STATUS_INVALID_DATA. */ ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if (key->KeyIndex & 0x40000000) { ++ /* Pairwise key */ ++ ++ pbssid = get_bssid(&padapter->mlmepriv); ++ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid); ++ ++ if (stainfo && padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ++ encryptionalgo = stainfo->dot118021XPrivacy; ++ else ++ encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm; ++ ++ if (key->KeyIndex & 0x000000FF) { ++ /* The key index is specified in the lower 8 bits by values of zero to 255. */ ++ /* The key index should be set to zero for a Pairwise key, and the driver should fail with */ ++ /* NDIS_STATUS_INVALID_DATA if the lower 8 bits is not zero */ ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* check BSSID */ ++ if (is_broadcast_ether_addr(key->BSSID)) { ++ ret = false; ++ goto exit; ++ } ++ ++ /* Check key length for TKIP. */ ++ if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* Check key length for AES. */ ++ if ((encryptionalgo == _AES_) && (key->KeyLength != 16)) { ++ /* For our supplicant, EAPPkt9x.vxd, cannot differentiate TKIP and AES case. */ ++ if (key->KeyLength == 32) { ++ key->KeyLength = 16; ++ } else { ++ ret = _FAIL; ++ goto exit; ++ } ++ } ++ ++ /* Check key length for WEP. For NDTEST, 2005.01.27, by rcnjko. */ ++ if ((encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_) && ++ (key->KeyLength != 5 && key->KeyLength != 13)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ bgroup = false; ++ } else { ++ /* Group key - KeyIndex(BIT(30) == 0) */ ++ /* when add wep key through add key and didn't assigned encryption type before */ ++ if ((padapter->securitypriv.ndisauthtype <= 3) && ++ (padapter->securitypriv.dot118021XGrpPrivacy == 0)) { ++ switch (key->KeyLength) { ++ case 5: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ break; ++ case 13: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ break; ++ default: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ break; ++ } ++ ++ encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } else { ++ encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy; ++ } ++ ++ if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) && !is_broadcast_ether_addr(key->BSSID)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* Check key length for TKIP */ ++ if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) { ++ ret = _FAIL; ++ goto exit; ++ } else if (encryptionalgo == _AES_ && (key->KeyLength != 16 && key->KeyLength != 32)) { ++ /* Check key length for AES */ ++ /* For NDTEST, we allow keylen = 32 in this case. 2005.01.27, by rcnjko. */ ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* Change the key length for EAPPkt9x.vxd. Added by Annie, 2005-11-03. */ ++ if ((encryptionalgo == _AES_) && (key->KeyLength == 32)) ++ key->KeyLength = 16; ++ ++ if (key->KeyIndex & 0x8000000) {/* error ??? 0x8000_0000 */ ++ bgrouptkey = true; ++ } ++ ++ if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE)) && ++ (check_fwstate(&padapter->mlmepriv, _FW_LINKED))) ++ bgrouptkey = true; ++ bgroup = true; ++ } ++ ++ /* If WEP encryption algorithm, just call rtw_set_802_11_add_wep(). */ ++ if ((padapter->securitypriv.dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) && ++ (encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_)) { ++ u32 keyindex; ++ u32 len = FIELD_OFFSET(struct ndis_802_11_key, KeyMaterial) + key->KeyLength; ++ struct ndis_802_11_wep *wep = &padapter->securitypriv.ndiswep; ++ ++ wep->Length = len; ++ keyindex = key->KeyIndex & 0x7fffffff; ++ wep->KeyIndex = keyindex; ++ wep->KeyLength = key->KeyLength; ++ ++ memcpy(wep->KeyMaterial, key->KeyMaterial, key->KeyLength); ++ memcpy(&padapter->securitypriv.dot11DefKey[keyindex].skey[0], key->KeyMaterial, key->KeyLength); ++ ++ padapter->securitypriv.dot11DefKeylen[keyindex] = key->KeyLength; ++ padapter->securitypriv.dot11PrivacyKeyIndex = keyindex; ++ ++ ret = rtw_set_802_11_add_wep(padapter, wep); ++ goto exit; ++ } ++ if (key->KeyIndex & 0x20000000) { ++ /* SetRSC */ ++ if (bgroup) { ++ unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL; ++ memcpy(&padapter->securitypriv.dot11Grprxpn, &keysrc, 8); ++ } else { ++ unsigned long long keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL; ++ memcpy(&padapter->securitypriv.dot11Grptxpn, &keysrc, 8); ++ } ++ } ++ ++ /* Indicate this key idx is used for TX */ ++ /* Save the key in KeyMaterial */ ++ if (bgroup) { /* Group transmit key */ ++ int res; ++ ++ if (bgrouptkey) ++ padapter->securitypriv.dot118021XGrpKeyid = (u8)key->KeyIndex; ++ if ((key->KeyIndex & 0x3) == 0) { ++ ret = _FAIL; ++ goto exit; ++ } ++ memset(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], 0, 16); ++ memset(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16); ++ memset(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16); ++ ++ if ((key->KeyIndex & 0x10000000)) { ++ memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8); ++ memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8); ++ } else { ++ memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8); ++ memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8); ++ } ++ ++ /* set group key by index */ ++ memcpy(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial, key->KeyLength); ++ ++ key->KeyIndex = key->KeyIndex & 0x03; ++ ++ padapter->securitypriv.binstallGrpkey = true; ++ ++ padapter->securitypriv.bcheck_grpkey = false; ++ ++ res = rtw_set_key(padapter, &padapter->securitypriv, key->KeyIndex, 1); ++ ++ if (res == _FAIL) ++ ret = _FAIL; ++ ++ goto exit; ++ ++ } else { /* Pairwise Key */ ++ u8 res; ++ ++ pbssid = get_bssid(&padapter->mlmepriv); ++ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid); ++ ++ if (stainfo) { ++ memset(&stainfo->dot118021x_UncstKey, 0, 16);/* clear keybuffer */ ++ ++ memcpy(&stainfo->dot118021x_UncstKey, key->KeyMaterial, 16); ++ ++ if (encryptionalgo == _TKIP_) { ++ padapter->securitypriv.busetkipkey = false; ++ ++ /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */ ++ ++ /* if TKIP, save the Receive/Transmit MIC key in KeyMaterial[128-255] */ ++ if ((key->KeyIndex & 0x10000000)) { ++ memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 16, 8); ++ memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 24, 8); ++ ++ } else { ++ memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 24, 8); ++ memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 16, 8); ++ } ++ } ++ ++ /* Set key to CAM through H2C command */ ++ if (bgrouptkey) /* never go to here */ ++ res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, false); ++ else ++ res = rtw_setstakey_cmd(padapter, (unsigned char *)stainfo, true); ++ if (!res) ++ ret = _FAIL; ++ } ++ } ++exit: ++ ++ return ret; ++} ++ ++u8 rtw_set_802_11_remove_key(struct adapter *padapter, struct ndis_802_11_remove_key *key) ++{ ++ u8 *pbssid; ++ struct sta_info *stainfo; ++ u8 bgroup = (key->KeyIndex & 0x4000000) > 0 ? false : true; ++ u8 keyIndex = (u8)key->KeyIndex & 0x03; ++ u8 ret = _SUCCESS; ++ ++ if ((key->KeyIndex & 0xbffffffc) > 0) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if (bgroup) { ++ /* clear group key by index */ ++ ++ memset(&padapter->securitypriv.dot118021XGrpKey[keyIndex], 0, 16); ++ ++ /* \todo Send a H2C Command to Firmware for removing this Key in CAM Entry. */ ++ } else { ++ pbssid = get_bssid(&padapter->mlmepriv); ++ stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid); ++ if (stainfo) { ++ /* clear key by BSSID */ ++ memset(&stainfo->dot118021x_UncstKey, 0, 16); ++ ++ /* \todo Send a H2C Command to Firmware for disable this Key in CAM Entry. */ ++ } else { ++ ret = _FAIL; ++ goto exit; ++ } ++ } ++exit: ++ ++ return ret; ++} ++ ++/* ++* rtw_get_cur_max_rate - ++* @adapter: pointer to struct adapter structure ++* ++* Return 0 or 100Kbps ++*/ ++u16 rtw_get_cur_max_rate(struct adapter *adapter) ++{ ++ int i = 0; ++ u8 *p; ++ u16 rate = 0, max_rate = 0; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct registry_priv *pregistrypriv = &adapter->registrypriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ struct ieee80211_ht_cap *pht_capie; ++ u8 rf_type = 0; ++ u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0; ++ u16 mcs_rate = 0; ++ u32 ht_ielen = 0; ++ ++ if (adapter->registrypriv.mp_mode == 1) { ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) ++ return 0; ++ } ++ ++ if ((!check_fwstate(pmlmepriv, _FW_LINKED)) && ++ (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) ++ return 0; ++ ++ if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N)) { ++ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength - 12); ++ if (p && ht_ielen > 0) { ++ pht_capie = (struct ieee80211_ht_cap *)(p + 2); ++ ++ memcpy(&mcs_rate, pht_capie->mcs.rx_mask, 2); ++ ++ /* cur_bwmod is updated by beacon, pmlmeinfo is updated by association response */ ++ bw_40MHz = (pmlmeext->cur_bwmode && (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH & pmlmeinfo->HT_info.infos[0])) ? 1 : 0; ++ ++ short_GI_20 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_20) ? 1 : 0; ++ short_GI_40 = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & IEEE80211_HT_CAP_SGI_40) ? 1 : 0; ++ ++ rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ max_rate = rtw_mcs_rate( ++ rf_type, ++ bw_40MHz & (pregistrypriv->cbw40_enable), ++ short_GI_20, ++ short_GI_40, ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate ++ ); ++ } ++ } else { ++ while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) { ++ rate = pcur_bss->SupportedRates[i] & 0x7F; ++ if (rate > max_rate) ++ max_rate = rate; ++ i++; ++ } ++ ++ max_rate *= 5; ++ } ++ ++ return max_rate; ++} ++ ++/* ++* rtw_set_scan_mode - ++* @adapter: pointer to struct adapter structure ++* @scan_mode: ++* ++* Return _SUCCESS or _FAIL ++*/ ++int rtw_set_scan_mode(struct adapter *adapter, enum rt_scan_type scan_mode) ++{ ++ if (scan_mode != SCAN_ACTIVE && scan_mode != SCAN_PASSIVE) ++ return _FAIL; ++ ++ adapter->mlmepriv.scan_mode = scan_mode; ++ ++ return _SUCCESS; ++} ++ ++/* ++* rtw_set_channel_plan - ++* @adapter: pointer to struct adapter structure ++* @channel_plan: ++* ++* Return _SUCCESS or _FAIL ++*/ ++int rtw_set_channel_plan(struct adapter *adapter, u8 channel_plan) ++{ ++ /* handle by cmd_thread to sync with scan operation */ ++ return rtw_set_chplan_cmd(adapter, channel_plan, 1); ++} ++ ++/* ++* rtw_set_country - ++* @adapter: pointer to struct adapter structure ++* @country_code: string of country code ++* ++* Return _SUCCESS or _FAIL ++*/ ++int rtw_set_country(struct adapter *adapter, const char *country_code) ++{ ++ int channel_plan = RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G; ++ ++ DBG_88E("%s country_code:%s\n", __func__, country_code); ++ ++ /* TODO: should have a table to match country code and RT_CHANNEL_DOMAIN */ ++ /* TODO: should consider 2-character and 3-character country code */ ++ if (0 == strcmp(country_code, "US")) ++ channel_plan = RT_CHANNEL_DOMAIN_FCC; ++ else if (0 == strcmp(country_code, "EU")) ++ channel_plan = RT_CHANNEL_DOMAIN_ETSI; ++ else if (0 == strcmp(country_code, "JP")) ++ channel_plan = RT_CHANNEL_DOMAIN_MKK; ++ else if (0 == strcmp(country_code, "CN")) ++ channel_plan = RT_CHANNEL_DOMAIN_CHINA; ++ else ++ DBG_88E("%s unknown country_code:%s\n", __func__, country_code); ++ ++ return rtw_set_channel_plan(adapter, channel_plan); ++} +diff --git a/drivers/staging/r8188eu/core/rtw_iol.c b/drivers/staging/r8188eu/core/rtw_iol.c +new file mode 100644 +index 000000000000..5c1b19679cad +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_iol.c +@@ -0,0 +1,192 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/rtw_iol.h" ++ ++struct xmit_frame *rtw_IOL_accquire_xmit_frame(struct adapter *adapter) ++{ ++ struct xmit_frame *xmit_frame; ++ struct xmit_buf *xmitbuf; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv = &adapter->xmitpriv; ++ ++ xmit_frame = rtw_alloc_xmitframe(pxmitpriv); ++ if (!xmit_frame) { ++ DBG_88E("%s rtw_alloc_xmitframe return null\n", __func__); ++ goto exit; ++ } ++ ++ xmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (!xmitbuf) { ++ DBG_88E("%s rtw_alloc_xmitbuf return null\n", __func__); ++ rtw_free_xmitframe(pxmitpriv, xmit_frame); ++ xmit_frame = NULL; ++ goto exit; ++ } ++ ++ xmit_frame->frame_tag = MGNT_FRAMETAG; ++ xmit_frame->pxmitbuf = xmitbuf; ++ xmit_frame->buf_addr = xmitbuf->pbuf; ++ xmitbuf->priv_data = xmit_frame; ++ ++ pattrib = &xmit_frame->attrib; ++ update_mgntframe_attrib(adapter, pattrib); ++ pattrib->qsel = 0x10;/* Beacon */ ++ pattrib->subtype = WIFI_BEACON; ++ pattrib->pktlen = 0; ++ pattrib->last_txcmdsz = 0; ++exit: ++ return xmit_frame; ++} ++ ++int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, u32 cmd_len) ++{ ++ struct pkt_attrib *pattrib = &xmit_frame->attrib; ++ u16 buf_offset; ++ u32 ori_len; ++ ++ buf_offset = TXDESC_OFFSET; ++ ori_len = buf_offset + pattrib->pktlen; ++ ++ /* check if the io_buf can accommodate new cmds */ ++ if (ori_len + cmd_len + 8 > MAX_XMITBUF_SZ) { ++ DBG_88E("%s %u is large than MAX_XMITBUF_SZ:%u, can't accommodate new cmds\n", ++ __func__, ori_len + cmd_len + 8, MAX_XMITBUF_SZ); ++ return _FAIL; ++ } ++ ++ memcpy(xmit_frame->buf_addr + buf_offset + pattrib->pktlen, IOL_cmds, cmd_len); ++ pattrib->pktlen += cmd_len; ++ pattrib->last_txcmdsz += cmd_len; ++ ++ return _SUCCESS; ++} ++ ++bool rtw_IOL_applied(struct adapter *adapter) ++{ ++ if (1 == adapter->registrypriv.fw_iol) ++ return true; ++ ++ if ((2 == adapter->registrypriv.fw_iol) && (!adapter_to_dvobj(adapter)->ishighspeed)) ++ return true; ++ return false; ++} ++ ++int rtw_IOL_exec_cmds_sync(struct adapter *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt) ++{ ++ return rtw_hal_iol_cmd(adapter, xmit_frame, max_wating_ms, bndy_cnt); ++} ++ ++int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary) ++{ ++ return _SUCCESS; ++} ++ ++int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask) ++{ ++ struct ioreg_cfg cmd = {8, IOREG_CMD_WB_REG, 0x0, 0x0, 0x0}; ++ ++ cmd.address = cpu_to_le16(addr); ++ cmd.data = cpu_to_le32(value); ++ ++ if (mask != 0xFF) { ++ cmd.length = 12; ++ cmd.mask = cpu_to_le32(mask); ++ } ++ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); ++} ++ ++int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask) ++{ ++ struct ioreg_cfg cmd = {8, IOREG_CMD_WW_REG, 0x0, 0x0, 0x0}; ++ ++ cmd.address = cpu_to_le16(addr); ++ cmd.data = cpu_to_le32(value); ++ ++ if (mask != 0xFFFF) { ++ cmd.length = 12; ++ cmd.mask = cpu_to_le32(mask); ++ } ++ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); ++} ++ ++int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask) ++{ ++ struct ioreg_cfg cmd = {8, IOREG_CMD_WD_REG, 0x0, 0x0, 0x0}; ++ ++ cmd.address = cpu_to_le16(addr); ++ cmd.data = cpu_to_le32(value); ++ ++ if (mask != 0xFFFFFFFF) { ++ cmd.length = 12; ++ cmd.mask = cpu_to_le32(mask); ++ } ++ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); ++} ++ ++int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask) ++{ ++ struct ioreg_cfg cmd = {8, IOREG_CMD_W_RF, 0x0, 0x0, 0x0}; ++ ++ cmd.address = cpu_to_le16((rf_path << 8) | ((addr) & 0xFF)); ++ cmd.data = cpu_to_le32(value); ++ ++ if (mask != 0x000FFFFF) { ++ cmd.length = 12; ++ cmd.mask = cpu_to_le32(mask); ++ } ++ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); ++} ++ ++int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us) ++{ ++ struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0}; ++ cmd.address = cpu_to_le16(us); ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); ++} ++ ++int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms) ++{ ++ struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0}; ++ ++ cmd.address = cpu_to_le16(ms); ++ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); ++} ++ ++int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame) ++{ ++ struct ioreg_cfg cmd = {4, IOREG_CMD_END, cpu_to_le16(0xFFFF), cpu_to_le32(0xFF), 0x0}; ++ ++ return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); ++} ++ ++u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame) ++{ ++ u8 is_cmd_bndy = false; ++ if (((pxmit_frame->attrib.pktlen + 32) % 256) + 8 >= 256) { ++ rtw_IOL_append_END_cmd(pxmit_frame); ++ pxmit_frame->attrib.pktlen = ((((pxmit_frame->attrib.pktlen + 32) / 256) + 1) * 256); ++ ++ pxmit_frame->attrib.last_txcmdsz = pxmit_frame->attrib.pktlen; ++ is_cmd_bndy = true; ++ } ++ return is_cmd_bndy; ++} ++ ++void rtw_IOL_cmd_buf_dump(struct adapter *Adapter, int buf_len, u8 *pbuf) ++{ ++ int i; ++ int j = 1; ++ ++ pr_info("###### %s ######\n", __func__); ++ for (i = 0; i < buf_len; i++) { ++ printk("%02x-", *(pbuf + i)); ++ ++ if (j % 32 == 0) ++ printk("\n"); ++ j++; ++ } ++ printk("\n"); ++ pr_info("=============ioreg_cmd len=%d===============\n", buf_len); ++} +diff --git a/drivers/staging/r8188eu/core/rtw_led.c b/drivers/staging/r8188eu/core/rtw_led.c +new file mode 100644 +index 000000000000..b33e34cce12e +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_led.c +@@ -0,0 +1,1612 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#include "../include/drv_types.h" ++#include "../include/rtw_led.h" ++ ++/* */ ++/* Description: */ ++/* Callback function of LED BlinkTimer, */ ++/* it just schedules to corresponding BlinkWorkItem/led_blink_hdl */ ++/* */ ++void BlinkTimerCallback(struct timer_list *t) ++{ ++ struct LED_871x *pLed = from_timer(pLed, t, BlinkTimer); ++ struct adapter *padapter = pLed->padapter; ++ ++ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped)) ++ return; ++ ++ _set_workitem(&pLed->BlinkWorkItem); ++} ++ ++/* */ ++/* Description: */ ++/* Callback function of LED BlinkWorkItem. */ ++/* We dispatch acture LED blink action according to LedStrategy. */ ++/* */ ++void BlinkWorkItemCallback(struct work_struct *work) ++{ ++ struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem); ++ BlinkHandler(pLed); ++} ++ ++/* */ ++/* Description: */ ++/* Reset status of LED_871x object. */ ++/* */ ++void ResetLedStatus(struct LED_871x *pLed) ++{ ++ pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */ ++ pLed->bLedOn = false; /* true if LED is ON, false if LED is OFF. */ ++ ++ pLed->bLedBlinkInProgress = false; /* true if it is blinking, false o.w.. */ ++ pLed->bLedWPSBlinkInProgress = false; ++ ++ pLed->BlinkTimes = 0; /* Number of times to toggle led state for blinking. */ ++ pLed->BlinkingLedState = LED_UNKNOWN; /* Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */ ++ ++ pLed->bLedNoLinkBlinkInProgress = false; ++ pLed->bLedLinkBlinkInProgress = false; ++ pLed->bLedStartToLinkBlinkInProgress = false; ++ pLed->bLedScanBlinkInProgress = false; ++} ++ ++/*Description: */ ++/* Initialize an LED_871x object. */ ++void InitLed871x(struct adapter *padapter, struct LED_871x *pLed, enum LED_PIN_871x LedPin) ++{ ++ pLed->padapter = padapter; ++ pLed->LedPin = LedPin; ++ ++ ResetLedStatus(pLed); ++ ++ timer_setup(&pLed->BlinkTimer, BlinkTimerCallback, 0); ++ _init_workitem(&pLed->BlinkWorkItem, BlinkWorkItemCallback, pLed); ++} ++ ++/* */ ++/* Description: */ ++/* DeInitialize an LED_871x object. */ ++/* */ ++void DeInitLed871x(struct LED_871x *pLed) ++{ ++ _cancel_workitem_sync(&pLed->BlinkWorkItem); ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ ResetLedStatus(pLed); ++} ++ ++/* */ ++/* Description: */ ++/* Implementation of LED blinking behavior. */ ++/* It toggle off LED and schedule corresponding timer if necessary. */ ++/* */ ++ ++static void SwLedBlink(struct LED_871x *pLed) ++{ ++ struct adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 bStopBlinking = false; ++ ++ /* Change LED according to BlinkingLedState specified. */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) ++ SwLedOn(padapter, pLed); ++ else ++ SwLedOff(padapter, pLed); ++ ++ /* Determine if we shall change LED state again. */ ++ pLed->BlinkTimes--; ++ switch (pLed->CurrLedState) { ++ case LED_BLINK_NORMAL: ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ break; ++ case LED_BLINK_StartToBlink: ++ if (check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ bStopBlinking = true; ++ if (check_fwstate(pmlmepriv, _FW_LINKED) && ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) ++ bStopBlinking = true; ++ else if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ break; ++ case LED_BLINK_WPS: ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ break; ++ default: ++ bStopBlinking = true; ++ break; ++ } ++ ++ if (bStopBlinking) { ++ if (check_fwstate(pmlmepriv, _FW_LINKED) && !pLed->bLedOn) { ++ SwLedOn(padapter, pLed); ++ } else if (check_fwstate(pmlmepriv, _FW_LINKED) && pLed->bLedOn) { ++ SwLedOff(padapter, pLed); ++ } ++ pLed->BlinkTimes = 0; ++ pLed->bLedBlinkInProgress = false; ++ } else { ++ /* Assign LED state to toggle. */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ /* Schedule a timer to toggle LED state. */ ++ switch (pLed->CurrLedState) { ++ case LED_BLINK_NORMAL: ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ break; ++ case LED_BLINK_SLOWLY: ++ case LED_BLINK_StartToBlink: ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ case LED_BLINK_WPS: ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_LONG_INTERVAL); ++ break; ++ default: ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SLOWLY_INTERVAL); ++ break; ++ } ++ } ++} ++ ++static void SwLedBlink1(struct LED_871x *pLed) ++{ ++ struct adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 bStopBlinking = false; ++ ++ /* Change LED according to BlinkingLedState specified. */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) ++ SwLedOn(padapter, pLed); ++ else ++ SwLedOff(padapter, pLed); ++ ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ ResetLedStatus(pLed); ++ return; ++ } ++ ++ switch (pLed->CurrLedState) { ++ case LED_BLINK_SLOWLY: ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ break; ++ case LED_BLINK_NORMAL: ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_LINK_INTERVAL_ALPHA); ++ break; ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ if (bStopBlinking) { ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->bLedLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_LINK_INTERVAL_ALPHA); ++ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ pLed->bLedScanBlinkInProgress = false; ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ if (bStopBlinking) { ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->bLedLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_LINK_INTERVAL_ALPHA); ++ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ pLed->BlinkTimes = 0; ++ pLed->bLedBlinkInProgress = false; ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_BLINK_WPS: ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ break; ++ case LED_BLINK_WPS_STOP: /* WPS success */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) ++ bStopBlinking = false; ++ else ++ bStopBlinking = true; ++ ++ if (bStopBlinking) { ++ pLed->bLedLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_LINK_INTERVAL_ALPHA); ++ ++ pLed->bLedWPSBlinkInProgress = false; ++ } else { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void SwLedBlink2(struct LED_871x *pLed) ++{ ++ struct adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 bStopBlinking = false; ++ ++ /* Change LED according to BlinkingLedState specified. */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) ++ SwLedOn(padapter, pLed); ++ else ++ SwLedOff(padapter, pLed); ++ ++ switch (pLed->CurrLedState) { ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ SwLedOn(padapter, pLed); ++ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ SwLedOff(padapter, pLed); ++ } ++ pLed->bLedScanBlinkInProgress = false; ++ } else { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ SwLedOn(padapter, pLed); ++ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ SwLedOff(padapter, pLed); ++ } ++ pLed->bLedBlinkInProgress = false; ++ } else { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void SwLedBlink3(struct LED_871x *pLed) ++{ ++ struct adapter *padapter = pLed->padapter; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 bStopBlinking = false; ++ ++ /* Change LED according to BlinkingLedState specified. */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) { ++ SwLedOn(padapter, pLed); ++ } else { ++ if (pLed->CurrLedState != LED_BLINK_WPS_STOP) ++ SwLedOff(padapter, pLed); ++ } ++ ++ switch (pLed->CurrLedState) { ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if (!pLed->bLedOn) ++ SwLedOn(padapter, pLed); ++ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if (pLed->bLedOn) ++ SwLedOff(padapter, pLed); ++ } ++ pLed->bLedScanBlinkInProgress = false; ++ } else { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if (!pLed->bLedOn) ++ SwLedOn(padapter, pLed); ++ } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ ++ if (pLed->bLedOn) ++ SwLedOff(padapter, pLed); ++ } ++ pLed->bLedBlinkInProgress = false; ++ } else { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ case LED_BLINK_WPS: ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ break; ++ case LED_BLINK_WPS_STOP: /* WPS success */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); ++ bStopBlinking = false; ++ } else { ++ bStopBlinking = true; ++ } ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ SwLedOn(padapter, pLed); ++ } ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void SwLedBlink4(struct LED_871x *pLed) ++{ ++ struct adapter *padapter = pLed->padapter; ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ struct LED_871x *pLed1 = &ledpriv->SwLed1; ++ u8 bStopBlinking = false; ++ ++ /* Change LED according to BlinkingLedState specified. */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) ++ SwLedOn(padapter, pLed); ++ else ++ SwLedOff(padapter, pLed); ++ ++ if (!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN) { ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ pLed1->CurrLedState = RTW_LED_OFF; ++ SwLedOff(padapter, pLed1); ++ } ++ ++ switch (pLed->CurrLedState) { ++ case LED_BLINK_SLOWLY: ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ break; ++ case LED_BLINK_StartToBlink: ++ if (pLed->bLedOn) { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SLOWLY_INTERVAL); ++ } else { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = false; ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { ++ SwLedOff(padapter, pLed); ++ } else { ++ pLed->bLedNoLinkBlinkInProgress = false; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ pLed->bLedScanBlinkInProgress = false; ++ } else { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { ++ SwLedOff(padapter, pLed); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { ++ SwLedOff(padapter, pLed); ++ } else { ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ pLed->bLedBlinkInProgress = false; ++ } else { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { ++ SwLedOff(padapter, pLed); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ case LED_BLINK_WPS: ++ if (pLed->bLedOn) { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SLOWLY_INTERVAL); ++ } else { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ case LED_BLINK_WPS_STOP: /* WPS authentication fail */ ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ break; ++ case LED_BLINK_WPS_STOP_OVERLAP: /* WPS session overlap */ ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) { ++ if (pLed->bLedOn) ++ pLed->BlinkTimes = 1; ++ else ++ bStopBlinking = true; ++ } ++ ++ if (bStopBlinking) { ++ pLed->BlinkTimes = 10; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_LINK_INTERVAL_ALPHA); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void SwLedBlink5(struct LED_871x *pLed) ++{ ++ struct adapter *padapter = pLed->padapter; ++ u8 bStopBlinking = false; ++ ++ /* Change LED according to BlinkingLedState specified. */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) ++ SwLedOn(padapter, pLed); ++ else ++ SwLedOff(padapter, pLed); ++ ++ switch (pLed->CurrLedState) { ++ case LED_BLINK_SCAN: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if (pLed->bLedOn) ++ SwLedOff(padapter, pLed); ++ } else { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if (!pLed->bLedOn) ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ ++ pLed->bLedScanBlinkInProgress = false; ++ } else { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { ++ SwLedOff(padapter, pLed); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ case LED_BLINK_TXRX: ++ pLed->BlinkTimes--; ++ if (pLed->BlinkTimes == 0) ++ bStopBlinking = true; ++ ++ if (bStopBlinking) { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if (pLed->bLedOn) ++ SwLedOff(padapter, pLed); ++ } else { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if (!pLed->bLedOn) ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ ++ pLed->bLedBlinkInProgress = false; ++ } else { ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) { ++ SwLedOff(padapter, pLed); ++ } else { ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void SwLedBlink6(struct LED_871x *pLed) ++{ ++ struct adapter *padapter = pLed->padapter; ++ ++ /* Change LED according to BlinkingLedState specified. */ ++ if (pLed->BlinkingLedState == RTW_LED_ON) ++ SwLedOn(padapter, pLed); ++ else ++ SwLedOff(padapter, pLed); ++} ++ ++ /* ALPHA, added by chiyoko, 20090106 */ ++static void SwLedControlMode1(struct adapter *padapter, enum LED_CTL_MODE LedAction) ++{ ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ struct LED_871x *pLed = &ledpriv->SwLed0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ switch (LedAction) { ++ case LED_CTL_POWER_ON: ++ case LED_CTL_START_TO_LINK: ++ case LED_CTL_NO_LINK: ++ if (!pLed->bLedNoLinkBlinkInProgress) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ return; ++ if (pLed->bLedLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_LINK: ++ if (!pLed->bLedLinkBlinkInProgress) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ return; ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ pLed->bLedLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_NORMAL; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_LINK_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_SITE_SURVEY: ++ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { ++ ; ++ } else if (!pLed->bLedScanBlinkInProgress) { ++ if (IS_LED_WPS_BLINKING(pLed)) ++ return; ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ pLed->bLedScanBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if (!pLed->bLedBlinkInProgress) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ return; ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedLinkBlinkInProgress = false; ++ } ++ pLed->bLedBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_START_WPS: /* wait until xinpin finish */ ++ case LED_CTL_START_WPS_BOTTON: ++ if (!pLed->bLedWPSBlinkInProgress) { ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ pLed->bLedWPSBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_WPS; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_STOP_WPS: ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ if (pLed->bLedWPSBlinkInProgress) ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ else ++ pLed->bLedWPSBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_WPS_STOP; ++ if (pLed->bLedOn) { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); ++ } else { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ break; ++ case LED_CTL_STOP_WPS_FAIL: ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ break; ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ SwLedOff(padapter, pLed); ++ break; ++ default: ++ break; ++ } ++} ++ ++ /* Arcadyan/Sitecom , added by chiyoko, 20090216 */ ++static void SwLedControlMode2(struct adapter *padapter, enum LED_CTL_MODE LedAction) ++{ ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct LED_871x *pLed = &ledpriv->SwLed0; ++ ++ switch (LedAction) { ++ case LED_CTL_SITE_SURVEY: ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { ++ } else if (!pLed->bLedScanBlinkInProgress) { ++ if (IS_LED_WPS_BLINKING(pLed)) ++ return; ++ ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ pLed->bLedScanBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ return; ++ pLed->bLedBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_LINK: ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ _set_timer(&pLed->BlinkTimer, 0); ++ break; ++ case LED_CTL_START_WPS: /* wait until xinpin finish */ ++ case LED_CTL_START_WPS_BOTTON: ++ if (!pLed->bLedWPSBlinkInProgress) { ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ pLed->bLedWPSBlinkInProgress = true; ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ break; ++ case LED_CTL_STOP_WPS: ++ pLed->bLedWPSBlinkInProgress = false; ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else { ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ break; ++ case LED_CTL_STOP_WPS_FAIL: ++ pLed->bLedWPSBlinkInProgress = false; ++ if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) { ++ SwLedOff(padapter, pLed); ++ } else { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ break; ++ case LED_CTL_START_TO_LINK: ++ case LED_CTL_NO_LINK: ++ if (!IS_LED_BLINKING(pLed)) { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ break; ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ ++ _set_timer(&pLed->BlinkTimer, 0); ++ break; ++ default: ++ break; ++ } ++} ++ ++ /* COREGA, added by chiyoko, 20090316 */ ++ static void SwLedControlMode3(struct adapter *padapter, enum LED_CTL_MODE LedAction) ++{ ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct LED_871x *pLed = &ledpriv->SwLed0; ++ ++ switch (LedAction) { ++ case LED_CTL_SITE_SURVEY: ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { ++ } else if (!pLed->bLedScanBlinkInProgress) { ++ if (IS_LED_WPS_BLINKING(pLed)) ++ return; ++ ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ pLed->bLedScanBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if ((!pLed->bLedBlinkInProgress) && (check_fwstate(pmlmepriv, _FW_LINKED))) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ return; ++ pLed->bLedBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_LINK: ++ if (IS_LED_WPS_BLINKING(pLed)) ++ return; ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ ++ _set_timer(&pLed->BlinkTimer, 0); ++ break; ++ case LED_CTL_START_WPS: /* wait until xinpin finish */ ++ case LED_CTL_START_WPS_BOTTON: ++ if (!pLed->bLedWPSBlinkInProgress) { ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ pLed->bLedWPSBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_WPS; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_STOP_WPS: ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } else { ++ pLed->bLedWPSBlinkInProgress = true; ++ } ++ ++ pLed->CurrLedState = LED_BLINK_WPS_STOP; ++ if (pLed->bLedOn) { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); ++ } else { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ break; ++ case LED_CTL_STOP_WPS_FAIL: ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, 0); ++ break; ++ case LED_CTL_START_TO_LINK: ++ case LED_CTL_NO_LINK: ++ if (!IS_LED_BLINKING(pLed)) { ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ break; ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ ++ _set_timer(&pLed->BlinkTimer, 0); ++ break; ++ default: ++ break; ++ } ++} ++ ++ /* Edimax-Belkin, added by chiyoko, 20090413 */ ++static void SwLedControlMode4(struct adapter *padapter, enum LED_CTL_MODE LedAction) ++{ ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct LED_871x *pLed = &ledpriv->SwLed0; ++ struct LED_871x *pLed1 = &ledpriv->SwLed1; ++ ++ switch (LedAction) { ++ case LED_CTL_START_TO_LINK: ++ if (pLed1->bLedWPSBlinkInProgress) { ++ pLed1->bLedWPSBlinkInProgress = false; ++ _cancel_timer_ex(&pLed1->BlinkTimer); ++ ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ pLed1->CurrLedState = RTW_LED_OFF; ++ ++ if (pLed1->bLedOn) ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ ++ if (!pLed->bLedStartToLinkBlinkInProgress) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ return; ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ ++ pLed->bLedStartToLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_StartToBlink; ++ if (pLed->bLedOn) { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SLOWLY_INTERVAL); ++ } else { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ } ++ } ++ break; ++ case LED_CTL_LINK: ++ case LED_CTL_NO_LINK: ++ /* LED1 settings */ ++ if (LedAction == LED_CTL_LINK) { ++ if (pLed1->bLedWPSBlinkInProgress) { ++ pLed1->bLedWPSBlinkInProgress = false; ++ _cancel_timer_ex(&pLed1->BlinkTimer); ++ ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ pLed1->CurrLedState = RTW_LED_OFF; ++ ++ if (pLed1->bLedOn) ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ } ++ ++ if (!pLed->bLedNoLinkBlinkInProgress) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ return; ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_SITE_SURVEY: ++ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { ++ } else if (!pLed->bLedScanBlinkInProgress) { ++ if (IS_LED_WPS_BLINKING(pLed)) ++ return; ++ ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ pLed->bLedScanBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if (!pLed->bLedBlinkInProgress) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) ++ return; ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ pLed->bLedBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_START_WPS: /* wait until xinpin finish */ ++ case LED_CTL_START_WPS_BOTTON: ++ if (pLed1->bLedWPSBlinkInProgress) { ++ pLed1->bLedWPSBlinkInProgress = false; ++ _cancel_timer_ex(&pLed1->BlinkTimer); ++ ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ pLed1->CurrLedState = RTW_LED_OFF; ++ ++ if (pLed1->bLedOn) ++ _set_timer(&pLed->BlinkTimer, 0); ++ } ++ ++ if (!pLed->bLedWPSBlinkInProgress) { ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ pLed->bLedWPSBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_WPS; ++ if (pLed->bLedOn) { ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SLOWLY_INTERVAL); ++ } else { ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ } ++ } ++ break; ++ case LED_CTL_STOP_WPS: /* WPS connect success */ ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ ++ break; ++ case LED_CTL_STOP_WPS_FAIL: /* WPS authentication fail */ ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ ++ /* LED1 settings */ ++ if (pLed1->bLedWPSBlinkInProgress) ++ _cancel_timer_ex(&pLed1->BlinkTimer); ++ else ++ pLed1->bLedWPSBlinkInProgress = true; ++ pLed1->CurrLedState = LED_BLINK_WPS_STOP; ++ if (pLed1->bLedOn) ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed1->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ break; ++ case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ pLed->bLedNoLinkBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SLOWLY; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NO_LINK_INTERVAL_ALPHA); ++ ++ /* LED1 settings */ ++ if (pLed1->bLedWPSBlinkInProgress) ++ _cancel_timer_ex(&pLed1->BlinkTimer); ++ else ++ pLed1->bLedWPSBlinkInProgress = true; ++ pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; ++ pLed1->BlinkTimes = 10; ++ if (pLed1->bLedOn) ++ pLed1->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed1->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_NORMAL_INTERVAL); ++ break; ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ ++ if (pLed->bLedNoLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedNoLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedLinkBlinkInProgress = false; ++ } ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ if (pLed->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedWPSBlinkInProgress = false; ++ } ++ if (pLed->bLedScanBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedScanBlinkInProgress = false; ++ } ++ if (pLed->bLedStartToLinkBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedStartToLinkBlinkInProgress = false; ++ } ++ if (pLed1->bLedWPSBlinkInProgress) { ++ _cancel_timer_ex(&pLed1->BlinkTimer); ++ pLed1->bLedWPSBlinkInProgress = false; ++ } ++ pLed1->BlinkingLedState = LED_UNKNOWN; ++ SwLedOff(padapter, pLed); ++ SwLedOff(padapter, pLed1); ++ break; ++ default: ++ break; ++ } ++} ++ ++ /* Sercomm-Belkin, added by chiyoko, 20090415 */ ++static void ++SwLedControlMode5( ++ struct adapter *padapter, ++ enum LED_CTL_MODE LedAction ++) ++{ ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct LED_871x *pLed = &ledpriv->SwLed0; ++ ++ switch (LedAction) { ++ case LED_CTL_POWER_ON: ++ case LED_CTL_NO_LINK: ++ case LED_CTL_LINK: /* solid blue */ ++ pLed->CurrLedState = RTW_LED_ON; ++ pLed->BlinkingLedState = RTW_LED_ON; ++ ++ _set_timer(&pLed->BlinkTimer, 0); ++ break; ++ case LED_CTL_SITE_SURVEY: ++ if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED))) { ++ } else if (!pLed->bLedScanBlinkInProgress) { ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ pLed->bLedScanBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_SCAN; ++ pLed->BlinkTimes = 24; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_SCAN_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_TX: ++ case LED_CTL_RX: ++ if (!pLed->bLedBlinkInProgress) { ++ if (pLed->CurrLedState == LED_BLINK_SCAN) ++ return; ++ pLed->bLedBlinkInProgress = true; ++ pLed->CurrLedState = LED_BLINK_TXRX; ++ pLed->BlinkTimes = 2; ++ if (pLed->bLedOn) ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ else ++ pLed->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed->BlinkTimer, LED_BLINK_FASTER_INTERVAL_ALPHA); ++ } ++ break; ++ case LED_CTL_POWER_OFF: ++ pLed->CurrLedState = RTW_LED_OFF; ++ pLed->BlinkingLedState = RTW_LED_OFF; ++ ++ if (pLed->bLedBlinkInProgress) { ++ _cancel_timer_ex(&pLed->BlinkTimer); ++ pLed->bLedBlinkInProgress = false; ++ } ++ SwLedOff(padapter, pLed); ++ break; ++ default: ++ break; ++ } ++} ++ ++ /* WNC-Corega, added by chiyoko, 20090902 */ ++static void ++SwLedControlMode6( ++ struct adapter *padapter, ++ enum LED_CTL_MODE LedAction ++) ++{ ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ struct LED_871x *pLed0 = &ledpriv->SwLed0; ++ ++ switch (LedAction) { ++ case LED_CTL_POWER_ON: ++ case LED_CTL_LINK: ++ case LED_CTL_NO_LINK: ++ _cancel_timer_ex(&pLed0->BlinkTimer); ++ pLed0->CurrLedState = RTW_LED_ON; ++ pLed0->BlinkingLedState = RTW_LED_ON; ++ _set_timer(&pLed0->BlinkTimer, 0); ++ break; ++ case LED_CTL_POWER_OFF: ++ SwLedOff(padapter, pLed0); ++ break; ++ default: ++ break; ++ } ++} ++ ++/* */ ++/* Description: */ ++/* Handler function of LED Blinking. */ ++/* We dispatch acture LED blink action according to LedStrategy. */ ++/* */ ++void BlinkHandler(struct LED_871x *pLed) ++{ ++ struct adapter *padapter = pLed->padapter; ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ ++ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped)) ++ return; ++ ++ switch (ledpriv->LedStrategy) { ++ case SW_LED_MODE0: ++ SwLedBlink(pLed); ++ break; ++ case SW_LED_MODE1: ++ SwLedBlink1(pLed); ++ break; ++ case SW_LED_MODE2: ++ SwLedBlink2(pLed); ++ break; ++ case SW_LED_MODE3: ++ SwLedBlink3(pLed); ++ break; ++ case SW_LED_MODE4: ++ SwLedBlink4(pLed); ++ break; ++ case SW_LED_MODE5: ++ SwLedBlink5(pLed); ++ break; ++ case SW_LED_MODE6: ++ SwLedBlink6(pLed); ++ break; ++ default: ++ break; ++ } ++} ++ ++void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction) ++{ ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ struct registry_priv *registry_par; ++ ++ if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) || ++ (!padapter->hw_init_completed)) ++ return; ++ ++ if (!ledpriv->bRegUseLed) ++ return; ++ ++ registry_par = &padapter->registrypriv; ++ if (!registry_par->led_enable) ++ return; ++ ++ if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on && ++ padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) && ++ (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX || ++ LedAction == LED_CTL_SITE_SURVEY || ++ LedAction == LED_CTL_LINK || ++ LedAction == LED_CTL_NO_LINK || ++ LedAction == LED_CTL_POWER_ON)) ++ return; ++ ++ switch (ledpriv->LedStrategy) { ++ case SW_LED_MODE0: ++ break; ++ case SW_LED_MODE1: ++ SwLedControlMode1(padapter, LedAction); ++ break; ++ case SW_LED_MODE2: ++ SwLedControlMode2(padapter, LedAction); ++ break; ++ case SW_LED_MODE3: ++ SwLedControlMode3(padapter, LedAction); ++ break; ++ case SW_LED_MODE4: ++ SwLedControlMode4(padapter, LedAction); ++ break; ++ case SW_LED_MODE5: ++ SwLedControlMode5(padapter, LedAction); ++ break; ++ case SW_LED_MODE6: ++ SwLedControlMode6(padapter, LedAction); ++ break; ++ default: ++ break; ++ } ++} +diff --git a/drivers/staging/r8188eu/core/rtw_mlme.c b/drivers/staging/r8188eu/core/rtw_mlme.c +new file mode 100644 +index 000000000000..1115ff5d865a +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_mlme.c +@@ -0,0 +1,2199 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTW_MLME_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/xmit_osdep.h" ++#include "../include/hal_intf.h" ++#include "../include/mlme_osdep.h" ++#include "../include/sta_info.h" ++#include "../include/wifi.h" ++#include "../include/wlan_bssdef.h" ++#include "../include/rtw_ioctl_set.h" ++#include "../include/usb_osintf.h" ++ ++extern unsigned char MCS_rate_2R[16]; ++extern unsigned char MCS_rate_1R[16]; ++ ++void rtw_set_roaming(struct adapter *adapter, u8 to_roaming) ++{ ++ if (to_roaming == 0) ++ adapter->mlmepriv.to_join = false; ++ adapter->mlmepriv.to_roaming = to_roaming; ++} ++ ++u8 rtw_to_roaming(struct adapter *adapter) ++{ ++ return adapter->mlmepriv.to_roaming; ++} ++ ++int _rtw_init_mlme_priv(struct adapter *padapter) ++{ ++ int i; ++ u8 *pbuf; ++ struct wlan_network *pnetwork; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ int res = _SUCCESS; ++ ++ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */ ++ ++ pmlmepriv->nic_hdl = (u8 *)padapter; ++ ++ pmlmepriv->pscanned = NULL; ++ pmlmepriv->fw_state = 0; ++ pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; ++ pmlmepriv->scan_mode = SCAN_ACTIVE;/* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */ ++ ++ spin_lock_init(&pmlmepriv->lock); ++ _rtw_init_queue(&pmlmepriv->free_bss_pool); ++ _rtw_init_queue(&pmlmepriv->scanned_queue); ++ ++ set_scanned_network_val(pmlmepriv, 0); ++ ++ memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ ++ pbuf = vzalloc(MAX_BSS_CNT * (sizeof(struct wlan_network))); ++ ++ if (!pbuf) { ++ res = _FAIL; ++ goto exit; ++ } ++ pmlmepriv->free_bss_buf = pbuf; ++ ++ pnetwork = (struct wlan_network *)pbuf; ++ ++ for (i = 0; i < MAX_BSS_CNT; i++) { ++ INIT_LIST_HEAD(&pnetwork->list); ++ ++ list_add_tail(&pnetwork->list, &pmlmepriv->free_bss_pool.queue); ++ ++ pnetwork++; ++ } ++ ++ /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ ++ ++ rtw_clear_scan_deny(padapter); ++ ++ rtw_init_mlme_timer(padapter); ++ ++exit: ++ ++ return res; ++} ++ ++static void rtw_mfree_mlme_priv_lock(struct mlme_priv *pmlmepriv) ++{ ++} ++ ++#if defined(CONFIG_88EU_AP_MODE) ++static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) ++{ ++ kfree(*ppie); ++ *plen = 0; ++ *ppie = NULL; ++} ++ ++void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) ++{ ++ kfree(pmlmepriv->assoc_req); ++ kfree(pmlmepriv->assoc_rsp); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len); ++ ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len); ++ rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len); ++} ++#else ++void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) ++{ ++} ++#endif ++ ++void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) ++{ ++ ++ rtw_free_mlme_priv_ie_data(pmlmepriv); ++ ++ if (pmlmepriv) { ++ rtw_mfree_mlme_priv_lock(pmlmepriv); ++ ++ vfree(pmlmepriv->free_bss_buf); ++ } ++ ++} ++ ++int _rtw_enqueue_network(struct __queue *queue, struct wlan_network *pnetwork) ++{ ++ ++ if (!pnetwork) ++ goto exit; ++ ++ spin_lock_bh(&queue->lock); ++ ++ list_add_tail(&pnetwork->list, &queue->queue); ++ ++ spin_unlock_bh(&queue->lock); ++ ++exit: ++ ++ return _SUCCESS; ++} ++ ++struct wlan_network *_rtw_dequeue_network(struct __queue *queue) ++{ ++ struct wlan_network *pnetwork; ++ ++ spin_lock_bh(&queue->lock); ++ ++ if (list_empty(&queue->queue)) { ++ pnetwork = NULL; ++ } else { ++ pnetwork = container_of((&queue->queue)->next, struct wlan_network, list); ++ ++ list_del_init(&pnetwork->list); ++ } ++ ++ spin_unlock_bh(&queue->lock); ++ ++ return pnetwork; ++} ++ ++struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv)/* _queue *free_queue) */ ++{ ++ struct wlan_network *pnetwork; ++ struct __queue *free_queue = &pmlmepriv->free_bss_pool; ++ struct list_head *plist = NULL; ++ ++ spin_lock_bh(&free_queue->lock); ++ ++ if (list_empty(&free_queue->queue)) { ++ pnetwork = NULL; ++ goto exit; ++ } ++ plist = (&free_queue->queue)->next; ++ ++ pnetwork = container_of(plist, struct wlan_network, list); ++ ++ list_del_init(&pnetwork->list); ++ ++ pnetwork->network_type = 0; ++ pnetwork->fixed = false; ++ pnetwork->last_scanned = jiffies; ++ pnetwork->aid = 0; ++ pnetwork->join_res = 0; ++ ++ pmlmepriv->num_of_scanned++; ++ ++exit: ++ spin_unlock_bh(&free_queue->lock); ++ ++ return pnetwork; ++} ++ ++void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 isfreeall) ++{ ++ u32 curr_time, delta_time; ++ u32 lifetime = SCANQUEUE_LIFETIME; ++ struct __queue *free_queue = &pmlmepriv->free_bss_pool; ++ ++ if (!pnetwork) ++ return; ++ ++ if (pnetwork->fixed) ++ return; ++ curr_time = jiffies; ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) ++ lifetime = 1; ++ if (!isfreeall) { ++ delta_time = (curr_time - pnetwork->last_scanned) / HZ; ++ if (delta_time < lifetime)/* unit:sec */ ++ return; ++ } ++ spin_lock_bh(&free_queue->lock); ++ list_del_init(&pnetwork->list); ++ list_add_tail(&pnetwork->list, &free_queue->queue); ++ pmlmepriv->num_of_scanned--; ++ spin_unlock_bh(&free_queue->lock); ++} ++ ++void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) ++{ ++ struct __queue *free_queue = &pmlmepriv->free_bss_pool; ++ ++ if (!pnetwork) ++ return; ++ if (pnetwork->fixed) ++ return; ++ list_del_init(&pnetwork->list); ++ list_add_tail(&pnetwork->list, get_list_head(free_queue)); ++ pmlmepriv->num_of_scanned--; ++} ++ ++/* ++ return the wlan_network with the matching addr ++ ++ Shall be calle under atomic context... to avoid possible racing condition... ++*/ ++struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr) ++{ ++ struct list_head *phead, *plist; ++ struct wlan_network *pnetwork = NULL; ++ u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; ++ ++ if (!memcmp(zero_addr, addr, ETH_ALEN)) { ++ pnetwork = NULL; ++ goto exit; ++ } ++ phead = get_list_head(scanned_queue); ++ plist = phead->next; ++ ++ while (plist != phead) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ if (!memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN)) ++ break; ++ plist = plist->next; ++ } ++ if (plist == phead) ++ pnetwork = NULL; ++exit: ++ ++ return pnetwork; ++} ++ ++void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall) ++{ ++ struct list_head *phead, *plist; ++ struct wlan_network *pnetwork; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct __queue *scanned_queue = &pmlmepriv->scanned_queue; ++ ++ spin_lock_bh(&scanned_queue->lock); ++ ++ phead = get_list_head(scanned_queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ ++ plist = plist->next; ++ ++ _rtw_free_network(pmlmepriv, pnetwork, isfreeall); ++ } ++ spin_unlock_bh(&scanned_queue->lock); ++ ++} ++ ++int rtw_if_up(struct adapter *padapter) ++{ ++ int res; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved || ++ !check_fwstate(&padapter->mlmepriv, _FW_LINKED)) ++ res = false; ++ else ++ res = true; ++ ++ return res; ++} ++ ++void rtw_generate_random_ibss(u8 *pibss) ++{ ++ u32 curtime = jiffies; ++ ++ pibss[0] = 0x02; /* in ad-hoc mode bit1 must set to 1 */ ++ pibss[1] = 0x11; ++ pibss[2] = 0x87; ++ pibss[3] = (u8)(curtime & 0xff);/* p[0]; */ ++ pibss[4] = (u8)((curtime >> 8) & 0xff);/* p[1]; */ ++ pibss[5] = (u8)((curtime >> 16) & 0xff);/* p[2]; */ ++} ++ ++u8 *rtw_get_capability_from_ie(u8 *ie) ++{ ++ return ie + 8 + 2; ++} ++ ++u16 rtw_get_capability(struct wlan_bssid_ex *bss) ++{ ++ __le16 val; ++ ++ memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2); ++ ++ return le16_to_cpu(val); ++} ++ ++u8 *rtw_get_timestampe_from_ie(u8 *ie) ++{ ++ return ie + 0; ++} ++ ++u8 *rtw_get_beacon_interval_from_ie(u8 *ie) ++{ ++ return ie + 8; ++} ++ ++int rtw_init_mlme_priv(struct adapter *padapter)/* struct mlme_priv *pmlmepriv) */ ++{ ++ int res; ++ ++ res = _rtw_init_mlme_priv(padapter);/* (pmlmepriv); */ ++ ++ return res; ++} ++ ++void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) ++{ ++ _rtw_free_mlme_priv(pmlmepriv); ++} ++ ++static struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) ++{ ++ struct wlan_network *pnetwork; ++ ++ pnetwork = _rtw_alloc_network(pmlmepriv); ++ ++ return pnetwork; ++} ++ ++static void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, ++ struct wlan_network *pnetwork) ++{ ++ ++ _rtw_free_network_nolock(pmlmepriv, pnetwork); ++ ++} ++ ++void rtw_free_network_queue(struct adapter *dev, u8 isfreeall) ++{ ++ ++ _rtw_free_network_queue(dev, isfreeall); ++ ++} ++ ++/* ++ return the wlan_network with the matching addr ++ ++ Shall be calle under atomic context... to avoid possible racing condition... ++*/ ++struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr) ++{ ++ struct wlan_network *pnetwork = _rtw_find_network(scanned_queue, addr); ++ ++ return pnetwork; ++} ++ ++int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork) ++{ ++ int ret = true; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ ++ if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) && ++ (pnetwork->network.Privacy == 0)) ++ ret = false; ++ else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) && ++ (pnetwork->network.Privacy == 1)) ++ ret = false; ++ else ++ ret = true; ++ return ret; ++} ++ ++static int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b) ++{ ++ return (a->Ssid.SsidLength == b->Ssid.SsidLength) && ++ !memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength); ++} ++ ++int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) ++{ ++ u16 s_cap, d_cap; ++ __le16 le_scap, le_dcap; ++ ++ memcpy((u8 *)&le_scap, rtw_get_capability_from_ie(src->IEs), 2); ++ memcpy((u8 *)&le_dcap, rtw_get_capability_from_ie(dst->IEs), 2); ++ ++ s_cap = le16_to_cpu(le_scap); ++ d_cap = le16_to_cpu(le_dcap); ++ ++ return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) && ++ ((!memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN))) && ++ ((!memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength))) && ++ ((s_cap & WLAN_CAPABILITY_IBSS) == ++ (d_cap & WLAN_CAPABILITY_IBSS)) && ++ ((s_cap & WLAN_CAPABILITY_BSS) == ++ (d_cap & WLAN_CAPABILITY_BSS))); ++} ++ ++struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue) ++{ ++ struct list_head *plist, *phead; ++ struct wlan_network *pwlan = NULL; ++ struct wlan_network *oldest = NULL; ++ ++ phead = get_list_head(scanned_queue); ++ ++ plist = phead->next; ++ ++ while (1) { ++ if (phead == plist) ++ break; ++ ++ pwlan = container_of(plist, struct wlan_network, list); ++ ++ if (!pwlan->fixed) { ++ if (!oldest || time_after(oldest->last_scanned, pwlan->last_scanned)) ++ oldest = pwlan; ++ } ++ ++ plist = plist->next; ++ } ++ ++ return oldest; ++} ++ ++void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, ++ struct adapter *padapter, bool update_ie) ++{ ++ long rssi_ori = dst->Rssi; ++ u8 sq_smp = src->PhyInfo.SignalQuality; ++ u8 ss_final; ++ u8 sq_final; ++ long rssi_final; ++ ++ rtw_hal_antdiv_rssi_compared(padapter, dst, src); /* this will update src.Rssi, need consider again */ ++ ++ /* The rule below is 1/5 for sample value, 4/5 for history value */ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&padapter->mlmepriv.cur_network.network, src)) { ++ /* Take the recvpriv's value for the connected AP*/ ++ ss_final = padapter->recvpriv.signal_strength; ++ sq_final = padapter->recvpriv.signal_qual; ++ /* the rssi value here is undecorated, and will be used for antenna diversity */ ++ if (sq_smp != 101) /* from the right channel */ ++ rssi_final = dst->Rssi; //(src->Rssi+dst->Rssi*4)/5; ++ else ++ rssi_final = rssi_ori; ++ } else { ++// if (sq_smp != 101) { /* from the right channel */ ++ ss_final = (u32)dst->PhyInfo.SignalStrength; //((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5; ++ sq_final = (u32)dst->PhyInfo.SignalQuality; //((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5; ++ rssi_final = dst->Rssi; //(src->Rssi+dst->Rssi*4)/5; ++// } else { ++// /* bss info not receiving from the right channel, use the original RX signal infos */ ++// ss_final = dst->PhyInfo.SignalStrength; ++// sq_final = dst->PhyInfo.SignalQuality; ++// rssi_final = dst->Rssi; ++// } ++ } ++ if (update_ie) { ++ dst->Reserved[0] = src->Reserved[0]; ++ dst->Reserved[1] = src->Reserved[1]; ++ memcpy((u8 *)dst, (u8 *)src, get_wlan_bssid_ex_sz(src)); ++ } ++ dst->PhyInfo.SignalStrength = ss_final; ++ dst->PhyInfo.SignalQuality = sq_final; ++ dst->Rssi = rssi_final; ++ ++} ++ ++static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex *pnetwork) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) && ++ is_same_network(&pmlmepriv->cur_network.network, pnetwork)) { ++ update_network(&pmlmepriv->cur_network.network, pnetwork, adapter, true); ++ rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(struct ndis_802_11_fixed_ie), ++ pmlmepriv->cur_network.network.IELength); ++ } ++ ++} ++ ++/* ++Caller must hold pmlmepriv->lock first. ++*/ ++void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target) ++{ ++ struct list_head *plist, *phead; ++ u32 bssid_ex_sz; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ struct wlan_network *oldest = NULL; ++ ++ spin_lock_bh(&queue->lock); ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ ++ if (is_same_network(&pnetwork->network, target)) ++ break; ++ if ((oldest == ((struct wlan_network *)0)) || ++ time_after(oldest->last_scanned, pnetwork->last_scanned)) ++ oldest = pnetwork; ++ plist = plist->next; ++ } ++ /* If we didn't find a match, then get a new network slot to initialize ++ * with this beacon's information */ ++ if (phead == plist) { ++ if (list_empty(&pmlmepriv->free_bss_pool.queue)) { ++ /* If there are no more slots, expire the oldest */ ++ pnetwork = oldest; ++ ++ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &target->PhyInfo.Optimum_antenna); ++ memcpy(&pnetwork->network, target, get_wlan_bssid_ex_sz(target)); ++ /* variable initialize */ ++ pnetwork->fixed = false; ++ pnetwork->last_scanned = jiffies; ++ ++ pnetwork->network_type = 0; ++ pnetwork->aid = 0; ++ pnetwork->join_res = 0; ++ ++ /* bss info not receiving from the right channel */ ++ if (pnetwork->network.PhyInfo.SignalQuality == 101) ++ pnetwork->network.PhyInfo.SignalQuality = 0; ++ } else { ++ /* Otherwise just pull from the free list */ ++ ++ pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */ ++ ++ if (!pnetwork) ++ goto exit; ++ ++ bssid_ex_sz = get_wlan_bssid_ex_sz(target); ++ target->Length = bssid_ex_sz; ++ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &target->PhyInfo.Optimum_antenna); ++ memcpy(&pnetwork->network, target, bssid_ex_sz); ++ ++ pnetwork->last_scanned = jiffies; ++ ++ /* bss info not receiving from the right channel */ ++ if (pnetwork->network.PhyInfo.SignalQuality == 101) ++ pnetwork->network.PhyInfo.SignalQuality = 0; ++ list_add_tail(&pnetwork->list, &queue->queue); ++ } ++ } else { ++ /* we have an entry and we are going to update it. But this entry may ++ * be already expired. In this case we do the same as we found a new ++ * net and call the new_net handler ++ */ ++ bool update_ie = true; ++ ++ pnetwork->last_scanned = jiffies; ++ ++ /* target.Reserved[0]== 1, means that scanned network is a bcn frame. */ ++ /* probe resp(3) > beacon(1) > probe req(2) */ ++ if ((target->Reserved[0] != 2) && ++ (target->Reserved[0] >= pnetwork->network.Reserved[0])) ++ update_ie = true; ++ else ++ update_ie = false; ++ update_network(&pnetwork->network, target, adapter, update_ie); ++ } ++ ++exit: ++ spin_unlock_bh(&queue->lock); ++ ++} ++ ++static void rtw_add_network(struct adapter *adapter, ++ struct wlan_bssid_ex *pnetwork) ++{ ++ ++#if defined(CONFIG_88EU_P2P) ++ rtw_wlan_bssid_ex_remove_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO); ++#endif ++ update_current_network(adapter, pnetwork); ++ rtw_update_scanned_network(adapter, pnetwork); ++ ++} ++ ++/* select the desired network based on the capability of the (i)bss. */ ++/* check items: (1) security */ ++/* (2) network_type */ ++/* (3) WMM */ ++/* (4) HT */ ++/* (5) others */ ++static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwork) ++{ ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u32 desired_encmode; ++ u32 privacy; ++ ++ /* u8 wps_ie[512]; */ ++ uint wps_ielen; ++ ++ int bselected = true; ++ ++ desired_encmode = psecuritypriv->ndisencryptstatus; ++ privacy = pnetwork->network.Privacy; ++ ++ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { ++ if (rtw_get_wps_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, pnetwork->network.IELength - _FIXED_IE_LENGTH_, NULL, &wps_ielen)) ++ return true; ++ else ++ return false; ++ } ++ if (adapter->registrypriv.wifi_spec == 1) { /* for correct flow of 8021X to do.... */ ++ u8 *p = NULL; ++ uint ie_len = 0; ++ ++ if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0)) ++ bselected = false; ++ if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { ++ p = rtw_get_ie(pnetwork->network.IEs + _BEACON_IE_OFFSET_, ++ _RSN_IE_2_, &ie_len, ++ (pnetwork->network.IELength - ++ _BEACON_IE_OFFSET_)); ++ if (p && ie_len > 0) ++ bselected = true; ++ else ++ bselected = false; ++ } ++ } ++ ++ if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { ++ DBG_88E("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); ++ bselected = false; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { ++ if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) ++ bselected = false; ++ } ++ ++ return bselected; ++} ++ ++void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ u32 len; ++ struct wlan_bssid_ex *pnetwork; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ pnetwork = (struct wlan_bssid_ex *)pbuf; ++ ++ len = get_wlan_bssid_ex_sz(pnetwork); ++ if (len > (sizeof(struct wlan_bssid_ex))) ++ return; ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ /* update IBSS_network 's timestamp */ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { ++ if (!memcmp(&pmlmepriv->cur_network.network.MacAddress, pnetwork->MacAddress, ETH_ALEN)) { ++ struct wlan_network *ibss_wlan = NULL; ++ ++ memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8); ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->MacAddress); ++ if (ibss_wlan) { ++ memcpy(ibss_wlan->network.IEs, pnetwork->IEs, 8); ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ goto exit; ++ } ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ } ++ } ++ ++ /* lock pmlmepriv->lock when you accessing network_q */ ++ if (!check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { ++ if (pnetwork->Ssid.Ssid[0] == 0) ++ pnetwork->Ssid.SsidLength = 0; ++ rtw_add_network(adapter, pnetwork); ++ } ++ ++exit: ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 timer_cancelled = 0; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (pmlmepriv->wps_probe_req_ie) { ++ pmlmepriv->wps_probe_req_ie_len = 0; ++ kfree(pmlmepriv->wps_probe_req_ie); ++ pmlmepriv->wps_probe_req_ie = NULL; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { ++ timer_cancelled = 1; ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ } ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ if (timer_cancelled) ++ _cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ rtw_set_signal_stat_timer(&adapter->recvpriv); ++ ++ if (pmlmepriv->to_join) { ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { ++ if (!check_fwstate(pmlmepriv, _FW_LINKED)) { ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ++ if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS) { ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ } else { ++ struct wlan_bssid_ex *pdev_network = &adapter->registrypriv.dev_network; ++ u8 *pibss = adapter->registrypriv.dev_network.MacAddress; ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ ++ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ rtw_update_registrypriv_dev_network(adapter); ++ rtw_generate_random_ibss(pibss); ++ ++ pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; ++ ++ rtw_createbss_cmd(adapter); ++ pmlmepriv->to_join = false; ++ } ++ } ++ } else { ++ int s_ret; ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ pmlmepriv->to_join = false; ++ s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv); ++ if (_SUCCESS == s_ret) { ++ _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); ++ } else if (s_ret == 2) { /* there is no need to wait for join */ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ rtw_indicate_connect(adapter); ++ } else { ++ DBG_88E("try_to_join, but select scanning queue fail, to_roaming:%d\n", ++ pmlmepriv->to_roaming); ++ if (rtw_to_roaming(adapter) != 0) { ++ if (--pmlmepriv->to_roaming == 0 || ++ _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)) { ++ rtw_set_roaming(adapter, 0); ++ rtw_free_assoc_resources(adapter, 1); ++ rtw_indicate_disconnect(adapter); ++ } else { ++ pmlmepriv->to_join = true; ++ } ++ } else { ++ rtw_indicate_disconnect(adapter); ++ } ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ } ++ } ++ } ++ ++ indicate_wx_scan_complete_event(adapter); ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ p2p_ps_wk_cmd(adapter, P2P_PS_SCAN_DONE, 0); ++ ++ rtw_os_xmit_schedule(adapter); ++} ++ ++void rtw_dummy_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++} ++ ++void rtw_fwdbg_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++} ++ ++static void free_scanqueue(struct mlme_priv *pmlmepriv) ++{ ++ struct __queue *free_queue = &pmlmepriv->free_bss_pool; ++ struct __queue *scan_queue = &pmlmepriv->scanned_queue; ++ struct list_head *plist, *phead, *ptemp; ++ ++ spin_lock_bh(&scan_queue->lock); ++ spin_lock_bh(&free_queue->lock); ++ ++ phead = get_list_head(scan_queue); ++ plist = phead->next; ++ ++ while (plist != phead) { ++ ptemp = plist->next; ++ list_del_init(plist); ++ list_add_tail(plist, &free_queue->queue); ++ plist = ptemp; ++ pmlmepriv->num_of_scanned--; ++ } ++ ++ spin_unlock_bh(&free_queue->lock); ++ spin_unlock_bh(&scan_queue->lock); ++} ++ ++/* ++*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue) ++{ ++ struct wlan_network *pwlan = NULL; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_AP_STATE)) { ++ struct sta_info *psta; ++ ++ psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress); ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ rtw_free_stainfo(adapter, psta); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE)) { ++ struct sta_info *psta; ++ ++ rtw_free_all_stainfo(adapter); ++ ++ psta = rtw_get_bcmc_stainfo(adapter); ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ rtw_free_stainfo(adapter, psta); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ rtw_init_bcmc_stainfo(adapter); ++ } ++ ++ if (lock_scanned_queue) ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if (pwlan) ++ pwlan->fixed = false; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1))) ++ rtw_free_network_nolock(pmlmepriv, pwlan); ++ ++ if (lock_scanned_queue) ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ pmlmepriv->key_mask = 0; ++ ++} ++ ++/* ++*rtw_indicate_connect: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_indicate_connect(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ pmlmepriv->to_join = false; ++ ++ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { ++ set_fwstate(pmlmepriv, _FW_LINKED); ++ ++ rtw_led_control(padapter, LED_CTL_LINK); ++ ++ rtw_os_indicate_connect(padapter); ++ } ++ ++ pmlmepriv->to_roaming = 0; ++ ++ rtw_set_scan_deny(padapter, 3000); ++} ++ ++/* ++*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock ++*/ ++void rtw_indicate_disconnect(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS); ++ ++ if (pmlmepriv->to_roaming > 0) ++ _clr_fwstate_(pmlmepriv, _FW_LINKED); ++ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) || ++ (pmlmepriv->to_roaming <= 0)) { ++ rtw_os_indicate_disconnect(padapter); ++ ++ _clr_fwstate_(pmlmepriv, _FW_LINKED); ++ rtw_led_control(padapter, LED_CTL_NO_LINK); ++ rtw_clear_scan_deny(padapter); ++ } ++ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); ++ ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 1); ++ ++} ++ ++inline void rtw_indicate_scan_done(struct adapter *padapter, bool aborted) ++{ ++ rtw_os_indicate_scan_done(padapter, aborted); ++} ++ ++void rtw_scan_abort(struct adapter *adapter) ++{ ++ u32 start; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ ++ start = jiffies; ++ pmlmeext->scan_abort = true; ++ while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) && ++ rtw_get_passing_time_ms(start) <= 200) { ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) ++ break; ++ DBG_88E(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev)); ++ msleep(20); ++ } ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { ++ if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved) ++ DBG_88E(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); ++ rtw_indicate_scan_done(adapter, true); ++ } ++ pmlmeext->scan_abort = false; ++} ++ ++static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, struct wlan_network *pnetwork) ++{ ++ int i; ++ struct sta_info *bmc_sta, *psta = NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress); ++ if (!psta) ++ psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress); ++ ++ if (psta) { /* update ptarget_sta */ ++ DBG_88E("%s\n", __func__); ++ psta->aid = pnetwork->join_res; ++ psta->mac_id = 0; ++ /* sta mode */ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); ++ /* security related */ ++ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { ++ padapter->securitypriv.binstallGrpkey = false; ++ padapter->securitypriv.busetkipkey = false; ++ padapter->securitypriv.bgrpkey_handshake = false; ++ psta->ieee8021x_blocked = true; ++ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype)); ++ memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype)); ++ memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype)); ++ memset((u8 *)&psta->dot11txpn, 0, sizeof(union pn48)); ++ memset((u8 *)&psta->dot11rxpn, 0, sizeof(union pn48)); ++ } ++ /* Commented by Albert 2012/07/21 */ ++ /* When doing the WPS, the wps_ie_len won't equal to 0 */ ++ /* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */ ++ if (padapter->securitypriv.wps_ie_len != 0) { ++ psta->ieee8021x_blocked = true; ++ padapter->securitypriv.wps_ie_len = 0; ++ } ++ /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ ++ /* if A-MPDU Rx is enabled, resetting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ ++ /* todo: check if AP can send A-MPDU packets */ ++ for (i = 0; i < 16; i++) { ++ /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ preorder_ctrl->enable = false; ++ preorder_ctrl->indicate_seq = 0xffff; ++ preorder_ctrl->wend_b = 0xffff; ++ preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ ++ } ++ bmc_sta = rtw_get_bcmc_stainfo(padapter); ++ if (bmc_sta) { ++ for (i = 0; i < 16; i++) { ++ /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ ++ preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; ++ preorder_ctrl->enable = false; ++ preorder_ctrl->indicate_seq = 0xffff; ++ preorder_ctrl->wend_b = 0xffff; ++ preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */ ++ } ++ } ++ /* misc. */ ++ update_sta_info(padapter, psta); ++ } ++ return psta; ++} ++ ++/* pnetwork: returns from rtw_joinbss_event_callback */ ++/* ptarget_wlan: found from scanned_queue */ ++static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ ++ DBG_88E("%s\n", __func__); ++ ++ /* why not use ptarget_wlan?? */ ++ memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); ++ /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */ ++ cur_network->network.IELength = ptarget_wlan->network.IELength; ++ memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ); ++ ++ cur_network->aid = pnetwork->join_res; ++ ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++ padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength; ++ padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality; ++ /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */ ++ padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength); ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++ ++ /* update fw_state will clr _FW_UNDER_LINKING here indirectly */ ++ switch (pnetwork->network.InfrastructureMode) { ++ case Ndis802_11Infrastructure: ++ if (pmlmepriv->fw_state & WIFI_UNDER_WPS) ++ pmlmepriv->fw_state = WIFI_STATION_STATE | WIFI_UNDER_WPS; ++ else ++ pmlmepriv->fw_state = WIFI_STATION_STATE; ++ break; ++ case Ndis802_11IBSS: ++ pmlmepriv->fw_state = WIFI_ADHOC_STATE; ++ break; ++ default: ++ pmlmepriv->fw_state = WIFI_NULL_STATE; ++ break; ++ } ++ ++ rtw_update_protection(padapter, (cur_network->network.IEs) + ++ sizeof(struct ndis_802_11_fixed_ie), ++ (cur_network->network.IELength)); ++ rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength); ++} ++ ++/* Notes: the function could be > passive_level (the same context as Rx tasklet) */ ++/* pnetwork: returns from rtw_joinbss_event_callback */ ++/* ptarget_wlan: found from scanned_queue */ ++/* if join_res > 0, for (fw_state == WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. */ ++/* if join_res > 0, for (fw_state == WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. */ ++/* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan != NULL). */ ++ ++void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) ++{ ++ u8 timer_cancelled; ++ struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct wlan_network *pnetwork = (struct wlan_network *)pbuf; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; ++ unsigned int the_same_macaddr = false; ++ ++ rtw_get_encrypt_decrypt_from_registrypriv(adapter); ++ ++ the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); ++ ++ pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network); ++ if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) ++ return; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (pnetwork->join_res > 0) { ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { ++ /* s1. find ptarget_wlan */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ if (the_same_macaddr) { ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ } else { ++ pcur_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ if (pcur_wlan) ++ pcur_wlan->fixed = false; ++ ++ pcur_sta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if (pcur_sta) { ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ rtw_free_stainfo(adapter, pcur_sta); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ } ++ ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ if (ptarget_wlan) ++ ptarget_wlan->fixed = true; ++ } ++ } ++ } else { ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ if (ptarget_wlan) ++ ptarget_wlan->fixed = true; ++ } ++ } ++ ++ /* s2. update cur_network */ ++ if (ptarget_wlan) { ++ rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork); ++ } else { ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ goto ignore_joinbss_callback; ++ } ++ ++ /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); ++ if (!ptarget_sta) { ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ goto ignore_joinbss_callback; ++ } ++ } ++ ++ /* s4. indicate connect */ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ pmlmepriv->cur_network_scanned = ptarget_wlan; ++ rtw_indicate_connect(adapter); ++ } ++ ++ /* s5. Cancle assoc_timer */ ++ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); ++ } else { ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ goto ignore_joinbss_callback; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ } else if (pnetwork->join_res == -4) { ++ rtw_reset_securitypriv(adapter); ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ } else { /* if join_res < 0 (join fails), then try again */ ++ _set_timer(&pmlmepriv->assoc_timer, 1); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ } ++ ++ignore_joinbss_callback: ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ struct wlan_network *pnetwork = (struct wlan_network *)pbuf; ++ ++ mlmeext_joinbss_event_callback(adapter, pnetwork->join_res); ++ ++ rtw_os_xmit_schedule(adapter); ++ ++} ++ ++static u8 search_max_mac_id(struct adapter *padapter) ++{ ++ u8 mac_id; ++#if defined(CONFIG_88EU_AP_MODE) ++ u8 aid; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++#endif ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++#if defined(CONFIG_88EU_AP_MODE) ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ for (aid = (pstapriv->max_num_sta); aid > 0; aid--) { ++ if (pstapriv->sta_aid[aid - 1]) ++ break; ++ } ++ mac_id = aid + 1; ++ } else ++#endif ++ {/* adhoc id = 31~2 */ ++ for (mac_id = (NUM_STA - 1); mac_id >= IBSS_START_MAC_ID; mac_id--) { ++ if (pmlmeinfo->FW_sta_info[mac_id].status == 1) ++ break; ++ } ++ } ++ return mac_id; ++} ++ ++/* FOR AP , AD-HOC mode */ ++void rtw_sta_media_status_rpt(struct adapter *adapter, struct sta_info *psta, ++ u32 mstatus) ++{ ++ u16 media_status_rpt; ++ u8 macid; ++ ++ if (!psta) ++ return; ++ ++ macid = search_max_mac_id(adapter); ++ rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&macid); ++ /* MACID|OPMODE:1 connect */ ++ media_status_rpt = (u16)((psta->mac_id << 8) | mstatus); ++ rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, ++ (u8 *)&media_status_rpt); ++} ++ ++void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ struct sta_info *psta; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ struct wlan_network *ptarget_wlan = NULL; ++ ++ if (!rtw_access_ctrl(adapter, pstassoc->macaddr)) ++ return; ++ ++#if defined(CONFIG_88EU_AP_MODE) ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if (psta) ++ rtw_indicate_sta_assoc_event(adapter, psta); ++ return; ++ } ++#endif ++ /* for AD-HOC mode */ ++ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if (psta) ++ /* the sta have been in sta_info_queue => do nothing */ ++ return; /* between drv has received this event before and fw have not yet to set key to CAM_ENTRY) */ ++ psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr); ++ if (!psta) ++ return; ++ /* to do: init sta_info variable */ ++ psta->qos_option = 0; ++ psta->mac_id = (uint)pstassoc->cam_id; ++ DBG_88E("%s\n", __func__); ++ /* for ad-hoc mode */ ++ rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, true); ++ rtw_sta_media_status_rpt(adapter, psta, 1); ++ if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ++ psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm; ++ psta->ieee8021x_blocked = false; ++ spin_lock_bh(&pmlmepriv->lock); ++ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) { ++ if (adapter->stapriv.asoc_sta_count == 2) { ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); ++ pmlmepriv->cur_network_scanned = ptarget_wlan; ++ if (ptarget_wlan) ++ ptarget_wlan->fixed = true; ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ ++ rtw_indicate_connect(adapter); ++ } ++ } ++ spin_unlock_bh(&pmlmepriv->lock); ++ mlmeext_sta_add_event_callback(adapter, psta); ++} ++ ++void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) ++{ ++ int mac_id = -1; ++ struct sta_info *psta; ++ struct wlan_network *pwlan = NULL; ++ struct wlan_bssid_ex *pdev_network = NULL; ++ u8 *pibss = NULL; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct stadel_event *pstadel = (struct stadel_event *)pbuf; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ ++ psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr); ++ if (psta) ++ mac_id = psta->mac_id; ++ else ++ mac_id = pstadel->mac_id; ++ ++ DBG_88E("%s(mac_id=%d)=%pM\n", __func__, mac_id, pstadel->macaddr); ++ ++ if (mac_id >= 0) { ++ u16 media_status; ++ media_status = (mac_id << 8) | 0; /* MACID|OPMODE:0 means disconnect */ ++ /* for STA, AP, ADHOC mode, report disconnect stauts to FW */ ++ rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ return; ++ ++ mlmeext_sta_del_event_callback(adapter); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ if (adapter->registrypriv.wifi_spec == 1) ++ rtw_set_roaming(adapter, 0); /* don't roam */ ++ else if (rtw_to_roaming(adapter) > 0) ++ pmlmepriv->to_roaming--; /* this stadel_event is caused by roaming, decrease to_roaming */ ++ else if (rtw_to_roaming(adapter) == 0) ++ rtw_set_roaming(adapter, ++ adapter->registrypriv.max_roaming_times); ++ ++ if (*((unsigned short *)(pstadel->rsvd)) != WLAN_REASON_EXPIRATION_CHK) ++ rtw_set_roaming(adapter, 0); /* don't roam */ ++ ++ rtw_free_uc_swdec_pending_queue(adapter); ++ ++ rtw_free_assoc_resources(adapter, 1); ++ rtw_indicate_disconnect(adapter); ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ /* remove the network entry in scanned_queue */ ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if (pwlan) { ++ pwlan->fixed = false; ++ rtw_free_network_nolock(pmlmepriv, pwlan); ++ } ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ _rtw_roaming(adapter, tgt_network); ++ } ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ rtw_free_stainfo(adapter, psta); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ if (adapter->stapriv.asoc_sta_count == 1) { /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ /* free old ibss network */ ++ pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); ++ if (pwlan) { ++ pwlan->fixed = false; ++ rtw_free_network_nolock(pmlmepriv, pwlan); ++ } ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ /* re-create ibss */ ++ pdev_network = &adapter->registrypriv.dev_network; ++ pibss = adapter->registrypriv.dev_network.MacAddress; ++ ++ memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); ++ ++ memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ rtw_update_registrypriv_dev_network(adapter); ++ ++ rtw_generate_random_ibss(pibss); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { ++ set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); ++ _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); ++ } ++ ++ rtw_createbss_cmd(adapter); ++ } ++ } ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++} ++ ++/* ++* _rtw_join_timeout_handler - Timeout/faliure handler for CMD JoinBss ++* @adapter: pointer to struct adapter structure ++*/ ++void _rtw_join_timeout_handler (struct adapter *adapter) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ int do_join_r; ++ ++ DBG_88E("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv)); ++ ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) ++ return; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (rtw_to_roaming(adapter) > 0) { /* join timeout caused by roaming */ ++ while (1) { ++ pmlmepriv->to_roaming--; ++ if (rtw_to_roaming(adapter) != 0) { /* try another */ ++ DBG_88E("%s try another roaming\n", __func__); ++ do_join_r = rtw_do_join(adapter); ++ if (_SUCCESS != do_join_r) { ++ DBG_88E("%s roaming do_join return %d\n", __func__, do_join_r); ++ continue; ++ } ++ break; ++ } else { ++ DBG_88E("%s We've try roaming but fail\n", __func__); ++ rtw_indicate_disconnect(adapter); ++ break; ++ } ++ } ++ } else { ++ rtw_indicate_disconnect(adapter); ++ free_scanqueue(pmlmepriv);/* */ ++ } ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++} ++ ++/* ++* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey ++* @adapter: pointer to struct adapter structure ++*/ ++void rtw_scan_timeout_handler (struct adapter *adapter) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ DBG_88E(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); ++ spin_lock_bh(&pmlmepriv->lock); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); ++ spin_unlock_bh(&pmlmepriv->lock); ++ rtw_indicate_scan_done(adapter, true); ++} ++ ++static void rtw_auto_scan_handler(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ /* auto site survey per 60sec */ ++ if (pmlmepriv->scan_interval > 0) { ++ pmlmepriv->scan_interval--; ++ if (pmlmepriv->scan_interval == 0) { ++ DBG_88E("%s\n", __func__); ++ rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); ++ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ ++ } ++ } ++} ++ ++void rtw_dynamic_check_timer_handlder(struct adapter *adapter) ++{ ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct registry_priv *pregistrypriv = &adapter->registrypriv; ++ ++ if (!adapter) ++ return; ++ if (!adapter->hw_init_completed) ++ return; ++ if ((adapter->bDriverStopped) || (adapter->bSurpriseRemoved)) ++ return; ++ if (adapter->net_closed) ++ return; ++ rtw_dynamic_chk_wk_cmd(adapter); ++ ++ if (pregistrypriv->wifi_spec == 1) { ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++#endif ++ { ++ /* auto site survey */ ++ rtw_auto_scan_handler(adapter); ++ } ++ } ++ ++ rcu_read_lock(); ++ ++ if (rcu_dereference(adapter->pnetdev->rx_handler_data) && ++ check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) { ++ /* expire NAT2.5 entry */ ++ nat25_db_expire(adapter); ++ ++ if (adapter->pppoe_connection_in_progress > 0) { ++ adapter->pppoe_connection_in_progress--; ++ } ++ ++ /* due to rtw_dynamic_check_timer_handlder() is called every 2 seconds */ ++ if (adapter->pppoe_connection_in_progress > 0) { ++ adapter->pppoe_connection_in_progress--; ++ } ++ } ++ ++ rcu_read_unlock(); ++} ++ ++#define RTW_SCAN_RESULT_EXPIRE 2000 ++ ++/* ++* Select a new join candidate from the original @param candidate and @param competitor ++* @return true: candidate is updated ++* @return false: candidate is not updated ++*/ ++static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv ++ , struct wlan_network **candidate, struct wlan_network *competitor) ++{ ++ int updated = false; ++ struct adapter *adapter = container_of(pmlmepriv, struct adapter, mlmepriv); ++ ++ /* check bssid, if needed */ ++ if (pmlmepriv->assoc_by_bssid) { ++ if (memcmp(competitor->network.MacAddress, pmlmepriv->assoc_bssid, ETH_ALEN)) ++ goto exit; ++ } ++ ++ /* check ssid, if needed */ ++ if (pmlmepriv->assoc_ssid.SsidLength) { ++ if (competitor->network.Ssid.SsidLength != pmlmepriv->assoc_ssid.SsidLength || ++ memcmp(competitor->network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength)) ++ goto exit; ++ } ++ ++ if (!rtw_is_desired_network(adapter, competitor)) ++ goto exit; ++ ++ if (rtw_to_roaming(adapter) > 0) { ++ if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= RTW_SCAN_RESULT_EXPIRE || ++ !is_same_ess(&competitor->network, &pmlmepriv->cur_network.network)) ++ goto exit; ++ } ++ ++ if (!*candidate || (*candidate)->network.Rssi < competitor->network.Rssi) { ++ *candidate = competitor; ++ updated = true; ++ } ++ if (updated) { ++ DBG_88E("[by_bssid:%u][assoc_ssid:%s]new candidate: %s(%pM rssi:%d\n", ++ pmlmepriv->assoc_by_bssid, ++ pmlmepriv->assoc_ssid.Ssid, ++ (*candidate)->network.Ssid.Ssid, ++ (*candidate)->network.MacAddress, ++ (int)(*candidate)->network.Rssi); ++ DBG_88E("[to_roaming:%u]\n", rtw_to_roaming(adapter)); ++ } ++ ++exit: ++ return updated; ++} ++ ++/* ++Calling context: ++The caller of the sub-routine will be in critical section... ++The caller must hold the following spinlock ++pmlmepriv->lock ++*/ ++ ++int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) ++{ ++ int ret; ++ struct list_head *phead; ++ struct adapter *adapter; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ struct wlan_network *candidate = NULL; ++ u8 supp_ant_div = false; ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ phead = get_list_head(queue); ++ adapter = (struct adapter *)pmlmepriv->nic_hdl; ++ pmlmepriv->pscanned = phead->next; ++ while (phead != pmlmepriv->pscanned) { ++ pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list); ++ if (!pnetwork) { ++ ret = _FAIL; ++ goto exit; ++ } ++ pmlmepriv->pscanned = pmlmepriv->pscanned->next; ++ rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork); ++ } ++ if (!candidate) { ++ DBG_88E("%s: return _FAIL(candidate==NULL)\n", __func__); ++ ret = _FAIL; ++ goto exit; ++ } else { ++ DBG_88E("%s: candidate: %s(%pM ch:%u)\n", __func__, ++ candidate->network.Ssid.Ssid, candidate->network.MacAddress, ++ candidate->network.Configuration.DSConfig); ++ } ++ ++ /* check for situation of _FW_LINKED */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ DBG_88E("%s: _FW_LINKED while ask_for_joinbss!!!\n", __func__); ++ ++ rtw_disassoc_cmd(adapter, 0, true); ++ rtw_indicate_disconnect(adapter); ++ rtw_free_assoc_resources(adapter, 0); ++ } ++ ++ rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(supp_ant_div)); ++ if (supp_ant_div) { ++ u8 cur_ant; ++ rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(cur_ant)); ++ DBG_88E("#### Opt_Ant_(%s), cur_Ant(%s)\n", ++ (2 == candidate->network.PhyInfo.Optimum_antenna) ? "A" : "B", ++ (2 == cur_ant) ? "A" : "B" ++ ); ++ } ++ ++ ret = rtw_joinbss_cmd(adapter, candidate); ++ ++exit: ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ return ret; ++} ++ ++int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv) ++{ ++ struct cmd_obj *pcmd; ++ struct setauth_parm *psetauthparm; ++ struct cmd_priv *pcmdpriv = &adapter->cmdpriv; ++ int res = _SUCCESS; ++ ++ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!pcmd) { ++ res = _FAIL; /* try again */ ++ goto exit; ++ } ++ ++ psetauthparm = kzalloc(sizeof(struct setauth_parm), GFP_KERNEL); ++ if (!psetauthparm) { ++ kfree(pcmd); ++ res = _FAIL; ++ goto exit; ++ } ++ memset(psetauthparm, 0, sizeof(struct setauth_parm)); ++ psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm; ++ pcmd->cmdcode = _SetAuth_CMD_; ++ pcmd->parmbuf = (unsigned char *)psetauthparm; ++ pcmd->cmdsz = (sizeof(struct setauth_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ INIT_LIST_HEAD(&pcmd->list); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++exit: ++ ++ return res; ++} ++ ++int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, int keyid, u8 set_tx) ++{ ++ u8 keylen; ++ struct cmd_obj *pcmd; ++ struct setkey_parm *psetkeyparm; ++ struct cmd_priv *pcmdpriv = &adapter->cmdpriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ int res = _SUCCESS; ++ ++ pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!pcmd) { ++ res = _FAIL; /* try again */ ++ goto exit; ++ } ++ psetkeyparm = kzalloc(sizeof(struct setkey_parm), GFP_KERNEL); ++ if (!psetkeyparm) { ++ kfree(pcmd); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ memset(psetkeyparm, 0, sizeof(struct setkey_parm)); ++ ++ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ++ psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy; ++ else ++ psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm; ++ psetkeyparm->keyid = (u8)keyid;/* 0~3 */ ++ psetkeyparm->set_tx = set_tx; ++ pmlmepriv->key_mask |= BIT(psetkeyparm->keyid); ++ DBG_88E("==> rtw_set_key algorithm(%x), keyid(%x), key_mask(%x)\n", ++ psetkeyparm->algorithm, psetkeyparm->keyid, pmlmepriv->key_mask); ++ ++ switch (psetkeyparm->algorithm) { ++ case _WEP40_: ++ keylen = 5; ++ memcpy(&psetkeyparm->key[0], &psecuritypriv->dot11DefKey[keyid].skey[0], keylen); ++ break; ++ case _WEP104_: ++ keylen = 13; ++ memcpy(&psetkeyparm->key[0], &psecuritypriv->dot11DefKey[keyid].skey[0], keylen); ++ break; ++ case _TKIP_: ++ keylen = 16; ++ memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); ++ psetkeyparm->grpkey = 1; ++ break; ++ case _AES_: ++ keylen = 16; ++ memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); ++ psetkeyparm->grpkey = 1; ++ break; ++ default: ++ res = _FAIL; ++ goto exit; ++ } ++ pcmd->cmdcode = _SetKey_CMD_; ++ pcmd->parmbuf = (u8 *)psetkeyparm; ++ pcmd->cmdsz = (sizeof(struct setkey_parm)); ++ pcmd->rsp = NULL; ++ pcmd->rspsz = 0; ++ INIT_LIST_HEAD(&pcmd->list); ++ res = rtw_enqueue_cmd(pcmdpriv, pcmd); ++exit: ++ return res; ++} ++ ++/* adjust IEs for rtw_joinbss_cmd in WMM */ ++int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len) ++{ ++ unsigned int ielength = 0; ++ unsigned int i, j; ++ ++ i = 12; /* after the fixed IE */ ++ while (i < in_len) { ++ ielength = initial_out_len; ++ ++ if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 && in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 && in_ie[i + 5] == 0x02 && i + 5 < in_len) { ++ /* WMM element ID and OUI */ ++ /* Append WMM IE to the last index of out_ie */ ++ ++ for (j = i; j < i + 9; j++) { ++ out_ie[ielength] = in_ie[j]; ++ ielength++; ++ } ++ out_ie[initial_out_len + 1] = 0x07; ++ out_ie[initial_out_len + 6] = 0x00; ++ out_ie[initial_out_len + 8] = 0x00; ++ break; ++ } ++ i += (in_ie[i + 1] + 2); /* to the next IE element */ ++ } ++ return ielength; ++} ++ ++/* */ ++/* Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */ ++/* Added by Annie, 2006-05-07. */ ++/* */ ++/* Search by BSSID, */ ++/* Return Value: */ ++/* -1 :if there is no pre-auth key in the table */ ++/* >= 0 :if there is pre-auth key, and return the entry id */ ++/* */ ++/* */ ++ ++static int SecIsInPMKIDList(struct adapter *Adapter, u8 *bssid) ++{ ++ struct security_priv *psecuritypriv = &Adapter->securitypriv; ++ int i = 0; ++ ++ do { ++ if ((psecuritypriv->PMKIDList[i].bUsed) && ++ (!memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN))) { ++ break; ++ } else { ++ i++; ++ /* continue; */ ++ } ++ ++ } while (i < NUM_PMKID_CACHE); ++ ++ if (i == NUM_PMKID_CACHE) { ++ i = -1;/* Could not find. */ ++ } else { ++ /* There is one Pre-Authentication Key for the specific BSSID. */ ++ } ++ return i; ++} ++ ++/* */ ++/* Check the RSN IE length */ ++/* If the RSN IE length <= 20, the RSN IE didn't include the PMKID information */ ++/* 0-11th element in the array are the fixed IE */ ++/* 12th element in the array is the IE */ ++/* 13th element in the array is the IE length */ ++/* */ ++ ++static int rtw_append_pmkid(struct adapter *Adapter, int iEntry, u8 *ie, uint ie_len) ++{ ++ struct security_priv *psecuritypriv = &Adapter->securitypriv; ++ ++ if (ie[13] <= 20) { ++ /* The RSN IE didn't include the PMK ID, append the PMK information */ ++ ie[ie_len] = 1; ++ ie_len++; ++ ie[ie_len] = 0; /* PMKID count = 0x0100 */ ++ ie_len++; ++ memcpy(&ie[ie_len], &psecuritypriv->PMKIDList[iEntry].PMKID, 16); ++ ++ ie_len += 16; ++ ie[13] += 18;/* PMKID length = 2+16 */ ++ } ++ return ie_len; ++} ++ ++int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len) ++{ ++ u8 authmode = 0; ++ uint ielength; ++ int iEntry; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ uint ndisauthmode = psecuritypriv->ndisauthtype; ++ ++ /* copy fixed ie only */ ++ memcpy(out_ie, in_ie, 12); ++ ielength = 12; ++ if ((ndisauthmode == Ndis802_11AuthModeWPA) || ++ (ndisauthmode == Ndis802_11AuthModeWPAPSK)) ++ authmode = _WPA_IE_ID_; ++ if ((ndisauthmode == Ndis802_11AuthModeWPA2) || ++ (ndisauthmode == Ndis802_11AuthModeWPA2PSK)) ++ authmode = _WPA2_IE_ID_; ++ ++ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { ++ memcpy(out_ie + ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len); ++ ++ ielength += psecuritypriv->wps_ie_len; ++ } else if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) { ++ /* copy RSN or SSN */ ++ memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1] + 2); ++ ielength += psecuritypriv->supplicant_ie[1] + 2; ++ rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie); ++ } ++ ++ iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); ++ if (iEntry < 0) { ++ return ielength; ++ } else { ++ if (authmode == _WPA2_IE_ID_) ++ ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength); ++ } ++ ++ return ielength; ++} ++ ++void rtw_init_registrypriv_dev_network(struct adapter *adapter) ++{ ++ struct registry_priv *pregistrypriv = &adapter->registrypriv; ++ struct eeprom_priv *peepriv = &adapter->eeprompriv; ++ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; ++ u8 *myhwaddr = myid(peepriv); ++ ++ memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN); ++ ++ memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ pdev_network->Configuration.Length = sizeof(struct ndis_802_11_config); ++ pdev_network->Configuration.BeaconPeriod = 100; ++ pdev_network->Configuration.FHConfig.Length = 0; ++ pdev_network->Configuration.FHConfig.HopPattern = 0; ++ pdev_network->Configuration.FHConfig.HopSet = 0; ++ pdev_network->Configuration.FHConfig.DwellTime = 0; ++ ++} ++ ++void rtw_update_registrypriv_dev_network(struct adapter *adapter) ++{ ++ int sz = 0; ++ struct registry_priv *pregistrypriv = &adapter->registrypriv; ++ struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; ++ ++ pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0); /* adhoc no 802.1x */ ++ ++ pdev_network->Rssi = 0; ++ ++ switch (pregistrypriv->wireless_mode) { ++ case WIRELESS_11B: ++ pdev_network->NetworkTypeInUse = (Ndis802_11DS); ++ break; ++ case WIRELESS_11G: ++ case WIRELESS_11BG: ++ case WIRELESS_11_24N: ++ case WIRELESS_11G_24N: ++ case WIRELESS_11BG_24N: ++ pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); ++ break; ++ default: ++ /* TODO */ ++ break; ++ } ++ ++ pdev_network->Configuration.DSConfig = (pregistrypriv->channel); ++ ++ if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) ++ pdev_network->Configuration.ATIMWindow = (0); ++ ++ pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode); ++ ++ /* 1. Supported rates */ ++ /* 2. IE */ ++ ++ sz = rtw_generate_ie(pregistrypriv); ++ pdev_network->IELength = sz; ++ pdev_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network); ++ ++ /* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */ ++ /* pdev_network->IELength = cpu_to_le32(sz); */ ++ ++} ++ ++void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter) ++{ ++ ++} ++ ++/* the function is at passive_level */ ++void rtw_joinbss_reset(struct adapter *padapter) ++{ ++ u8 threshold; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ /* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */ ++ pmlmepriv->num_FortyMHzIntolerant = 0; ++ ++ pmlmepriv->num_sta_no_ht = 0; ++ ++ phtpriv->ampdu_enable = false;/* reset to disabled */ ++ ++ /* TH = 1 => means that invalidate usb rx aggregation */ ++ /* TH = 0 => means that validate usb rx aggregation, use init value. */ ++ if (phtpriv->ht_option) { ++ if (padapter->registrypriv.wifi_spec == 1) ++ threshold = 1; ++ else ++ threshold = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); ++ } else { ++ threshold = 1; ++ rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); ++ } ++} ++ ++/* the function is >= passive_level */ ++unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len) ++{ ++ u32 ielen, out_len; ++ enum ht_cap_ampdu_factor max_rx_ampdu_factor; ++ unsigned char *p; ++ struct ieee80211_ht_cap ht_capie; ++ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ u32 rx_packet_offset, max_recvbuf_sz; ++ ++ phtpriv->ht_option = false; ++ ++ p = rtw_get_ie(in_ie + 12, _HT_CAPABILITY_IE_, &ielen, in_len - 12); ++ ++ if (p && ielen > 0) { ++ if (pqospriv->qos_option == 0) { ++ out_len = *pout_len; ++ rtw_set_ie(out_ie + out_len, _VENDOR_SPECIFIC_IE_, ++ _WMM_IE_Length_, WMM_IE, pout_len); ++ ++ pqospriv->qos_option = 1; ++ } ++ ++ out_len = *pout_len; ++ ++ memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap)); ++ ++ ht_capie.cap_info = cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ++ IEEE80211_HT_CAP_SGI_20 | ++ IEEE80211_HT_CAP_SGI_40 | ++ IEEE80211_HT_CAP_TX_STBC | ++ IEEE80211_HT_CAP_DSSSCCK40); ++ ++ 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); ++ ++ /* ++ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k ++ AMPDU_para [4:2]:Min MPDU Start Spacing ++ */ ++ ++ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); ++ ht_capie.ampdu_params_info = (max_rx_ampdu_factor & 0x03); ++ ++ if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) ++ ht_capie.ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & (0x07 << 2)); ++ else ++ ht_capie.ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & 0x00); ++ ++ rtw_set_ie(out_ie + out_len, _HT_CAPABILITY_IE_, ++ sizeof(struct ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len); ++ ++ phtpriv->ht_option = true; ++ ++ p = rtw_get_ie(in_ie + 12, _HT_ADD_INFO_IE_, &ielen, in_len - 12); ++ if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { ++ out_len = *pout_len; ++ rtw_set_ie(out_ie + out_len, _HT_ADD_INFO_IE_, ielen, p + 2, pout_len); ++ } ++ } ++ return phtpriv->ht_option; ++} ++ ++/* the function is > passive_level (in critical_section) */ ++void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len) ++{ ++ u8 *p, max_ampdu_sz; ++ int len; ++ struct ieee80211_ht_cap *pht_capie; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (!phtpriv->ht_option) ++ return; ++ ++ if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable)) ++ return; ++ ++ DBG_88E("+rtw_update_ht_cap()\n"); ++ ++ /* maybe needs check if ap supports rx ampdu. */ ++ if ((!phtpriv->ampdu_enable) && (pregistrypriv->ampdu_enable == 1)) { ++ if (pregistrypriv->wifi_spec == 1) ++ phtpriv->ampdu_enable = false; ++ else ++ phtpriv->ampdu_enable = true; ++ } else if (pregistrypriv->ampdu_enable == 2) { ++ phtpriv->ampdu_enable = true; ++ } ++ ++ /* check Max Rx A-MPDU Size */ ++ len = 0; ++ p = rtw_get_ie(pie + sizeof(struct ndis_802_11_fixed_ie), _HT_CAPABILITY_IE_, &len, ie_len - sizeof(struct ndis_802_11_fixed_ie)); ++ if (p && len > 0) { ++ pht_capie = (struct ieee80211_ht_cap *)(p + 2); ++ max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR); ++ max_ampdu_sz = 1 << (max_ampdu_sz + 3); /* max_ampdu_sz (kbytes); */ ++ phtpriv->rx_ampdu_maxlen = max_ampdu_sz; ++ } ++ len = 0; ++ p = rtw_get_ie(pie + sizeof(struct ndis_802_11_fixed_ie), _HT_ADD_INFO_IE_, &len, ie_len - sizeof(struct ndis_802_11_fixed_ie)); ++ ++ /* update cur_bwmode & cur_ch_offset */ ++ if ((pregistrypriv->cbw40_enable) && ++ (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & BIT(1)) && ++ (pmlmeinfo->HT_info.infos[0] & BIT(2))) { ++ int i; ++ u8 rf_type; ++ ++ padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ /* update the MCS rates */ ++ for (i = 0; i < 16; i++) { ++ if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ else ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; ++ } ++ /* switch to the 40M Hz mode according to the AP */ ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) { ++ case HT_EXTCHNL_OFFSET_UPPER: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ case HT_EXTCHNL_OFFSET_LOWER: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ default: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ } ++ ++ /* Config SM Power Save setting */ ++ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info) & 0x0C) >> 2; ++ if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) ++ DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); ++ ++ /* Config current HT Protection mode. */ ++ pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; ++} ++ ++void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ u8 issued; ++ int priority; ++ struct sta_info *psta = NULL; ++ struct ht_priv *phtpriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ if (is_multicast_ether_addr(pattrib->ra) || ++ padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100) ++ return; ++ ++ priority = pattrib->priority; ++ ++ if (pattrib->psta) ++ psta = pattrib->psta; ++ else ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ ++ if (!psta) ++ return; ++ ++ phtpriv = &psta->htpriv; ++ ++ if ((phtpriv->ht_option) && (phtpriv->ampdu_enable)) { ++ issued = (phtpriv->agg_enable_bitmap >> priority) & 0x1; ++ issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1; ++ ++ if (0 == issued) { ++ DBG_88E("rtw_issue_addbareq_cmd, p=%d\n", priority); ++ psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); ++ rtw_addbareq_cmd(padapter, (u8)priority, pattrib->ra); ++ } ++ } ++} ++ ++void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ _rtw_roaming(padapter, tgt_network); ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ int do_join_r; ++ ++ struct wlan_network *pnetwork; ++ ++ if (tgt_network) ++ pnetwork = tgt_network; ++ else ++ pnetwork = &pmlmepriv->cur_network; ++ ++ if (0 < rtw_to_roaming(padapter)) { ++ DBG_88E("roaming from %s(%pM length:%d\n", ++ pnetwork->network.Ssid.Ssid, pnetwork->network.MacAddress, ++ pnetwork->network.Ssid.SsidLength); ++ memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid, sizeof(struct ndis_802_11_ssid)); ++ ++ pmlmepriv->assoc_by_bssid = false; ++ ++ while (1) { ++ do_join_r = rtw_do_join(padapter); ++ if (_SUCCESS == do_join_r) { ++ break; ++ } else { ++ DBG_88E("roaming do_join return %d\n", do_join_r); ++ pmlmepriv->to_roaming--; ++ ++ if (0 < pmlmepriv->to_roaming) { ++ continue; ++ } else { ++ DBG_88E("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__); ++ rtw_indicate_disconnect(padapter); ++ break; ++ } ++ } ++ } ++ } ++} +diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c +new file mode 100644 +index 000000000000..5a472a4954b0 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c +@@ -0,0 +1,8327 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_MLME_EXT_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/wifi.h" ++#include "../include/rtw_mlme_ext.h" ++#include "../include/wlan_bssdef.h" ++#include "../include/mlme_osdep.h" ++#include "../include/recv_osdep.h" ++ ++static struct mlme_handler mlme_sta_tbl[] = { ++ {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, ++ {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, ++ {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, ++ {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, ++ {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, ++ {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, ++ ++ /*---------------------------------------------------------- ++ below 2 are reserved ++ -----------------------------------------------------------*/ ++ {0, "DoReserved", &DoReserved}, ++ {0, "DoReserved", &DoReserved}, ++ {WIFI_BEACON, "OnBeacon", &OnBeacon}, ++ {WIFI_ATIM, "OnATIM", &OnAtim}, ++ {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, ++ {WIFI_AUTH, "OnAuth", &OnAuthClient}, ++ {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, ++ {WIFI_ACTION, "OnAction", &OnAction}, ++}; ++ ++static struct action_handler OnAction_tbl[] = { ++ {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct}, ++ {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction_qos}, ++ {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction_dls}, ++ {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back}, ++ {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public}, ++ {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved}, ++ {RTW_WLAN_CATEGORY_FT, "ACTION_FT", &DoReserved}, ++ {RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht}, ++ {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved}, ++ {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm}, ++ {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p}, ++}; ++ ++static u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; ++ ++/************************************************** ++OUI definitions for the vendor specific IE ++***************************************************/ ++unsigned char RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; ++unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02}; ++unsigned char WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; ++unsigned char P2P_OUI[] = {0x50, 0x6F, 0x9A, 0x09}; ++unsigned char WFD_OUI[] = {0x50, 0x6F, 0x9A, 0x0A}; ++ ++unsigned char WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++unsigned char WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ ++unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02}; ++unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02}; ++ ++extern unsigned char REALTEK_96B_IE[]; ++ ++/******************************************************** ++MCS rate definitions ++*********************************************************/ ++unsigned char MCS_rate_2R[16] = {0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++unsigned char MCS_rate_1R[16] = {0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; ++ ++/******************************************************** ++ChannelPlan definitions ++*********************************************************/ ++static struct rt_channel_plan_2g RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = { ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */ ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, /* 0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */ ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* 0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */ ++ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, /* 0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */ ++ {{10, 11, 12, 13}, 4}, /* 0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */ ++ {{}, 0}, /* 0x05, RT_CHANNEL_DOMAIN_2G_NULL */ ++}; ++ ++static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { ++ /* 0x00 ~ 0x1F , Old Define ===== */ ++ {0x02}, /* 0x00, RT_CHANNEL_DOMAIN_FCC */ ++ {0x02}, /* 0x01, RT_CHANNEL_DOMAIN_IC */ ++ {0x01}, /* 0x02, RT_CHANNEL_DOMAIN_ETSI */ ++ {0x01}, /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */ ++ {0x01}, /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */ ++ {0x03}, /* 0x05, RT_CHANNEL_DOMAIN_MKK */ ++ {0x03}, /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */ ++ {0x01}, /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */ ++ {0x03}, /* 0x08, RT_CHANNEL_DOMAIN_TELEC */ ++ {0x03}, /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */ ++ {0x00}, /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */ ++ {0x02}, /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */ ++ {0x01}, /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */ ++ {0x02}, /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */ ++ {0x02}, /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */ ++ {0x02}, /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */ ++ {0x01}, /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */ ++ {0x02}, /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */ ++ {0x01}, /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ ++ {0x02}, /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */ ++ {0x00}, /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */ ++ {0x00}, /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */ ++ {0x03}, /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */ ++ {0x05}, /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */ ++ {0x02}, /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */ ++ {0x00}, /* 0x1A, */ ++ {0x00}, /* 0x1B, */ ++ {0x00}, /* 0x1C, */ ++ {0x00}, /* 0x1D, */ ++ {0x00}, /* 0x1E, */ ++ /* 0x20 ~ 0x7F , New Define ===== */ ++ {0x00}, /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */ ++ {0x01}, /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */ ++ {0x02}, /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */ ++ {0x03}, /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */ ++ {0x04}, /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */ ++ {0x02}, /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */ ++ {0x00}, /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */ ++ {0x03}, /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */ ++ {0x00}, /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */ ++ {0x00}, /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */ ++ {0x00}, /* 0x2A, */ ++ {0x00}, /* 0x2B, */ ++ {0x00}, /* 0x2C, */ ++ {0x00}, /* 0x2D, */ ++ {0x00}, /* 0x2E, */ ++ {0x00}, /* 0x2F, */ ++ {0x00}, /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */ ++ {0x00}, /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */ ++ {0x00}, /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */ ++ {0x00}, /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */ ++ {0x02}, /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */ ++ {0x00}, /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */ ++ {0x00}, /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */ ++ {0x03}, /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */ ++ {0x03}, /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */ ++ {0x02}, /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */ ++ {0x00}, /* 0x3A, */ ++ {0x00}, /* 0x3B, */ ++ {0x00}, /* 0x3C, */ ++ {0x00}, /* 0x3D, */ ++ {0x00}, /* 0x3E, */ ++ {0x00}, /* 0x3F, */ ++ {0x02}, /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */ ++ {0x03}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */ ++}; ++ ++static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; /* use the conbination for max channel numbers */ ++ ++/* ++ * Search the @param channel_num in given @param channel_set ++ * @ch_set: the given channel set ++ * @ch: the given channel number ++ * ++ * return the index of channel_num in channel_set, -1 if not found ++ */ ++int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch) ++{ ++ int i; ++ for (i = 0; ch_set[i].ChannelNum != 0; i++) { ++ if (ch == ch_set[i].ChannelNum) ++ break; ++ } ++ ++ if (i >= ch_set[i].ChannelNum) ++ return -1; ++ return i; ++} ++ ++/**************************************************************************** ++ ++Following are the initialization functions for WiFi MLME ++ ++*****************************************************************************/ ++ ++int init_hw_mlme_ext(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ return _SUCCESS; ++} ++ ++static void init_mlme_ext_priv_value(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ unsigned char mixed_datarate[NumRates] = { ++ _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, ++ _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, ++ _48M_RATE_, _54M_RATE_, 0xff ++ }; ++ unsigned char mixed_basicrate[NumRates] = { ++ _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, ++ _12M_RATE_, _24M_RATE_, 0xff, ++ }; ++ ++ atomic_set(&pmlmeext->event_seq, 0); ++ pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ ++ ++ pmlmeext->cur_channel = padapter->registrypriv.channel; ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmlmeext->retry = 0; ++ ++ pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; ++ ++ memcpy(pmlmeext->datarate, mixed_datarate, NumRates); ++ memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); ++ ++ pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; ++ ++ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; ++ pmlmeext->sitesurvey_res.channel_idx = 0; ++ pmlmeext->sitesurvey_res.bss_cnt = 0; ++ pmlmeext->scan_abort = false; ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ pmlmeinfo->reauth_count = 0; ++ pmlmeinfo->reassoc_count = 0; ++ pmlmeinfo->link_count = 0; ++ pmlmeinfo->auth_seq = 0; ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; ++ pmlmeinfo->key_index = 0; ++ pmlmeinfo->iv = 0; ++ ++ pmlmeinfo->enc_algo = _NO_PRIVACY_; ++ pmlmeinfo->authModeToggle = 0; ++ ++ memset(pmlmeinfo->chg_txt, 0, 128); ++ ++ pmlmeinfo->slotTime = SHORT_SLOT_TIME; ++ pmlmeinfo->preamble_mode = PREAMBLE_AUTO; ++ ++ pmlmeinfo->dialogToken = 0; ++ ++ pmlmeext->action_public_rxseq = 0xffff; ++ pmlmeext->action_public_dialog_token = 0xff; ++} ++ ++static int has_channel(struct rt_channel_info *channel_set, ++ u8 chanset_size, ++ u8 chan) { ++ int i; ++ ++ for (i = 0; i < chanset_size; i++) { ++ if (channel_set[i].ChannelNum == chan) ++ return 1; ++ } ++ return 0; ++} ++ ++static void init_channel_list(struct adapter *padapter, struct rt_channel_info *channel_set, ++ u8 chanset_size, ++ struct p2p_channels *channel_list) { ++ struct p2p_oper_class_map op_class[] = { ++ { IEEE80211G, 81, 1, 13, 1, BW20 }, ++ { IEEE80211G, 82, 14, 14, 1, BW20 }, ++ { -1, 0, 0, 0, 0, BW20 } ++ }; ++ ++ int cla, op; ++ ++ cla = 0; ++ ++ for (op = 0; op_class[op].op_class; op++) { ++ u8 ch; ++ struct p2p_oper_class_map *o = &op_class[op]; ++ struct p2p_reg_class *reg = NULL; ++ ++ for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { ++ if (!has_channel(channel_set, chanset_size, ch)) { ++ continue; ++ } ++ ++ if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc)) ++ continue; ++ ++ if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) && ++ ((BW40MINUS == o->bw) || (BW40PLUS == o->bw))) ++ continue; ++ ++ if (!reg) { ++ reg = &channel_list->reg_class[cla]; ++ cla++; ++ reg->reg_class = o->op_class; ++ reg->channels = 0; ++ } ++ reg->channel[reg->channels] = ch; ++ reg->channels++; ++ } ++ } ++ channel_list->reg_classes = cla; ++} ++ ++static u8 init_channel_set(struct adapter *padapter, u8 ChannelPlan, struct rt_channel_info *channel_set) ++{ ++ u8 index, chanset_size = 0; ++ u8 b2_4GBand = false; ++ u8 Index2G = 0; ++ ++ memset(channel_set, 0, sizeof(struct rt_channel_info) * MAX_CHANNEL_NUM); ++ ++ if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX && ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) { ++ DBG_88E("ChannelPlan ID %x error !!!!!\n", ChannelPlan); ++ return chanset_size; ++ } ++ ++ if (padapter->registrypriv.wireless_mode & WIRELESS_11G) { ++ b2_4GBand = true; ++ if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan) ++ Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; ++ else ++ Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; ++ } ++ ++ if (b2_4GBand) { ++ for (index = 0; index < RTW_ChannelPlan2G[Index2G].Len; index++) { ++ channel_set[chanset_size].ChannelNum = RTW_ChannelPlan2G[Index2G].Channel[index]; ++ ++ if ((RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN == ChannelPlan) ||/* Channel 1~11 is active, and 12~14 is passive */ ++ (RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == ChannelPlan)) { ++ if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11) ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14)) ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 == ChannelPlan || ++ RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) {/* channel 12~13, passive scan */ ++ if (channel_set[chanset_size].ChannelNum <= 11) ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ else ++ channel_set[chanset_size].ScanType = SCAN_PASSIVE; ++ } else { ++ channel_set[chanset_size].ScanType = SCAN_ACTIVE; ++ } ++ ++ chanset_size++; ++ } ++ } ++ return chanset_size; ++} ++ ++int init_mlme_ext_priv(struct adapter *padapter) ++{ ++ int res = _SUCCESS; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ pmlmeext->padapter = padapter; ++ ++ init_mlme_ext_priv_value(padapter); ++ pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq; ++ ++ init_mlme_ext_timer(padapter); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ init_mlme_ap_info(padapter); ++#endif ++ ++ pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set); ++ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); ++ ++ pmlmeext->chan_scan_time = SURVEY_TO; ++ pmlmeext->mlmeext_init = true; ++ ++ pmlmeext->active_keep_alive_check = true; ++ ++ return res; ++} ++ ++void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext) ++{ ++ struct adapter *padapter = pmlmeext->padapter; ++ ++ if (!padapter) ++ return; ++ ++ if (padapter->bDriverStopped) { ++ _cancel_timer_ex(&pmlmeext->survey_timer); ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ /* _cancel_timer_ex(&pmlmeext->ADDBA_timer); */ ++ } ++} ++ ++static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, struct recv_frame *precv_frame) ++{ ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ u8 *pframe = precv_frame->rx_data; ++ ++ if (ptable->func) { ++ /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ ++ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && ++ memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) ++ return; ++ ptable->func(padapter, precv_frame); ++ } ++} ++ ++void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ int index; ++ struct mlme_handler *ptable; ++#ifdef CONFIG_88EU_AP_MODE ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#endif /* CONFIG_88EU_AP_MODE */ ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ u8 *pframe = precv_frame->rx_data; ++ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe)); ++ ++ if (GetFrameType(pframe) != WIFI_MGT_TYPE) ++ return; ++ ++ /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ ++ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && ++ memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) ++ return; ++ ++ ptable = mlme_sta_tbl; ++ ++ index = GetFrameSubType(pframe) >> 4; ++ ++ if (index > 13) ++ return; ++ ptable += index; ++ ++ if (psta) { ++ if (GetRetry(pframe)) { ++ if (precv_frame->attrib.seq_num == psta->RxMgmtFrameSeqNum) { ++ /* drop the duplicate management frame */ ++ DBG_88E("Drop duplicate management frame with seq_num=%d.\n", precv_frame->attrib.seq_num); ++ return; ++ } ++ } ++ psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num; ++ } ++ ++#ifdef CONFIG_88EU_AP_MODE ++ switch (GetFrameSubType(pframe)) { ++ case WIFI_AUTH: ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ ptable->func = &OnAuth; ++ else ++ ptable->func = &OnAuthClient; ++ fallthrough; ++ case WIFI_ASSOCREQ: ++ case WIFI_REASSOCREQ: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ case WIFI_PROBEREQ: ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ else ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ case WIFI_BEACON: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ case WIFI_ACTION: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ break; ++ default: ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ rtw_hostapd_mlme_rx(padapter, precv_frame); ++ break; ++ } ++#else ++ _mgt_dispatcher(padapter, ptable, precv_frame); ++#endif ++} ++ ++#ifdef CONFIG_88EU_P2P ++static u32 p2p_listen_state_process(struct adapter *padapter, unsigned char *da) ++{ ++ bool response = true; ++ ++ /* do nothing if the device name is empty */ ++ if (!padapter->wdinfo.device_name_len) ++ response = false; ++ ++ if (response) ++ issue_probersp_p2p(padapter, da); ++ ++ return _SUCCESS; ++} ++#endif /* CONFIG_88EU_P2P */ ++ ++/**************************************************************************** ++ ++Following are the callback functions for each subtype of the management frames ++ ++*****************************************************************************/ ++ ++unsigned int OnProbeReq(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ unsigned int ielen; ++ unsigned char *p; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur = &pmlmeinfo->network; ++ u8 *pframe = precv_frame->rx_data; ++ uint len = precv_frame->len; ++ u8 is_valid_p2p_probereq = false; ++ ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 wifi_test_chk_rate = 1; ++ ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && ++ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) && ++ !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && ++ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) && ++ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)) { ++ /* mcs_rate = 0 -> CCK 1M rate */ ++ /* mcs_rate = 1 -> CCK 2M rate */ ++ /* mcs_rate = 2 -> CCK 5.5M rate */ ++ /* mcs_rate = 3 -> CCK 11M rate */ ++ /* In the P2P mode, the driver should not support the CCK rate */ ++ ++ /* Commented by Kurt 2012/10/16 */ ++ /* IOT issue: Google Nexus7 use 1M rate to send p2p_probe_req after GO nego completed and Nexus7 is client */ ++ if (wifi_test_chk_rate == 1) { ++ is_valid_p2p_probereq = process_probe_req_p2p_ie(pwdinfo, pframe, len); ++ if (is_valid_p2p_probereq) { ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { ++ /* FIXME */ ++ report_survey_event(padapter, precv_frame); ++ p2p_listen_state_process(padapter, get_sa(pframe)); ++ ++ return _SUCCESS; ++ } ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ goto _continue; ++ } ++ } ++ } ++ ++_continue: ++#endif /* CONFIG_88EU_P2P */ ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ return _SUCCESS; ++ ++ if (!check_fwstate(pmlmepriv, _FW_LINKED) && ++ !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE)) ++ return _SUCCESS; ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); ++ ++ /* check (wildcard) SSID */ ++ if (p) { ++ if (is_valid_p2p_probereq) ++ goto _issue_probersp; ++ ++ if ((ielen != 0 && memcmp((void *)(p + 2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) || ++ (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) ++ return _SUCCESS; ++ ++_issue_probersp: ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) && ++ (pmlmepriv->cur_network.join_res || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) ++ issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq); ++ } ++ return _SUCCESS; ++} ++ ++unsigned int OnProbeRsp(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 *pframe = precv_frame->rx_data; ++#endif ++ ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { ++ if (pwdinfo->tx_prov_disc_info.benable) { ++ if (!memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr2Ptr(pframe), ETH_ALEN)) { ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { ++ pwdinfo->tx_prov_disc_info.benable = false; ++ issue_p2p_provision_request(padapter, ++ pwdinfo->tx_prov_disc_info.ssid.Ssid, ++ pwdinfo->tx_prov_disc_info.ssid.SsidLength, ++ pwdinfo->tx_prov_disc_info.peerDevAddr); ++ } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ pwdinfo->tx_prov_disc_info.benable = false; ++ issue_p2p_provision_request(padapter, NULL, 0, ++ pwdinfo->tx_prov_disc_info.peerDevAddr); ++ } ++ } ++ } ++ return _SUCCESS; ++ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { ++ if (pwdinfo->nego_req_info.benable) { ++ DBG_88E("[%s] P2P State is GONEGO ING!\n", __func__); ++ if (!memcmp(pwdinfo->nego_req_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN)) { ++ pwdinfo->nego_req_info.benable = false; ++ issue_p2p_GO_request(padapter, pwdinfo->nego_req_info.peerDevAddr); ++ } ++ } ++ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) { ++ if (pwdinfo->invitereq_info.benable) { ++ DBG_88E("[%s] P2P_STATE_TX_INVITE_REQ!\n", __func__); ++ if (!memcmp(pwdinfo->invitereq_info.peer_macaddr, GetAddr2Ptr(pframe), ETH_ALEN)) { ++ pwdinfo->invitereq_info.benable = false; ++ issue_p2p_invitation_request(padapter, pwdinfo->invitereq_info.peer_macaddr); ++ } ++ } ++ } ++#endif ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { ++ report_survey_event(padapter, precv_frame); ++ return _SUCCESS; ++ } ++ ++ return _SUCCESS; ++} ++ ++unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ int cam_idx; ++ struct sta_info *psta; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->rx_data; ++ uint len = precv_frame->len; ++ struct wlan_bssid_ex *pbss; ++ int ret = _SUCCESS; ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { ++ report_survey_event(padapter, precv_frame); ++ return _SUCCESS; ++ } ++ ++ if (!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) { ++ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { ++ /* we should update current network before auth, or some IE is wrong */ ++ pbss = kmalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC); ++ if (pbss) { ++ if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) { ++ update_network(&pmlmepriv->cur_network.network, pbss, padapter, true); ++ rtw_get_bcn_info(&pmlmepriv->cur_network); ++ } ++ kfree(pbss); ++ } ++ ++ /* check the vendor of the assoc AP */ ++ pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe + sizeof(struct rtw_ieee80211_hdr_3addr), len - sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ /* update TSF Value */ ++ update_TSF(pmlmeext, pframe, len); ++ ++ /* start auth */ ++ start_clnt_auth(padapter); ++ ++ return _SUCCESS; ++ } ++ ++ if (((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (psta) { ++ ret = rtw_check_bcn_info(padapter, pframe, len); ++ if (!ret) { ++ DBG_88E_LEVEL(_drv_info_, "ap has changed, disconnect now\n "); ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress, 0); ++ return _SUCCESS; ++ } ++ /* update WMM, ERP in the beacon */ ++ /* todo: the timer is used instead of the number of the beacon received */ ++ if ((sta_rx_pkts(psta) & 0xf) == 0) ++ update_beacon_info(padapter, pframe, len, psta); ++ process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN)); ++ } ++ } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (psta) { ++ /* update WMM, ERP in the beacon */ ++ /* todo: the timer is used instead of the number of the beacon received */ ++ if ((sta_rx_pkts(psta) & 0xf) == 0) ++ update_beacon_info(padapter, pframe, len, psta); ++ } else { ++ /* allocate a new CAM entry for IBSS station */ ++ cam_idx = allocate_fw_sta_entry(padapter); ++ if (cam_idx == NUM_STA) ++ goto _END_ONBEACON_; ++ ++ /* get supported rate */ ++ if (update_sta_support_rate(padapter, (pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_), (len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) { ++ pmlmeinfo->FW_sta_info[cam_idx].status = 0; ++ goto _END_ONBEACON_; ++ } ++ ++ /* update TSF Value */ ++ update_TSF(pmlmeext, pframe, len); ++ ++ /* report sta add event */ ++ report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx); ++ } ++ } ++ } ++ ++_END_ONBEACON_: ++ ++ return _SUCCESS; ++} ++ ++unsigned int OnAuth(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++#ifdef CONFIG_88EU_AP_MODE ++ unsigned int auth_mode, ie_len; ++ u16 seq; ++ unsigned char *sa, *p; ++ u16 algorithm; ++ int status; ++ static struct sta_info stat; ++ struct sta_info *pstat = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 *pframe = precv_frame->rx_data; ++ uint len = precv_frame->len; ++ ++ if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) ++ return _FAIL; ++ ++ DBG_88E("+OnAuth\n"); ++ ++ sa = GetAddr2Ptr(pframe); ++ ++ auth_mode = psecuritypriv->dot11AuthAlgrthm; ++ seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + 2)); ++ algorithm = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN)); ++ ++ DBG_88E("auth alg=%x, seq=%X\n", algorithm, seq); ++ ++ if (auth_mode == 2 && psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && ++ psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) ++ auth_mode = 0; ++ ++ if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */ ++ (algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */ ++ DBG_88E("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n", ++ algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); ++ ++ status = _STATS_NO_SUPP_ALG_; ++ ++ goto auth_fail; ++ } ++ ++ if (!rtw_access_ctrl(padapter, sa)) { ++ status = _STATS_UNABLE_HANDLE_STA_; ++ goto auth_fail; ++ } ++ ++ pstat = rtw_get_stainfo(pstapriv, sa); ++ if (!pstat) { ++ /* allocate a new one */ ++ DBG_88E("going to alloc stainfo for sa=%pM\n", sa); ++ pstat = rtw_alloc_stainfo(pstapriv, sa); ++ if (!pstat) { ++ DBG_88E(" Exceed the upper limit of supported clients...\n"); ++ status = _STATS_UNABLE_HANDLE_STA_; ++ goto auth_fail; ++ } ++ ++ pstat->state = WIFI_FW_AUTH_NULL; ++ pstat->auth_seq = 0; ++ } else { ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (!list_empty(&pstat->asoc_list)) { ++ list_del_init(&pstat->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ if (seq == 1) { ++ /* TODO: STA re_auth and auth timeout */ ++ } ++ } ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ if (list_empty(&pstat->auth_list)) { ++ list_add_tail(&pstat->auth_list, &pstapriv->auth_list); ++ pstapriv->auth_list_cnt++; ++ } ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ if (pstat->auth_seq == 0) ++ pstat->expire_to = pstapriv->auth_to; ++ ++ if ((pstat->auth_seq + 1) != seq) { ++ DBG_88E("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", ++ seq, pstat->auth_seq + 1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ ++ if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) { ++ if (seq == 1) { ++ pstat->state &= ~WIFI_FW_AUTH_NULL; ++ pstat->state |= WIFI_FW_AUTH_SUCCESS; ++ pstat->expire_to = pstapriv->assoc_to; ++ pstat->authalg = algorithm; ++ } else { ++ DBG_88E("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", ++ seq, pstat->auth_seq + 1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ } else { /* shared system or auto authentication */ ++ if (seq == 1) { ++ /* prepare for the challenging txt... */ ++ ++ pstat->state &= ~WIFI_FW_AUTH_NULL; ++ pstat->state |= WIFI_FW_AUTH_STATE; ++ pstat->authalg = algorithm; ++ pstat->auth_seq = 2; ++ } else if (seq == 3) { ++ /* checking for challenging txt... */ ++ DBG_88E("checking for challenging txt...\n"); ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&ie_len, ++ len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); ++ ++ if (!p || ie_len <= 0) { ++ DBG_88E("auth rejected because challenge failure!(1)\n"); ++ status = _STATS_CHALLENGE_FAIL_; ++ goto auth_fail; ++ } ++ ++ if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) { ++ pstat->state &= (~WIFI_FW_AUTH_STATE); ++ pstat->state |= WIFI_FW_AUTH_SUCCESS; ++ /* challenging txt is correct... */ ++ pstat->expire_to = pstapriv->assoc_to; ++ } else { ++ DBG_88E("auth rejected because challenge failure!\n"); ++ status = _STATS_CHALLENGE_FAIL_; ++ goto auth_fail; ++ } ++ } else { ++ DBG_88E("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", ++ seq, pstat->auth_seq + 1); ++ status = _STATS_OUT_OF_AUTH_SEQ_; ++ goto auth_fail; ++ } ++ } ++ ++ /* Now, we are going to issue_auth... */ ++ pstat->auth_seq = seq + 1; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_)); ++#endif ++ ++ if (pstat->state & WIFI_FW_AUTH_SUCCESS) ++ pstat->auth_seq = 0; ++ ++ return _SUCCESS; ++ ++auth_fail: ++ ++ if (pstat) ++ rtw_free_stainfo(padapter, pstat); ++ ++ pstat = &stat; ++ memset((char *)pstat, '\0', sizeof(stat)); ++ pstat->auth_seq = 2; ++ memcpy(pstat->hwaddr, sa, 6); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ issue_auth(padapter, pstat, (unsigned short)status); ++#endif ++ ++#endif ++ return _FAIL; ++} ++ ++unsigned int OnAuthClient(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ unsigned int seq, len, status, offset; ++ unsigned char *p; ++ unsigned int go2asoc = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 *pframe = precv_frame->rx_data; ++ uint pkt_len = precv_frame->len; ++ ++ DBG_88E("%s\n", __func__); ++ ++ /* check A1 matches or not */ ++ if (memcmp(myid(&padapter->eeprompriv), get_da(pframe), ETH_ALEN)) ++ return _SUCCESS; ++ ++ if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) ++ return _SUCCESS; ++ ++ offset = (GetPrivacy(pframe)) ? 4 : 0; ++ ++ seq = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 2)); ++ status = le16_to_cpu(*(__le16 *)((size_t)pframe + WLAN_HDR_A3_LEN + offset + 4)); ++ ++ if (status != 0) { ++ DBG_88E("clnt auth fail, status: %d\n", status); ++ if (status == 13) { /* pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; ++ else ++ pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; ++ } ++ ++ set_link_timer(pmlmeext, 1); ++ goto authclnt_fail; ++ } ++ ++ if (seq == 2) { ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) { ++ /* legendary shared system */ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, ++ pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); ++ ++ if (!p) ++ goto authclnt_fail; ++ ++ memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); ++ pmlmeinfo->auth_seq = 3; ++ issue_auth(padapter, NULL, 0); ++ set_link_timer(pmlmeext, REAUTH_TO); ++ ++ return _SUCCESS; ++ } else { ++ /* open system */ ++ go2asoc = 1; ++ } ++ } else if (seq == 4) { ++ if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ++ go2asoc = 1; ++ else ++ goto authclnt_fail; ++ } else { ++ /* this is also illegal */ ++ goto authclnt_fail; ++ } ++ ++ if (go2asoc) { ++ DBG_88E_LEVEL(_drv_info_, "auth success, start assoc\n"); ++ start_clnt_assoc(padapter); ++ return _SUCCESS; ++ } ++authclnt_fail: ++ return _FAIL; ++} ++ ++unsigned int OnAssocReq(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++#ifdef CONFIG_88EU_AP_MODE ++ u16 capab_info; ++ struct rtw_ieee802_11_elems elems; ++ struct sta_info *pstat; ++ unsigned char reassoc, *p, *pos, *wpa_ie; ++ unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; ++ int i, ie_len, wpa_ie_len, left; ++ unsigned char supportRate[16]; ++ int supportRateNum; ++ unsigned short status = _STATS_SUCCESSFUL_; ++ unsigned short frame_type, ie_offset = 0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur = &pmlmeinfo->network; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->rx_data; ++ uint pkt_len = precv_frame->len; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 p2p_status_code = P2P_STATUS_SUCCESS; ++ u8 *p2pie; ++ u32 p2pielen = 0; ++#endif /* CONFIG_88EU_P2P */ ++ ++ if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) ++ return _FAIL; ++ ++ frame_type = GetFrameSubType(pframe); ++ if (frame_type == WIFI_ASSOCREQ) { ++ reassoc = 0; ++ ie_offset = _ASOCREQ_IE_OFFSET_; ++ } else { /* WIFI_REASSOCREQ */ ++ reassoc = 1; ++ ie_offset = _REASOCREQ_IE_OFFSET_; ++ } ++ ++ if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) { ++ DBG_88E("handle_assoc(reassoc=%d) - too short payload (len=%lu)" ++ "\n", reassoc, (unsigned long)pkt_len); ++ return _FAIL; ++ } ++ ++ pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (pstat == (struct sta_info *)NULL) { ++ status = _RSON_CLS2_; ++ goto asoc_class2_error; ++ } ++ ++ capab_info = get_unaligned_le16(pframe + WLAN_HDR_A3_LEN); ++ ++ left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset); ++ pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset); ++ ++ DBG_88E("%s\n", __func__); ++ ++ /* check if this stat has been successfully authenticated/assocated */ ++ if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) { ++ if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) { ++ status = _RSON_CLS2_; ++ goto asoc_class2_error; ++ } else { ++ pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); ++ pstat->state |= WIFI_FW_ASSOC_STATE; ++ } ++ } else { ++ pstat->state &= (~WIFI_FW_AUTH_SUCCESS); ++ pstat->state |= WIFI_FW_ASSOC_STATE; ++ } ++ pstat->capability = capab_info; ++ /* now parse all ieee802_11 ie to point to elems */ ++ if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || ++ !elems.ssid) { ++ DBG_88E("STA %pM sent invalid association request\n", ++ pstat->hwaddr); ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } ++ ++ /* now we should check all the fields... */ ++ /* checking SSID */ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len, ++ pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (!p) ++ status = _STATS_FAILURE_; ++ ++ if (ie_len == 0) { /* broadcast ssid, however it is not allowed in assocreq */ ++ status = _STATS_FAILURE_; ++ } else { ++ /* check if ssid match */ ++ if (memcmp((void *)(p + 2), cur->Ssid.Ssid, cur->Ssid.SsidLength)) ++ status = _STATS_FAILURE_; ++ ++ if (ie_len != cur->Ssid.SsidLength) ++ status = _STATS_FAILURE_; ++ } ++ ++ if (_STATS_SUCCESSFUL_ != status) ++ goto OnAssocReqFail; ++ ++ /* check if the supported rate is ok */ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (!p) { ++ DBG_88E("Rx a sta assoc-req which supported rate is empty!\n"); ++ /* use our own rate set as statoin used */ ++ /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */ ++ /* supportRateNum = AP_BSSRATE_LEN; */ ++ ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } else { ++ memcpy(supportRate, p + 2, ie_len); ++ supportRateNum = ie_len; ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _EXT_SUPPORTEDRATES_IE_, &ie_len, ++ pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p) { ++ if (supportRateNum <= sizeof(supportRate)) { ++ memcpy(supportRate + supportRateNum, p + 2, ie_len); ++ supportRateNum += ie_len; ++ } ++ } ++ } ++ ++ /* todo: mask supportRate between AP & STA -> move to update raid */ ++ /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */ ++ ++ /* update station supportRate */ ++ pstat->bssratelen = supportRateNum; ++ memcpy(pstat->bssrateset, supportRate, supportRateNum); ++ UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen); ++ ++ /* check RSN/WPA/WPS */ ++ pstat->dot8021xalg = 0; ++ pstat->wpa_psk = 0; ++ pstat->wpa_group_cipher = 0; ++ pstat->wpa2_group_cipher = 0; ++ pstat->wpa_pairwise_cipher = 0; ++ pstat->wpa2_pairwise_cipher = 0; ++ memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); ++ if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { ++ int group_cipher = 0, pairwise_cipher = 0; ++ ++ wpa_ie = elems.rsn_ie; ++ wpa_ie_len = elems.rsn_ie_len; ++ ++ if (rtw_parse_wpa2_ie(wpa_ie - 2, wpa_ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { ++ pstat->dot8021xalg = 1;/* psk, todo:802.1x */ ++ pstat->wpa_psk |= BIT(1); ++ ++ pstat->wpa2_group_cipher = group_cipher & psecuritypriv->wpa2_group_cipher; ++ pstat->wpa2_pairwise_cipher = pairwise_cipher & psecuritypriv->wpa2_pairwise_cipher; ++ ++ if (!pstat->wpa2_group_cipher) ++ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; ++ ++ if (!pstat->wpa2_pairwise_cipher) ++ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; ++ } else { ++ status = WLAN_STATUS_INVALID_IE; ++ } ++ } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { ++ int group_cipher = 0, pairwise_cipher = 0; ++ ++ wpa_ie = elems.wpa_ie; ++ wpa_ie_len = elems.wpa_ie_len; ++ ++ if (rtw_parse_wpa_ie(wpa_ie - 2, wpa_ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { ++ pstat->dot8021xalg = 1;/* psk, todo:802.1x */ ++ pstat->wpa_psk |= BIT(0); ++ ++ pstat->wpa_group_cipher = group_cipher & psecuritypriv->wpa_group_cipher; ++ pstat->wpa_pairwise_cipher = pairwise_cipher & psecuritypriv->wpa_pairwise_cipher; ++ ++ if (!pstat->wpa_group_cipher) ++ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; ++ ++ if (!pstat->wpa_pairwise_cipher) ++ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; ++ } else { ++ status = WLAN_STATUS_INVALID_IE; ++ } ++ } else { ++ wpa_ie = NULL; ++ wpa_ie_len = 0; ++ } ++ ++ if (_STATS_SUCCESSFUL_ != status) ++ goto OnAssocReqFail; ++ ++ pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); ++ if (!wpa_ie) { ++ if (elems.wps_ie) { ++ DBG_88E("STA included WPS IE in " ++ "(Re)Association Request - assume WPS is " ++ "used\n"); ++ pstat->flags |= WLAN_STA_WPS; ++ /* wpabuf_free(sta->wps_ie); */ ++ /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ ++ /* elems.wps_ie_len - 4); */ ++ } else { ++ DBG_88E("STA did not include WPA/RSN IE " ++ "in (Re)Association Request - possible WPS " ++ "use\n"); ++ pstat->flags |= WLAN_STA_MAYBE_WPS; ++ } ++ ++ /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ ++ /* that the selected registrar of AP is _FLASE */ ++ if ((psecuritypriv->wpa_psk > 0) && (pstat->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { ++ if (pmlmepriv->wps_beacon_ie) { ++ u8 selected_registrar = 0; ++ ++ rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR, &selected_registrar, NULL); ++ ++ if (!selected_registrar) { ++ DBG_88E("selected_registrar is false , or AP is not ready to do WPS\n"); ++ ++ status = _STATS_UNABLE_HANDLE_STA_; ++ ++ goto OnAssocReqFail; ++ } ++ } ++ } ++ } else { ++ int copy_len; ++ ++ if (psecuritypriv->wpa_psk == 0) { ++ DBG_88E("STA %pM: WPA/RSN IE in association " ++ "request, but AP don't support WPA/RSN\n", pstat->hwaddr); ++ ++ status = WLAN_STATUS_INVALID_IE; ++ ++ goto OnAssocReqFail; ++ } ++ ++ if (elems.wps_ie) { ++ DBG_88E("STA included WPS IE in " ++ "(Re)Association Request - WPS is " ++ "used\n"); ++ pstat->flags |= WLAN_STA_WPS; ++ copy_len = 0; ++ } else { ++ copy_len = ((wpa_ie_len + 2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)) : (wpa_ie_len + 2); ++ } ++ if (copy_len > 0) ++ memcpy(pstat->wpa_ie, wpa_ie - 2, copy_len); ++ } ++ /* check if there is WMM IE & support WWM-PS */ ++ pstat->flags &= ~WLAN_STA_WME; ++ pstat->qos_option = 0; ++ pstat->qos_info = 0; ++ pstat->has_legacy_ac = true; ++ pstat->uapsd_vo = 0; ++ pstat->uapsd_vi = 0; ++ pstat->uapsd_be = 0; ++ pstat->uapsd_bk = 0; ++ if (pmlmepriv->qospriv.qos_option) { ++ p = pframe + WLAN_HDR_A3_LEN + ie_offset; ie_len = 0; ++ for (;;) { ++ p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); ++ if (p) { ++ if (!memcmp(p + 2, WMM_IE, 6)) { ++ pstat->flags |= WLAN_STA_WME; ++ ++ pstat->qos_option = 1; ++ pstat->qos_info = *(p + 8); ++ ++ pstat->max_sp_len = (pstat->qos_info >> 5) & 0x3; ++ ++ if ((pstat->qos_info & 0xf) != 0xf) ++ pstat->has_legacy_ac = true; ++ else ++ pstat->has_legacy_ac = false; ++ ++ if (pstat->qos_info & 0xf) { ++ if (pstat->qos_info & BIT(0)) ++ pstat->uapsd_vo = BIT(0) | BIT(1); ++ else ++ pstat->uapsd_vo = 0; ++ ++ if (pstat->qos_info & BIT(1)) ++ pstat->uapsd_vi = BIT(0) | BIT(1); ++ else ++ pstat->uapsd_vi = 0; ++ ++ if (pstat->qos_info & BIT(2)) ++ pstat->uapsd_bk = BIT(0) | BIT(1); ++ else ++ pstat->uapsd_bk = 0; ++ ++ if (pstat->qos_info & BIT(3)) ++ pstat->uapsd_be = BIT(0) | BIT(1); ++ else ++ pstat->uapsd_be = 0; ++ } ++ break; ++ } ++ } else { ++ break; ++ } ++ p = p + ie_len + 2; ++ } ++ } ++ ++ /* save HT capabilities in the sta object */ ++ memset(&pstat->htpriv.ht_cap, 0, sizeof(struct ieee80211_ht_cap)); ++ if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_cap)) { ++ pstat->flags |= WLAN_STA_HT; ++ ++ pstat->flags |= WLAN_STA_WME; ++ ++ memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct ieee80211_ht_cap)); ++ } else { ++ pstat->flags &= ~WLAN_STA_HT; ++ } ++ if ((!pmlmepriv->htpriv.ht_option) && (pstat->flags & WLAN_STA_HT)) { ++ status = _STATS_FAILURE_; ++ goto OnAssocReqFail; ++ } ++ ++ if ((pstat->flags & WLAN_STA_HT) && ++ ((pstat->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) || ++ (pstat->wpa_pairwise_cipher & WPA_CIPHER_TKIP))) { ++ DBG_88E("HT: %pM tried to " ++ "use TKIP with HT association\n", pstat->hwaddr); ++ ++ /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */ ++ /* goto OnAssocReqFail; */ ++ } ++ ++ pstat->flags |= WLAN_STA_NONERP; ++ for (i = 0; i < pstat->bssratelen; i++) { ++ if ((pstat->bssrateset[i] & 0x7f) > 22) { ++ pstat->flags &= ~WLAN_STA_NONERP; ++ break; ++ } ++ } ++ ++ if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) ++ pstat->flags |= WLAN_STA_SHORT_PREAMBLE; ++ else ++ pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; ++ ++ if (status != _STATS_SUCCESSFUL_) ++ goto OnAssocReqFail; ++ ++#ifdef CONFIG_88EU_P2P ++ pstat->is_p2p_device = false; ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, pkt_len - WLAN_HDR_A3_LEN - ie_offset, NULL, &p2pielen); ++ if (p2pie) { ++ pstat->is_p2p_device = true; ++ p2p_status_code = (u8)process_assoc_req_p2p_ie(pwdinfo, pframe, pkt_len, pstat); ++ if (p2p_status_code > 0) { ++ pstat->p2p_status_code = p2p_status_code; ++ status = _STATS_CAP_FAIL_; ++ goto OnAssocReqFail; ++ } ++ } ++ } ++ pstat->p2p_status_code = p2p_status_code; ++#endif /* CONFIG_88EU_P2P */ ++ ++ /* TODO: identify_proprietary_vendor_ie(); */ ++ /* Realtek proprietary IE */ ++ /* identify if this is Broadcom sta */ ++ /* identify if this is ralink sta */ ++ /* Customer proprietary IE */ ++ ++ /* get a unique AID */ ++ if (pstat->aid > 0) { ++ DBG_88E(" old AID %d\n", pstat->aid); ++ } else { ++ for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) ++ if (!pstapriv->sta_aid[pstat->aid - 1]) ++ break; ++ ++ /* if (pstat->aid > NUM_STA) { */ ++ if (pstat->aid > pstapriv->max_num_sta) { ++ pstat->aid = 0; ++ ++ DBG_88E(" no room for more AIDs\n"); ++ ++ status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; ++ ++ goto OnAssocReqFail; ++ } else { ++ pstapriv->sta_aid[pstat->aid - 1] = pstat; ++ DBG_88E("allocate new AID=(%d)\n", pstat->aid); ++ } ++ } ++ ++ pstat->state &= (~WIFI_FW_ASSOC_STATE); ++ pstat->state |= WIFI_FW_ASSOC_SUCCESS; ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ if (!list_empty(&pstat->auth_list)) { ++ list_del_init(&pstat->auth_list); ++ pstapriv->auth_list_cnt--; ++ } ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&pstat->asoc_list)) { ++ pstat->expire_to = pstapriv->expire_to; ++ list_add_tail(&pstat->asoc_list, &pstapriv->asoc_list); ++ pstapriv->asoc_list_cnt++; ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ /* now the station is qualified to join our BSS... */ ++ if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) { ++#ifdef CONFIG_88EU_AP_MODE ++ /* 1 bss_cap_update & sta_info_update */ ++ bss_cap_update_on_sta_join(padapter, pstat); ++ sta_info_update(padapter, pstat); ++ ++ /* issue assoc rsp before notify station join event. */ ++ if (frame_type == WIFI_ASSOCREQ) ++ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); ++ else ++ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); ++ ++ /* 2 - report to upper layer */ ++ DBG_88E("indicate_sta_join_event to upper layer - hostapd\n"); ++ rtw_indicate_sta_assoc_event(padapter, pstat); ++ ++ /* 3-(1) report sta add event */ ++ report_add_sta_event(padapter, pstat->hwaddr, pstat->aid); ++#endif ++ } ++ ++ return _SUCCESS; ++ ++asoc_class2_error: ++ ++#ifdef CONFIG_88EU_AP_MODE ++ issue_deauth(padapter, (void *)GetAddr2Ptr(pframe), status); ++#endif ++ ++ return _FAIL; ++ ++OnAssocReqFail: ++ ++#ifdef CONFIG_88EU_AP_MODE ++ pstat->aid = 0; ++ if (frame_type == WIFI_ASSOCREQ) ++ issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); ++ else ++ issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); ++#endif ++ ++#endif /* CONFIG_88EU_AP_MODE */ ++ ++ return _FAIL; ++} ++ ++unsigned int OnAssocRsp(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ uint i; ++ int res; ++ unsigned short status; ++ struct ndis_802_11_var_ie *pIE; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ /* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */ ++ u8 *pframe = precv_frame->rx_data; ++ uint pkt_len = precv_frame->len; ++ ++ DBG_88E("%s\n", __func__); ++ ++ /* check A1 matches or not */ ++ if (memcmp(myid(&padapter->eeprompriv), get_da(pframe), ETH_ALEN)) ++ return _SUCCESS; ++ ++ if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) ++ return _SUCCESS; ++ ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) ++ return _SUCCESS; ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ /* status */ ++ status = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 2)); ++ if (status > 0) { ++ DBG_88E("assoc reject, status code: %d\n", status); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ res = -4; ++ goto report_assoc_result; ++ } ++ ++ /* get capabilities */ ++ pmlmeinfo->capability = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ /* set slot time */ ++ pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20; ++ ++ /* AID */ ++ pmlmeinfo->aid = (int)(le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN + 4)) & 0x3fff); ++ res = pmlmeinfo->aid; ++ ++ /* following are moved to join event callback function */ ++ /* to handle HT, WMM, rate adaptive, update MAC reg */ ++ /* for not to handle the synchronous IO in the tasklet */ ++ for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) { ++ pIE = (struct ndis_802_11_var_ie *)(pframe + i); ++ ++ switch (pIE->ElementID) { ++ case _VENDOR_SPECIFIC_IE_: ++ if (!memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */ ++ WMM_param_handler(padapter, pIE); ++ break; ++ case _HT_CAPABILITY_IE_: /* HT caps */ ++ HT_caps_handler(padapter, pIE); ++ break; ++ case _HT_EXTRA_INFO_IE_: /* HT info */ ++ HT_info_handler(padapter, pIE); ++ break; ++ case _ERPINFO_IE_: ++ ERP_IE_handler(padapter, pIE); ++ break; ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ ++ /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ ++ UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates); ++ ++report_assoc_result: ++ if (res > 0) ++ rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len); ++ else ++ kfree(pmlmepriv->assoc_rsp); ++ ++ report_join_res(padapter, res); ++ ++ return _SUCCESS; ++} ++ ++unsigned int OnDeAuth(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ unsigned short reason; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 *pframe = precv_frame->rx_data; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ /* check A3 */ ++ if (!(!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) ++ return _SUCCESS; ++ ++#ifdef CONFIG_88EU_P2P ++ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { ++ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); ++ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ DBG_88E("%s Reason code(%d)\n", __func__, reason); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_88E_LEVEL(_drv_always_, "ap recv deauth reason code(%d) sta:%pM\n", ++ reason, GetAddr2Ptr(pframe)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (psta) { ++ u8 updated = 0; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (!list_empty(&psta->asoc_list)) { ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, false, reason); ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ associated_clients_update(padapter, updated); ++ } ++ ++ return _SUCCESS; ++ } else ++#endif ++ { ++ int ignore_received_deauth = 0; ++ ++ /* Before sending the auth frame to start the STA/GC mode connection with AP/GO, ++ * we will send the deauth first. ++ * However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. ++ * Added the following code to avoid this case. ++ */ ++ if ((pmlmeinfo->state & WIFI_FW_AUTH_STATE) || ++ (pmlmeinfo->state & WIFI_FW_ASSOC_STATE)) { ++ if (reason == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA) { ++ ignore_received_deauth = 1; ++ } else if (WLAN_REASON_PREV_AUTH_NOT_VALID == reason) { ++ // TODO: 802.11r ++ ignore_received_deauth = 1; ++ } ++ } ++ ++ DBG_88E_LEVEL(_drv_always_, "sta recv deauth reason code(%d) sta:%pM, ignore = %d\n", ++ reason, GetAddr3Ptr(pframe), ignore_received_deauth); ++ ++ if (!ignore_received_deauth) ++ receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); ++ } ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = false; ++ return _SUCCESS; ++} ++ ++unsigned int OnDisassoc(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ u16 reason; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 *pframe = precv_frame->rx_data; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ /* check A3 */ ++ if (!(!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) ++ return _SUCCESS; ++ ++#ifdef CONFIG_88EU_P2P ++ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { ++ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); ++ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN)); ++ ++ DBG_88E("%s Reason code(%d)\n", __func__, reason); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", ++ reason, GetAddr2Ptr(pframe)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ if (psta) { ++ u8 updated = 0; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (!list_empty(&psta->asoc_list)) { ++ list_del_init(&psta->asoc_list); ++ pstapriv->asoc_list_cnt--; ++ updated = ap_free_sta(padapter, psta, false, reason); ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ associated_clients_update(padapter, updated); ++ } ++ ++ return _SUCCESS; ++ } else ++#endif ++ { ++ DBG_88E_LEVEL(_drv_always_, "ap recv disassoc reason code(%d) sta:%pM\n", ++ reason, GetAddr3Ptr(pframe)); ++ ++ receive_disconnect(padapter, GetAddr3Ptr(pframe), reason); ++ } ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = false; ++ return _SUCCESS; ++} ++ ++unsigned int OnAtim(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ DBG_88E("%s\n", __func__); ++ return _SUCCESS; ++} ++ ++unsigned int on_action_spct(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->rx_data; ++ u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ u8 category; ++ u8 action; ++ ++ DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); ++ ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ ++ if (!psta) ++ goto exit; ++ ++ category = frame_body[0]; ++ if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT) ++ goto exit; ++ ++ action = frame_body[1]; ++ switch (action) { ++ case RTW_WLAN_ACTION_SPCT_MSR_REQ: ++ case RTW_WLAN_ACTION_SPCT_MSR_RPRT: ++ case RTW_WLAN_ACTION_SPCT_TPC_REQ: ++ case RTW_WLAN_ACTION_SPCT_TPC_RPRT: ++ break; ++ case RTW_WLAN_ACTION_SPCT_CHL_SWITCH: ++ break; ++ default: ++ break; ++ } ++ ++exit: ++ return ret; ++} ++ ++unsigned int OnAction_qos(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction_dls(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction_back(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ u8 *addr; ++ struct sta_info *psta = NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ unsigned char *frame_body; ++ unsigned char category, action; ++ unsigned short tid, status, reason_code = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 *pframe = precv_frame->rx_data; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ /* check RA matches or not */ ++ if (memcmp(myid(&padapter->eeprompriv), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */ ++ return _SUCCESS; ++ ++ DBG_88E("%s\n", __func__); ++ ++ if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) ++ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) ++ return _SUCCESS; ++ ++ addr = GetAddr2Ptr(pframe); ++ psta = rtw_get_stainfo(pstapriv, addr); ++ ++ if (!psta) ++ return _SUCCESS; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ category = frame_body[0]; ++ if (category == RTW_WLAN_CATEGORY_BACK) { /* representing Block Ack */ ++ if (!pmlmeinfo->HT_enable) ++ return _SUCCESS; ++ action = frame_body[1]; ++ DBG_88E("%s, action=%d\n", __func__, action); ++ switch (action) { ++ case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ ++ memcpy(&pmlmeinfo->ADDBA_req, &frame_body[2], sizeof(struct ADDBA_request)); ++ process_addba_req(padapter, (u8 *)&pmlmeinfo->ADDBA_req, addr); ++ ++ if (pmlmeinfo->bAcceptAddbaReq) ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0); ++ else ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */ ++ break; ++ case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ ++ status = get_unaligned_le16(&frame_body[3]); ++ tid = ((frame_body[5] >> 2) & 0x7); ++ if (status == 0) { /* successful */ ++ DBG_88E("agg_enable for TID=%d\n", tid); ++ psta->htpriv.agg_enable_bitmap |= 1 << tid; ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); ++ } else { ++ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); ++ } ++ break; ++ case RTW_WLAN_ACTION_DELBA: /* DELBA */ ++ if ((frame_body[3] & BIT(3)) == 0) { ++ psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); ++ psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); ++ reason_code = get_unaligned_le16(&frame_body[4]); ++ } else if ((frame_body[3] & BIT(3)) == BIT(3)) { ++ tid = (frame_body[3] >> 4) & 0x0F; ++ preorder_ctrl = &psta->recvreorder_ctrl[tid]; ++ preorder_ctrl->enable = false; ++ preorder_ctrl->indicate_seq = 0xffff; ++ } ++ DBG_88E("%s(): DELBA: %x(%x)\n", __func__, pmlmeinfo->agg_enable_bitmap, reason_code); ++ /* todo: how to notify the host while receiving DELETE BA */ ++ break; ++ default: ++ break; ++ } ++ } ++ return _SUCCESS; ++} ++ ++#ifdef CONFIG_88EU_P2P ++ ++static int get_reg_classes_full_count(struct p2p_channels *channel_list) ++{ ++ int cnt = 0; ++ int i; ++ ++ for (i = 0; i < channel_list->reg_classes; i++) { ++ cnt += channel_list->reg_class[i].channels; ++ } ++ ++ return cnt; ++} ++ ++void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr) ++{ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_GO_NEGO_REQ; ++ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; ++ u8 wpsielen = 0, p2pielen = 0; ++ u16 len_channellist_attr = 0; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ DBG_88E("[%s] In\n", __func__); ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pwdinfo->negotiation_dialog_token = 1; /* Initialize the dialog value */ ++ pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &pattrib->pktlen); ++ ++ /* WPS Section */ ++ wpsielen = 0; ++ /* WPS OUI */ ++ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); ++ wpsielen += 4; ++ ++ /* WPS version */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); ++ wpsielen += 2; ++ ++ /* Value: */ ++ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ ++ ++ /* Device Password ID */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); ++ wpsielen += 2; ++ ++ /* Value: */ ++ ++ if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); ++ else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN) ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); ++ else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); ++ ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); ++ ++ /* P2P IE Section. */ ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20110306 */ ++ /* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */ ++ /* 1. P2P Capability */ ++ /* 2. Group Owner Intent */ ++ /* 3. Configuration Timeout */ ++ /* 4. Listen Channel */ ++ /* 5. Extended Listen Timing */ ++ /* 6. Intended P2P Interface Address */ ++ /* 7. Channel List */ ++ /* 8. P2P Device Info */ ++ /* 9. Operating Channel */ ++ ++ /* P2P Capability */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Device Capability Bitmap, 1 byte */ ++ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ /* Group Capability Bitmap, 1 byte */ ++ if (pwdinfo->persistent_supported) ++ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; ++ else ++ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; ++ ++ /* Group Owner Intent */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Todo the tie breaker bit. */ ++ p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); ++ ++ /* Configuration Timeout */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ ++ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ ++ ++ /* Listen Channel */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ ++ ++ /* Channel Number */ ++ p2pie[p2pielen++] = pwdinfo->listen_channel; /* listening channel number */ ++ ++ /* Extended Listen Timing ATTR */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Availability Period */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); ++ p2pielen += 2; ++ ++ /* Availability Interval */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); ++ p2pielen += 2; ++ ++ /* Intended P2P Interface Address */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* Channel List */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; ++ ++ /* Length: */ ++ /* Country String(3) */ ++ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ ++ /* + number of channels in all classes */ ++ len_channellist_attr = 3 ++ + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes) ++ + get_reg_classes_full_count(&pmlmeext->channel_list); ++ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Channel Entry List */ ++ ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ /* Operating Class */ ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ /* Number of Channels */ ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ /* Channel List */ ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++ ++ /* Device Info */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; ++ ++ /* Length: */ ++ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ ++ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address */ ++ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* Config Method */ ++ /* This field should be big endian. Noted by P2P specification. */ ++ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); ++ ++ p2pielen += 2; ++ ++ /* Primary Device Type */ ++ /* Category ID */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); ++ p2pielen += 2; ++ ++ /* OUI */ ++ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); ++ p2pielen += 4; ++ ++ /* Sub Category ID */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); ++ p2pielen += 2; ++ ++ /* Number of Secondary Device Types */ ++ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ ++ ++ /* Device Name */ ++ /* Type: */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); ++ p2pielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); ++ p2pielen += pwdinfo->device_name_len; ++ ++ /* Operating Channel */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; ++ ++ /* Channel Number */ ++ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result) ++{ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_GO_NEGO_RESP; ++ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; ++ u8 p2pielen = 0; ++ uint wpsielen = 0; ++ u16 wps_devicepassword_id = 0x0000; ++ __be16 be_tmp; ++ uint wps_devicepassword_id_len = 0; ++ u16 len_channellist_attr = 0; ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ DBG_88E("[%s] In, result=%d\n", __func__, result); ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pwdinfo->negotiation_dialog_token = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */ ++ pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &pattrib->pktlen); ++ ++ /* Commented by Albert 20110328 */ ++ /* Try to get the device password ID from the WPS IE of group negotiation request frame */ ++ /* WiFi Direct test plan 5.1.15 */ ++ rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen); ++ rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len); ++ wps_devicepassword_id = be16_to_cpu(be_tmp); ++ ++ memset(wpsie, 0x00, 255); ++ wpsielen = 0; ++ ++ /* WPS Section */ ++ wpsielen = 0; ++ /* WPS OUI */ ++ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); ++ wpsielen += 4; ++ ++ /* WPS version */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); ++ wpsielen += 2; ++ ++ /* Value: */ ++ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ ++ ++ /* Device Password ID */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); ++ wpsielen += 2; ++ ++ /* Value: */ ++ if (wps_devicepassword_id == WPS_DPID_USER_SPEC) ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); ++ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); ++ else ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); ++ wpsielen += 2; ++ ++ /* Commented by Kurt 20120113 */ ++ /* If some device wants to do p2p handshake without sending prov_disc_req */ ++ /* We have to get peer_req_cm from here. */ ++ if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) { ++ if (wps_devicepassword_id == WPS_DPID_USER_SPEC) ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); ++ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); ++ else ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); ++ ++ /* P2P IE Section. */ ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20100908 */ ++ /* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */ ++ /* 1. Status */ ++ /* 2. P2P Capability */ ++ /* 3. Group Owner Intent */ ++ /* 4. Configuration Timeout */ ++ /* 5. Operating Channel */ ++ /* 6. Intended P2P Interface Address */ ++ /* 7. Channel List */ ++ /* 8. Device Info */ ++ /* 9. Group ID (Only GO) */ ++ ++ /* ToDo: */ ++ ++ /* P2P Status */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_STATUS; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); ++ p2pielen += 2; ++ ++ /* Value: */ ++ p2pie[p2pielen++] = result; ++ ++ /* P2P Capability */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Device Capability Bitmap, 1 byte */ ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { ++ /* Commented by Albert 2011/03/08 */ ++ /* According to the P2P specification */ ++ /* if the sending device will be client, the P2P Capability should be reserved of group negotiation response frame */ ++ p2pie[p2pielen++] = 0; ++ } else { ++ /* Be group owner or meet the error case */ ++ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; ++ } ++ ++ /* Group Capability Bitmap, 1 byte */ ++ if (pwdinfo->persistent_supported) { ++ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; ++ } else { ++ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; ++ } ++ ++ /* Group Owner Intent */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); ++ p2pielen += 2; ++ ++ /* Value: */ ++ if (pwdinfo->peer_intent & 0x01) { ++ /* Peer's tie breaker bit is 1, our tie breaker bit should be 0 */ ++ p2pie[p2pielen++] = (pwdinfo->intent << 1); ++ } else { ++ /* Peer's tie breaker bit is 0, our tie breaker bit should be 1 */ ++ p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); ++ } ++ ++ /* Configuration Timeout */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ ++ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ ++ ++ /* Operating Channel */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; ++ ++ /* Channel Number */ ++ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ ++ ++ /* Intended P2P Interface Address */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* Channel List */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; ++ ++ /* Country String(3) */ ++ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ ++ /* + number of channels in all classes */ ++ len_channellist_attr = 3 ++ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes ++ + get_reg_classes_full_count(&pmlmeext->channel_list); ++ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); ++ ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Channel Entry List */ ++ ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ /* Operating Class */ ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ /* Number of Channels */ ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ /* Channel List */ ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++ ++ /* Device Info */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; ++ ++ /* Length: */ ++ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ ++ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address */ ++ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* Config Method */ ++ /* This field should be big endian. Noted by P2P specification. */ ++ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); ++ ++ p2pielen += 2; ++ ++ /* Primary Device Type */ ++ /* Category ID */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); ++ p2pielen += 2; ++ ++ /* OUI */ ++ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); ++ p2pielen += 4; ++ ++ /* Sub Category ID */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); ++ p2pielen += 2; ++ ++ /* Number of Secondary Device Types */ ++ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ ++ ++ /* Device Name */ ++ /* Type: */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); ++ p2pielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); ++ p2pielen += pwdinfo->device_name_len; ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ /* Group ID Attribute */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* p2P Device Address */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* SSID */ ++ memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); ++ p2pielen += pwdinfo->nego_ssidlen; ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static void issue_p2p_GO_confirm(struct adapter *padapter, u8 *raddr, u8 result) ++{ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_GO_NEGO_CONF; ++ u8 p2pie[255] = { 0x00 }; ++ u8 p2pielen = 0; ++ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ DBG_88E("[%s] In\n", __func__); ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &pattrib->pktlen); ++ ++ /* P2P IE Section. */ ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20110306 */ ++ /* According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes */ ++ /* 1. Status */ ++ /* 2. P2P Capability */ ++ /* 3. Operating Channel */ ++ /* 4. Channel List */ ++ /* 5. Group ID (if this WiFi is GO) */ ++ ++ /* P2P Status */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_STATUS; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); ++ p2pielen += 2; ++ ++ /* Value: */ ++ p2pie[p2pielen++] = result; ++ ++ /* P2P Capability */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Device Capability Bitmap, 1 byte */ ++ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ /* Group Capability Bitmap, 1 byte */ ++ if (pwdinfo->persistent_supported) ++ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; ++ else ++ p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; ++ ++ /* Operating Channel */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; ++ p2pie[p2pielen++] = pwdinfo->peer_operating_ch; ++ } else { ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; ++ ++ /* Channel Number */ ++ p2pie[p2pielen++] = pwdinfo->operating_channel; /* Use the listen channel as the operating channel */ ++ } ++ ++ /* Channel List */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(pwdinfo->channel_list_attr_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len); ++ p2pielen += pwdinfo->channel_list_attr_len; ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ /* Group ID Attribute */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* p2P Device Address */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* SSID */ ++ memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); ++ p2pielen += pwdinfo->nego_ssidlen; ++ } ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++void issue_p2p_invitation_request(struct adapter *padapter, u8 *raddr) ++{ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_INVIT_REQ; ++ u8 p2pie[255] = { 0x00 }; ++ u8 p2pielen = 0; ++ u8 dialogToken = 3; ++ u16 len_channellist_attr = 0; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, raddr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &dialogToken, &pattrib->pktlen); ++ ++ /* P2P IE Section. */ ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20101011 */ ++ /* According to the P2P Specification, the P2P Invitation request frame should contain 7 P2P attributes */ ++ /* 1. Configuration Timeout */ ++ /* 2. Invitation Flags */ ++ /* 3. Operating Channel (Only GO) */ ++ /* 4. P2P Group BSSID (Should be included if I am the GO) */ ++ /* 5. Channel List */ ++ /* 6. P2P Group ID */ ++ /* 7. P2P Device Info */ ++ ++ /* Configuration Timeout */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ ++ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ ++ ++ /* Invitation Flags */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); ++ p2pielen += 2; ++ ++ /* Value: */ ++ p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT; ++ ++ /* Operating Channel */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; ++ ++ /* Channel Number */ ++ p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch; /* operating channel number */ ++ ++ if (!memcmp(myid(&padapter->eeprompriv), pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) { ++ /* P2P Group BSSID */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address for GO */ ++ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ } ++ ++ /* Channel List */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; ++ ++ /* Length: */ ++ /* Country String(3) */ ++ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ ++ /* + number of channels in all classes */ ++ len_channellist_attr = 3 ++ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes ++ + get_reg_classes_full_count(&pmlmeext->channel_list); ++ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); ++ ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Channel Entry List */ ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ /* Operating Class */ ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ /* Number of Channels */ ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ /* Channel List */ ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++ ++ /* P2P Group ID */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address for GO */ ++ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* SSID */ ++ memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, pwdinfo->invitereq_info.ssidlen); ++ p2pielen += pwdinfo->invitereq_info.ssidlen; ++ ++ /* Device Info */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; ++ ++ /* Length: */ ++ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ ++ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address */ ++ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* Config Method */ ++ /* This field should be big endian. Noted by P2P specification. */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); ++ p2pielen += 2; ++ ++ /* Primary Device Type */ ++ /* Category ID */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); ++ p2pielen += 2; ++ ++ /* OUI */ ++ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); ++ p2pielen += 4; ++ ++ /* Sub Category ID */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); ++ p2pielen += 2; ++ ++ /* Number of Secondary Device Types */ ++ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ ++ ++ /* Device Name */ ++ /* Type: */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); ++ p2pielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); ++ p2pielen += pwdinfo->device_name_len; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++void issue_p2p_invitation_response(struct adapter *padapter, u8 *raddr, u8 dialogToken, u8 status_code) ++{ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_INVIT_RESP; ++ u8 p2pie[255] = { 0x00 }; ++ u8 p2pielen = 0; ++ u16 len_channellist_attr = 0; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, raddr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &dialogToken, &pattrib->pktlen); ++ ++ /* P2P IE Section. */ ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20101005 */ ++ /* According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes */ ++ /* 1. Status */ ++ /* 2. Configuration Timeout */ ++ /* 3. Operating Channel (Only GO) */ ++ /* 4. P2P Group BSSID (Only GO) */ ++ /* 5. Channel List */ ++ ++ /* P2P Status */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_STATUS; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */ ++ /* Sent the event receiving the P2P Invitation Req frame to DMP UI. */ ++ /* DMP had to compare the MAC address to find out the profile. */ ++ /* So, the WiFi driver will send the P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */ ++ /* If the UI found the corresponding profile, the WiFi driver sends the P2P Invitation Req */ ++ /* to NB to rebuild the persistent group. */ ++ p2pie[p2pielen++] = status_code; ++ ++ /* Configuration Timeout */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ ++ p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ ++ ++ if (status_code == P2P_STATUS_SUCCESS) { ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ /* The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO */ ++ /* In this case, the P2P Invitation response frame should carry the two more P2P attributes. */ ++ /* First one is operating channel attribute. */ ++ /* Second one is P2P Group BSSID attribute. */ ++ ++ /* Operating Channel */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ ++ ++ /* Channel Number */ ++ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ ++ ++ /* P2P Group BSSID */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address for GO */ ++ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ } ++ ++ /* Channel List */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CH_LIST; ++ ++ /* Length: */ ++ /* Country String(3) */ ++ /* + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */ ++ /* + number of channels in all classes */ ++ len_channellist_attr = 3 ++ + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes ++ + get_reg_classes_full_count(&pmlmeext->channel_list); ++ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Channel Entry List */ ++ { ++ int i, j; ++ for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { ++ /* Operating Class */ ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; ++ ++ /* Number of Channels */ ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; ++ ++ /* Channel List */ ++ for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) { ++ p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; ++ } ++ } ++ } ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++void issue_p2p_provision_request(struct adapter *padapter, u8 *pssid, u8 ussidlen, u8 *pdev_raddr) ++{ ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u8 dialogToken = 1; ++ u8 oui_subtype = P2P_PROVISION_DISC_REQ; ++ u8 wpsie[100] = { 0x00 }; ++ u8 wpsielen = 0; ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u32 p2pielen = 0; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ DBG_88E("[%s] In\n", __func__); ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, pdev_raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pdev_raddr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &dialogToken, &pattrib->pktlen); ++ ++ p2pielen = build_prov_disc_request_p2p_ie(pwdinfo, pframe, pssid, ussidlen, pdev_raddr); ++ ++ pframe += p2pielen; ++ pattrib->pktlen += p2pielen; ++ ++ wpsielen = 0; ++ /* WPS OUI */ ++ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); ++ wpsielen += 4; ++ ++ /* WPS version */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); ++ wpsielen += 2; ++ ++ /* Value: */ ++ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ ++ ++ /* Config Method */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); ++ wpsielen += 2; ++ ++ /* Value: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request); ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo) ++{ ++ u8 i, match_result = 0; ++ ++ DBG_88E("[%s] peermac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, ++ peermacaddr[0], peermacaddr[1], peermacaddr[2], peermacaddr[3], peermacaddr[4], peermacaddr[5]); ++ ++ for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) { ++ DBG_88E("[%s] profileinfo_mac=%.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, ++ profileinfo->peermac[0], profileinfo->peermac[1], profileinfo->peermac[2], ++ profileinfo->peermac[3], profileinfo->peermac[4], profileinfo->peermac[5]); ++ if (!memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) { ++ match_result = 1; ++ DBG_88E("[%s] Match!\n", __func__); ++ break; ++ } ++ } ++ return match_result; ++} ++ ++void issue_probersp_p2p(struct adapter *padapter, unsigned char *da) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned char *mac; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ u16 beacon_interval = 100; ++ u16 capInfo = 0; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 wpsie[255] = { 0x00 }; ++ u32 wpsielen = 0, p2pielen = 0; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&padapter->eeprompriv); ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ ++ /* Use the device address for BSSID field. */ ++ memcpy(pwlanhdr->addr3, mac, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(fctrl, WIFI_PROBERSP); ++ ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = pattrib->hdrlen; ++ pframe += pattrib->hdrlen; ++ ++ /* timestamp will be inserted by hardware */ ++ pframe += 8; ++ pattrib->pktlen += 8; ++ ++ /* beacon interval: 2 bytes */ ++ memcpy(pframe, (unsigned char *)&beacon_interval, 2); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* capability info: 2 bytes */ ++ /* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) */ ++ capInfo |= cap_ShortPremble; ++ capInfo |= cap_ShortSlot; ++ ++ memcpy(pframe, (unsigned char *)&capInfo, 2); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pattrib->pktlen); ++ ++ /* supported rates... */ ++ /* Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */ ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen); ++ ++ /* DS parameter set */ ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pattrib->pktlen); ++ ++ /* Todo: WPS IE */ ++ /* Noted by Albert 20100907 */ ++ /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */ ++ ++ wpsielen = 0; ++ /* WPS OUI */ ++ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); ++ wpsielen += 4; ++ ++ /* WPS version */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); ++ wpsielen += 2; ++ ++ /* Value: */ ++ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ ++ ++ /* WiFi Simple Config State */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); ++ wpsielen += 2; ++ ++ /* Value: */ ++ wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; /* Not Configured. */ ++ ++ /* Response Type */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); ++ wpsielen += 2; ++ ++ /* Value: */ ++ wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X; ++ ++ /* UUID-E */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010); ++ wpsielen += 2; ++ ++ /* Value: */ ++ memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ wpsielen += 0x10; ++ ++ /* Manufacturer */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007); ++ wpsielen += 2; ++ ++ /* Value: */ ++ memcpy(wpsie + wpsielen, "Realtek", 7); ++ wpsielen += 7; ++ ++ /* Model Name */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006); ++ wpsielen += 2; ++ ++ /* Value: */ ++ memcpy(wpsie + wpsielen, "8188EU", 6); ++ wpsielen += 6; ++ ++ /* Model Number */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); ++ wpsielen += 2; ++ ++ /* Value: */ ++ wpsie[wpsielen++] = 0x31; /* character 1 */ ++ ++ /* Serial Number */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN); ++ wpsielen += 2; ++ ++ /* Value: */ ++ memcpy(wpsie + wpsielen, "123456", ETH_ALEN); ++ wpsielen += ETH_ALEN; ++ ++ /* Primary Device Type */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); ++ wpsielen += 2; ++ ++ /* Value: */ ++ /* Category ID */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); ++ wpsielen += 2; ++ ++ /* OUI */ ++ *(__be32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI); ++ wpsielen += 4; ++ ++ /* Sub Category ID */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); ++ wpsielen += 2; ++ ++ /* Device Name */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len); ++ wpsielen += 2; ++ ++ /* Value: */ ++ if (pwdinfo->device_name_len) { ++ memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len); ++ wpsielen += pwdinfo->device_name_len; ++ } ++ ++ /* Config Method */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); ++ wpsielen += 2; ++ ++ /* Value: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm); ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); ++ ++ p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe); ++ pframe += p2pielen; ++ pattrib->pktlen += p2pielen; ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static int _issue_probereq_p2p(struct adapter *padapter, u8 *da, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned char *mac; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; ++ u16 wpsielen = 0, p2pielen = 0; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ goto exit; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&padapter->eeprompriv); ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ if (da) { ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, da, ETH_ALEN); ++ } else { ++ if ((pwdinfo->p2p_info.scan_op_ch_only) || (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { ++ /* This two flags will be set when this is only the P2P client mode. */ ++ memcpy(pwlanhdr->addr1, pwdinfo->p2p_peer_interface_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pwdinfo->p2p_peer_interface_addr, ETH_ALEN); ++ } else { ++ /* broadcast probe request frame */ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); ++ } ++ } ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_PROBEREQ); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) ++ pframe = rtw_set_ie(pframe, _SSID_IE_, pwdinfo->tx_prov_disc_info.ssid.SsidLength, pwdinfo->tx_prov_disc_info.ssid.Ssid, &pattrib->pktlen); ++ else ++ pframe = rtw_set_ie(pframe, _SSID_IE_, P2P_WILDCARD_SSID_LEN, pwdinfo->p2p_wildcard_ssid, &pattrib->pktlen); ++ ++ /* Use the OFDM rate in the P2P probe request frame. (6(B), 9(B), 12(B), 24(B), 36, 48, 54) */ ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen); ++ ++ /* WPS IE */ ++ /* Noted by Albert 20110221 */ ++ /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */ ++ ++ wpsielen = 0; ++ /* WPS OUI */ ++ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI); ++ wpsielen += 4; ++ ++ /* WPS version */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); ++ wpsielen += 2; ++ ++ /* Value: */ ++ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ ++ ++ if (!pmlmepriv->wps_probe_req_ie) { ++ /* UUID-E */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010); ++ wpsielen += 2; ++ ++ /* Value: */ ++ memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ wpsielen += 0x10; ++ ++ /* Config Method */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); ++ wpsielen += 2; ++ ++ /* Value: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm); ++ wpsielen += 2; ++ } ++ ++ /* Device Name */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len); ++ wpsielen += 2; ++ ++ /* Value: */ ++ memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len); ++ wpsielen += pwdinfo->device_name_len; ++ ++ /* Primary Device Type */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); ++ wpsielen += 2; ++ ++ /* Value: */ ++ /* Category ID */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI); ++ wpsielen += 2; ++ ++ /* OUI */ ++ *(__be32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI); ++ wpsielen += 4; ++ ++ /* Sub Category ID */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP); ++ wpsielen += 2; ++ ++ /* Device Password ID */ ++ /* Type: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); ++ wpsielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); ++ wpsielen += 2; ++ ++ /* Value: */ ++ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); /* Registrar-specified */ ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20110221 */ ++ /* According to the P2P Specification, the probe request frame should contain 5 P2P attributes */ ++ /* 1. P2P Capability */ ++ /* 2. P2P Device ID if this probe request wants to find the specific P2P device */ ++ /* 3. Listen Channel */ ++ /* 4. Extended Listen Timing */ ++ /* 5. Operating Channel if this WiFi is working as the group owner now */ ++ ++ /* P2P Capability */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Device Capability Bitmap, 1 byte */ ++ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ /* Group Capability Bitmap, 1 byte */ ++ if (pwdinfo->persistent_supported) ++ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; ++ else ++ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; ++ ++ /* Listen Channel */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ ++ ++ /* Channel Number */ ++ p2pie[p2pielen++] = pwdinfo->listen_channel; /* listen channel */ ++ ++ /* Extended Listen Timing */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Availability Period */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); ++ p2pielen += 2; ++ ++ /* Availability Interval */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); ++ p2pielen += 2; ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ /* Operating Channel (if this WiFi is working as the group owner now) */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Country String */ ++ p2pie[p2pielen++] = 'X'; ++ p2pie[p2pielen++] = 'X'; ++ ++ /* The third byte should be set to 0x04. */ ++ /* Described in the "Operating Channel Attribute" section. */ ++ p2pie[p2pielen++] = 0x04; ++ ++ /* Operating Class */ ++ p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ ++ ++ /* Channel Number */ ++ p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ ++ } ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); ++ ++ if (pmlmepriv->wps_probe_req_ie) { ++ /* WPS IE */ ++ memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); ++ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; ++ pframe += pmlmepriv->wps_probe_req_ie_len; ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (wait_ack) { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } else { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++inline void issue_probereq_p2p(struct adapter *adapter, u8 *da) ++{ ++ _issue_probereq_p2p(adapter, da, false); ++} ++ ++int issue_probereq_p2p_ex(struct adapter *adapter, u8 *da, int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = jiffies; ++ ++ do { ++ ret = _issue_probereq_p2p(adapter, da, wait_ms > 0); ++ ++ i++; ++ ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); ++ ++ if (ret != _FAIL) { ++ ret = _SUCCESS; ++ goto exit; ++ } ++ ++ if (try_cnt && wait_ms) { ++ if (da) ++ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(adapter), da, rtw_get_oper_ch(adapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ else ++ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(adapter), rtw_get_oper_ch(adapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ } ++exit: ++ return ret; ++} ++ ++#endif /* CONFIG_88EU_P2P */ ++ ++static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token) ++{ ++ struct adapter *adapter = recv_frame->adapter; ++ struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; ++ u8 *frame = recv_frame->rx_data; ++ u16 seq_ctrl = ((recv_frame->attrib.seq_num & 0xffff) << 4) | ++ (recv_frame->attrib.frag_num & 0xf); ++ ++ if (GetRetry(frame)) { ++ if (token >= 0) { ++ if ((seq_ctrl == mlmeext->action_public_rxseq) && (token == mlmeext->action_public_dialog_token)) { ++ DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x, token:%d\n", ++ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token); ++ return _FAIL; ++ } ++ } else { ++ if (seq_ctrl == mlmeext->action_public_rxseq) { ++ DBG_88E(FUNC_ADPT_FMT" seq_ctrl = 0x%x, rxseq = 0x%x\n", ++ FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq); ++ return _FAIL; ++ } ++ } ++ } ++ ++ mlmeext->action_public_rxseq = seq_ctrl; ++ ++ if (token >= 0) ++ mlmeext->action_public_dialog_token = token; ++ ++ return _SUCCESS; ++} ++ ++static unsigned int on_action_public_p2p(struct recv_frame *precv_frame) ++{ ++ u8 *pframe = precv_frame->rx_data; ++ u8 *frame_body; ++ u8 dialogToken = 0; ++#ifdef CONFIG_88EU_P2P ++ struct adapter *padapter = precv_frame->adapter; ++ uint len = precv_frame->len; ++ u8 *p2p_ie; ++ u32 p2p_ielen; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 result = P2P_STATUS_SUCCESS; ++ u8 empty_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++#endif /* CONFIG_88EU_P2P */ ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ dialogToken = frame_body[7]; ++ ++ if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL) ++ return _FAIL; ++ ++#ifdef CONFIG_88EU_P2P ++ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); ++ /* Do nothing if the driver doesn't enable the P2P function. */ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) ++ return _SUCCESS; ++ ++ len -= sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ switch (frame_body[6]) { /* OUI Subtype */ ++ case P2P_GO_NEGO_REQ: ++ DBG_88E("[%s] Got GO Nego Req Frame\n", __func__); ++ memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) { ++ /* Commented by Albert 20110526 */ ++ /* In this case, this means the previous nego fail doesn't be reset yet. */ ++ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); ++ /* Restore the previous p2p state */ ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ DBG_88E("[%s] Restore the previous p2p state to %d\n", __func__, rtw_p2p_state(pwdinfo)); ++ } ++ ++ /* Commented by Kurt 20110902 */ ++ /* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ ++ /* Commented by Kurt 20120113 */ ++ /* Get peer_dev_addr here if peer doesn't issue prov_disc frame. */ ++ if (!memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN)) ++ memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN); ++ ++ result = process_p2p_group_negotation_req(pwdinfo, frame_body, len); ++ issue_p2p_GO_response(padapter, GetAddr2Ptr(pframe), frame_body, len, result); ++ ++ /* Commented by Albert 20110718 */ ++ /* No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */ ++ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); ++ break; ++ case P2P_GO_NEGO_RESP: ++ DBG_88E("[%s] Got GO Nego Resp Frame\n", __func__); ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { ++ /* Commented by Albert 20110425 */ ++ /* The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */ ++ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); ++ pwdinfo->nego_req_info.benable = false; ++ result = process_p2p_group_negotation_resp(pwdinfo, frame_body, len); ++ issue_p2p_GO_confirm(pwdinfo->padapter, GetAddr2Ptr(pframe), result); ++ if (P2P_STATUS_SUCCESS == result) { ++ if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) { ++ pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch; ++ pwdinfo->p2p_info.scan_op_ch_only = 1; ++ _set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH); ++ } ++ } ++ /* Reset the dialog token for group negotiation frames. */ ++ pwdinfo->negotiation_dialog_token = 1; ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) ++ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); ++ } else { ++ DBG_88E("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __func__); ++ } ++ break; ++ case P2P_GO_NEGO_CONF: ++ DBG_88E("[%s] Got GO Nego Confirm Frame\n", __func__); ++ result = process_p2p_group_negotation_confirm(pwdinfo, frame_body, len); ++ if (P2P_STATUS_SUCCESS == result) { ++ if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) { ++ pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch; ++ pwdinfo->p2p_info.scan_op_ch_only = 1; ++ _set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH); ++ } ++ } ++ break; ++ case P2P_INVIT_REQ: ++ /* Added by Albert 2010/10/05 */ ++ /* Received the P2P Invite Request frame. */ ++ ++ DBG_88E("[%s] Got invite request frame!\n", __func__); ++ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); ++ if (p2p_ie) { ++ /* Parse the necessary information from the P2P Invitation Request frame. */ ++ /* For example: The MAC address of sending this P2P Invitation Request frame. */ ++ u32 attr_contentlen = 0; ++ u8 status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ struct group_id_info group_id; ++ u8 invitation_flag = 0; ++ ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen); ++ if (attr_contentlen) { ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen); ++ /* Commented by Albert 20120510 */ ++ /* Copy to the pwdinfo->p2p_peer_interface_addr. */ ++ /* So that the WFD UI (or Sigma) can get the peer interface address by using the following command. */ ++ /* #> iwpriv wlan0 p2p_get peer_ifa */ ++ /* After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */ ++ ++ if (attr_contentlen) { ++ DBG_88E("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__, ++ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], ++ pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3], ++ pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]); ++ } ++ ++ if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT) { ++ /* Re-invoke the persistent group. */ ++ ++ memset(&group_id, 0x00, sizeof(struct group_id_info)); ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen); ++ if (attr_contentlen) { ++ if (!memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) { ++ /* The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ status_code = P2P_STATUS_SUCCESS; ++ } else { ++ /* The p2p device sending this p2p invitation request wants to be the persistent GO. */ ++ if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[0])) { ++ u8 operatingch_info[5] = { 0x00 }; ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) { ++ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4])) { ++ /* The operating channel is acceptable for this device. */ ++ pwdinfo->rx_invitereq_info.operation_ch[0] = operatingch_info[4]; ++ pwdinfo->rx_invitereq_info.scan_op_ch_only = 1; ++ _set_timer(&pwdinfo->reset_ch_sitesurvey, P2P_RESET_SCAN_CH); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ status_code = P2P_STATUS_SUCCESS; ++ } else { ++ /* The operating channel isn't supported by this device. */ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ status_code = P2P_STATUS_FAIL_NO_COMMON_CH; ++ _set_timer(&pwdinfo->restore_p2p_state_timer, 3000); ++ } ++ } else { ++ /* Commented by Albert 20121130 */ ++ /* Intel will use the different P2P IE to store the operating channel information */ ++ /* Workaround for Intel WiDi 3.5 */ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ status_code = P2P_STATUS_SUCCESS; ++ } ++ } else { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); ++ status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; ++ } ++ } ++ } else { ++ DBG_88E("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__); ++ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ } else { ++ /* Received the invitation to join a P2P group. */ ++ ++ memset(&group_id, 0x00, sizeof(struct group_id_info)); ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *)&group_id, &attr_contentlen); ++ if (attr_contentlen) { ++ if (!memcmp(group_id.go_device_addr, myid(&padapter->eeprompriv), ETH_ALEN)) { ++ /* In this case, the GO can't be myself. */ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); ++ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } else { ++ /* The p2p device sending this p2p invitation request wants to join an existing P2P group */ ++ /* Commented by Albert 2012/06/28 */ ++ /* In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */ ++ /* The peer device address should be the destination address for the provisioning discovery request. */ ++ /* Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */ ++ /* The peer interface address should be the address for WPS mac address */ ++ memcpy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr, ETH_ALEN); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN); ++ status_code = P2P_STATUS_SUCCESS; ++ } ++ } else { ++ DBG_88E("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__); ++ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ } ++ } else { ++ DBG_88E("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __func__); ++ status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ ++ DBG_88E("[%s] status_code = %d\n", __func__, status_code); ++ ++ pwdinfo->inviteresp_info.token = frame_body[7]; ++ issue_p2p_invitation_response(padapter, GetAddr2Ptr(pframe), pwdinfo->inviteresp_info.token, status_code); ++ } ++ break; ++ case P2P_INVIT_RESP: { ++ u8 attr_content = 0x00; ++ u32 attr_contentlen = 0; ++ ++ DBG_88E("[%s] Got invite response frame!\n", __func__); ++ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); ++ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); ++ if (p2p_ie) { ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); ++ ++ if (attr_contentlen == 1) { ++ DBG_88E("[%s] Status = %d\n", __func__, attr_content); ++ pwdinfo->invitereq_info.benable = false; ++ ++ if (attr_content == P2P_STATUS_SUCCESS) { ++ if (!memcmp(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv), ETH_ALEN)) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } else { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK); ++ } else { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); ++ } ++ } else { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); ++ } ++ } else { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); ++ } ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL)) ++ _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); ++ break; ++ } ++ case P2P_DEVDISC_REQ: ++ process_p2p_devdisc_req(pwdinfo, pframe, len); ++ break; ++ case P2P_DEVDISC_RESP: ++ process_p2p_devdisc_resp(pwdinfo, pframe, len); ++ break; ++ case P2P_PROVISION_DISC_REQ: ++ DBG_88E("[%s] Got Provisioning Discovery Request Frame\n", __func__); ++ process_p2p_provdisc_req(pwdinfo, pframe, len); ++ memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, GetAddr2Ptr(pframe), ETH_ALEN); ++ ++ /* 20110902 Kurt */ ++ /* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ); ++ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT); ++ break; ++ case P2P_PROVISION_DISC_RESP: ++ /* Commented by Albert 20110707 */ ++ /* Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */ ++ DBG_88E("[%s] Got Provisioning Discovery Response Frame\n", __func__); ++ /* Commented by Albert 20110426 */ ++ /* The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */ ++ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP); ++ process_p2p_provdisc_resp(pwdinfo, pframe); ++ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT); ++ break; ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ return _SUCCESS; ++} ++ ++static unsigned int on_action_public_vendor(struct recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->rx_data; ++ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (!memcmp(frame_body + 2, P2P_OUI, 4)) { ++ ret = on_action_public_p2p(precv_frame); ++ } ++ ++ return ret; ++} ++ ++static unsigned int on_action_public_default(struct recv_frame *precv_frame, u8 action) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->rx_data; ++ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ u8 token; ++ ++ token = frame_body[2]; ++ ++ if (rtw_action_public_decache(precv_frame, token) == _FAIL) ++ goto exit; ++ ++ ret = _SUCCESS; ++ ++exit: ++ return ret; ++} ++ ++unsigned int on_action_public(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ unsigned int ret = _FAIL; ++ u8 *pframe = precv_frame->rx_data; ++ u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ u8 category, action; ++ ++ /* check RA matches or not */ ++ if (memcmp(myid(&padapter->eeprompriv), GetAddr1Ptr(pframe), ETH_ALEN)) ++ goto exit; ++ ++ category = frame_body[0]; ++ if (category != RTW_WLAN_CATEGORY_PUBLIC) ++ goto exit; ++ ++ action = frame_body[1]; ++ switch (action) { ++ case ACT_PUBLIC_VENDOR: ++ ret = on_action_public_vendor(precv_frame); ++ break; ++ default: ++ ret = on_action_public_default(precv_frame, action); ++ break; ++ } ++ ++exit: ++ return ret; ++} ++ ++unsigned int OnAction_ht(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction_wmm(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction_p2p(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++#ifdef CONFIG_88EU_P2P ++ u8 *frame_body; ++ u8 category, OUI_Subtype; ++ u8 *pframe = precv_frame->rx_data; ++ uint len = precv_frame->len; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("%s\n", __func__); ++ ++ /* check RA matches or not */ ++ if (memcmp(myid(&padapter->eeprompriv), GetAddr1Ptr(pframe), ETH_ALEN))/* for if1, sta/ap mode */ ++ return _SUCCESS; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ category = frame_body[0]; ++ if (category != RTW_WLAN_CATEGORY_P2P) ++ return _SUCCESS; ++ ++ if (be32_to_cpu(*((__be32 *)(frame_body + 1))) != P2POUI) ++ return _SUCCESS; ++ ++ len -= sizeof(struct rtw_ieee80211_hdr_3addr); ++ OUI_Subtype = frame_body[5]; ++ ++ switch (OUI_Subtype) { ++ case P2P_NOTICE_OF_ABSENCE: ++ break; ++ case P2P_PRESENCE_REQUEST: ++ process_p2p_presence_req(pwdinfo, pframe, len); ++ break; ++ case P2P_PRESENCE_RESPONSE: ++ break; ++ case P2P_GO_DISC_REQUEST: ++ break; ++ default: ++ break; ++ } ++#endif /* CONFIG_88EU_P2P */ ++ return _SUCCESS; ++} ++ ++unsigned int OnAction(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ int i; ++ unsigned char category; ++ struct action_handler *ptable; ++ unsigned char *frame_body; ++ u8 *pframe = precv_frame->rx_data; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ category = frame_body[0]; ++ ++ for (i = 0; i < sizeof(OnAction_tbl) / sizeof(struct action_handler); i++) { ++ ptable = &OnAction_tbl[i]; ++ if (category == ptable->num) ++ ptable->func(padapter, precv_frame); ++ } ++ return _SUCCESS; ++} ++ ++unsigned int DoReserved(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ return _SUCCESS; ++} ++ ++struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_frame *pmgntframe; ++ struct xmit_buf *pxmitbuf; ++ ++ pmgntframe = rtw_alloc_xmitframe(pxmitpriv); ++ if (!pmgntframe) { ++ DBG_88E("%s, alloc xmitframe fail\n", __func__); ++ return NULL; ++ } ++ ++ pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv); ++ if (!pxmitbuf) { ++ DBG_88E("%s, alloc xmitbuf fail\n", __func__); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ return NULL; ++ } ++ pmgntframe->frame_tag = MGNT_FRAMETAG; ++ pmgntframe->pxmitbuf = pxmitbuf; ++ pmgntframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pmgntframe; ++ return pmgntframe; ++} ++ ++/**************************************************************************** ++ ++Following are some TX fuctions for WiFi MLME ++ ++*****************************************************************************/ ++ ++void update_mgnt_tx_rate(struct adapter *padapter, u8 rate) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ pmlmeext->tx_rate = rate; ++ DBG_88E("%s(): rate = %x\n", __func__, rate); ++} ++ ++void update_mgntframe_attrib(struct adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); ++ ++ pattrib->hdrlen = 24; ++ pattrib->nr_frags = 1; ++ pattrib->priority = 7; ++ pattrib->mac_id = 0; ++ pattrib->qsel = 0x12; ++ ++ pattrib->pktlen = 0; ++ ++ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ pattrib->raid = 6;/* b mode */ ++ else ++ pattrib->raid = 5;/* a/g mode */ ++ ++ pattrib->encrypt = _NO_PRIVACY_; ++ pattrib->bswenc = false; ++ ++ pattrib->qos_en = false; ++ pattrib->ht_en = false; ++ pattrib->bwmode = HT_CHANNEL_WIDTH_20; ++ pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pattrib->sgi = false; ++ ++ pattrib->seqnum = pmlmeext->mgnt_seq; ++ ++ pattrib->retry_ctrl = true; ++} ++ ++void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ return; ++ ++ rtw_hal_mgnt_xmit(padapter, pmgntframe); ++} ++ ++s32 dump_mgntframe_and_wait(struct adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) ++{ ++ s32 ret = _FAIL; ++ struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; ++ struct submit_ctx sctx; ++ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ return ret; ++ ++ rtw_sctx_init(&sctx, timeout_ms); ++ pxmitbuf->sctx = &sctx; ++ ++ ret = rtw_hal_mgnt_xmit(padapter, pmgntframe); ++ ++ if (ret == _SUCCESS) ++ ret = rtw_sctx_wait(&sctx); ++ ++ return ret; ++} ++ ++s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, struct xmit_frame *pmgntframe) ++{ ++ s32 ret = _FAIL; ++ u32 timeout_ms = 500;/* 500ms */ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ return -1; ++ ++ _enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); ++ pxmitpriv->ack_tx = true; ++ ++ pmgntframe->ack_report = 1; ++ if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) { ++ ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms); ++ } ++ ++ pxmitpriv->ack_tx = false; ++ _exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); ++ ++ return ret; ++} ++ ++static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) ++{ ++ u8 *ssid_ie; ++ int ssid_len_ori; ++ int len_diff = 0; ++ ++ ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); ++ ++ if (ssid_ie && ssid_len_ori > 0) { ++ switch (hidden_ssid_mode) { ++ case 1: { ++ u8 *next_ie = ssid_ie + 2 + ssid_len_ori; ++ u32 remain_len = 0; ++ ++ remain_len = ies_len - (next_ie - ies); ++ ++ ssid_ie[1] = 0; ++ memcpy(ssid_ie + 2, next_ie, remain_len); ++ len_diff -= ssid_len_ori; ++ ++ break; ++ } ++ case 2: ++ memset(&ssid_ie[2], 0, ssid_len_ori); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return len_diff; ++} ++ ++void issue_beacon(struct adapter *padapter, int timeout_ms) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned int rate_len; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) { ++ DBG_88E("%s, alloc mgnt frame fail\n", __func__); ++ return; ++ } ++#if defined(CONFIG_88EU_AP_MODE) ++ spin_lock_bh(&pmlmepriv->bcn_update_lock); ++#endif /* if defined (CONFIG_88EU_AP_MODE) */ ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->qsel = 0x10; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); ++ /* pmlmeext->mgnt_seq++; */ ++ SetFrameSubType(pframe, WIFI_BEACON); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { ++#ifdef CONFIG_88EU_P2P ++ /* for P2P : Primary Device Type & Device Name */ ++ u32 wpsielen = 0, insert_len = 0; ++ u8 *wpsie = NULL; ++ wpsie = rtw_get_wps_ie(cur_network->IEs + _FIXED_IE_LENGTH_, cur_network->IELength - _FIXED_IE_LENGTH_, NULL, &wpsielen); ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen > 0) { ++ uint wps_offset, remainder_ielen; ++ u8 *premainder_ie, *pframe_wscie; ++ ++ wps_offset = (uint)(wpsie - cur_network->IEs); ++ premainder_ie = wpsie + wpsielen; ++ remainder_ielen = cur_network->IELength - wps_offset - wpsielen; ++ pframe_wscie = pframe + wps_offset; ++ memcpy(pframe, cur_network->IEs, wps_offset + wpsielen); ++ pframe += (wps_offset + wpsielen); ++ pattrib->pktlen += (wps_offset + wpsielen); ++ ++ /* now pframe is end of wsc ie, insert Primary Device Type & Device Name */ ++ /* Primary Device Type */ ++ /* Type: */ ++ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); ++ insert_len += 2; ++ ++ /* Length: */ ++ *(__be16 *)(pframe + insert_len) = cpu_to_be16(0x0008); ++ insert_len += 2; ++ ++ /* Value: */ ++ /* Category ID */ ++ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); ++ insert_len += 2; ++ ++ /* OUI */ ++ *(__be32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI); ++ insert_len += 4; ++ ++ /* Sub Category ID */ ++ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); ++ insert_len += 2; ++ ++ /* Device Name */ ++ /* Type: */ ++ *(__be16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); ++ insert_len += 2; ++ ++ /* Length: */ ++ *(__be16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len); ++ insert_len += 2; ++ ++ /* Value: */ ++ memcpy(pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len); ++ insert_len += pwdinfo->device_name_len; ++ ++ /* update wsc ie length */ ++ *(pframe_wscie + 1) = (wpsielen - 2) + insert_len; ++ ++ /* pframe move to end */ ++ pframe += insert_len; ++ pattrib->pktlen += insert_len; ++ ++ /* copy remainder_ie to pframe */ ++ memcpy(pframe, premainder_ie, remainder_ielen); ++ pframe += remainder_ielen; ++ pattrib->pktlen += remainder_ielen; ++ } else ++#endif /* CONFIG_88EU_P2P */ ++ { ++ int len_diff; ++ memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ len_diff = update_hidden_ssid( ++ pframe + _BEACON_IE_OFFSET_ ++ , cur_network->IELength - _BEACON_IE_OFFSET_ ++ , pmlmeinfo->hidden_ssid_mode ++ ); ++ pframe += (cur_network->IELength + len_diff); ++ pattrib->pktlen += (cur_network->IELength + len_diff); ++ } ++ ++ { ++ u8 *wps_ie; ++ uint wps_ielen; ++ u8 sr = 0; ++ wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr + TXDESC_OFFSET + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, ++ pattrib->pktlen - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_, NULL, &wps_ielen); ++ if (wps_ie && wps_ielen > 0) ++ rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); ++ if (sr != 0) ++ set_fwstate(pmlmepriv, WIFI_UNDER_WPS); ++ else ++ _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); ++ } ++ ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ u32 len; ++ len = build_beacon_p2p_ie(pwdinfo, pframe); ++ ++ pframe += len; ++ pattrib->pktlen += len; ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ goto _issue_bcn; ++ } ++ ++ /* below for ad-hoc mode */ ++ ++ /* timestamp will be inserted by hardware */ ++ pframe += 8; ++ pattrib->pktlen += 8; ++ ++ /* beacon interval: 2 bytes */ ++ ++ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* capability info: 2 bytes */ ++ ++ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); ++ ++ /* supported rates... */ ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); ++ ++ /* DS parameter set */ ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&cur_network->Configuration.DSConfig, &pattrib->pktlen); ++ ++ { ++ u8 erpinfo = 0; ++ u32 ATIMWindow; ++ /* IBSS Parameter Set... */ ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); ++ ++ /* ERP IE */ ++ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); ++ } ++ ++ /* EXTERNDED SUPPORTED RATE */ ++ if (rate_len > 8) ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); ++ /* todo:HT for adhoc */ ++_issue_bcn: ++ ++#if defined(CONFIG_88EU_AP_MODE) ++ pmlmepriv->update_bcn = false; ++ ++ spin_unlock_bh(&pmlmepriv->bcn_update_lock); ++#endif /* if defined (CONFIG_88EU_AP_MODE) */ ++ ++ if ((pattrib->pktlen + TXDESC_SIZE) > 512) { ++ DBG_88E("beacon frame too large\n"); ++ return; ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ /* DBG_88E("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */ ++ if (timeout_ms > 0) ++ dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); ++ else ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned char *mac, *bssid; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++#if defined(CONFIG_88EU_AP_MODE) ++ u8 *pwps_ie; ++ uint wps_ielen; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++#endif /* if defined (CONFIG_88EU_AP_MODE) */ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ unsigned int rate_len; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) { ++ DBG_88E("%s, alloc mgnt frame fail\n", __func__); ++ return; ++ } ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&padapter->eeprompriv); ++ bssid = cur_network->MacAddress; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(fctrl, WIFI_PROBERSP); ++ ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = pattrib->hdrlen; ++ pframe += pattrib->hdrlen; ++ ++ if (cur_network->IELength > MAX_IE_SZ) ++ return; ++ ++#if defined(CONFIG_88EU_AP_MODE) ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { ++ pwps_ie = rtw_get_wps_ie(cur_network->IEs + _FIXED_IE_LENGTH_, cur_network->IELength - _FIXED_IE_LENGTH_, NULL, &wps_ielen); ++ ++ /* inerset & update wps_probe_resp_ie */ ++ if (pmlmepriv->wps_probe_resp_ie && pwps_ie && wps_ielen > 0) { ++ uint wps_offset, remainder_ielen; ++ u8 *premainder_ie; ++ ++ wps_offset = (uint)(pwps_ie - cur_network->IEs); ++ ++ premainder_ie = pwps_ie + wps_ielen; ++ ++ remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; ++ ++ memcpy(pframe, cur_network->IEs, wps_offset); ++ pframe += wps_offset; ++ pattrib->pktlen += wps_offset; ++ ++ wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ ++ if ((wps_offset + wps_ielen + 2) <= MAX_IE_SZ) { ++ memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen + 2); ++ pframe += wps_ielen + 2; ++ pattrib->pktlen += wps_ielen + 2; ++ } ++ ++ if ((wps_offset + wps_ielen + 2 + remainder_ielen) <= MAX_IE_SZ) { ++ memcpy(pframe, premainder_ie, remainder_ielen); ++ pframe += remainder_ielen; ++ pattrib->pktlen += remainder_ielen; ++ } ++ } else { ++ memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ pframe += cur_network->IELength; ++ pattrib->pktlen += cur_network->IELength; ++ } ++ } else ++#endif ++ { ++ /* timestamp will be inserted by hardware */ ++ pframe += 8; ++ pattrib->pktlen += 8; ++ ++ /* beacon interval: 2 bytes */ ++ ++ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* capability info: 2 bytes */ ++ ++ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* below for ad-hoc mode */ ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); ++ ++ /* supported rates... */ ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); ++ ++ /* DS parameter set */ ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&cur_network->Configuration.DSConfig, &pattrib->pktlen); ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { ++ u8 erpinfo = 0; ++ u32 ATIMWindow; ++ /* IBSS Parameter Set... */ ++ /* ATIMWindow = cur->Configuration.ATIMWindow; */ ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); ++ ++ /* ERP IE */ ++ pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); ++ } ++ ++ /* EXTERNDED SUPPORTED RATE */ ++ if (rate_len > 8) ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); ++ /* todo:HT for adhoc */ ++ } ++ ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && is_valid_p2p_probereq) { ++ u32 len; ++ len = build_probe_resp_p2p_ie(pwdinfo, pframe); ++ ++ pframe += len; ++ pattrib->pktlen += len; ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static int _issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned char *mac; ++ unsigned char bssrate[NumRates]; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ int bssrate_len = 0; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ goto exit; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&padapter->eeprompriv); ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ if (da) { ++ /* unicast probe request frame */ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, da, ETH_ALEN); ++ } else { ++ /* broadcast probe request frame */ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); ++ } ++ ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_PROBEREQ); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (pssid) ++ pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &pattrib->pktlen); ++ else ++ pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &pattrib->pktlen); ++ ++ get_rate_set(padapter, bssrate, &bssrate_len); ++ ++ if (bssrate_len > 8) { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, bssrate, &pattrib->pktlen); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, bssrate_len - 8, bssrate + 8, &pattrib->pktlen); ++ } else { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, bssrate_len, bssrate, &pattrib->pktlen); ++ } ++ ++ /* add wps_ie for wps2.0 */ ++ if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) { ++ memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); ++ pframe += pmlmepriv->wps_probe_req_ie_len; ++ pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (wait_ack) { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } else { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++inline void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da) ++{ ++ _issue_probereq(padapter, pssid, da, false); ++} ++ ++int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, u8 *da, ++ int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = jiffies; ++ ++ do { ++ ret = _issue_probereq(padapter, pssid, da, wait_ms > 0); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ ++ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); ++ ++ if (ret != _FAIL) { ++ ret = _SUCCESS; ++ goto exit; ++ } ++ ++ if (try_cnt && wait_ms) { ++ if (da) ++ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ else ++ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ } ++exit: ++ return ret; ++} ++ ++/* if psta == NULL, indiate we are station(client) now... */ ++void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned int val32; ++ u16 val16; ++#ifdef CONFIG_88EU_AP_MODE ++ __le16 le_val16; ++#endif ++ int use_shared_key = 0; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_AUTH); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (psta) {/* for AP mode */ ++#ifdef CONFIG_88EU_AP_MODE ++ ++ memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); ++ ++ /* setting auth algo number */ ++ val16 = (u16)psta->authalg; ++ ++ if (status != _STATS_SUCCESSFUL_) ++ val16 = 0; ++ ++ if (val16) { ++ le_val16 = cpu_to_le16(val16); ++ use_shared_key = 1; ++ } else { ++ le_val16 = 0; ++ } ++ ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_val16, &pattrib->pktlen); ++ ++ /* setting auth seq number */ ++ val16 = (u16)psta->auth_seq; ++ le_val16 = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_val16, &pattrib->pktlen); ++ ++ /* setting status code... */ ++ val16 = status; ++ le_val16 = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_val16, &pattrib->pktlen); ++ ++ /* added challenging text... */ ++ if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) ++ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &pattrib->pktlen); ++#endif ++ } else { ++ __le32 le_tmp32; ++ __le16 le_tmp16; ++ memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ /* setting auth algo number */ ++ val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/* 0:OPEN System, 1:Shared key */ ++ if (val16) ++ use_shared_key = 1; ++ ++ /* setting IV for auth seq #3 */ ++ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { ++ val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30)); ++ le_tmp32 = cpu_to_le32(val32); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&le_tmp32, &pattrib->pktlen); ++ ++ pattrib->iv_len = 4; ++ } ++ ++ le_tmp16 = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&le_tmp16, &pattrib->pktlen); ++ ++ /* setting auth seq number */ ++ val16 = pmlmeinfo->auth_seq; ++ le_tmp16 = cpu_to_le16(val16); ++ pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&le_tmp16, &pattrib->pktlen); ++ ++ /* setting status code... */ ++ le_tmp16 = cpu_to_le16(status); ++ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&le_tmp16, &pattrib->pktlen); ++ ++ /* then checking to see if sending challenging text... */ ++ if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { ++ pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &pattrib->pktlen); ++ ++ SetPrivacy(fctrl); ++ ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pattrib->encrypt = _WEP40_; ++ ++ pattrib->icv_len = 4; ++ ++ pattrib->pktlen += pattrib->icv_len; ++ } ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ rtw_wep_encrypt(padapter, (u8 *)pmgntframe); ++ DBG_88E("%s\n", __func__); ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type) ++{ ++#ifdef CONFIG_88EU_AP_MODE ++ struct xmit_frame *pmgntframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ struct pkt_attrib *pattrib; ++ unsigned char *pbuf, *pframe; ++ unsigned short val; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network; ++ u8 *ie = pnetwork->IEs; ++ __le16 lestatus, leval; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ DBG_88E("%s\n", __func__); ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN); ++ memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) ++ SetFrameSubType(pwlanhdr, pkt_type); ++ else ++ return; ++ ++ pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen += pattrib->hdrlen; ++ pframe += pattrib->hdrlen; ++ ++ /* capability */ ++ val = *(unsigned short *)rtw_get_capability_from_ie(ie); ++ ++ pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_, (unsigned char *)&val, &pattrib->pktlen); ++ ++ lestatus = cpu_to_le16(status); ++ pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&lestatus, &pattrib->pktlen); ++ ++ leval = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); ++ pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_, (unsigned char *)&leval, &pattrib->pktlen); ++ ++ if (pstat->bssratelen <= 8) { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &pattrib->pktlen); ++ } else { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &pattrib->pktlen); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, pstat->bssratelen - 8, pstat->bssrateset + 8, &pattrib->pktlen); ++ } ++ ++ if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) { ++ uint ie_len = 0; ++ ++ /* FILL HT CAP INFO IE */ ++ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if (pbuf && ie_len > 0) { ++ memcpy(pframe, pbuf, ie_len + 2); ++ pframe += (ie_len + 2); ++ pattrib->pktlen += (ie_len + 2); ++ } ++ ++ /* FILL HT ADD INFO IE */ ++ pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); ++ if (pbuf && ie_len > 0) { ++ memcpy(pframe, pbuf, ie_len + 2); ++ pframe += (ie_len + 2); ++ pattrib->pktlen += (ie_len + 2); ++ } ++ } ++ ++ /* FILL WMM IE */ ++ if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) { ++ uint ie_len = 0; ++ unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; ++ ++ for (pbuf = ie + _BEACON_IE_OFFSET_;; pbuf += (ie_len + 2)) { ++ pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); ++ if (pbuf && !memcmp(pbuf + 2, WMM_PARA_IE, 6)) { ++ memcpy(pframe, pbuf, ie_len + 2); ++ pframe += (ie_len + 2); ++ pattrib->pktlen += (ie_len + 2); ++ break; ++ } ++ ++ if (!pbuf || ie_len == 0) ++ break; ++ } ++ } ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6, REALTEK_96B_IE, &pattrib->pktlen); ++ ++ /* add WPS IE ie for wps 2.0 */ ++ if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) { ++ memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); ++ ++ pframe += pmlmepriv->wps_assoc_resp_ie_len; ++ pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; ++ } ++ ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && (pstat->is_p2p_device)) { ++ u32 len; ++ ++ len = build_assoc_resp_p2p_ie(pwdinfo, pframe, pstat->p2p_status_code); ++ ++ pframe += len; ++ pattrib->pktlen += len; ++ } ++#endif /* CONFIG_88EU_P2P */ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ dump_mgntframe(padapter, pmgntframe); ++#endif ++} ++ ++void issue_assocreq(struct adapter *padapter) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe, *p; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ __le16 le_tmp; ++ unsigned int i, j, ie_len, index = 0; ++ unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates]; ++ struct ndis_802_11_var_ie *pIE; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ int bssrate_len = 0, sta_bssrate_len = 0; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 p2pie[255] = { 0x00 }; ++ u16 p2pielen = 0; ++#endif /* CONFIG_88EU_P2P */ ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ goto exit; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ASSOCREQ); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ /* caps */ ++ ++ memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); ++ ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* listen interval */ ++ /* todo: listen interval for power saving */ ++ le_tmp = cpu_to_le16(3); ++ memcpy(pframe, (unsigned char *)&le_tmp, 2); ++ pframe += 2; ++ pattrib->pktlen += 2; ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &pattrib->pktlen); ++ ++ /* supported rate & extended supported rate */ ++ ++ /* Check if the AP's supported rates are also supported by STA. */ ++ get_rate_set(padapter, sta_bssrate, &sta_bssrate_len); ++ ++ if (pmlmeext->cur_channel == 14)/* for JAPAN, channel 14 can only uses B Mode(CCK) */ ++ sta_bssrate_len = 4; ++ ++ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ if (pmlmeinfo->network.SupportedRates[i] == 0) ++ break; ++ DBG_88E("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]); ++ } ++ ++ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ if (pmlmeinfo->network.SupportedRates[i] == 0) ++ break; ++ ++ /* Check if the AP's supported rates are also supported by STA. */ ++ for (j = 0; j < sta_bssrate_len; j++) { ++ /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ ++ if ((pmlmeinfo->network.SupportedRates[i] | IEEE80211_BASIC_RATE_MASK) ++ == (sta_bssrate[j] | IEEE80211_BASIC_RATE_MASK)) ++ break; ++ } ++ ++ if (j == sta_bssrate_len) { ++ /* the rate is not supported by STA */ ++ DBG_88E("%s(): the rate[%d]=%02X is not supported by STA!\n", __func__, i, pmlmeinfo->network.SupportedRates[i]); ++ } else { ++ /* the rate is supported by STA */ ++ bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; ++ } ++ } ++ ++ bssrate_len = index; ++ DBG_88E("bssrate_len=%d\n", bssrate_len); ++ ++ if (bssrate_len == 0) { ++ rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pmgntframe); ++ goto exit; /* don't connect to AP if no joint supported rate */ ++ } ++ ++ if (bssrate_len > 8) { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, bssrate, &pattrib->pktlen); ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, bssrate_len - 8, bssrate + 8, &pattrib->pktlen); ++ } else { ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, bssrate_len, bssrate, &pattrib->pktlen); ++ } ++ ++ /* RSN */ ++ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); ++ if (p) ++ pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, p + 2, &pattrib->pktlen); ++ ++ /* HT caps */ ++ if (padapter->mlmepriv.htpriv.ht_option) { ++ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _HT_CAPABILITY_IE_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); ++ if (p && !is_ap_in_tkip(padapter)) { ++ memcpy(&pmlmeinfo->HT_caps, p + 2, sizeof(struct HT_caps_element)); ++ ++ /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ ++ if (pregpriv->cbw40_enable == 0) ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= cpu_to_le16(~(BIT(6) | BIT(1))); ++ else ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(BIT(1)); ++ ++ /* todo: disable SM power save mode */ ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x000c); ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ switch (rf_type) { ++ case RF_1T1R: ++ if (pregpriv->rx_stbc) ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */ ++ memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R, 16); ++ break; ++ case RF_2T2R: ++ case RF_1T2R: ++ default: ++ if ((pregpriv->rx_stbc == 0x3) ||/* enable for 2.4/5 GHz */ ++ ((pmlmeext->cur_wireless_mode & WIRELESS_11_24N) && (pregpriv->rx_stbc == 0x1)) || /* enable for 2.4GHz */ ++ (pregpriv->wifi_spec == 1)) { ++ DBG_88E("declare supporting RX STBC\n"); ++ pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */ ++ } ++ memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R, 16); ++ break; ++ } ++ pframe = rtw_set_ie(pframe, _HT_CAPABILITY_IE_, ie_len, (u8 *)(&pmlmeinfo->HT_caps), &pattrib->pktlen); ++ } ++ } ++ ++ /* vendor specific IE, such as WPA, WMM, WPS */ ++ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) { ++ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i); ++ ++ switch (pIE->ElementID) { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) || ++ (!memcmp(pIE->data, WMM_OUI, 4)) || ++ (!memcmp(pIE->data, WPS_OUI, 4))) { ++ if (!padapter->registrypriv.wifi_spec) { ++ /* Commented by Kurt 20110629 */ ++ /* In some older APs, WPS handshake */ ++ /* would be fail if we append vender extensions informations to AP */ ++ if (!memcmp(pIE->data, WPS_OUI, 4)) ++ pIE->Length = 14; ++ } ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, pIE->Length, pIE->data, &pattrib->pktlen); ++ } ++ break; ++ default: ++ break; ++ } ++ i += (pIE->Length + 2); ++ } ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6, REALTEK_96B_IE, &pattrib->pktlen); ++ ++#ifdef CONFIG_88EU_P2P ++ ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { ++ /* Should add the P2P IE in the association request frame. */ ++ /* P2P OUI */ ++ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20101109 */ ++ /* According to the P2P Specification, the association request frame should contain 3 P2P attributes */ ++ /* 1. P2P Capability */ ++ /* 2. Extended Listen Timing */ ++ /* 3. Device Info */ ++ /* Commented by Albert 20110516 */ ++ /* 4. P2P Interface */ ++ ++ /* P2P Capability */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Device Capability Bitmap, 1 byte */ ++ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ /* Group Capability Bitmap, 1 byte */ ++ if (pwdinfo->persistent_supported) ++ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; ++ else ++ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; ++ ++ /* Extended Listen Timing */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Availability Period */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); ++ p2pielen += 2; ++ ++ /* Availability Interval */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); ++ p2pielen += 2; ++ ++ /* Device Info */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; ++ ++ /* Length: */ ++ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ ++ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address */ ++ memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* Config Method */ ++ /* This field should be big endian. Noted by P2P specification. */ ++ if ((pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) || ++ (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)) ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); ++ else ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); ++ ++ p2pielen += 2; ++ ++ /* Primary Device Type */ ++ /* Category ID */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); ++ p2pielen += 2; ++ ++ /* OUI */ ++ *(__be32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); ++ p2pielen += 4; ++ ++ /* Sub Category ID */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); ++ p2pielen += 2; ++ ++ /* Number of Secondary Device Types */ ++ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ ++ ++ /* Device Name */ ++ /* Type: */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); ++ p2pielen += 2; ++ ++ /* Length: */ ++ *(__be16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); ++ p2pielen += pwdinfo->device_name_len; ++ ++ /* P2P Interface */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_INTERFACE; ++ ++ /* Length: */ ++ *(__le16 *)(p2pie + p2pielen) = cpu_to_le16(0x000D); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Device Address */ ++ p2pielen += ETH_ALEN; ++ ++ p2pie[p2pielen++] = 1; /* P2P Interface Address Count */ ++ ++ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Interface Address List */ ++ p2pielen += ETH_ALEN; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &pattrib->pktlen); ++ } ++ ++#endif /* CONFIG_88EU_P2P */ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ dump_mgntframe(padapter, pmgntframe); ++ ++ ret = _SUCCESS; ++ ++exit: ++ if (ret == _SUCCESS) ++ rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen); ++ else ++ kfree(pmlmepriv->assoc_req); ++} ++ ++/* when wait_ack is ture, this function shoule be called at process context */ ++static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ ++ if (!padapter) ++ goto exit; ++ ++ pxmitpriv = &padapter->xmitpriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ goto exit; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = false; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) ++ SetFrDs(fctrl); ++ else if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) ++ SetToDs(fctrl); ++ ++ if (power_mode) ++ SetPwrMgt(fctrl); ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_DATA_NULL); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (wait_ack) { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } else { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++/* when wait_ms > 0 , this function shoule be called at process context */ ++/* da == NULL for station mode */ ++int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = jiffies; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ /* da == NULL, assum it's null data for sta to ap*/ ++ if (!da) ++ da = get_my_bssid(&pmlmeinfo->network); ++ ++ do { ++ ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); ++ ++ if (ret != _FAIL) { ++ ret = _SUCCESS; ++ goto exit; ++ } ++ ++ if (try_cnt && wait_ms) { ++ if (da) ++ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ else ++ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ } ++exit: ++ return ret; ++} ++ ++/* when wait_ack is ture, this function shoule be called at process context */ ++static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack) ++{ ++ int ret = _FAIL; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ unsigned short *qc; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ DBG_88E("%s\n", __func__); ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ goto exit; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ pattrib->hdrlen += 2; ++ pattrib->qos_en = true; ++ pattrib->eosp = 1; ++ pattrib->ack_policy = 0; ++ pattrib->mdata = 0; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) ++ SetFrDs(fctrl); ++ else if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) ++ SetToDs(fctrl); ++ ++ if (pattrib->mdata) ++ SetMData(fctrl); ++ ++ qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); ++ ++ SetPriority(qc, tid); ++ ++ SetEOSP(qc, pattrib->eosp); ++ ++ SetAckpolicy(qc, pattrib->ack_policy); ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (wait_ack) { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } else { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++/* when wait_ms > 0 , this function shoule be called at process context */ ++/* da == NULL for station mode */ ++int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = jiffies; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ /* da == NULL, assum it's null data for sta to ap*/ ++ if (!da) ++ da = get_my_bssid(&pmlmeinfo->network); ++ ++ do { ++ ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); ++ ++ if (ret != _FAIL) { ++ ret = _SUCCESS; ++ goto exit; ++ } ++ ++ if (try_cnt && wait_ms) { ++ if (da) ++ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ else ++ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ } ++exit: ++ return ret; ++} ++ ++static int _issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ int ret = _FAIL; ++ __le16 le_tmp; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++#ifdef CONFIG_88EU_P2P ++ if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) && (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { ++ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); ++ _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ goto exit; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ pattrib->retry_ctrl = false; ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_DEAUTH); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ le_tmp = cpu_to_le16(reason); ++ pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_, (unsigned char *)&le_tmp, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ if (wait_ack) { ++ ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); ++ } else { ++ dump_mgntframe(padapter, pmgntframe); ++ ret = _SUCCESS; ++ } ++ ++exit: ++ return ret; ++} ++ ++int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason) ++{ ++ DBG_88E("%s to %pM\n", __func__, da); ++ return _issue_deauth(padapter, da, reason, false); ++} ++ ++int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt, ++ int wait_ms) ++{ ++ int ret; ++ int i = 0; ++ u32 start = jiffies; ++ ++ do { ++ ret = _issue_deauth(padapter, da, reason, wait_ms > 0); ++ ++ i++; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ break; ++ ++ if (i < try_cnt && wait_ms > 0 && ret == _FAIL) ++ msleep(wait_ms); ++ } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); ++ ++ if (ret != _FAIL) { ++ ret = _SUCCESS; ++ goto exit; ++ } ++ ++ if (try_cnt && wait_ms) { ++ if (da) ++ DBG_88E(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(padapter), da, rtw_get_oper_ch(padapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ else ++ DBG_88E(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", ++ FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), ++ ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); ++ } ++exit: ++ return ret; ++} ++ ++void issue_action_spct_ch_switch(struct adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ DBG_88E(FUNC_NDEV_FMT" ra =%pM, ch:%u, offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), ra, new_ch, ch_offset); ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */ ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); /* TA */ ++ memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */ ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ /* category, action */ ++ { ++ u8 category, action; ++ category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT; ++ action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH; ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ } ++ ++ pframe = rtw_set_ie_ch_switch(pframe, &pattrib->pktlen, 0, new_ch, 0); ++ pframe = rtw_set_ie_secondary_ch_offset(pframe, &pattrib->pktlen, ++ hal_ch_offset_to_secondary_ch_offset(ch_offset)); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) ++{ ++ u8 category = RTW_WLAN_CATEGORY_BACK; ++ u16 start_seq; ++ u16 BA_para_set; ++ u16 reason_code; ++ u16 BA_timeout_value; ++ __le16 le_tmp; ++ u16 BA_starting_seqctrl = 0; ++ enum ht_cap_ampdu_factor max_rx_ampdu_factor; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ u8 *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status); ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &pattrib->pktlen); ++ ++ if (category == 3) { ++ switch (action) { ++ case 0: /* ADDBA req */ ++ do { ++ pmlmeinfo->dialogToken++; ++ } while (pmlmeinfo->dialogToken == 0); ++ pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->dialogToken, &pattrib->pktlen); ++ ++ BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */ ++ le_tmp = cpu_to_le16(BA_para_set); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); ++ ++ BA_timeout_value = 5000;/* 5ms */ ++ le_tmp = cpu_to_le16(BA_timeout_value); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); ++ ++ psta = rtw_get_stainfo(pstapriv, raddr); ++ if (psta) { ++ start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07] & 0xfff) + 1; ++ ++ DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07); ++ ++ psta->BA_starting_seqctrl[status & 0x07] = start_seq; ++ ++ BA_starting_seqctrl = start_seq << 4; ++ } ++ le_tmp = cpu_to_le16(BA_starting_seqctrl); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); ++ break; ++ case 1: /* ADDBA rsp */ ++ pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->ADDBA_req.dialog_token, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&status, &pattrib->pktlen); ++ BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; ++ rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); ++ switch (max_rx_ampdu_factor) { ++ case MAX_AMPDU_FACTOR_64K: ++ BA_para_set |= 0x1000; /* 64 buffer size */ ++ break; ++ case MAX_AMPDU_FACTOR_32K: ++ BA_para_set |= 0x0800; /* 32 buffer size */ ++ break; ++ case MAX_AMPDU_FACTOR_16K: ++ BA_para_set |= 0x0400; /* 16 buffer size */ ++ break; ++ case MAX_AMPDU_FACTOR_8K: ++ BA_para_set |= 0x0200; /* 8 buffer size */ ++ break; ++ default: ++ BA_para_set |= 0x1000; /* 64 buffer size */ ++ break; ++ } ++ ++ if (pregpriv->ampdu_amsdu == 0)/* disabled */ ++ BA_para_set = BA_para_set & ~BIT(0); ++ else if (pregpriv->ampdu_amsdu == 1)/* enabled */ ++ BA_para_set = BA_para_set | BIT(0); ++ le_tmp = cpu_to_le16(BA_para_set); ++ ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeinfo->ADDBA_req.BA_timeout_value, &pattrib->pktlen); ++ break; ++ case 2:/* DELBA */ ++ BA_para_set = (status & 0x1F) << 3; ++ le_tmp = cpu_to_le16(BA_para_set); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); ++ ++ reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */ ++ le_tmp = cpu_to_le16(reason_code); ++ pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static void issue_action_BSSCoexistPacket(struct adapter *padapter) ++{ ++ struct list_head *plist, *phead; ++ unsigned char category, action; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct wlan_network *pnetwork = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ u8 InfoContent[16] = {0}; ++ u8 ICS[8][15]; ++ if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) ++ return; ++ ++ if (pmlmeinfo->bwmode_updated) ++ return; ++ ++ DBG_88E("%s\n", __func__); ++ ++ category = RTW_WLAN_CATEGORY_PUBLIC; ++ action = ACT_PUBLIC_BSSCOEXIST; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ ++ /* */ ++ if (pmlmepriv->num_FortyMHzIntolerant > 0) { ++ u8 iedata = 0; ++ ++ iedata |= BIT(2);/* 20 MHz BSS Width Request */ ++ ++ pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &pattrib->pktlen); ++ } ++ ++ /* */ ++ memset(ICS, 0, sizeof(ICS)); ++ if (pmlmepriv->num_sta_no_ht > 0) { ++ int i; ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ int len; ++ u8 *p; ++ struct wlan_bssid_ex *pbss_network; ++ ++ pnetwork = container_of(plist, struct wlan_network, list); ++ ++ plist = plist->next; ++ ++ pbss_network = (struct wlan_bssid_ex *)&pnetwork->network; ++ ++ p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); ++ if (!p || len == 0) { /* non-HT */ ++ if ((pbss_network->Configuration.DSConfig <= 0) || (pbss_network->Configuration.DSConfig > 14)) ++ continue; ++ ++ ICS[0][pbss_network->Configuration.DSConfig] = 1; ++ ++ if (ICS[0][0] == 0) ++ ICS[0][0] = 1; ++ } ++ } ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ for (i = 0; i < 8; i++) { ++ if (ICS[i][0] == 1) { ++ int j, k = 0; ++ ++ InfoContent[k] = i; ++ /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */ ++ k++; ++ ++ for (j = 1; j <= 14; j++) { ++ if (ICS[i][j] == 1) { ++ if (k < 16) { ++ InfoContent[k] = j; /* channel number */ ++ /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ ++ k++; ++ } ++ } ++ } ++ ++ pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &pattrib->pktlen); ++ } ++ } ++ } ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta = NULL; ++ /* struct recv_reorder_ctrl *preorder_ctrl; */ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u16 tid; ++ ++ if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) ++ if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) ++ return _SUCCESS; ++ ++ psta = rtw_get_stainfo(pstapriv, addr); ++ if (!psta) ++ return _SUCCESS; ++ ++ if (initiator == 0) { /* recipient */ ++ for (tid = 0; tid < MAXTID; tid++) { ++ if (psta->recvreorder_ctrl[tid].enable) { ++ DBG_88E("rx agg disable tid(%d)\n", tid); ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F)); ++ psta->recvreorder_ctrl[tid].enable = false; ++ psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; ++ } ++ } ++ } else if (initiator == 1) { /* originator */ ++ for (tid = 0; tid < MAXTID; tid++) { ++ if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { ++ DBG_88E("tx agg disable tid(%d)\n", tid); ++ issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F)); ++ psta->htpriv.agg_enable_bitmap &= ~BIT(tid); ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); ++ } ++ } ++ } ++ ++ return _SUCCESS; ++} ++ ++unsigned int send_beacon(struct adapter *padapter) ++{ ++ u8 bxmitok = false; ++ int issue = 0; ++ int poll = 0; ++ ++ u32 start = jiffies; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); ++ do { ++ issue_beacon(padapter, 100); ++ issue++; ++ do { ++ yield(); ++ rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); ++ poll++; ++ } while ((poll % 10) != 0 && !bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ } while (!bxmitok && issue < 100 && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); ++ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ return _FAIL; ++ if (!bxmitok) { ++ DBG_88E("%s fail! %u ms\n", __func__, rtw_get_passing_time_ms(start)); ++ return _FAIL; ++ } else { ++ u32 passing_time = rtw_get_passing_time_ms(start); ++ ++ if (passing_time > 100 || issue > 3) ++ DBG_88E("%s success, issue:%d, poll:%d, %u ms\n", __func__, issue, poll, rtw_get_passing_time_ms(start)); ++ return _SUCCESS; ++ } ++} ++ ++/**************************************************************************** ++ ++Following are some utitity fuctions for WiFi MLME ++ ++*****************************************************************************/ ++ ++void site_survey(struct adapter *padapter) ++{ ++ unsigned char survey_channel = 0, val8; ++ enum rt_scan_type ScanType = SCAN_PASSIVE; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u32 initialgain = 0; ++ ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) { ++ if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { ++ survey_channel = pwdinfo->rx_invitereq_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; ++ } else { ++ survey_channel = pwdinfo->p2p_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx]; ++ } ++ ScanType = SCAN_ACTIVE; ++ } else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) { ++ /* Commented by Albert 2011/06/03 */ ++ /* The driver is in the find phase, it should go through the social channel. */ ++ int ch_set_idx; ++ survey_channel = pwdinfo->social_chan[pmlmeext->sitesurvey_res.channel_idx]; ++ ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, survey_channel); ++ if (ch_set_idx >= 0) ++ ScanType = pmlmeext->channel_set[ch_set_idx].ScanType; ++ else ++ ScanType = SCAN_ACTIVE; ++ } else ++#endif /* CONFIG_88EU_P2P */ ++ { ++ struct rtw_ieee80211_channel *ch; ++ if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) { ++ ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx]; ++ survey_channel = ch->hw_value; ++ ScanType = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE; ++ } ++ } ++ ++ if (survey_channel != 0) { ++ /* PAUSE 4-AC Queue when site_survey */ ++ /* rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ ++ /* val8 |= 0x0f; */ ++ /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ ++ if (pmlmeext->sitesurvey_res.channel_idx == 0) ++ set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ else ++ SelectChannel(padapter, survey_channel); ++ ++ if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */ ++ #ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || ++ rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) { ++ issue_probereq_p2p(padapter, NULL); ++ issue_probereq_p2p(padapter, NULL); ++ issue_probereq_p2p(padapter, NULL); ++ } else ++ #endif /* CONFIG_88EU_P2P */ ++ { ++ int i; ++ for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { ++ if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) { ++ /* todo: to issue two probe req??? */ ++ issue_probereq(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL); ++ /* msleep(SURVEY_TO>>1); */ ++ issue_probereq(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL); ++ } ++ } ++ ++ if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { ++ /* todo: to issue two probe req??? */ ++ issue_probereq(padapter, NULL, NULL); ++ /* msleep(SURVEY_TO>>1); */ ++ issue_probereq(padapter, NULL, NULL); ++ } ++ } ++ } ++ ++ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); ++ } else { ++ /* channel number is 0 or this channel is not valid. */ ++ ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) { ++ if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only)) { ++ /* Set the find_phase_state_exchange_cnt to P2P_FINDPHASE_EX_CNT. */ ++ /* This will let the following flow to run the scanning end. */ ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); ++ } ++ } ++ ++ if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) { ++ /* Set the P2P State to the listen state of find phase and set the current channel to the listen channel */ ++ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN); ++ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; ++ ++ initialgain = 0xff; /* restore RX GAIN */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ /* turn on dynamic functions */ ++ Restore_DM_Func_Flag(padapter); ++ /* Switch_DM_Func(padapter, DYNAMIC_FUNC_DIG|DYNAMIC_FUNC_HP|DYNAMIC_FUNC_SS, true); */ ++ ++ _set_timer(&pwdinfo->find_phase_timer, (u32)((u32)(pwdinfo->listen_dwell) * 100)); ++ } else ++#endif /* CONFIG_88EU_P2P */ ++ { ++ /* 20100721:Interrupt scan operation here. */ ++ /* For SW antenna diversity before link, it needs to switch to another antenna and scan again. */ ++ /* It compares the scan result and select beter one to do connection. */ ++ if (rtw_hal_antdiv_before_linked(padapter)) { ++ pmlmeext->sitesurvey_res.bss_cnt = 0; ++ pmlmeext->sitesurvey_res.channel_idx = -1; ++ pmlmeext->chan_scan_time = SURVEY_TO / 2; ++ set_survey_timer(pmlmeext, pmlmeext->chan_scan_time); ++ return; ++ } ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); ++#endif /* CONFIG_88EU_P2P */ ++ ++ pmlmeext->sitesurvey_res.state = SCAN_COMPLETE; ++ ++ /* switch back to the original channel */ ++ ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN)) ++ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ else ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++#endif /* CONFIG_88EU_P2P */ ++ ++ /* flush 4-AC Queue after site_survey */ ++ /* val8 = 0; */ ++ /* rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */ ++ ++ /* config MSR */ ++ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); ++ ++ initialgain = 0xff; /* restore RX GAIN */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ /* turn on dynamic functions */ ++ Restore_DM_Func_Flag(padapter); ++ /* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */ ++ ++ if (is_client_associated_to_ap(padapter)) ++ issue_nulldata(padapter, NULL, 0, 3, 500); ++ ++ val8 = 0; /* survey done */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ ++ report_surveydone_event(padapter); ++ ++ pmlmeext->chan_scan_time = SURVEY_TO; ++ pmlmeext->sitesurvey_res.state = SCAN_DISABLE; ++ ++ issue_action_BSSCoexistPacket(padapter); ++ issue_action_BSSCoexistPacket(padapter); ++ issue_action_BSSCoexistPacket(padapter); ++ } ++ } ++} ++ ++/* collect bss info from Beacon and Probe request/response frames. */ ++u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid) ++{ ++ int i; ++ u32 len; ++ u8 *p; ++ u16 val16, subtype; ++ u8 *pframe = precv_frame->rx_data; ++ u32 packet_len = precv_frame->len; ++ u8 ie_offset; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ __le32 le32_tmp; ++ ++ len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (len > MAX_IE_SZ) ++ return _FAIL; ++ ++ memset(bssid, 0, sizeof(struct wlan_bssid_ex)); ++ ++ subtype = GetFrameSubType(pframe); ++ ++ if (subtype == WIFI_BEACON) { ++ bssid->Reserved[0] = 1; ++ ie_offset = _BEACON_IE_OFFSET_; ++ } else { ++ /* FIXME : more type */ ++ if (subtype == WIFI_PROBEREQ) { ++ ie_offset = _PROBEREQ_IE_OFFSET_; ++ bssid->Reserved[0] = 2; ++ } else if (subtype == WIFI_PROBERSP) { ++ ie_offset = _PROBERSP_IE_OFFSET_; ++ bssid->Reserved[0] = 3; ++ } else { ++ bssid->Reserved[0] = 0; ++ ie_offset = _FIXED_IE_LENGTH_; ++ } ++ } ++ ++ bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; ++ ++ /* below is to copy the information element */ ++ bssid->IELength = len; ++ memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); ++ ++ /* get the signal strength */ ++ bssid->Rssi = precv_frame->attrib.phy_info.recvpower; /* in dBM.raw data */ ++ bssid->PhyInfo.SignalQuality = precv_frame->attrib.phy_info.SignalQuality;/* in percentage */ ++ bssid->PhyInfo.SignalStrength = precv_frame->attrib.phy_info.SignalStrength;/* in percentage */ ++ rtw_hal_get_def_var(padapter, HAL_DEF_CURRENT_ANTENNA, &bssid->PhyInfo.Optimum_antenna); ++ ++ /* checking SSID */ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset); ++ if (!p) { ++ DBG_88E("marc: cannot find SSID for survey event\n"); ++ return _FAIL; ++ } ++ ++ if (*(p + 1)) { ++ if (len > NDIS_802_11_LENGTH_SSID) { ++ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); ++ return _FAIL; ++ } ++ memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); ++ bssid->Ssid.SsidLength = *(p + 1); ++ } else { ++ bssid->Ssid.SsidLength = 0; ++ } ++ ++ memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); ++ ++ /* checking rate info... */ ++ i = 0; ++ p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); ++ if (p) { ++ if (len > NDIS_802_11_LENGTH_RATES_EX) { ++ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); ++ return _FAIL; ++ } ++ memcpy(bssid->SupportedRates, (p + 2), len); ++ i = len; ++ } ++ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); ++ if (p) { ++ if (len > (NDIS_802_11_LENGTH_RATES_EX - i)) { ++ DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); ++ return _FAIL; ++ } ++ memcpy(bssid->SupportedRates + i, (p + 2), len); ++ } ++ ++ /* todo: */ ++ bssid->NetworkTypeInUse = Ndis802_11OFDM24; ++ ++ if (bssid->IELength < 12) ++ return _FAIL; ++ ++ /* Checking for DSConfig */ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); ++ ++ bssid->Configuration.DSConfig = 0; ++ bssid->Configuration.Length = 0; ++ ++ if (p) { ++ bssid->Configuration.DSConfig = *(p + 2); ++ } else {/* In 5G, some ap do not have DSSET IE */ ++ /* checking HT info for channel */ ++ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); ++ if (p) { ++ struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); ++ bssid->Configuration.DSConfig = HT_info->primary_channel; ++ } else { /* use current channel */ ++ bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter); ++ } ++ } ++ ++ memcpy(&le32_tmp, rtw_get_beacon_interval_from_ie(bssid->IEs), 2); ++ bssid->Configuration.BeaconPeriod = le32_to_cpu(le32_tmp); ++ ++ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); ++ ++ if (val16 & BIT(0)) { ++ bssid->InfrastructureMode = Ndis802_11Infrastructure; ++ memcpy(bssid->MacAddress, GetAddr2Ptr(pframe), ETH_ALEN); ++ } else { ++ bssid->InfrastructureMode = Ndis802_11IBSS; ++ memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN); ++ } ++ ++ if (val16 & BIT(4)) ++ bssid->Privacy = 1; ++ else ++ bssid->Privacy = 0; ++ ++ bssid->Configuration.ATIMWindow = 0; ++ ++ /* 20/40 BSS Coexistence check */ ++ if ((pregistrypriv->wifi_spec == 1) && (!pmlmeinfo->bwmode_updated)) { ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); ++ if (p && len > 0) { ++ struct HT_caps_element *pHT_caps; ++ pHT_caps = (struct HT_caps_element *)(p + 2); ++ ++ if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & BIT(14)) ++ pmlmepriv->num_FortyMHzIntolerant++; ++ } else { ++ pmlmepriv->num_sta_no_ht++; ++ } ++ } ++ ++ /* mark bss info receiving from nearby channel as SignalQuality 101 */ ++ if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) ++ bssid->PhyInfo.SignalQuality = 101; ++ return _SUCCESS; ++} ++ ++void start_create_ibss(struct adapter *padapter) ++{ ++ unsigned short caps; ++ u8 val8; ++ u8 join_type; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&pmlmeinfo->network); ++ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; ++ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); ++ ++ /* update wireless mode */ ++ update_wireless_mode(padapter); ++ ++ /* udpate capability */ ++ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); ++ update_capinfo(padapter, caps); ++ if (caps & cap_IBSS) {/* adhoc master */ ++ val8 = 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ /* switch channel */ ++ /* SelectChannel(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ ++ beacon_timing_control(padapter); ++ ++ /* set msr to WIFI_FW_ADHOC_STATE */ ++ pmlmeinfo->state = WIFI_FW_ADHOC_STATE; ++ Set_MSR(padapter, (pmlmeinfo->state & 0x3)); ++ ++ /* issue beacon */ ++ if (send_beacon(padapter) == _FAIL) { ++ report_join_res(padapter, -1); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ } else { ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); ++ join_type = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ ++ report_join_res(padapter, 1); ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ rtw_indicate_connect(padapter); ++ } ++ } else { ++ DBG_88E("start_create_ibss, invalid cap:%x\n", caps); ++ return; ++ } ++ /* update bc/mc sta_info */ ++ update_bmc_sta(padapter); ++} ++ ++void start_clnt_join(struct adapter *padapter) ++{ ++ unsigned short caps; ++ u8 val8; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&pmlmeinfo->network); ++ int beacon_timeout; ++ ++ pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; ++ pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); ++ ++ /* update wireless mode */ ++ update_wireless_mode(padapter); ++ ++ /* udpate capability */ ++ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); ++ update_capinfo(padapter, caps); ++ if (caps & cap_ESS) { ++ Set_MSR(padapter, WIFI_FW_STATION_STATE); ++ ++ val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ /* switch channel */ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ /* here wait for receiving the beacon to start auth */ ++ /* and enable a timer */ ++ beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval); ++ set_link_timer(pmlmeext, beacon_timeout); ++ _set_timer(&padapter->mlmepriv.assoc_timer, ++ (REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO * REASSOC_LIMIT) + beacon_timeout); ++ ++ pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; ++ } else if (caps & cap_IBSS) { /* adhoc client */ ++ Set_MSR(padapter, WIFI_FW_ADHOC_STATE); ++ ++ val8 = 0xcf; ++ rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); ++ ++ /* switch channel */ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ beacon_timing_control(padapter); ++ ++ pmlmeinfo->state = WIFI_FW_ADHOC_STATE; ++ ++ report_join_res(padapter, 1); ++ } else { ++ return; ++ } ++} ++ ++void start_clnt_auth(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); ++ pmlmeinfo->state |= WIFI_FW_AUTH_STATE; ++ ++ pmlmeinfo->auth_seq = 1; ++ pmlmeinfo->reauth_count = 0; ++ pmlmeinfo->reassoc_count = 0; ++ pmlmeinfo->link_count = 0; ++ pmlmeext->retry = 0; ++ ++ /* Because of AP's not receiving deauth before */ ++ /* AP may: 1)not response auth or 2)deauth us after link is complete */ ++ /* issue deauth before issuing auth to deal with the situation */ ++ /* Commented by Albert 2012/07/21 */ ++ /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ ++ issue_deauth(padapter, (&pmlmeinfo->network)->MacAddress, WLAN_REASON_DEAUTH_LEAVING); ++ ++ DBG_88E_LEVEL(_drv_info_, "start auth\n"); ++ issue_auth(padapter, NULL, 0); ++ ++ set_link_timer(pmlmeext, REAUTH_TO); ++} ++ ++void start_clnt_assoc(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); ++ pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); ++ ++ issue_assocreq(padapter); ++ ++ set_link_timer(pmlmeext, REASSOC_TO); ++} ++ ++unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ /* check A3 */ ++ if (!(!memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) ++ return _SUCCESS; ++ ++ DBG_88E("%s\n", __func__); ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_del_sta_event(padapter, MacAddr, reason); ++ } else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -2); ++ } ++ } ++ return _SUCCESS; ++} ++ ++static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid) ++{ ++ struct registry_priv *pregistrypriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct rt_channel_info *chplan_new; ++ u8 channel; ++ u8 i; ++ ++ pregistrypriv = &padapter->registrypriv; ++ pmlmeext = &padapter->mlmeextpriv; ++ ++ /* Adjust channel plan by AP Country IE */ ++ if (pregistrypriv->enable80211d && ++ (!pmlmeext->update_channel_plan_by_ap_done)) { ++ u8 *ie, *p; ++ u32 len; ++ struct rt_channel_plan chplan_ap; ++ struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM]; ++ u8 country[4]; ++ u8 fcn; /* first channel number */ ++ u8 noc; /* number of channel */ ++ u8 j, k; ++ ++ ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (!ie) ++ return; ++ if (len < 6) ++ return; ++ ie += 2; ++ p = ie; ++ ie += len; ++ ++ memset(country, 0, 4); ++ memcpy(country, p, 3); ++ p += 3; ++ ++ i = 0; ++ while ((ie - p) >= 3) { ++ fcn = *(p++); ++ noc = *(p++); ++ p++; ++ ++ for (j = 0; j < noc; j++) { ++ channel = fcn + j; ++ chplan_ap.Channel[i++] = channel; ++ } ++ } ++ chplan_ap.Len = i; ++ ++ memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); ++ ++ memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); ++ chplan_new = pmlmeext->channel_set; ++ ++ i = 0; ++ j = 0; ++ k = 0; ++ if (pregistrypriv->wireless_mode & WIRELESS_11G) { ++ do { ++ if ((i == MAX_CHANNEL_NUM) || ++ (chplan_sta[i].ChannelNum == 0)) ++ break; ++ ++ if (j == chplan_ap.Len) ++ break; ++ ++ if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ i++; ++ j++; ++ k++; ++ } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } while (1); ++ ++ /* change AP not support channel to Passive scan */ ++ while ((i < MAX_CHANNEL_NUM) && ++ (chplan_sta[i].ChannelNum != 0) && ++ (chplan_sta[i].ChannelNum <= 14)) { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++ chplan_new[k].ScanType = SCAN_PASSIVE; ++ i++; ++ k++; ++ } ++ ++ /* add channel AP supported */ ++ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { ++ chplan_new[k].ChannelNum = chplan_ap.Channel[j]; ++ chplan_new[k].ScanType = SCAN_ACTIVE; ++ j++; ++ k++; ++ } ++ } else { ++ /* keep original STA 2.4G channel plan */ ++ while ((i < MAX_CHANNEL_NUM) && ++ (chplan_sta[i].ChannelNum != 0) && ++ (chplan_sta[i].ChannelNum <= 14)) { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++ chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ i++; ++ k++; ++ } ++ ++ /* skip AP 2.4G channel plan */ ++ while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) ++ j++; ++ } ++ ++ /* keep original STA 5G channel plan */ ++ while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { ++ chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; ++ chplan_new[k].ScanType = chplan_sta[i].ScanType; ++ i++; ++ k++; ++ } ++ ++ pmlmeext->update_channel_plan_by_ap_done = 1; ++ } ++ ++ /* If channel is used by AP, set channel scan type to active */ ++ channel = bssid->Configuration.DSConfig; ++ chplan_new = pmlmeext->channel_set; ++ i = 0; ++ while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) { ++ if (chplan_new[i].ChannelNum == channel) { ++ if (chplan_new[i].ScanType == SCAN_PASSIVE) ++ chplan_new[i].ScanType = SCAN_ACTIVE; ++ break; ++ } ++ i++; ++ } ++} ++ ++/**************************************************************************** ++ ++Following are the functions to report events ++ ++*****************************************************************************/ ++ ++void report_survey_event(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct survey_event *psurvey_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext; ++ struct cmd_priv *pcmdpriv; ++ /* u8 *pframe = precv_frame->rx_data; */ ++ /* uint len = precv_frame->len; */ ++ ++ if (!padapter) ++ return; ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ pcmdpriv = &padapter->cmdpriv; ++ ++ pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!pcmd_obj) ++ return; ++ ++ cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); ++ pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); ++ if (!pevtcmd) { ++ kfree(pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct survey_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ ++ if (collect_bss_info(padapter, precv_frame, (struct wlan_bssid_ex *)&psurvey_evt->bss) == _FAIL) { ++ kfree(pcmd_obj); ++ kfree(pevtcmd); ++ return; ++ } ++ ++ process_80211d(padapter, &psurvey_evt->bss); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++ ++ pmlmeext->sitesurvey_res.bss_cnt++; ++} ++ ++void report_surveydone_event(struct adapter *padapter) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct surveydone_event *psurveydone_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!pcmd_obj) ++ return; ++ ++ cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header)); ++ pevtcmd = kzalloc(cmdsz, GFP_KERNEL); ++ if (!pevtcmd) { ++ kfree(pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct surveydone_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; ++ ++ DBG_88E("survey done event(%x)\n", psurveydone_evt->bss_cnt); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++} ++ ++void report_join_res(struct adapter *padapter, int res) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct joinbss_event *pjoinbss_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!pcmd_obj) ++ return; ++ ++ cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); ++ pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); ++ if (!pevtcmd) { ++ kfree(pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct joinbss_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ memcpy((unsigned char *)(&pjoinbss_evt->network.network), &pmlmeinfo->network, sizeof(struct wlan_bssid_ex)); ++ pjoinbss_evt->network.join_res = res; ++ pjoinbss_evt->network.aid = res; ++ ++ DBG_88E("report_join_res(%d)\n", res); ++ ++ rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++} ++ ++void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct sta_info *psta; ++ int mac_id; ++ struct stadel_event *pdel_sta_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!pcmd_obj) ++ return; ++ ++ cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header)); ++ pevtcmd = kzalloc(cmdsz, GFP_KERNEL); ++ if (!pevtcmd) { ++ kfree(pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct stadel_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ memcpy((unsigned char *)(&pdel_sta_evt->macaddr), MacAddr, ETH_ALEN); ++ memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2); ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, MacAddr); ++ if (psta) ++ mac_id = (int)psta->mac_id; ++ else ++ mac_id = (-1); ++ ++ pdel_sta_evt->mac_id = mac_id; ++ ++ DBG_88E("report_del_sta_event: delete STA, mac_id =%d\n", mac_id); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++} ++ ++void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int cam_idx) ++{ ++ struct cmd_obj *pcmd_obj; ++ u8 *pevtcmd; ++ u32 cmdsz; ++ struct stassoc_event *padd_sta_evt; ++ struct C2HEvent_Header *pc2h_evt_hdr; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ ++ pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); ++ if (!pcmd_obj) ++ return; ++ ++ cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header)); ++ pevtcmd = kzalloc(cmdsz, GFP_KERNEL); ++ if (!pevtcmd) { ++ kfree(pcmd_obj); ++ return; ++ } ++ ++ INIT_LIST_HEAD(&pcmd_obj->list); ++ ++ pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); ++ pcmd_obj->cmdsz = cmdsz; ++ pcmd_obj->parmbuf = pevtcmd; ++ ++ pcmd_obj->rsp = NULL; ++ pcmd_obj->rspsz = 0; ++ ++ pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); ++ pc2h_evt_hdr->len = sizeof(struct stassoc_event); ++ pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); ++ pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); ++ ++ padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ++ memcpy((unsigned char *)(&padd_sta_evt->macaddr), MacAddr, ETH_ALEN); ++ padd_sta_evt->cam_id = cam_idx; ++ ++ DBG_88E("report_add_sta_event: add STA\n"); ++ ++ rtw_enqueue_cmd(pcmdpriv, pcmd_obj); ++} ++ ++/**************************************************************************** ++ ++Following are the event callback functions ++ ++*****************************************************************************/ ++ ++/* for sta/adhoc mode */ ++void update_sta_info(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ /* ERP */ ++ VCS_update(padapter, psta); ++ ++ /* HT */ ++ if (pmlmepriv->htpriv.ht_option) { ++ psta->htpriv.ht_option = true; ++ ++ psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable; ++ ++ if (support_short_GI(padapter, &pmlmeinfo->HT_caps)) ++ psta->htpriv.sgi = true; ++ ++ psta->qos_option = true; ++ } else { ++ psta->htpriv.ht_option = false; ++ ++ psta->htpriv.ampdu_enable = false; ++ ++ psta->htpriv.sgi = false; ++ psta->qos_option = false; ++ } ++ psta->htpriv.bwmode = pmlmeext->cur_bwmode; ++ psta->htpriv.ch_offset = pmlmeext->cur_ch_offset; ++ ++ psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ ++ psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ ++ ++ /* QoS */ ++ if (pmlmepriv->qospriv.qos_option) ++ psta->qos_option = true; ++ ++ psta->state = _FW_LINKED; ++} ++ ++void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) ++{ ++ struct sta_info *psta, *psta_bmc; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 join_type; ++ u16 media_status; ++ ++ if (join_res < 0) { ++ join_type = 1; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); ++ ++ /* restore to initial setting. */ ++ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); ++ ++ goto exit_mlmeext_joinbss_event_callback; ++ } ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { ++ /* for bc/mc */ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if (psta_bmc) { ++ pmlmeinfo->FW_sta_info[psta_bmc->mac_id].psta = psta_bmc; ++ update_bmc_sta_support_rate(padapter, psta_bmc->mac_id); ++ Update_RA_Entry(padapter, psta_bmc->mac_id); ++ } ++ } ++ ++ /* turn on dynamic functions */ ++ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); ++ ++ /* update IOT-releated issue */ ++ update_IOT_info(padapter); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); ++ ++ /* BCN interval */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval)); ++ ++ /* udpate capability */ ++ update_capinfo(padapter, pmlmeinfo->capability); ++ ++ /* WMM, Update EDCA param */ ++ WMMOnAssocRsp(padapter); ++ ++ /* HT */ ++ HTOnAssocRsp(padapter); ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); ++ if (psta) { /* only for infra. mode */ ++ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; ++ ++ psta->wireless_mode = pmlmeext->cur_wireless_mode; ++ ++ /* set per sta rate after updating HT cap. */ ++ set_sta_rate(padapter, psta); ++ rtw_hal_set_hwreg(padapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&psta->mac_id); ++ media_status = (psta->mac_id << 8) | 1; /* MACID|OPMODE: 1 means connect */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); ++ } ++ ++ join_type = 2; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { ++ /* correcting TSF */ ++ correct_TSF(padapter, pmlmeext); ++ } ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); ++ ++exit_mlmeext_joinbss_event_callback: ++ ++ DBG_88E("=>%s\n", __func__); ++} ++ ++void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 join_type; ++ ++ DBG_88E("%s\n", __func__); ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) {/* adhoc master or sta_count>1 */ ++ /* nothing to do */ ++ } else { /* adhoc client */ ++ /* correcting TSF */ ++ correct_TSF(padapter, pmlmeext); ++ ++ /* start beacon */ ++ if (send_beacon(padapter) == _FAIL) { ++ pmlmeinfo->FW_sta_info[psta->mac_id].status = 0; ++ pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE; ++ return; ++ } ++ pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; ++ } ++ ++ join_type = 2; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ } ++ ++ pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta; ++ ++ /* rate radaptive */ ++ Update_RA_Entry(padapter, psta->mac_id); ++ ++ /* update adhoc sta_info */ ++ update_sta_info(padapter, psta); ++} ++ ++void mlmeext_sta_del_event_callback(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter)) { ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); ++ ++ /* restore to initial setting. */ ++ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); ++ ++ /* switch to the 20M Hz mode after disconnect */ ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ /* SelectChannel(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); */ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ flush_all_cam_entry(padapter); ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ /* set MSR to no link state -> infra. mode */ ++ Set_MSR(padapter, _HW_STATE_STATION_); ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ } ++} ++ ++/**************************************************************************** ++ ++Following are the functions for the timer handlers ++ ++*****************************************************************************/ ++void _linked_rx_signal_strehgth_display(struct adapter *padapter); ++void _linked_rx_signal_strehgth_display(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 mac_id; ++ int UndecoratedSmoothedPWDB; ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) ++ mac_id = 0; ++ else if ((pmlmeinfo->state & 0x03) == _HW_STATE_AP_) ++ mac_id = 2; ++ ++ rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, &mac_id); ++ ++ rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); ++ DBG_88E("UndecoratedSmoothedPWDB:%d\n", UndecoratedSmoothedPWDB); ++} ++ ++static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 ret = false; ++ ++ if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) && ++ sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) && ++ sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta)) ++ ret = false; ++ else ++ ret = true; ++ ++ sta_update_last_rx_pkts(psta); ++ ++ return ret; ++} ++ ++void linked_status_chk(struct adapter *padapter) ++{ ++ u32 i; ++ struct sta_info *psta; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if (padapter->bRxRSSIDisplay) ++ _linked_rx_signal_strehgth_display(padapter); ++ ++ rtw_hal_sreset_linked_status_check(padapter); ++ ++ if (is_client_associated_to_ap(padapter)) { ++ /* linked infrastructure client mode */ ++ ++ int tx_chk = _SUCCESS, rx_chk = _SUCCESS; ++ int rx_chk_limit; ++ ++ rx_chk_limit = 4; ++ psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress); ++ if (psta) { ++ bool is_p2p_enable = false; ++ #ifdef CONFIG_88EU_P2P ++ is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE); ++ #endif ++ ++ if (!chk_ap_is_alive(padapter, psta)) ++ rx_chk = _FAIL; ++ ++ if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts) ++ tx_chk = _FAIL; ++ ++ if (pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL)) { ++ u8 backup_oper_channel = 0; ++ ++ /* switch to correct channel of current network before issue keep-alive frames */ ++ if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { ++ backup_oper_channel = rtw_get_oper_ch(padapter); ++ SelectChannel(padapter, pmlmeext->cur_channel); ++ } ++ ++ if (rx_chk != _SUCCESS) ++ issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1); ++ ++ if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) || rx_chk != _SUCCESS) { ++ tx_chk = issue_nulldata(padapter, psta->hwaddr, 0, 3, 1); ++ /* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */ ++ if (tx_chk == _SUCCESS && !is_p2p_enable) ++ rx_chk = _SUCCESS; ++ } ++ ++ /* back to the original operation channel */ ++ if (backup_oper_channel > 0) ++ SelectChannel(padapter, backup_oper_channel); ++ } else { ++ if (rx_chk != _SUCCESS) { ++ if (pmlmeext->retry == 0) { ++ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); ++ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); ++ issue_probereq(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress); ++ } ++ } ++ ++ if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) { ++ tx_chk = issue_nulldata(padapter, NULL, 0, 1, 0); ++ } ++ } ++ ++ if (rx_chk == _FAIL) { ++ pmlmeext->retry++; ++ if (pmlmeext->retry > rx_chk_limit) { ++ DBG_88E_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n", ++ FUNC_ADPT_ARG(padapter)); ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress, ++ WLAN_REASON_EXPIRATION_CHK); ++ return; ++ } ++ } else { ++ pmlmeext->retry = 0; ++ } ++ ++ if (tx_chk == _FAIL) { ++ pmlmeinfo->link_count &= 0xf; ++ } else { ++ pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts; ++ pmlmeinfo->link_count = 0; ++ } ++ } /* end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) */ ++ } else if (is_client_associated_to_ibss(padapter)) { ++ /* linked IBSS mode */ ++ /* for each assoc list entry to check the rx pkt counter */ ++ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) { ++ if (pmlmeinfo->FW_sta_info[i].status == 1) { ++ psta = pmlmeinfo->FW_sta_info[i].psta; ++ ++ if (NULL == psta) ++ continue; ++ if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) { ++ if (pmlmeinfo->FW_sta_info[i].retry < 3) { ++ pmlmeinfo->FW_sta_info[i].retry++; ++ } else { ++ pmlmeinfo->FW_sta_info[i].retry = 0; ++ pmlmeinfo->FW_sta_info[i].status = 0; ++ report_del_sta_event(padapter, psta->hwaddr ++ , 65535/* indicate disconnect caused by no rx */ ++ ); ++ } ++ } else { ++ pmlmeinfo->FW_sta_info[i].retry = 0; ++ pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta); ++ } ++ } ++ } ++ } ++} ++ ++void survey_timer_hdl(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct sitesurvey_parm *psurveyPara; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif ++ ++ /* issue rtw_sitesurvey_cmd */ ++ if (pmlmeext->sitesurvey_res.state > SCAN_START) { ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) ++ pmlmeext->sitesurvey_res.channel_idx++; ++ ++ if (pmlmeext->scan_abort) { ++ #ifdef CONFIG_88EU_P2P ++ if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) { ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); ++ pmlmeext->sitesurvey_res.channel_idx = 3; ++ DBG_88E("%s idx:%d, cnt:%u\n", __func__ ++ , pmlmeext->sitesurvey_res.channel_idx ++ , pwdinfo->find_phase_state_exchange_cnt ++ ); ++ } else ++ #endif ++ { ++ pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num; ++ DBG_88E("%s idx:%d\n", __func__ ++ , pmlmeext->sitesurvey_res.channel_idx ++ ); ++ } ++ ++ pmlmeext->scan_abort = false;/* reset */ ++ } ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) ++ goto exit_survey_timer_hdl; ++ ++ psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC); ++ if (!psurveyPara) { ++ kfree(ph2c); ++ goto exit_survey_timer_hdl; ++ } ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); ++ rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } ++ ++exit_survey_timer_hdl: ++ return; ++} ++ ++void link_timer_hdl(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { ++ DBG_88E("link_timer_hdl:no beacon while connecting\n"); ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -3); ++ } else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) { ++ /* re-auth timer */ ++ if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) { ++ pmlmeinfo->state = 0; ++ report_join_res(padapter, -1); ++ return; ++ } ++ ++ DBG_88E("link_timer_hdl: auth timeout and try again\n"); ++ pmlmeinfo->auth_seq = 1; ++ issue_auth(padapter, NULL, 0); ++ set_link_timer(pmlmeext, REAUTH_TO); ++ } else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) { ++ /* re-assoc timer */ ++ if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) { ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ report_join_res(padapter, -2); ++ return; ++ } ++ ++ DBG_88E("link_timer_hdl: assoc timeout and try again\n"); ++ issue_assocreq(padapter); ++ set_link_timer(pmlmeext, REASSOC_TO); ++ } ++} ++ ++void addba_timer_hdl(struct sta_info *psta) ++{ ++ struct ht_priv *phtpriv; ++ ++ if (!psta) ++ return; ++ ++ phtpriv = &psta->htpriv; ++ ++ if ((phtpriv->ht_option) && (phtpriv->ampdu_enable)) { ++ if (phtpriv->candidate_tid_bitmap) ++ phtpriv->candidate_tid_bitmap = 0x0; ++ } ++} ++ ++u8 NULL_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ return H2C_SUCCESS; ++} ++ ++u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ u8 type; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; ++ ++ if (psetop->mode == Ndis802_11APMode) { ++ pmlmeinfo->state = WIFI_FW_AP_STATE; ++ type = _HW_STATE_AP_; ++ } else if (psetop->mode == Ndis802_11Infrastructure) { ++ pmlmeinfo->state &= ~(BIT(0) | BIT(1));/* clear state */ ++ pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */ ++ type = _HW_STATE_STATION_; ++ } else if (psetop->mode == Ndis802_11IBSS) { ++ type = _HW_STATE_ADHOC_; ++ } else { ++ type = _HW_STATE_NOLINK_; ++ } ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); ++ /* Set_NETYPE0_MSR(padapter, type); */ ++ ++ return H2C_SUCCESS; ++} ++ ++u8 createbss_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&pmlmeinfo->network); ++ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; ++ /* u32 initialgain; */ ++ ++ if (pparm->network.InfrastructureMode == Ndis802_11APMode) { ++#ifdef CONFIG_88EU_AP_MODE ++ ++ if (pmlmeinfo->state == WIFI_FW_AP_STATE) { ++ /* todo: */ ++ return H2C_SUCCESS; ++ } ++#endif ++ } ++ ++ /* below is for ad-hoc master */ ++ if (pparm->network.InfrastructureMode == Ndis802_11IBSS) { ++ rtw_joinbss_reset(padapter); ++ ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmlmeinfo->ERP_enable = 0; ++ pmlmeinfo->WMM_enable = 0; ++ pmlmeinfo->HT_enable = 0; ++ pmlmeinfo->HT_caps_enable = 0; ++ pmlmeinfo->HT_info_enable = 0; ++ pmlmeinfo->agg_enable_bitmap = 0; ++ pmlmeinfo->candidate_tid_bitmap = 0; ++ ++ /* disable dynamic functions, such as high power, DIG */ ++ Save_DM_Func_Flag(padapter); ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); ++ ++ /* config the initial gain under linking, need to write the BB registers */ ++ /* initialgain = 0x1E; */ ++ /* rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */ ++ ++ /* cancel link timer */ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ /* clear CAM */ ++ flush_all_cam_entry(padapter); ++ ++ memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength)); ++ pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength; ++ ++ if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */ ++ return H2C_PARAMETERS_ERROR; ++ ++ memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength); ++ ++ start_create_ibss(padapter); ++ } ++ ++ return H2C_SUCCESS; ++} ++ ++u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ u8 join_type; ++ struct ndis_802_11_var_ie *pIE; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&pmlmeinfo->network); ++ struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; ++ u32 i; ++ ++ /* check already connecting to AP or not */ ++ if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { ++ if (pmlmeinfo->state & WIFI_FW_STATION_STATE) ++ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 5, 100); ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ /* clear CAM */ ++ flush_all_cam_entry(padapter); ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ /* set MSR to nolink -> infra. mode */ ++ Set_MSR(padapter, _HW_STATE_STATION_); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL); ++ } ++ ++ rtw_antenna_select_cmd(padapter, pparm->network.PhyInfo.Optimum_antenna, false); ++ ++ rtw_joinbss_reset(padapter); ++ ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmlmeinfo->ERP_enable = 0; ++ pmlmeinfo->WMM_enable = 0; ++ pmlmeinfo->HT_enable = 0; ++ pmlmeinfo->HT_caps_enable = 0; ++ pmlmeinfo->HT_info_enable = 0; ++ pmlmeinfo->agg_enable_bitmap = 0; ++ pmlmeinfo->candidate_tid_bitmap = 0; ++ pmlmeinfo->bwmode_updated = false; ++ ++ memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength)); ++ pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength; ++ ++ if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */ ++ return H2C_PARAMETERS_ERROR; ++ ++ memcpy(pnetwork->IEs, ((struct wlan_bssid_ex *)pbuf)->IEs, pnetwork->IELength); ++ ++ /* Check AP vendor to move rtw_joinbss_cmd() */ ++ ++ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pnetwork->IELength;) { ++ pIE = (struct ndis_802_11_var_ie *)(pnetwork->IEs + i); ++ ++ switch (pIE->ElementID) { ++ case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */ ++ if (!memcmp(pIE->data, WMM_OUI, 4)) ++ pmlmeinfo->WMM_enable = 1; ++ break; ++ case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */ ++ pmlmeinfo->HT_caps_enable = 1; ++ break; ++ case _HT_EXTRA_INFO_IE_: /* Get HT Info IE. */ ++ pmlmeinfo->HT_info_enable = 1; ++ ++ /* spec case only for cisco's ap because cisco's ap issue assoc rsp using mcs rate @40MHz or @20MHz */ ++ { ++ struct HT_info_element *pht_info = (struct HT_info_element *)(pIE->data); ++ ++ if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) { ++ /* switch to the 40M Hz mode according to the AP */ ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40; ++ switch (pht_info->infos[0] & 0x3) { ++ case 1: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ case 3: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ default: ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ ++ DBG_88E("set ch/bw before connected\n"); ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ /* disable dynamic functions, such as high power, DIG */ ++ ++ /* config the initial gain under linking, need to write the BB registers */ ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); ++ join_type = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); ++ ++ /* cancel link timer */ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ start_clnt_join(padapter); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 disconnect_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct disconnect_parm *param = (struct disconnect_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&pmlmeinfo->network); ++ u8 val8; ++ ++ if (is_client_associated_to_ap(padapter)) ++ issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms / 100, 100); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, NULL); ++ rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); ++ ++ /* restore to initial setting. */ ++ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); ++ ++ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { ++ /* Stop BCN */ ++ val8 = 0; ++ rtw_hal_set_hwreg(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8)); ++ } ++ ++ /* set MSR to no link state -> infra. mode */ ++ Set_MSR(padapter, _HW_STATE_STATION_); ++ ++ pmlmeinfo->state = WIFI_FW_NULL_STATE; ++ ++ /* switch to the 20M Hz mode after disconnect */ ++ pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20; ++ pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); ++ ++ flush_all_cam_entry(padapter); ++ ++ _cancel_timer_ex(&pmlmeext->link_timer); ++ ++ rtw_free_uc_swdec_pending_queue(padapter); ++ ++ return H2C_SUCCESS; ++} ++ ++static int rtw_scan_ch_decision(struct adapter *padapter, struct rtw_ieee80211_channel *out, ++ u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num) ++{ ++ int i, j; ++ int set_idx; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ /* clear out first */ ++ memset(out, 0, sizeof(struct rtw_ieee80211_channel) * out_num); ++ ++ /* acquire channels from in */ ++ j = 0; ++ for (i = 0; i < in_num; i++) { ++ set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, in[i].hw_value); ++ if (in[i].hw_value && !(in[i].flags & RTW_IEEE80211_CHAN_DISABLED) && ++ set_idx >= 0) { ++ memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel)); ++ ++ if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE) ++ out[j].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN; ++ ++ j++; ++ } ++ if (j >= out_num) ++ break; ++ } ++ ++ /* if out is empty, use channel_set as default */ ++ if (j == 0) { ++ for (i = 0; i < pmlmeext->max_chan_nums; i++) { ++ out[i].hw_value = pmlmeext->channel_set[i].ChannelNum; ++ ++ if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE) ++ out[i].flags &= RTW_IEEE80211_CHAN_PASSIVE_SCAN; ++ ++ j++; ++ } ++ } ++ ++ return j; ++} ++ ++u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; ++ u8 bdelayscan = false; ++ u8 val8; ++ u32 initialgain; ++ u32 i; ++ ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) { ++ /* for first time sitesurvey_cmd */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, NULL); ++ ++ pmlmeext->sitesurvey_res.state = SCAN_START; ++ pmlmeext->sitesurvey_res.bss_cnt = 0; ++ pmlmeext->sitesurvey_res.channel_idx = 0; ++ ++ for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { ++ if (pparm->ssid[i].SsidLength) { ++ memcpy(pmlmeext->sitesurvey_res.ssid[i].Ssid, pparm->ssid[i].Ssid, IW_ESSID_MAX_SIZE); ++ pmlmeext->sitesurvey_res.ssid[i].SsidLength = pparm->ssid[i].SsidLength; ++ } else { ++ pmlmeext->sitesurvey_res.ssid[i].SsidLength = 0; ++ } ++ } ++ ++ pmlmeext->sitesurvey_res.ch_num = rtw_scan_ch_decision(padapter ++ , pmlmeext->sitesurvey_res.ch, RTW_CHANNEL_SCAN_AMOUNT ++ , pparm->ch, pparm->ch_num ++ ); ++ ++ pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode; ++ ++ /* issue null data if associating to the AP */ ++ if (is_client_associated_to_ap(padapter)) { ++ pmlmeext->sitesurvey_res.state = SCAN_TXNULL; ++ ++ issue_nulldata(padapter, NULL, 1, 3, 500); ++ ++ bdelayscan = true; ++ } ++ if (bdelayscan) { ++ /* delay 50ms to protect nulldata(1). */ ++ set_survey_timer(pmlmeext, 50); ++ return H2C_SUCCESS; ++ } ++ } ++ ++ if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) { ++ /* disable dynamic functions, such as high power, DIG */ ++ Save_DM_Func_Flag(padapter); ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); ++ ++ /* config the initial gain under scanning, need to write the BB registers */ ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ initialgain = 0x1E; ++ else ++ initialgain = 0x28; ++#else /* CONFIG_88EU_P2P */ ++ initialgain = 0x1E; ++#endif /* CONFIG_88EU_P2P */ ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); ++ ++ /* set MSR to no link state */ ++ Set_MSR(padapter, _HW_STATE_NOLINK_); ++ ++ val8 = 1; /* under site survey */ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ ++ pmlmeext->sitesurvey_res.state = SCAN_PROCESS; ++ } ++ ++ site_survey(padapter); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 setauth_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct setauth_parm *pparm = (struct setauth_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (pparm->mode < 4) ++ pmlmeinfo->auth_algo = pparm->mode; ++ return H2C_SUCCESS; ++} ++ ++u8 setkey_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ unsigned short ctrl; ++ struct setkey_parm *pparm = (struct setkey_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++ /* main tx key for wep. */ ++ if (pparm->set_tx) ++ pmlmeinfo->key_index = pparm->keyid; ++ ++ /* write cam */ ++ ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; ++ ++ DBG_88E_LEVEL(_drv_info_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) " ++ "keyid:%d\n", pparm->algorithm, pparm->keyid); ++ write_cam(padapter, pparm->keyid, ctrl, null_sta, pparm->key); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ u16 ctrl = 0; ++ u8 cam_id;/* cam_entry */ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; ++ ++ /* cam_entry: */ ++ /* 0~3 for default key */ ++ ++ /* for concurrent mode (ap+sta): */ ++ /* default key is disable, using sw encrypt/decrypt */ ++ /* cam_entry = 4 for sta mode (macid = 0) */ ++ /* cam_entry(macid+3) = 5 ~ N for ap mode (aid = 1~N, macid = 2 ~N) */ ++ ++ /* for concurrent mode (sta+sta): */ ++ /* default key is disable, using sw encrypt/decrypt */ ++ /* cam_entry = 4 mapping to macid = 0 */ ++ /* cam_entry = 5 mapping to macid = 2 */ ++ ++ cam_id = 4; ++ ++ DBG_88E_LEVEL(_drv_info_, "set pairwise key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) camid:%d\n", ++ pparm->algorithm, cam_id); ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if (pparm->algorithm == _NO_PRIVACY_) /* clear cam entry */ { ++ clear_cam_entry(padapter, pparm->id); ++ return H2C_SUCCESS_RSP; ++ } ++ ++ psta = rtw_get_stainfo(pstapriv, pparm->addr); ++ if (psta) { ++ ctrl = (BIT(15) | ((pparm->algorithm) << 2)); ++ ++ DBG_88E("r871x_set_stakey_hdl(): enc_algorithm=%d\n", pparm->algorithm); ++ ++ if ((psta->mac_id < 1) || (psta->mac_id > (NUM_STA - 4))) { ++ DBG_88E("r871x_set_stakey_hdl():set_stakey failed, mac_id(aid)=%d\n", psta->mac_id); ++ return H2C_REJECTED; ++ } ++ ++ cam_id = (psta->mac_id + 3);/* 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */ ++ ++ DBG_88E("Write CAM, mac_addr =%x:%x:%x:%x:%x:%x, cam_entry=%d\n", pparm->addr[0], ++ pparm->addr[1], pparm->addr[2], pparm->addr[3], pparm->addr[4], ++ pparm->addr[5], cam_id); ++ ++ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); ++ ++ return H2C_SUCCESS_RSP; ++ } else { ++ DBG_88E("r871x_set_stakey_hdl(): sta has been free\n"); ++ return H2C_REJECTED; ++ } ++ } ++ ++ /* below for sta mode */ ++ ++ if (pparm->algorithm == _NO_PRIVACY_) { /* clear cam entry */ ++ clear_cam_entry(padapter, pparm->id); ++ return H2C_SUCCESS; ++ } ++ ctrl = BIT(15) | ((pparm->algorithm) << 2); ++ write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); ++ pmlmeinfo->enc_algo = pparm->algorithm; ++ return H2C_SUCCESS; ++} ++ ++u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, pparm->addr); ++ ++ if (!psta) ++ return H2C_SUCCESS; ++ ++ if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) || ++ ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { ++ issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); ++ _set_timer(&psta->addba_retry_timer, ADDBA_TO); ++ } else { ++ psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid); ++ } ++ return H2C_SUCCESS; ++} ++ ++u8 set_tx_beacon_cmd(struct adapter *padapter) ++{ ++ struct cmd_obj *ph2c; ++ struct Tx_Beacon_param *ptxBeacon_parm; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u8 res = _SUCCESS; ++ int len_diff = 0; ++ ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ ptxBeacon_parm = kzalloc(sizeof(struct Tx_Beacon_param), GFP_ATOMIC); ++ if (!ptxBeacon_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ memcpy(&ptxBeacon_parm->network, &pmlmeinfo->network, sizeof(struct wlan_bssid_ex)); ++ ++ len_diff = update_hidden_ssid(ptxBeacon_parm->network.IEs + _BEACON_IE_OFFSET_, ++ ptxBeacon_parm->network.IELength - _BEACON_IE_OFFSET_, ++ pmlmeinfo->hidden_ssid_mode); ++ ptxBeacon_parm->network.IELength += len_diff; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ ++exit: ++ ++ return res; ++} ++ ++u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ u8 evt_code; ++ u16 evt_sz; ++ uint *peventbuf; ++ void (*event_callback)(struct adapter *dev, u8 *pbuf); ++ struct evt_priv *pevt_priv = &padapter->evtpriv; ++ ++ peventbuf = (uint *)pbuf; ++ evt_sz = (u16)(*peventbuf & 0xffff); ++ evt_code = (u8)((*peventbuf >> 16) & 0xff); ++ ++ /* checking if event code is valid */ ++ if (evt_code >= MAX_C2HEVT) ++ goto _abort_event_; ++ ++ /* checking if event size match the event parm size */ ++ if ((wlanevents[evt_code].parmsize != 0) && ++ (wlanevents[evt_code].parmsize != evt_sz)) ++ goto _abort_event_; ++ ++ atomic_inc(&pevt_priv->event_seq); ++ ++ peventbuf += 2; ++ ++ if (peventbuf) { ++ event_callback = wlanevents[evt_code].event_callback; ++ event_callback(padapter, (u8 *)peventbuf); ++ ++ pevt_priv->evt_done_cnt++; ++ } ++ ++_abort_event_: ++ return H2C_SUCCESS; ++} ++ ++u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ return H2C_SUCCESS; ++} ++ ++u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ if (send_beacon(padapter) == _FAIL) { ++ DBG_88E("issue_beacon, fail!\n"); ++ return H2C_PARAMETERS_ERROR; ++ } ++#ifdef CONFIG_88EU_AP_MODE ++ else { /* tx bc/mc frames after update TIM */ ++ struct sta_info *psta_bmc; ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ /* for BC/MC Frames */ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if (!psta_bmc) ++ return H2C_SUCCESS; ++ ++ if ((pstapriv->tim_bitmap & BIT(0)) && (psta_bmc->sleepq_len > 0)) { ++ msleep(10);/* 10ms, ATIM(HIQ) Windows */ ++ spin_lock_bh(&psta_bmc->sleep_q.lock); ++ ++ xmitframe_phead = get_list_head(&psta_bmc->sleep_q); ++ xmitframe_plist = xmitframe_phead->next; ++ ++ while (xmitframe_phead != xmitframe_plist) { ++ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = xmitframe_plist->next; ++ ++ list_del_init(&pxmitframe->list); ++ ++ psta_bmc->sleepq_len--; ++ if (psta_bmc->sleepq_len > 0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ pxmitframe->attrib.triggered = 1; ++ ++ pxmitframe->attrib.qsel = 0x11;/* HIQ */ ++ ++ spin_unlock_bh(&psta_bmc->sleep_q.lock); ++ if (rtw_hal_xmit(padapter, pxmitframe)) ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ spin_lock_bh(&psta_bmc->sleep_q.lock); ++ } ++ spin_unlock_bh(&psta_bmc->sleep_q.lock); ++ } ++ } ++#endif ++ return H2C_SUCCESS; ++} ++ ++u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf) ++{ ++ struct set_ch_parm *set_ch_parm; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ set_ch_parm = (struct set_ch_parm *)pbuf; ++ ++ DBG_88E(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", ++ FUNC_NDEV_ARG(padapter->pnetdev), ++ set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset); ++ ++ pmlmeext->cur_channel = set_ch_parm->ch; ++ pmlmeext->cur_ch_offset = set_ch_parm->ch_offset; ++ pmlmeext->cur_bwmode = set_ch_parm->bw; ++ ++ set_channel_bwmode(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ struct SetChannelPlan_param *setChannelPlan_param; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ ++ setChannelPlan_param = (struct SetChannelPlan_param *)pbuf; ++ ++ pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set); ++ init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); ++ ++ return H2C_SUCCESS; ++} ++ ++u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ if (!pbuf) ++ return H2C_PARAMETERS_ERROR; ++ return H2C_SUCCESS; ++} ++ ++u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ return H2C_REJECTED; ++} ++ ++/* TDLS_WRCR : write RCR DATA BIT */ ++/* TDLS_SD_PTI : issue peer traffic indication */ ++/* TDLS_CS_OFF : go back to the channel linked with AP, terminating channel switch procedure */ ++/* TDLS_INIT_CH_SEN : init channel sensing, receive all data and mgnt frame */ ++/* TDLS_DONE_CH_SEN: channel sensing and report candidate channel */ ++/* TDLS_OFF_CH : first time set channel to off channel */ ++/* TDLS_BASE_CH : go back tp the channel linked with AP when set base channel as target channel */ ++/* TDLS_P_OFF_CH : periodically go to off channel */ ++/* TDLS_P_BASE_CH : periodically go back to base channel */ ++/* TDLS_RS_RCR : restore RCR */ ++/* TDLS_CKALV_PH1 : check alive timer phase1 */ ++/* TDLS_CKALV_PH2 : check alive timer phase2 */ ++/* TDLS_FREE_STA : free tdls sta */ ++u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf) ++{ ++ return H2C_REJECTED; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_mp.c b/drivers/staging/r8188eu/core/rtw_mp.c +new file mode 100644 +index 000000000000..dabdd0406f30 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_mp.c +@@ -0,0 +1,935 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTW_MP_C_ ++ ++#include "../include/drv_types.h" ++#include "../include/odm_precomp.h" ++#include "../include/rtl8188e_hal.h" ++ ++u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask) ++{ ++ return rtw_hal_read_bbreg(padapter, addr, bitmask); ++} ++ ++void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val) ++{ ++ rtw_hal_write_bbreg(padapter, addr, bitmask, val); ++} ++ ++u32 _read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask) ++{ ++ return rtw_hal_read_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bitmask); ++} ++ ++void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val) ++{ ++ rtw_hal_write_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bitmask, val); ++} ++ ++u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr) ++{ ++ return _read_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bRFRegOffsetMask); ++} ++ ++void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val) ++{ ++ _write_rfreg(padapter, (enum rf_radio_path)rfpath, addr, bRFRegOffsetMask, val); ++} ++ ++static void _init_mp_priv_(struct mp_priv *pmp_priv) ++{ ++ struct wlan_bssid_ex *pnetwork; ++ ++ memset(pmp_priv, 0, sizeof(struct mp_priv)); ++ ++ pmp_priv->mode = MP_OFF; ++ ++ pmp_priv->channel = 1; ++ pmp_priv->bandwidth = HT_CHANNEL_WIDTH_20; ++ pmp_priv->prime_channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ pmp_priv->rateidx = MPT_RATE_1M; ++ pmp_priv->txpoweridx = 0x2A; ++ ++ pmp_priv->antenna_tx = ANTENNA_A; ++ pmp_priv->antenna_rx = ANTENNA_AB; ++ ++ pmp_priv->check_mp_pkt = 0; ++ ++ pmp_priv->tx_pktcount = 0; ++ ++ pmp_priv->rx_pktcount = 0; ++ pmp_priv->rx_crcerrpktcount = 0; ++ ++ pmp_priv->network_macaddr[0] = 0x00; ++ pmp_priv->network_macaddr[1] = 0xE0; ++ pmp_priv->network_macaddr[2] = 0x4C; ++ pmp_priv->network_macaddr[3] = 0x87; ++ pmp_priv->network_macaddr[4] = 0x66; ++ pmp_priv->network_macaddr[5] = 0x55; ++ ++ pnetwork = &pmp_priv->mp_network.network; ++ memcpy(pnetwork->MacAddress, pmp_priv->network_macaddr, ETH_ALEN); ++ ++ pnetwork->Ssid.SsidLength = 8; ++ memcpy(pnetwork->Ssid.Ssid, "mp_871x", pnetwork->Ssid.SsidLength); ++} ++ ++static void mp_init_xmit_attrib(struct mp_tx *pmptx, struct adapter *padapter) ++{ ++ struct pkt_attrib *pattrib; ++ struct tx_desc *desc; ++ ++ /* init xmitframe attribute */ ++ pattrib = &pmptx->attrib; ++ memset(pattrib, 0, sizeof(struct pkt_attrib)); ++ desc = &pmptx->desc; ++ memset(desc, 0, TXDESC_SIZE); ++ ++ pattrib->ether_type = 0x8712; ++ memset(pattrib->dst, 0xFF, ETH_ALEN); ++ pattrib->ack_policy = 0; ++ pattrib->hdrlen = WLAN_HDR_A3_LEN; ++ pattrib->subtype = WIFI_DATA; ++ pattrib->priority = 0; ++ pattrib->qsel = pattrib->priority; ++ pattrib->nr_frags = 1; ++ pattrib->encrypt = 0; ++ pattrib->bswenc = false; ++ pattrib->qos_en = false; ++} ++ ++s32 init_mp_priv(struct adapter *padapter) ++{ ++ struct mp_priv *pmppriv = &padapter->mppriv; ++ ++ _init_mp_priv_(pmppriv); ++ pmppriv->papdater = padapter; ++ ++ pmppriv->tx.stop = 1; ++ mp_init_xmit_attrib(&pmppriv->tx, padapter); ++ ++ switch (padapter->registrypriv.rf_config) { ++ case RF_1T1R: ++ pmppriv->antenna_tx = ANTENNA_A; ++ pmppriv->antenna_rx = ANTENNA_A; ++ break; ++ case RF_1T2R: ++ default: ++ pmppriv->antenna_tx = ANTENNA_A; ++ pmppriv->antenna_rx = ANTENNA_AB; ++ break; ++ case RF_2T2R: ++ case RF_2T2R_GREEN: ++ pmppriv->antenna_tx = ANTENNA_AB; ++ pmppriv->antenna_rx = ANTENNA_AB; ++ break; ++ case RF_2T4R: ++ pmppriv->antenna_tx = ANTENNA_AB; ++ pmppriv->antenna_rx = ANTENNA_ABCD; ++ break; ++ } ++ ++ return _SUCCESS; ++} ++ ++void free_mp_priv(struct mp_priv *pmp_priv) ++{ ++ kfree(pmp_priv->pallocated_mp_xmitframe_buf); ++ pmp_priv->pallocated_mp_xmitframe_buf = NULL; ++ pmp_priv->pmp_xmtframe_buf = NULL; ++} ++ ++#define PHY_IQCalibrate(a, b) PHY_IQCalibrate_8188E(a, b) ++#define PHY_LCCalibrate(a) PHY_LCCalibrate_8188E(a) ++#define PHY_SetRFPathSwitch(a, b) PHY_SetRFPathSwitch_8188E(a, b) ++ ++s32 MPT_InitializeAdapter(struct adapter *pAdapter, u8 Channel) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ s32 rtStatus = _SUCCESS; ++ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx; ++ struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv; ++ ++ /* HW Initialization for 8190 MPT. */ ++ /* SW Initialization for 8190 MP. */ ++ pMptCtx->bMptDrvUnload = false; ++ pMptCtx->bMassProdTest = false; ++ pMptCtx->bMptIndexEven = true; /* default gain index is -6.0db */ ++ pMptCtx->h2cReqNum = 0x0; ++ /* Init mpt event. */ ++ /* init for BT MP */ ++ ++ pMptCtx->bMptWorkItemInProgress = false; ++ pMptCtx->CurrMptAct = NULL; ++ /* */ ++ ++ /* Don't accept any packets */ ++ rtw_write32(pAdapter, REG_RCR, 0); ++ ++ PHY_IQCalibrate(pAdapter, false); ++ dm_CheckTXPowerTracking(&pHalData->odmpriv); /* trigger thermal meter */ ++ PHY_LCCalibrate(pAdapter); ++ ++ pMptCtx->backup0xc50 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_XAAGCCore1, bMaskByte0); ++ pMptCtx->backup0xc58 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_XBAGCCore1, bMaskByte0); ++ pMptCtx->backup0xc30 = (u8)PHY_QueryBBReg(pAdapter, rOFDM0_RxDetector1, bMaskByte0); ++ pMptCtx->backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); ++ pMptCtx->backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); ++ ++ /* set ant to wifi side in mp mode */ ++ rtw_write16(pAdapter, 0x870, 0x300); ++ rtw_write16(pAdapter, 0x860, 0x110); ++ ++ if (pAdapter->registrypriv.mp_mode == 1) ++ pmlmepriv->fw_state = WIFI_MP_STATE; ++ ++ return rtStatus; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: MPT_DeInitAdapter() ++ * ++ * Overview: Extra DeInitialization for Mass Production Test. ++ * ++ * Input: struct adapter * pAdapter ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/08/2007 MHC Create Version 0. ++ * 05/18/2007 MHC Add normal driver MPHalt code. ++ * ++ *---------------------------------------------------------------------------*/ ++void MPT_DeInitAdapter(struct adapter *pAdapter) ++{ ++ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx; ++ ++ pMptCtx->bMptDrvUnload = true; ++} ++ ++static u8 mpt_ProStartTest(struct adapter *padapter) ++{ ++ struct mpt_context *pMptCtx = &padapter->mppriv.MptCtx; ++ ++ pMptCtx->bMassProdTest = true; ++ pMptCtx->bStartContTx = false; ++ pMptCtx->bCckContTx = false; ++ pMptCtx->bOfdmContTx = false; ++ pMptCtx->bSingleCarrier = false; ++ pMptCtx->bCarrierSuppression = false; ++ pMptCtx->bSingleTone = false; ++ ++ return _SUCCESS; ++} ++ ++/* ++ * General use ++ */ ++s32 SetPowerTracking(struct adapter *padapter, u8 enable) ++{ ++ Hal_SetPowerTracking(padapter, enable); ++ return 0; ++} ++ ++void GetPowerTracking(struct adapter *padapter, u8 *enable) ++{ ++ Hal_GetPowerTracking(padapter, enable); ++} ++ ++static void disable_dm(struct adapter *padapter) ++{ ++ u8 v8; ++ ++ /* 3 1. disable firmware dynamic mechanism */ ++ /* disable Power Training, Rate Adaptive */ ++ v8 = rtw_read8(padapter, REG_BCN_CTRL); ++ v8 &= ~EN_BCN_FUNCTION; ++ rtw_write8(padapter, REG_BCN_CTRL, v8); ++ ++ /* 3 2. disable driver dynamic mechanism */ ++ /* disable Dynamic Initial Gain */ ++ /* disable High Power */ ++ /* disable Power Tracking */ ++ Switch_DM_Func(padapter, DYNAMIC_FUNC_DISABLE, false); ++ ++ /* enable APK, LCK and IQK but disable power tracking */ ++ Switch_DM_Func(padapter, DYNAMIC_RF_CALIBRATION, true); ++} ++ ++/* This function initializes the DUT to the MP test mode */ ++s32 mp_start_test(struct adapter *padapter) ++{ ++ struct wlan_bssid_ex bssid; ++ struct sta_info *psta; ++ u32 length; ++ u8 val8; ++ s32 res = _SUCCESS; ++ struct mp_priv *pmppriv = &padapter->mppriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ ++ padapter->registrypriv.mp_mode = 1; ++ pmppriv->bSetTxPower = 0; /* for manually set tx power */ ++ ++ /* 3 disable dynamic mechanism */ ++ disable_dm(padapter); ++ ++ /* 3 0. update mp_priv */ ++ ++ if (padapter->registrypriv.rf_config == RF_819X_MAX_TYPE) { ++ switch (GET_RF_TYPE(padapter)) { ++ case RF_1T1R: ++ pmppriv->antenna_tx = ANTENNA_A; ++ pmppriv->antenna_rx = ANTENNA_A; ++ break; ++ case RF_1T2R: ++ default: ++ pmppriv->antenna_tx = ANTENNA_A; ++ pmppriv->antenna_rx = ANTENNA_AB; ++ break; ++ case RF_2T2R: ++ case RF_2T2R_GREEN: ++ pmppriv->antenna_tx = ANTENNA_AB; ++ pmppriv->antenna_rx = ANTENNA_AB; ++ break; ++ case RF_2T4R: ++ pmppriv->antenna_tx = ANTENNA_AB; ++ pmppriv->antenna_rx = ANTENNA_ABCD; ++ break; ++ } ++ } ++ ++ mpt_ProStartTest(padapter); ++ ++ /* 3 1. initialize a new struct wlan_bssid_ex */ ++/* memset(&bssid, 0, sizeof(struct wlan_bssid_ex)); */ ++ memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN); ++ bssid.Ssid.SsidLength = strlen("mp_pseudo_adhoc"); ++ memcpy(bssid.Ssid.Ssid, (u8 *)"mp_pseudo_adhoc", bssid.Ssid.SsidLength); ++ bssid.InfrastructureMode = Ndis802_11IBSS; ++ bssid.NetworkTypeInUse = Ndis802_11DS; ++ bssid.IELength = 0; ++ ++ length = get_wlan_bssid_ex_sz(&bssid); ++ if (length % 4) ++ bssid.Length = ((length >> 2) + 1) << 2; /* round up to multiple of 4 bytes. */ ++ else ++ bssid.Length = length; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) ++ goto end_of_mp_start_test; ++ ++ /* init mp_start_test status */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ rtw_disassoc_cmd(padapter, 500, true); ++ rtw_indicate_disconnect(padapter); ++ rtw_free_assoc_resources(padapter, 1); ++ } ++ pmppriv->prev_fw_state = get_fwstate(pmlmepriv); ++ if (padapter->registrypriv.mp_mode == 1) ++ pmlmepriv->fw_state = WIFI_MP_STATE; ++ set_fwstate(pmlmepriv, _FW_UNDER_LINKING); ++ ++ /* 3 2. create a new psta for mp driver */ ++ /* clear psta in the cur_network, if any */ ++ psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress); ++ if (psta) ++ rtw_free_stainfo(padapter, psta); ++ ++ psta = rtw_alloc_stainfo(&padapter->stapriv, bssid.MacAddress); ++ if (!psta) { ++ pmlmepriv->fw_state = pmppriv->prev_fw_state; ++ res = _FAIL; ++ goto end_of_mp_start_test; ++ } ++ ++ /* 3 3. join psudo AdHoc */ ++ tgt_network->join_res = 1; ++ tgt_network->aid = 1; ++ psta->aid = 1; ++ memcpy(&tgt_network->network, &bssid, length); ++ ++ rtw_indicate_connect(padapter); ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); ++ ++end_of_mp_start_test: ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++ if (res == _SUCCESS) { ++ /* set MSR to WIFI_FW_ADHOC_STATE */ ++ val8 = rtw_read8(padapter, MSR) & 0xFC; /* 0x0102 */ ++ val8 |= WIFI_FW_ADHOC_STATE; ++ rtw_write8(padapter, MSR, val8); /* Link in ad hoc network */ ++ } ++ return res; ++} ++/* */ ++/* This function change the DUT from the MP test mode into normal mode */ ++void mp_stop_test(struct adapter *padapter) ++{ ++ struct mp_priv *pmppriv = &padapter->mppriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_network *tgt_network = &pmlmepriv->cur_network; ++ struct sta_info *psta; ++ ++ if (pmppriv->mode == MP_ON) { ++ pmppriv->bSetTxPower = 0; ++ spin_lock_bh(&pmlmepriv->lock); ++ if (!check_fwstate(pmlmepriv, WIFI_MP_STATE)) ++ goto end_of_mp_stop_test; ++ ++ /* 3 1. disconnect psudo AdHoc */ ++ rtw_indicate_disconnect(padapter); ++ ++ /* 3 2. clear psta used in mp test mode. */ ++ psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress); ++ if (psta) ++ rtw_free_stainfo(padapter, psta); ++ ++ /* 3 3. return to normal state (default:station mode) */ ++ pmlmepriv->fw_state = pmppriv->prev_fw_state; /* WIFI_STATION_STATE; */ ++ ++ /* flush the cur_network */ ++ memset(tgt_network, 0, sizeof(struct wlan_network)); ++ ++ _clr_fwstate_(pmlmepriv, WIFI_MP_STATE); ++ ++end_of_mp_stop_test: ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ } ++} ++ ++/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ ++/* ++ * SetChannel ++ * Description ++ * Use H2C command to change channel, ++ * not only modify rf register, but also other setting need to be done. ++ */ ++void SetChannel(struct adapter *pAdapter) ++{ ++ Hal_SetChannel(pAdapter); ++} ++ ++/* ++ * Notice ++ * Switch bandwitdth may change center frequency(channel) ++ */ ++void SetBandwidth(struct adapter *pAdapter) ++{ ++ Hal_SetBandwidth(pAdapter); ++} ++ ++void SetAntenna(struct adapter *pAdapter) ++{ ++ Hal_SetAntenna(pAdapter); ++} ++ ++void SetAntennaPathPower(struct adapter *pAdapter) ++{ ++ Hal_SetAntennaPathPower(pAdapter); ++} ++ ++void SetTxPower(struct adapter *pAdapter) ++{ ++ Hal_SetTxPower(pAdapter); ++ } ++ ++void SetDataRate(struct adapter *pAdapter) ++{ ++ Hal_SetDataRate(pAdapter); ++} ++ ++void MP_PHY_SetRFPathSwitch(struct adapter *pAdapter, bool bMain) ++{ ++ PHY_SetRFPathSwitch(pAdapter, bMain); ++} ++ ++s32 SetThermalMeter(struct adapter *pAdapter, u8 target_ther) ++{ ++ return Hal_SetThermalMeter(pAdapter, target_ther); ++} ++ ++void GetThermalMeter(struct adapter *pAdapter, u8 *value) ++{ ++ Hal_GetThermalMeter(pAdapter, value); ++} ++ ++void SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetSingleCarrierTx(pAdapter, bStart); ++} ++ ++void SetSingleToneTx(struct adapter *pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetSingleToneTx(pAdapter, bStart); ++} ++ ++void SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetCarrierSuppressionTx(pAdapter, bStart); ++} ++ ++void SetContinuousTx(struct adapter *pAdapter, u8 bStart) ++{ ++ PhySetTxPowerLevel(pAdapter); ++ Hal_SetContinuousTx(pAdapter, bStart); ++} ++ ++void PhySetTxPowerLevel(struct adapter *pAdapter) ++{ ++ struct mp_priv *pmp_priv = &pAdapter->mppriv; ++ ++ if (pmp_priv->bSetTxPower == 0) /* for NO manually set power index */ ++ PHY_SetTxPowerLevel8188E(pAdapter, pmp_priv->channel); ++} ++ ++/* */ ++static void dump_mpframe(struct adapter *padapter, struct xmit_frame *pmpframe) ++{ ++ rtw_hal_mgnt_xmit(padapter, pmpframe); ++} ++ ++static struct xmit_frame *alloc_mp_xmitframe(struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_frame *pmpframe; ++ struct xmit_buf *pxmitbuf; ++ ++ pmpframe = rtw_alloc_xmitframe(pxmitpriv); ++ if (!pmpframe) ++ return NULL; ++ ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (!pxmitbuf) { ++ rtw_free_xmitframe(pxmitpriv, pmpframe); ++ return NULL; ++ } ++ ++ pmpframe->frame_tag = MP_FRAMETAG; ++ ++ pmpframe->pxmitbuf = pxmitbuf; ++ ++ pmpframe->buf_addr = pxmitbuf->pbuf; ++ ++ pxmitbuf->priv_data = pmpframe; ++ ++ return pmpframe; ++} ++ ++static int mp_xmit_packet_thread(void *context) ++{ ++ struct xmit_frame *pxmitframe; ++ struct mp_tx *pmptx; ++ struct mp_priv *pmp_priv; ++ struct xmit_priv *pxmitpriv; ++ struct adapter *padapter; ++ ++ pmp_priv = (struct mp_priv *)context; ++ pmptx = &pmp_priv->tx; ++ padapter = pmp_priv->papdater; ++ pxmitpriv = &padapter->xmitpriv; ++ ++ thread_enter("RTW_MP_THREAD"); ++ ++ /* DBG_88E("%s:pkTx Start\n", __func__); */ ++ while (1) { ++ pxmitframe = alloc_mp_xmitframe(pxmitpriv); ++ if (!pxmitframe) { ++ if (pmptx->stop || ++ padapter->bSurpriseRemoved || ++ padapter->bDriverStopped) { ++ goto exit; ++ } else { ++ msleep(1); ++ continue; ++ } ++ } ++ ++ memcpy((u8 *)(pxmitframe->buf_addr + TXDESC_OFFSET), pmptx->buf, pmptx->write_size); ++ memcpy(&pxmitframe->attrib, &pmptx->attrib, sizeof(struct pkt_attrib)); ++ ++ dump_mpframe(padapter, pxmitframe); ++ ++ pmptx->sended++; ++ pmp_priv->tx_pktcount++; ++ ++ if (pmptx->stop || ++ padapter->bSurpriseRemoved || ++ padapter->bDriverStopped) ++ goto exit; ++ if ((pmptx->count != 0) && ++ (pmptx->count == pmptx->sended)) ++ goto exit; ++ ++ flush_signals_thread(); ++ } ++ ++exit: ++ kfree(pmptx->pallocated_buf); ++ pmptx->pallocated_buf = NULL; ++ pmptx->stop = 1; ++ ++ thread_exit(); ++} ++ ++void fill_txdesc_for_mp(struct adapter *padapter, struct tx_desc *ptxdesc) ++{ ++ struct mp_priv *pmp_priv = &padapter->mppriv; ++ memcpy(ptxdesc, &pmp_priv->tx.desc, TXDESC_SIZE); ++} ++ ++void SetPacketTx(struct adapter *padapter) ++{ ++ u8 *ptr, *pkt_start, *pkt_end; ++ u32 pkt_size; ++ struct tx_desc *desc; ++ struct rtw_ieee80211_hdr *hdr; ++ u8 payload; ++ bool bmcast; ++ struct pkt_attrib *pattrib; ++ struct mp_priv *pmp_priv; ++ ++ pmp_priv = &padapter->mppriv; ++ if (pmp_priv->tx.stop) ++ return; ++ pmp_priv->tx.sended = 0; ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx_pktcount = 0; ++ ++ /* 3 1. update_attrib() */ ++ pattrib = &pmp_priv->tx.attrib; ++ memcpy(pattrib->src, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ bmcast = is_multicast_ether_addr(pattrib->ra); ++ if (bmcast) { ++ pattrib->mac_id = 1; ++ pattrib->psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ pattrib->mac_id = 0; ++ pattrib->psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); ++ } ++ ++ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen; ++ ++ /* 3 2. allocate xmit buffer */ ++ pkt_size = pattrib->last_txcmdsz; ++ ++ kfree(pmp_priv->tx.pallocated_buf); ++ pmp_priv->tx.write_size = pkt_size; ++ pmp_priv->tx.buf_size = pkt_size + XMITBUF_ALIGN_SZ; ++ pmp_priv->tx.pallocated_buf = kzalloc(pmp_priv->tx.buf_size, GFP_KERNEL); ++ if (!pmp_priv->tx.pallocated_buf) { ++ DBG_88E("%s: malloc(%d) fail!!\n", __func__, pmp_priv->tx.buf_size); ++ return; ++ } ++ pmp_priv->tx.buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pmp_priv->tx.pallocated_buf), XMITBUF_ALIGN_SZ); ++ ptr = pmp_priv->tx.buf; ++ ++ desc = &pmp_priv->tx.desc; ++ memset(desc, 0, TXDESC_SIZE); ++ pkt_start = ptr; ++ pkt_end = pkt_start + pkt_size; ++ ++ /* 3 3. init TX descriptor */ ++ /* offset 0 */ ++ desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); ++ desc->txdw0 |= cpu_to_le32(pkt_size & 0x0000FFFF); /* packet size */ ++ desc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00FF0000); /* 32 bytes for TX Desc */ ++ if (bmcast) ++ desc->txdw0 |= cpu_to_le32(BMC); /* broadcast packet */ ++ ++ desc->txdw1 |= cpu_to_le32((0x01 << 26) & 0xff000000); ++ /* offset 4 */ ++ desc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x3F); /* CAM_ID(MAC_ID) */ ++ desc->txdw1 |= cpu_to_le32((pattrib->qsel << QSEL_SHT) & 0x00001F00); /* Queue Select, TID */ ++ ++ desc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000); /* Rate Adaptive ID */ ++ /* offset 8 */ ++ /* offset 12 */ ++ ++ desc->txdw3 |= cpu_to_le32((pattrib->seqnum << 16) & 0x0fff0000); ++ ++ /* offset 16 */ ++ desc->txdw4 |= cpu_to_le32(HW_SSN); ++ desc->txdw4 |= cpu_to_le32(USERATE); ++ desc->txdw4 |= cpu_to_le32(DISDATAFB); ++ ++ if (pmp_priv->preamble) { ++ if (pmp_priv->rateidx <= MPT_RATE_54M) ++ desc->txdw4 |= cpu_to_le32(DATA_SHORT); /* CCK Short Preamble */ ++ } ++ if (pmp_priv->bandwidth == HT_CHANNEL_WIDTH_40) ++ desc->txdw4 |= cpu_to_le32(DATA_BW); ++ ++ /* offset 20 */ ++ desc->txdw5 |= cpu_to_le32(pmp_priv->rateidx & 0x0000001F); ++ ++ if (pmp_priv->preamble) { ++ if (pmp_priv->rateidx > MPT_RATE_54M) ++ desc->txdw5 |= cpu_to_le32(SGI); /* MCS Short Guard Interval */ ++ } ++ desc->txdw5 |= cpu_to_le32(RTY_LMT_EN); /* retry limit enable */ ++ desc->txdw5 |= cpu_to_le32(0x00180000); /* DATA/RTS Rate Fallback Limit */ ++ ++ /* 3 4. make wlan header, make_wlanhdr() */ ++ hdr = (struct rtw_ieee80211_hdr *)pkt_start; ++ SetFrameSubType(&hdr->frame_ctl, pattrib->subtype); ++ memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); /* DA */ ++ memcpy(hdr->addr2, pattrib->src, ETH_ALEN); /* SA */ ++ memcpy(hdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); /* RA, BSSID */ ++ ++ /* 3 5. make payload */ ++ ptr = pkt_start + pattrib->hdrlen; ++ ++ switch (pmp_priv->tx.payload) { ++ case 0: ++ payload = 0x00; ++ break; ++ case 1: ++ payload = 0x5a; ++ break; ++ case 2: ++ payload = 0xa5; ++ break; ++ case 3: ++ payload = 0xff; ++ break; ++ default: ++ payload = 0x00; ++ break; ++ } ++ ++ memset(ptr, payload, pkt_end - ptr); ++ ++ /* 3 6. start thread */ ++ pmp_priv->tx.PktTxThread = kthread_run(mp_xmit_packet_thread, pmp_priv, "RTW_MP_THREAD"); ++ if (IS_ERR(pmp_priv->tx.PktTxThread)) ++ DBG_88E("Create PktTx Thread Fail !!!!!\n"); ++} ++ ++void SetPacketRx(struct adapter *pAdapter, u8 bStartRx) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if (bStartRx) { ++ /* Accept CRC error and destination address */ ++ pHalData->ReceiveConfig = AAP | APM | AM | AB | APP_ICV | ++ AMF | ADF | APP_FCS | HTC_LOC_CTRL | ++ APP_MIC | APP_PHYSTS; ++ ++ pHalData->ReceiveConfig |= (RCR_ACRC32 | RCR_AAP); ++ ++ rtw_write32(pAdapter, REG_RCR, pHalData->ReceiveConfig); ++ ++ /* Accept all data frames */ ++ rtw_write16(pAdapter, REG_RXFLTMAP2, 0xFFFF); ++ } else { ++ rtw_write32(pAdapter, REG_RCR, 0); ++ } ++} ++ ++void ResetPhyRxPktCount(struct adapter *pAdapter) ++{ ++ u32 i, phyrx_set = 0; ++ ++ for (i = 0; i <= 0xF; i++) { ++ phyrx_set = 0; ++ phyrx_set |= _RXERR_RPT_SEL(i); /* select */ ++ phyrx_set |= RXERR_RPT_RST; /* set counter to zero */ ++ rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set); ++ } ++} ++ ++static u32 GetPhyRxPktCounts(struct adapter *pAdapter, u32 selbit) ++{ ++ /* selection */ ++ u32 phyrx_set = 0, count = 0; ++ ++ phyrx_set = _RXERR_RPT_SEL(selbit & 0xF); ++ rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set); ++ ++ /* Read packet count */ ++ count = rtw_read32(pAdapter, REG_RXERR_RPT) & RXERR_COUNTER_MASK; ++ ++ return count; ++} ++ ++u32 GetPhyRxPktReceived(struct adapter *pAdapter) ++{ ++ u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; ++ ++ OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_OK); ++ CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_OK); ++ HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_OK); ++ ++ return OFDM_cnt + CCK_cnt + HT_cnt; ++} ++ ++u32 GetPhyRxPktCRC32Error(struct adapter *pAdapter) ++{ ++ u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; ++ ++ OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_FAIL); ++ CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_FAIL); ++ HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_FAIL); ++ ++ return OFDM_cnt + CCK_cnt + HT_cnt; ++} ++ ++/* reg 0x808[9:0]: FFT data x */ ++/* reg 0x808[22]: 0 --> 1 to get 1 FFT data y */ ++/* reg 0x8B4[15:0]: FFT data y report */ ++static u32 rtw_GetPSDData(struct adapter *pAdapter, u32 point) ++{ ++ int psd_val; ++ ++ psd_val = rtw_read32(pAdapter, 0x808); ++ psd_val &= 0xFFBFFC00; ++ psd_val |= point; ++ ++ rtw_write32(pAdapter, 0x808, psd_val); ++ mdelay(1); ++ psd_val |= 0x00400000; ++ ++ rtw_write32(pAdapter, 0x808, psd_val); ++ mdelay(1); ++ psd_val = rtw_read32(pAdapter, 0x8B4); ++ ++ psd_val &= 0x0000FFFF; ++ ++ return psd_val; ++} ++ ++/* ++ *pts start_point_min stop_point_max ++ * 128 64 64 + 128 = 192 ++ * 256 128 128 + 256 = 384 ++ * 512 256 256 + 512 = 768 ++ * 1024 512 512 + 1024 = 1536 ++ */ ++u32 mp_query_psd(struct adapter *pAdapter, u8 *data) ++{ ++ u32 i, psd_pts = 0, psd_start = 0, psd_stop = 0; ++ u32 psd_data = 0; ++ ++ if (!netif_running(pAdapter->pnetdev)) ++ return 0; ++ ++ if (!check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE)) ++ return 0; ++ ++ if (strlen(data) == 0) { /* default value */ ++ psd_pts = 128; ++ psd_start = 64; ++ psd_stop = 128; ++ } else { ++ sscanf(data, "pts =%d, start =%d, stop =%d", &psd_pts, &psd_start, &psd_stop); ++ } ++ ++ memset(data, '\0', sizeof(*data)); ++ ++ i = psd_start; ++ while (i < psd_stop) { ++ if (i >= psd_pts) { ++ psd_data = rtw_GetPSDData(pAdapter, i - psd_pts); ++ } else { ++ psd_data = rtw_GetPSDData(pAdapter, i); ++ } ++ sprintf(data + strlen(data), "%x ", psd_data); ++ i++; ++ } ++ ++ msleep(100); ++ return strlen(data) + 1; ++} ++ ++void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv) ++{ ++ int i, res; ++ struct adapter *padapter = pxmitpriv->adapter; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; ++ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ ++ if (padapter->registrypriv.mp_mode == 0) { ++ max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ } else { ++ max_xmit_extbuf_size = 6000; ++ num_xmit_extbuf = 8; ++ } ++ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; ++ for (i = 0; i < num_xmit_extbuf; i++) { ++ rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ)); ++ ++ pxmitbuf++; ++ } ++ ++ vfree(pxmitpriv->pallocated_xmit_extbuf); ++ ++ if (padapter->registrypriv.mp_mode == 0) { ++ max_xmit_extbuf_size = 6000; ++ num_xmit_extbuf = 8; ++ } else { ++ max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ } ++ ++ /* Init xmit extension buff */ ++ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); ++ ++ pxmitpriv->pallocated_xmit_extbuf = vzalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4); ++ ++ if (!pxmitpriv->pallocated_xmit_extbuf) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4); ++ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; ++ ++ for (i = 0; i < num_xmit_extbuf; i++) { ++ INIT_LIST_HEAD(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->ext_tag = true; ++ ++ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ); ++ if (res == _FAIL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ list_add_tail(&pxmitbuf->list, &pxmitpriv->free_xmit_extbuf_queue.queue); ++ pxmitbuf++; ++ } ++ ++ pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; ++ ++exit: ++ ; ++} ++ ++void Hal_ProSetCrystalCap(struct adapter *pAdapter, u32 CrystalCapVal) ++{ ++ CrystalCapVal = CrystalCapVal & 0x3F; ++ ++ // write 0x24[16:11] = 0x24[22:17] = CrystalCap ++ PHY_SetBBReg(pAdapter, REG_AFE_XTAL_CTRL, 0x7FF800, ++ (CrystalCapVal | (CrystalCapVal << 6))); ++} +diff --git a/drivers/staging/r8188eu/core/rtw_mp_ioctl.c b/drivers/staging/r8188eu/core/rtw_mp_ioctl.c +new file mode 100644 +index 000000000000..c85f8e467337 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_mp_ioctl.c +@@ -0,0 +1,1170 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTW_MP_IOCTL_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/mlme_osdep.h" ++#include "../include/rtw_mp_ioctl.h" ++ ++/* rtl8188eu_oid_rtl_seg_81_85 section start **************** */ ++int rtl8188eu_oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->information_buf_len < sizeof(u8)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ if (poid_par_priv->type_of_oid == SET_OID) { ++ Adapter->registrypriv.wireless_mode = *(u8 *)poid_par_priv->information_buf; ++ } else if (poid_par_priv->type_of_oid == QUERY_OID) { ++ *(u8 *)poid_par_priv->information_buf = Adapter->registrypriv.wireless_mode; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } else { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ } ++ ++ return status; ++} ++/* rtl8188eu_oid_rtl_seg_81_87_80 section start **************** */ ++int rtl8188eu_oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct bb_reg_param *pbbreg; ++ u16 offset; ++ u32 value; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); ++ ++ offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */ ++ if (offset < BB_REG_BASE_ADDR) ++ offset |= BB_REG_BASE_ADDR; ++ ++ value = pbbreg->value; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ write_bbreg(Adapter, offset, 0xFFFFFFFF, value); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct bb_reg_param *pbbreg; ++ u16 offset; ++ u32 value; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); ++ ++ offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */ ++ if (offset < BB_REG_BASE_ADDR) ++ offset |= BB_REG_BASE_ADDR; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ value = read_bbreg(Adapter, offset, 0xFFFFFFFF); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ pbbreg->value = value; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct rf_reg_param *pbbreg; ++ u8 path; ++ u8 offset; ++ u32 value; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); ++ ++ if (pbbreg->path >= RF_PATH_MAX) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ if (pbbreg->offset > 0xFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ if (pbbreg->value > 0xFFFFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ path = (u8)pbbreg->path; ++ offset = (u8)pbbreg->offset; ++ value = pbbreg->value; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ write_rfreg(Adapter, path, offset, value); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct rf_reg_param *pbbreg; ++ u8 path; ++ u8 offset; ++ u32 value; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ int status = NDIS_STATUS_SUCCESS; ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); ++ ++ if (pbbreg->path >= RF_PATH_MAX) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ if (pbbreg->offset > 0xFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ path = (u8)pbbreg->path; ++ offset = (u8)pbbreg->offset; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ value = read_rfreg(Adapter, path, offset); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ pbbreg->value = value; ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ return status; ++} ++/* rtl8188eu_oid_rtl_seg_81_87_00 section end**************** */ ++/* */ ++ ++/* rtl8188eu_oid_rtl_seg_81_80_00 section start **************** */ ++/* */ ++int rtl8188eu_oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 ratevalue;/* 4 */ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ ratevalue = *((u32 *)poid_par_priv->information_buf);/* 4 */ ++ if (ratevalue >= MPT_RATE_LAST) ++ return NDIS_STATUS_INVALID_DATA; ++ ++ Adapter->mppriv.rateidx = ratevalue; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetDataRate(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 mode; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (Adapter->registrypriv.mp_mode == 0) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ /* IQCalibrateBcut(Adapter); */ ++ ++ mode = *((u32 *)poid_par_priv->information_buf); ++ Adapter->mppriv.mode = mode;/* 1 for loopback */ ++ ++ if (mp_start_test(Adapter) == _FAIL) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ goto exit; ++ } ++ ++exit: ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ mp_stop_test(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 Channel; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) { ++ *((u32 *)poid_par_priv->information_buf) = Adapter->mppriv.channel; ++ return NDIS_STATUS_SUCCESS; ++ } ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ Channel = *((u32 *)poid_par_priv->information_buf); ++ if (Channel > 14) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ Adapter->mppriv.channel = Channel; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetChannel(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u16 bandwidth; ++ u16 channel_offset; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ bandwidth = *((u32 *)poid_par_priv->information_buf);/* 4 */ ++ channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ ++ if (bandwidth != HT_CHANNEL_WIDTH_40) ++ bandwidth = HT_CHANNEL_WIDTH_20; ++ padapter->mppriv.bandwidth = (u8)bandwidth; ++ padapter->mppriv.prime_channel_offset = (u8)channel_offset; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetBandwidth(padapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 antenna; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ if (poid_par_priv->type_of_oid == SET_OID) { ++ antenna = *(u32 *)poid_par_priv->information_buf; ++ ++ Adapter->mppriv.antenna_tx = (u16)((antenna & 0xFFFF0000) >> 16); ++ Adapter->mppriv.antenna_rx = (u16)(antenna & 0x0000FFFF); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetAntenna(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ } else { ++ antenna = (Adapter->mppriv.antenna_tx << 16) | Adapter->mppriv.antenna_rx; ++ *(u32 *)poid_par_priv->information_buf = antenna; ++ } ++ ++ return status; ++} ++ ++int rtl8188eu_oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 tx_pwr_idx; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ tx_pwr_idx = *((u32 *)poid_par_priv->information_buf); ++ if (tx_pwr_idx > MAX_TX_PWR_INDEX_N_MODE) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ Adapter->mppriv.txpoweridx = (u8)tx_pwr_idx; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetTxPower(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++ ++/* */ ++/* rtl8188eu_oid_rtl_seg_81_80_20 section start **************** */ ++/* */ ++int rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if (poid_par_priv->information_buf_len == sizeof(u32)) { ++ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.tx_pktcount; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if (poid_par_priv->information_buf_len == sizeof(u32)) { ++ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.rx_pktcount; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ if (poid_par_priv->information_buf_len == sizeof(u32)) { ++ *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.rx_crcerrpktcount; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ return status; ++} ++/* */ ++ ++int rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ Adapter->mppriv.tx_pktcount = 0; ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ if (poid_par_priv->information_buf_len == sizeof(u32)) { ++ Adapter->mppriv.rx_pktcount = 0; ++ Adapter->mppriv.rx_crcerrpktcount = 0; ++ } else { ++ status = NDIS_STATUS_INVALID_LENGTH; ++ } ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ResetPhyRxPktCount(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ *(u32 *)poid_par_priv->information_buf = GetPhyRxPktReceived(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len != sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ *(u32 *)poid_par_priv->information_buf = GetPhyRxPktCRC32Error(Adapter); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ return status; ++} ++/* rtl8188eu_oid_rtl_seg_81_80_20 section end **************** */ ++int rtl8188eu_oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 bStartTest; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ bStartTest = *((u32 *)poid_par_priv->information_buf); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetContinuousTx(Adapter, (u8)bStartTest); ++ if (bStartTest) { ++ struct mp_priv *pmp_priv = &Adapter->mppriv; ++ if (pmp_priv->tx.stop == 0) { ++ pmp_priv->tx.stop = 1; ++ DBG_88E("%s: pkt tx is running...\n", __func__); ++ msleep(5); ++ } ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = 1; ++ SetPacketTx(Adapter); ++ } ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++ ++int rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 bStartTest; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ bStartTest = *((u32 *)poid_par_priv->information_buf); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetSingleCarrierTx(Adapter, (u8)bStartTest); ++ if (bStartTest) { ++ struct mp_priv *pmp_priv = &Adapter->mppriv; ++ if (pmp_priv->tx.stop == 0) { ++ pmp_priv->tx.stop = 1; ++ DBG_88E("%s: pkt tx is running...\n", __func__); ++ msleep(5); ++ } ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = 1; ++ SetPacketTx(Adapter); ++ } ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++ ++int rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 bStartTest; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ bStartTest = *((u32 *)poid_par_priv->information_buf); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetCarrierSuppressionTx(Adapter, (u8)bStartTest); ++ if (bStartTest) { ++ struct mp_priv *pmp_priv = &Adapter->mppriv; ++ if (pmp_priv->tx.stop == 0) { ++ pmp_priv->tx.stop = 1; ++ DBG_88E("%s: pkt tx is running...\n", __func__); ++ msleep(5); ++ } ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = 1; ++ SetPacketTx(Adapter); ++ } ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++ ++int rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u32 bStartTest; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ bStartTest = *((u32 *)poid_par_priv->information_buf); ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ SetSingleToneTx(Adapter, (u8)bStartTest); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++ ++int rtl8188eu_oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++int rtl8188eu_oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ int status = NDIS_STATUS_SUCCESS; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ rtw_hal_set_hwreg(Adapter, HW_VAR_TRIGGER_GPIO_0, NULL); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* rtl8188eu_oid_rtl_seg_81_80_00 section end **************** */ ++/* */ ++int rtl8188eu_oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct mp_rw_reg *RegRWStruct; ++ u32 offset, width; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf; ++ offset = RegRWStruct->offset; ++ width = RegRWStruct->width; ++ ++ if (offset > 0xFFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ switch (width) { ++ case 1: ++ RegRWStruct->value = rtw_read8(Adapter, offset); ++ break; ++ case 2: ++ RegRWStruct->value = rtw_read16(Adapter, offset); ++ break; ++ default: ++ width = 4; ++ RegRWStruct->value = rtw_read32(Adapter, offset); ++ break; ++ } ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *poid_par_priv->bytes_rw = width; ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct mp_rw_reg *RegRWStruct; ++ u32 offset, value; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *padapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ RegRWStruct = (struct mp_rw_reg *)poid_par_priv->information_buf; ++ offset = RegRWStruct->offset; ++ value = RegRWStruct->value; ++ ++ if (offset > 0xFFF) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ switch (RegRWStruct->width) { ++ case 1: ++ if (value > 0xFF) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ break; ++ } ++ rtw_write8(padapter, offset, (u8)value); ++ break; ++ case 2: ++ if (value > 0xFFFF) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ break; ++ } ++ rtw_write16(padapter, offset, (u16)value); ++ break; ++ case 4: ++ rtw_write32(padapter, offset, value); ++ break; ++ default: ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ break; ++ } ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++/* */ ++int rtl8188eu_oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++/* */ ++int rtl8188eu_oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_wr_attrib_mem_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ int status = NDIS_STATUS_SUCCESS; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (rtw_setdatarate_cmd(Adapter, poid_par_priv->information_buf) != _SUCCESS) ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ u8 thermal = 0; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ GetThermalMeter(Adapter, &thermal); ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ *(u32 *)poid_par_priv->information_buf = (u32)thermal; ++ *poid_par_priv->bytes_rw = sizeof(u32); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->information_buf_len < sizeof(u8)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ if (poid_par_priv->type_of_oid == SET_OID) { ++ u8 enable; ++ ++ enable = *(u8 *)poid_par_priv->information_buf; ++ ++ SetPowerTracking(Adapter, enable); ++ } else { ++ GetPowerTracking(Adapter, (u8 *)poid_par_priv->information_buf); ++ } ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++/* rtl8188eu_oid_rtl_seg_87_12_00 section start **************** */ ++int rtl8188eu_oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++int rtl8188eu_oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++int rtl8188eu_oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++int rtl8188eu_oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++int rtl8188eu_oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return NDIS_STATUS_SUCCESS; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct efuse_access_struct *pefuse; ++ u8 *data; ++ u16 addr = 0, cnts = 0, max_available_size = 0; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct efuse_access_struct)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ pefuse = (struct efuse_access_struct *)poid_par_priv->information_buf; ++ addr = pefuse->start_addr; ++ cnts = pefuse->cnts; ++ data = pefuse->data; ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ ++ if ((addr + cnts) > max_available_size) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ if (rtw_efuse_access(Adapter, false, addr, cnts, data) == _FAIL) ++ status = NDIS_STATUS_FAILURE; ++ else ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct efuse_access_struct *pefuse; ++ u8 *data; ++ u16 addr = 0, cnts = 0, max_available_size = 0; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ pefuse = (struct efuse_access_struct *)poid_par_priv->information_buf; ++ addr = pefuse->start_addr; ++ cnts = pefuse->cnts; ++ data = pefuse->data; ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ ++ if ((addr + cnts) > max_available_size) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ if (rtw_efuse_access(Adapter, true, addr, cnts, data) == _FAIL) ++ status = NDIS_STATUS_FAILURE; ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct pgpkt *ppgpkt; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ *poid_par_priv->bytes_rw = 0; ++ ++ if (poid_par_priv->information_buf_len < sizeof(struct pgpkt *)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ ppgpkt = (struct pgpkt *)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) { ++ Efuse_PowerSwitch(Adapter, false, true); ++ if (Efuse_PgPacketRead(Adapter, ppgpkt->offset, ppgpkt->data, false)) ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ else ++ status = NDIS_STATUS_FAILURE; ++ Efuse_PowerSwitch(Adapter, false, false); ++ } else { ++ Efuse_PowerSwitch(Adapter, true, true); ++ if (Efuse_PgPacketWrite(Adapter, ppgpkt->offset, ppgpkt->word_en, ppgpkt->data, false)) ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ else ++ status = NDIS_STATUS_FAILURE; ++ Efuse_PowerSwitch(Adapter, true, false); ++ } ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u16 size; ++ u8 ret; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ret = efuse_GetCurrentSize(Adapter, &size); ++ _irqlevel_changed_(&oldirql, RAISE); ++ if (ret == _SUCCESS) { ++ *(u32 *)poid_par_priv->information_buf = size; ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ } else { ++ status = NDIS_STATUS_FAILURE; ++ } ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ ++ if (poid_par_priv->type_of_oid != QUERY_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u32)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ *(u32 *)poid_par_priv->information_buf = efuse_GetMaxSize(Adapter); ++ *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status; ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) ++ status = rtl8188eu_oid_rt_pro_read_efuse_hdl(poid_par_priv); ++ else ++ status = rtl8188eu_oid_rt_pro_write_efuse_hdl(poid_par_priv); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ u8 *data; ++ int status = NDIS_STATUS_SUCCESS; ++ struct adapter *Adapter = (struct adapter *)(poid_par_priv->adapter_context); ++ u16 maplen = 0; ++ ++ EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&maplen, false); ++ ++ *poid_par_priv->bytes_rw = 0; ++ ++ if (poid_par_priv->information_buf_len < maplen) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ data = (u8 *)poid_par_priv->information_buf; ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) { ++ if (rtw_efuse_map_read(Adapter, 0, maplen, data) == _SUCCESS) ++ *poid_par_priv->bytes_rw = maplen; ++ else ++ status = NDIS_STATUS_FAILURE; ++ } else { ++ /* SET_OID */ ++ if (rtw_efuse_map_write(Adapter, 0, maplen, data) == _SUCCESS) ++ *poid_par_priv->bytes_rw = maplen; ++ else ++ status = NDIS_STATUS_FAILURE; ++ } ++ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++ ++int rtl8188eu_oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ return status; ++} ++ ++int rtl8188eu_oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) ++ return NDIS_STATUS_NOT_ACCEPTED; ++ ++ if (poid_par_priv->information_buf_len < sizeof(u8)) ++ return NDIS_STATUS_INVALID_LENGTH; ++ ++ return status; ++} ++ ++int rtl8188eu_oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++int rtl8188eu_oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} ++ ++int rtl8188eu_mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ struct mp_xmit_parm *pparm; ++ struct adapter *padapter; ++ struct mp_priv *pmp_priv; ++ struct pkt_attrib *pattrib; ++ ++ pparm = (struct mp_xmit_parm *)poid_par_priv->information_buf; ++ padapter = (struct adapter *)poid_par_priv->adapter_context; ++ pmp_priv = &padapter->mppriv; ++ ++ if (poid_par_priv->type_of_oid == QUERY_OID) { ++ pparm->enable = !pmp_priv->tx.stop; ++ pparm->count = pmp_priv->tx.sended; ++ } else { ++ if (pparm->enable == 0) { ++ pmp_priv->tx.stop = 1; ++ } else if (pmp_priv->tx.stop == 1) { ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = pparm->count; ++ pmp_priv->tx.payload = pparm->payload_type; ++ pattrib = &pmp_priv->tx.attrib; ++ pattrib->pktlen = pparm->length; ++ memcpy(pattrib->dst, pparm->da, ETH_ALEN); ++ SetPacketTx(padapter); ++ } else { ++ return NDIS_STATUS_FAILURE; ++ } ++ } ++ ++ return NDIS_STATUS_SUCCESS; ++} ++ ++/* */ ++int rtl8188eu_oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ int status = NDIS_STATUS_SUCCESS; ++ ++ if (poid_par_priv->type_of_oid != SET_OID) { ++ status = NDIS_STATUS_NOT_ACCEPTED; ++ return status; ++ } ++ ++ _irqlevel_changed_(&oldirql, LOWER); ++ ++ /* CALL the power_down function */ ++ _irqlevel_changed_(&oldirql, RAISE); ++ ++ return status; ++} ++/* */ ++int rtl8188eu_oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv) ++{ ++ return 0; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_p2p.c b/drivers/staging/r8188eu/core/rtw_p2p.c +new file mode 100644 +index 000000000000..e2b6cf2386e0 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_p2p.c +@@ -0,0 +1,1997 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTW_P2P_C_ ++ ++#include "../include/drv_types.h" ++#include "../include/rtw_p2p.h" ++#include "../include/wifi.h" ++ ++#ifdef CONFIG_88EU_P2P ++ ++static int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt) ++{ ++ int found = 0, i = 0; ++ ++ for (i = 0; i < ch_cnt; i++) { ++ if (ch_list[i] == desired_ch) { ++ found = 1; ++ break; ++ } ++ } ++ return found; ++} ++ ++static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ struct list_head *phead, *plist; ++ u32 len = 0; ++ u16 attr_len = 0; ++ u8 tmplen, *pdata_attr, *pstart, *pcur; ++ struct sta_info *psta = NULL; ++ struct adapter *padapter = pwdinfo->padapter; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ DBG_88E("%s\n", __func__); ++ ++ pdata_attr = kzalloc(MAX_P2P_IE_LEN, GFP_KERNEL); ++ ++ pstart = pdata_attr; ++ pcur = pdata_attr; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ phead = &pstapriv->asoc_list; ++ plist = phead->next; ++ ++ /* look up sta asoc_queue */ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, asoc_list); ++ ++ plist = plist->next; ++ ++ if (psta->is_p2p_device) { ++ tmplen = 0; ++ ++ pcur++; ++ ++ /* P2P device address */ ++ memcpy(pcur, psta->dev_addr, ETH_ALEN); ++ pcur += ETH_ALEN; ++ ++ /* P2P interface address */ ++ memcpy(pcur, psta->hwaddr, ETH_ALEN); ++ pcur += ETH_ALEN; ++ ++ *pcur = psta->dev_cap; ++ pcur++; ++ ++ /* u16*)(pcur) = cpu_to_be16(psta->config_methods); */ ++ RTW_PUT_BE16(pcur, psta->config_methods); ++ pcur += 2; ++ ++ memcpy(pcur, psta->primary_dev_type, 8); ++ pcur += 8; ++ ++ *pcur = psta->num_of_secdev_type; ++ pcur++; ++ ++ memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type * 8); ++ pcur += psta->num_of_secdev_type * 8; ++ ++ if (psta->dev_name_len > 0) { ++ /* u16*)(pcur) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ ++ RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME); ++ pcur += 2; ++ ++ /* u16*)(pcur) = cpu_to_be16(psta->dev_name_len); */ ++ RTW_PUT_BE16(pcur, psta->dev_name_len); ++ pcur += 2; ++ ++ memcpy(pcur, psta->dev_name, psta->dev_name_len); ++ pcur += psta->dev_name_len; ++ } ++ ++ tmplen = (u8)(pcur - pstart); ++ ++ *pstart = (tmplen - 1); ++ ++ attr_len += tmplen; ++ ++ /* pstart += tmplen; */ ++ pstart = pcur; ++ } ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ ++ if (attr_len > 0) ++ len = rtw_set_p2p_attr_content(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr); ++ ++ kfree(pdata_attr); ++ return len; ++} ++ ++static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct adapter *padapter = pwdinfo->padapter; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */ ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_GO_DISC_REQUEST; ++ u8 dialogToken = 0; ++ ++ DBG_88E("[%s]\n", __func__); ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ /* Build P2P action frame header */ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &dialogToken, &pattrib->pktlen); ++ ++ /* there is no IE in this P2P action frame */ ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct adapter *padapter = pwdinfo->padapter; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_DEVDISC_RESP; ++ u8 p2pie[8] = { 0x00 }; ++ u32 p2pielen = 0; ++ ++ DBG_88E("[%s]\n", __func__); ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ /* Build P2P public action frame header */ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &dialogToken, &pattrib->pktlen); ++ ++ /* Build P2P IE */ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* P2P_ATTR_STATUS */ ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8 *raddr, u8 *frame_body, u16 config_method) ++{ ++ struct adapter *padapter = pwdinfo->padapter; ++ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; ++ u8 action = P2P_PUB_ACTION_ACTION; ++ u8 dialogToken = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */ ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_PROVISION_DISC_RESP; ++ u8 wpsie[100] = { 0x00 }; ++ u8 wpsielen = 0; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &dialogToken, &pattrib->pktlen); ++ ++ wpsielen = 0; ++ /* WPS OUI */ ++ RTW_PUT_BE32(wpsie, WPSOUI); ++ wpsielen += 4; ++ ++ /* Config Method */ ++ /* Type: */ ++ RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD); ++ wpsielen += 2; ++ ++ /* Length: */ ++ RTW_PUT_BE16(wpsie + wpsielen, 0x0002); ++ wpsielen += 2; ++ ++ /* Value: */ ++ RTW_PUT_BE16(wpsie + wpsielen, config_method); ++ wpsielen += 2; ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *)wpsie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) ++{ ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ unsigned char *pframe; ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ struct adapter *padapter = pwdinfo->padapter; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */ ++ __be32 p2poui = cpu_to_be32(P2POUI); ++ u8 oui_subtype = P2P_PRESENCE_RESPONSE; ++ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; ++ u8 noa_attr_content[32] = { 0x00 }; ++ u32 p2pielen = 0; ++ ++ DBG_88E("[%s]\n", __func__); ++ ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ return; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(padapter, pattrib); ++ ++ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); ++ ++ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, da, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); ++ pmlmeext->mgnt_seq++; ++ SetFrameSubType(pframe, WIFI_ACTION); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ /* Build P2P action frame header */ ++ pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &oui_subtype, &pattrib->pktlen); ++ pframe = rtw_set_fixed_ie(pframe, 1, &dialogToken, &pattrib->pktlen); ++ ++ /* Add P2P IE header */ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Add Status attribute in P2P IE */ ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); ++ ++ /* Add NoA attribute in P2P IE */ ++ noa_attr_content[0] = 0x1;/* index */ ++ noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */ ++ ++ /* todo: Notice of Absence Descriptor(s) */ ++ ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content); ++ ++ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen); ++ ++ pattrib->last_txcmdsz = pattrib->pktlen; ++ ++ dump_mgntframe(padapter, pmgntframe); ++} ++ ++u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; ++ u16 capability = 0; ++ u32 len = 0, p2pielen = 0; ++ __le16 le_tmp; ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* According to the P2P Specification, the beacon frame should contain 3 P2P attributes */ ++ /* 1. P2P Capability */ ++ /* 2. P2P Device ID */ ++ /* 3. Notice of Absence (NOA) */ ++ ++ /* P2P Capability ATTR */ ++ /* Type: */ ++ /* Length: */ ++ /* Value: */ ++ /* Device Capability Bitmap, 1 byte */ ++ /* Be able to participate in additional P2P Groups and */ ++ /* support the P2P Invitation Procedure */ ++ /* Group Capability Bitmap, 1 byte */ ++ capability = P2P_DEVCAP_INVITATION_PROC | P2P_DEVCAP_CLIENT_DISCOVERABILITY; ++ capability |= ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8); ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) ++ capability |= (P2P_GRPCAP_GROUP_FORMATION << 8); ++ ++ le_tmp = cpu_to_le16(capability); ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8 *)&le_tmp); ++ ++ /* P2P Device ID ATTR */ ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr); ++ ++ /* Notice of Absence ATTR */ ++ /* Type: */ ++ /* Length: */ ++ /* Value: */ ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len); ++ return len; ++} ++ ++u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; ++ u32 len = 0, p2pielen = 0; ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20100907 */ ++ /* According to the P2P Specification, the probe response frame should contain 5 P2P attributes */ ++ /* 1. P2P Capability */ ++ /* 2. Extended Listen Timing */ ++ /* 3. Notice of Absence (NOA) (Only GO needs this) */ ++ /* 4. Device Info */ ++ /* 5. Group Info (Only GO need this) */ ++ ++ /* P2P Capability ATTR */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; ++ ++ /* Length: */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ ++ RTW_PUT_LE16(p2pie + p2pielen, 0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Device Capability Bitmap, 1 byte */ ++ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ /* Group Capability Bitmap, 1 byte */ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ p2pie[p2pielen] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS); ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) ++ p2pie[p2pielen] |= P2P_GRPCAP_GROUP_FORMATION; ++ ++ p2pielen++; ++ } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { ++ /* Group Capability Bitmap, 1 byte */ ++ if (pwdinfo->persistent_supported) ++ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; ++ else ++ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; ++ } ++ ++ /* Extended Listen Timing ATTR */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; ++ ++ /* Length: */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); */ ++ RTW_PUT_LE16(p2pie + p2pielen, 0x0004); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Availability Period */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ ++ RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); ++ p2pielen += 2; ++ ++ /* Availability Interval */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */ ++ RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); ++ p2pielen += 2; ++ ++ /* Notice of Absence ATTR */ ++ /* Type: */ ++ /* Length: */ ++ /* Value: */ ++ ++ /* Device Info ATTR */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; ++ ++ /* Length: */ ++ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ ++ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ ++ RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* Config Method */ ++ /* This field should be big endian. Noted by P2P specification. */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); */ ++ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm); ++ p2pielen += 2; ++ ++ /* Primary Device Type */ ++ /* Category ID */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); ++ p2pielen += 2; ++ ++ /* OUI */ ++ /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ ++ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); ++ p2pielen += 4; ++ ++ /* Sub Category ID */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); ++ p2pielen += 2; ++ ++ /* Number of Secondary Device Types */ ++ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ ++ ++ /* Device Name */ ++ /* Type: */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); ++ p2pielen += 2; ++ ++ /* Length: */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ ++ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); ++ p2pielen += pwdinfo->device_name_len; ++ ++ /* Group Info ATTR */ ++ /* Type: */ ++ /* Length: */ ++ /* Value: */ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen); ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len); ++ ++ return len; ++} ++ ++u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 *pssid, u8 ussidlen, u8 *pdev_raddr) ++{ ++ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; ++ u32 len = 0, p2pielen = 0; ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* Commented by Albert 20110301 */ ++ /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */ ++ /* 1. P2P Capability */ ++ /* 2. Device Info */ ++ /* 3. Group ID (When joining an operating P2P Group) */ ++ ++ /* P2P Capability ATTR */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; ++ ++ /* Length: */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */ ++ RTW_PUT_LE16(p2pie + p2pielen, 0x0002); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* Device Capability Bitmap, 1 byte */ ++ p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; ++ ++ /* Group Capability Bitmap, 1 byte */ ++ if (pwdinfo->persistent_supported) ++ p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; ++ else ++ p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; ++ ++ /* Device Info ATTR */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; ++ ++ /* Length: */ ++ /* 21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ ++ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */ ++ RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ /* P2P Device Address */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ /* Config Method */ ++ /* This field should be big endian. Noted by P2P specification. */ ++ if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) { ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); */ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC); ++ } else { ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); */ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY); ++ } ++ ++ p2pielen += 2; ++ ++ /* Primary Device Type */ ++ /* Category ID */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); ++ p2pielen += 2; ++ ++ /* OUI */ ++ /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */ ++ RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); ++ p2pielen += 4; ++ ++ /* Sub Category ID */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); ++ p2pielen += 2; ++ ++ /* Number of Secondary Device Types */ ++ p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ ++ ++ /* Device Name */ ++ /* Type: */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */ ++ RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); ++ p2pielen += 2; ++ ++ /* Length: */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */ ++ RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); ++ p2pielen += pwdinfo->device_name_len; ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { ++ /* Added by Albert 2011/05/19 */ ++ /* In this case, the pdev_raddr is the device address of the group owner. */ ++ ++ /* P2P Group ID ATTR */ ++ /* Type: */ ++ p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; ++ ++ /* Length: */ ++ /* u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + ussidlen); */ ++ RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen); ++ p2pielen += 2; ++ ++ /* Value: */ ++ memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN); ++ p2pielen += ETH_ALEN; ++ ++ memcpy(p2pie + p2pielen, pssid, ussidlen); ++ p2pielen += ussidlen; ++ } ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len); ++ ++ return len; ++} ++ ++u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code) ++{ ++ u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; ++ u32 len = 0, p2pielen = 0; ++ ++ /* P2P OUI */ ++ p2pielen = 0; ++ p2pie[p2pielen++] = 0x50; ++ p2pie[p2pielen++] = 0x6F; ++ p2pie[p2pielen++] = 0x9A; ++ p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ ++ ++ /* According to the P2P Specification, the Association response frame should contain 2 P2P attributes */ ++ /* 1. Status */ ++ /* 2. Extended Listen Timing (optional) */ ++ ++ /* Status ATTR */ ++ p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code); ++ ++ /* Extended Listen Timing ATTR */ ++ /* Type: */ ++ /* Length: */ ++ /* Value: */ ++ ++ pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *)p2pie, &len); ++ ++ return len; ++} ++ ++u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) ++{ ++ u32 len = 0; ++ ++ return len; ++} ++ ++u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ u8 *p; ++ u32 ret = false; ++ u8 *p2pie; ++ u32 p2pielen = 0; ++ int ssid_len = 0, rate_cnt = 0; ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); ++ ++ if (rate_cnt <= 4) { ++ int i, g_rate = 0; ++ ++ for (i = 0; i < rate_cnt; i++) { ++ if (((*(p + 2 + i) & 0xff) != 0x02) && ++ ((*(p + 2 + i) & 0xff) != 0x04) && ++ ((*(p + 2 + i) & 0xff) != 0x0B) && ++ ((*(p + 2 + i) & 0xff) != 0x16)) ++ g_rate = 1; ++ } ++ ++ if (g_rate == 0) { ++ /* There is no OFDM rate included in SupportedRates IE of this probe request frame */ ++ /* The driver should response this probe request. */ ++ return ret; ++ } ++ } else { ++ /* rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */ ++ /* We should proceed the following check for this probe request. */ ++ } ++ ++ /* Added comments by Albert 20100906 */ ++ /* There are several items we should check here. */ ++ /* 1. This probe request frame must contain the P2P IE. (Done) */ ++ /* 2. This probe request frame must contain the wildcard SSID. (Done) */ ++ /* 3. Wildcard BSSID. (Todo) */ ++ /* 4. Destination Address. (Done in mgt_dispatcher function) */ ++ /* 5. Requested Device Type in WSC IE. (Todo) */ ++ /* 6. Device ID attribute in P2P IE. (Todo) */ ++ ++ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len, ++ len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); ++ ++ ssid_len &= 0xff; /* Just last 1 byte is valid for ssid len of the probe request */ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_, NULL, &p2pielen); ++ if (p2pie) { ++ if (p && !memcmp((void *)(p + 2), (void *)pwdinfo->p2p_wildcard_ssid, 7)) { ++ /* todo: */ ++ /* Check Requested Device Type attributes in WSC IE. */ ++ /* Check Device ID attribute in P2P IE */ ++ ++ ret = true; ++ } else if (p && ssid_len == 0) { ++ ret = true; ++ } ++ } else { ++ /* non -p2p device */ ++ } ++ } ++ ++ return ret; ++} ++ ++u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta) ++{ ++ u8 status_code = P2P_STATUS_SUCCESS; ++ u8 *pbuf, *pattr_content = NULL; ++ u32 attr_contentlen = 0; ++ u16 cap_attr = 0; ++ unsigned short frame_type, ie_offset = 0; ++ u8 *ies; ++ u32 ies_len; ++ u8 *p2p_ie; ++ u32 p2p_ielen = 0; ++ __be16 be_tmp; ++ __le16 le_tmp; ++ ++ if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) ++ return P2P_STATUS_FAIL_REQUEST_UNABLE; ++ ++ frame_type = GetFrameSubType(pframe); ++ if (frame_type == WIFI_ASSOCREQ) ++ ie_offset = _ASOCREQ_IE_OFFSET_; ++ else /* WIFI_REASSOCREQ */ ++ ie_offset = _REASOCREQ_IE_OFFSET_; ++ ++ ies = pframe + WLAN_HDR_A3_LEN + ie_offset; ++ ies_len = len - WLAN_HDR_A3_LEN - ie_offset; ++ ++ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); ++ ++ if (!p2p_ie) { ++ DBG_88E("[%s] P2P IE not Found!!\n", __func__); ++ status_code = P2P_STATUS_FAIL_INVALID_PARAM; ++ } else { ++ DBG_88E("[%s] P2P IE Found!!\n", __func__); ++ } ++ ++ while (p2p_ie) { ++ /* Check P2P Capability ATTR */ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&le_tmp, (uint *)&attr_contentlen)) { ++ DBG_88E("[%s] Got P2P Capability Attr!!\n", __func__); ++ cap_attr = le16_to_cpu(le_tmp); ++ psta->dev_cap = cap_attr & 0xff; ++ } ++ ++ /* Check Extended Listen Timing ATTR */ ++ ++ /* Check P2P Device Info ATTR */ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint *)&attr_contentlen)) { ++ DBG_88E("[%s] Got P2P DEVICE INFO Attr!!\n", __func__); ++ pattr_content = kzalloc(attr_contentlen, GFP_KERNEL); ++ pbuf = pattr_content; ++ if (pattr_content) { ++ u8 num_of_secdev_type; ++ u16 dev_name_len; ++ ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, pattr_content, (uint *)&attr_contentlen); ++ ++ memcpy(psta->dev_addr, pattr_content, ETH_ALEN);/* P2P Device Address */ ++ ++ pattr_content += ETH_ALEN; ++ ++ memcpy(&be_tmp, pattr_content, 2);/* Config Methods */ ++ psta->config_methods = be16_to_cpu(be_tmp); ++ ++ pattr_content += 2; ++ ++ memcpy(psta->primary_dev_type, pattr_content, 8); ++ ++ pattr_content += 8; ++ ++ num_of_secdev_type = *pattr_content; ++ pattr_content += 1; ++ ++ if (num_of_secdev_type == 0) { ++ psta->num_of_secdev_type = 0; ++ } else { ++ u32 len; ++ ++ psta->num_of_secdev_type = num_of_secdev_type; ++ ++ len = (sizeof(psta->secdev_types_list) < (num_of_secdev_type * 8)) ? ++ (sizeof(psta->secdev_types_list)) : (num_of_secdev_type * 8); ++ ++ memcpy(psta->secdev_types_list, pattr_content, len); ++ ++ pattr_content += (num_of_secdev_type * 8); ++ } ++ ++ psta->dev_name_len = 0; ++ if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(__be16 *)pattr_content)) { ++ dev_name_len = be16_to_cpu(*(__be16 *)(pattr_content + 2)); ++ ++ psta->dev_name_len = (sizeof(psta->dev_name) < dev_name_len) ? sizeof(psta->dev_name) : dev_name_len; ++ ++ memcpy(psta->dev_name, pattr_content + 4, psta->dev_name_len); ++ } ++ kfree(pbuf); ++ } ++ } ++ ++ /* Get the next P2P IE */ ++ p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++ ++ return status_code; ++} ++ ++u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ u8 *frame_body; ++ u8 status, dialogToken; ++ struct sta_info *psta = NULL; ++ struct adapter *padapter = pwdinfo->padapter; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *p2p_ie; ++ u32 p2p_ielen = 0; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ dialogToken = frame_body[7]; ++ status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; ++ ++ p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); ++ if (p2p_ie) { ++ u8 groupid[38] = { 0x00 }; ++ u8 dev_addr[ETH_ALEN] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { ++ if (!memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) && ++ !memcmp(pwdinfo->p2p_group_ssid, groupid + ETH_ALEN, pwdinfo->p2p_group_ssid_len)) { ++ attr_contentlen = 0; ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_ID, dev_addr, &attr_contentlen)) { ++ struct list_head *phead, *plist; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ phead = &pstapriv->asoc_list; ++ plist = phead->next; ++ ++ /* look up sta asoc_queue */ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, asoc_list); ++ ++ plist = plist->next; ++ ++ if (psta->is_p2p_device && (psta->dev_cap & P2P_DEVCAP_CLIENT_DISCOVERABILITY) && ++ !memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) { ++ /* issue GO Discoverability Request */ ++ issue_group_disc_req(pwdinfo, psta->hwaddr); ++ status = P2P_STATUS_SUCCESS; ++ break; ++ } else { ++ status = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ } ++ } ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ } else { ++ status = P2P_STATUS_FAIL_INVALID_PARAM; ++ } ++ } else { ++ status = P2P_STATUS_FAIL_INVALID_PARAM; ++ } ++ } ++ } ++ ++ /* issue Device Discoverability Response */ ++ issue_p2p_devdisc_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken); ++ ++ return (status == P2P_STATUS_SUCCESS) ? true : false; ++} ++ ++u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ return true; ++} ++ ++u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ u8 *frame_body; ++ u8 *wpsie; ++ uint wps_ielen = 0, attr_contentlen = 0; ++ u16 uconfig_method = 0; ++ __be16 be_tmp; ++ ++ frame_body = (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ wpsie = rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen); ++ if (wpsie) { ++ if (rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD, (u8 *)&be_tmp, &attr_contentlen)) { ++ uconfig_method = be16_to_cpu(be_tmp); ++ switch (uconfig_method) { ++ case WPS_CM_DISPLYA: ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); ++ break; ++ case WPS_CM_LABEL: ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "lab", 3); ++ break; ++ case WPS_CM_PUSH_BUTTON: ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); ++ break; ++ case WPS_CM_KEYPAD: ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); ++ break; ++ } ++ issue_p2p_provision_resp(pwdinfo, GetAddr2Ptr(pframe), frame_body, uconfig_method); ++ } ++ } ++ DBG_88E("[%s] config method = %s\n", __func__, pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req); ++ return true; ++} ++ ++u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe) ++{ ++ return true; ++} ++ ++static u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list) ++{ ++ u8 i = 0, j = 0; ++ u8 temp = 0; ++ u8 ch_no = 0; ++ ch_content += 3; ++ ch_cnt -= 3; ++ ++ while (ch_cnt > 0) { ++ ch_content += 1; ++ ch_cnt -= 1; ++ temp = *ch_content; ++ for (i = 0 ; i < temp ; i++, j++) ++ peer_ch_list[j] = *(ch_content + 1 + i); ++ ch_content += (temp + 1); ++ ch_cnt -= (temp + 1); ++ ch_no += temp; ++ } ++ ++ return ch_no; ++} ++ ++static u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned) ++{ ++ int i = 0, j = 0, temp = 0; ++ u8 ch_no = 0; ++ ++ for (i = 0; i < peer_ch_num; i++) { ++ for (j = temp; j < pmlmeext->max_chan_nums; j++) { ++ if (*(peer_ch_list + i) == pmlmeext->channel_set[j].ChannelNum) { ++ ch_list_inclusioned[ch_no++] = *(peer_ch_list + i); ++ temp = j; ++ break; ++ } ++ } ++ } ++ ++ return ch_no; ++} ++ ++u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ struct adapter *padapter = pwdinfo->padapter; ++ u8 result = P2P_STATUS_SUCCESS; ++ u32 p2p_ielen = 0, wps_ielen = 0; ++ u8 *ies; ++ u32 ies_len; ++ u8 *p2p_ie; ++ u8 *wpsie; ++ u16 wps_devicepassword_id = 0x0000; ++ uint wps_devicepassword_id_len = 0; ++ __be16 be_tmp; ++ ++ wpsie = rtw_get_wps_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen); ++ if (wpsie) { ++ /* Commented by Kurt 20120113 */ ++ /* If some device wants to do p2p handshake without sending prov_disc_req */ ++ /* We have to get peer_req_cm from here. */ ++ if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) { ++ rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len); ++ wps_devicepassword_id = be16_to_cpu(be_tmp); ++ ++ if (wps_devicepassword_id == WPS_DPID_USER_SPEC) ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); ++ else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); ++ else ++ memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); ++ } ++ } else { ++ DBG_88E("[%s] WPS IE not Found!!\n", __func__); ++ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ return result; ++ } ++ ++ if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) { ++ result = P2P_STATUS_FAIL_INFO_UNAVAILABLE; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY); ++ return result; ++ } ++ ++ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); ++ ++ if (!p2p_ie) { ++ DBG_88E("[%s] P2P IE not Found!!\n", __func__); ++ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ } ++ ++ while (p2p_ie) { ++ u8 attr_content = 0x00; ++ u32 attr_contentlen = 0; ++ u8 ch_content[50] = { 0x00 }; ++ uint ch_cnt = 0; ++ u8 peer_ch_list[50] = { 0x00 }; ++ u8 peer_ch_num = 0; ++ u8 ch_list_inclusioned[50] = { 0x00 }; ++ u8 ch_num_inclusioned = 0; ++ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING); ++ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, &attr_content, &attr_contentlen)) { ++ DBG_88E("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01); ++ pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ ++ ++ if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) { ++ /* Try to match the tie breaker value */ ++ if (pwdinfo->intent == P2P_MAX_INTENT) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; ++ } else { ++ if (attr_content & 0x01) ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ else ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ } else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } else { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ /* Store the group id information. */ ++ memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); ++ memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); ++ } ++ } ++ ++ attr_contentlen = 0; ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) { ++ if (attr_contentlen != ETH_ALEN) ++ memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); ++ } ++ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) { ++ peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list); ++ ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); ++ ++ if (ch_num_inclusioned == 0) { ++ DBG_88E("[%s] No common channel in channel list!\n", __func__); ++ result = P2P_STATUS_FAIL_NO_COMMON_CH; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ break; ++ } ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, ++ ch_list_inclusioned, ch_num_inclusioned)) { ++ u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; ++ attr_contentlen = 0; ++ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) ++ peer_operating_ch = operatingch_info[4]; ++ ++ if (rtw_p2p_is_channel_list_ok(peer_operating_ch, ++ ch_list_inclusioned, ch_num_inclusioned)) { ++ /** ++ * Change our operating channel as peer's for compatibility. ++ */ ++ pwdinfo->operating_channel = peer_operating_ch; ++ DBG_88E("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel); ++ } else { ++ /* Take first channel of ch_list_inclusioned as operating channel */ ++ pwdinfo->operating_channel = ch_list_inclusioned[0]; ++ DBG_88E("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel); ++ } ++ } ++ } ++ } ++ ++ /* Get the next P2P IE */ ++ p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++ return result; ++} ++ ++u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ struct adapter *padapter = pwdinfo->padapter; ++ u8 result = P2P_STATUS_SUCCESS; ++ u32 p2p_ielen, wps_ielen; ++ u8 *ies; ++ u32 ies_len; ++ u8 *p2p_ie; ++ ++ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ /* Be able to know which one is the P2P GO and which one is P2P client. */ ++ ++ if (rtw_get_wps_ie(ies, ies_len, NULL, &wps_ielen)) { ++ } else { ++ DBG_88E("[%s] WPS IE not Found!!\n", __func__); ++ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ } ++ ++ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); ++ if (!p2p_ie) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; ++ } else { ++ u8 attr_content = 0x00; ++ u32 attr_contentlen = 0; ++ u8 operatingch_info[5] = { 0x00 }; ++ u8 groupid[38]; ++ u8 peer_ch_list[50] = { 0x00 }; ++ u8 peer_ch_num = 0; ++ u8 ch_list_inclusioned[50] = { 0x00 }; ++ u8 ch_num_inclusioned = 0; ++ ++ while (p2p_ie) { /* Found the P2P IE. */ ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); ++ if (attr_contentlen == 1) { ++ DBG_88E("[%s] Status = %d\n", __func__, attr_content); ++ if (attr_content == P2P_STATUS_SUCCESS) { ++ /* Do nothing. */ ++ } else { ++ if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content) { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY); ++ } else { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ } ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ result = attr_content; ++ break; ++ } ++ } ++ ++ /* Try to get the peer's interface address */ ++ attr_contentlen = 0; ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) { ++ if (attr_contentlen != ETH_ALEN) ++ memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); ++ } ++ ++ /* Try to get the peer's intent and tie breaker value. */ ++ attr_content = 0x00; ++ attr_contentlen = 0; ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, &attr_content, &attr_contentlen)) { ++ DBG_88E("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01); ++ pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ ++ ++ if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) { ++ /* Try to match the tie breaker value */ ++ if (pwdinfo->intent == P2P_MAX_INTENT) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ } else { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ if (attr_content & 0x01) ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ else ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ } else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } else { ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ /* Store the group id information. */ ++ memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); ++ memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); ++ } ++ } ++ ++ /* Try to get the operation channel information */ ++ ++ attr_contentlen = 0; ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) { ++ DBG_88E("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]); ++ pwdinfo->peer_operating_ch = operatingch_info[4]; ++ } ++ ++ /* Try to get the channel list information */ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len)) { ++ DBG_88E("[%s] channel list attribute found, len = %d\n", __func__, pwdinfo->channel_list_attr_len); ++ ++ peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list); ++ ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); ++ ++ if (ch_num_inclusioned == 0) { ++ DBG_88E("[%s] No common channel in channel list!\n", __func__); ++ result = P2P_STATUS_FAIL_NO_COMMON_CH; ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ break; ++ } ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, ++ ch_list_inclusioned, ch_num_inclusioned)) { ++ u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; ++ attr_contentlen = 0; ++ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) ++ peer_operating_ch = operatingch_info[4]; ++ ++ if (rtw_p2p_is_channel_list_ok(peer_operating_ch, ++ ch_list_inclusioned, ch_num_inclusioned)) { ++ /** ++ * Change our operating channel as peer's for compatibility. ++ */ ++ pwdinfo->operating_channel = peer_operating_ch; ++ DBG_88E("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel); ++ } else { ++ /* Take first channel of ch_list_inclusioned as operating channel */ ++ pwdinfo->operating_channel = ch_list_inclusioned[0]; ++ DBG_88E("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel); ++ } ++ } ++ } ++ } else { ++ DBG_88E("[%s] channel list attribute not found!\n", __func__); ++ } ++ ++ /* Try to get the group id information if peer is GO */ ++ attr_contentlen = 0; ++ memset(groupid, 0x00, 38); ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { ++ memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); ++ memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); ++ } ++ ++ /* Get the next P2P IE */ ++ p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++ } ++ return result; ++} ++ ++u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ u8 *ies; ++ u32 ies_len; ++ u8 *p2p_ie; ++ u32 p2p_ielen = 0; ++ u8 result = P2P_STATUS_SUCCESS; ++ ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; ++ ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); ++ while (p2p_ie) { /* Found the P2P IE. */ ++ u8 attr_content = 0x00, operatingch_info[5] = { 0x00 }; ++ u8 groupid[38] = { 0x00 }; ++ u32 attr_contentlen = 0; ++ ++ pwdinfo->negotiation_dialog_token = 1; ++ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); ++ if (attr_contentlen == 1) { ++ DBG_88E("[%s] Status = %d\n", __func__, attr_content); ++ result = attr_content; ++ ++ if (attr_content == P2P_STATUS_SUCCESS) { ++ u8 bcancelled = 0; ++ ++ _cancel_timer(&pwdinfo->restore_p2p_state_timer, &bcancelled); ++ ++ /* Commented by Albert 20100911 */ ++ /* Todo: Need to handle the case which both Intents are the same. */ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1)) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1)) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ } else { ++ /* Have to compare the Tie Breaker */ ++ if (pwdinfo->peer_intent & 0x01) ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ else ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ } ++ } else { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); ++ break; ++ } ++ } ++ ++ /* Try to get the group id information */ ++ attr_contentlen = 0; ++ memset(groupid, 0x00, 38); ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { ++ DBG_88E("[%s] Ssid = %s, ssidlen = %zu\n", __func__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN])); ++ memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); ++ memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); ++ } ++ ++ attr_contentlen = 0; ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) { ++ DBG_88E("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]); ++ pwdinfo->peer_operating_ch = operatingch_info[4]; ++ } ++ ++ /* Get the next P2P IE */ ++ p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++ return result; ++} ++ ++u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) ++{ ++ u8 *frame_body; ++ u8 dialogToken = 0; ++ u8 status = P2P_STATUS_SUCCESS; ++ ++ frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); ++ ++ dialogToken = frame_body[6]; ++ ++ /* todo: check NoA attribute */ ++ ++ issue_p2p_presence_resp(pwdinfo, GetAddr2Ptr(pframe), status, dialogToken); ++ ++ return true; ++} ++ ++static void find_phase_handler(struct adapter *padapter) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ndis_802_11_ssid ssid; ++ ++ memset((unsigned char *)&ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ memcpy(ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN); ++ ssid.SsidLength = P2P_WILDCARD_SSID_LEN; ++ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ spin_unlock_bh(&pmlmepriv->lock); ++ ++} ++ ++void p2p_concurrent_handler(struct adapter *padapter); ++ ++static void restore_p2p_state_handler(struct adapter *padapter) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { ++ /* In the P2P client mode, the driver should not switch back to its listen channel */ ++ /* because this P2P client should stay at the operating channel of P2P GO. */ ++ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } ++ ++} ++ ++static void pre_tx_invitereq_handler(struct adapter *padapter) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 val8 = 1; ++ ++ set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); ++ ++} ++ ++static void pre_tx_provdisc_handler(struct adapter *padapter) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 val8 = 1; ++ ++ set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); ++ ++} ++ ++static void pre_tx_negoreq_handler(struct adapter *padapter) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 val8 = 1; ++ ++ set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); ++ issue_probereq_p2p(padapter, NULL); ++ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); ++ ++} ++ ++void p2p_protocol_wk_hdl(struct adapter *padapter, int intCmdType) ++{ ++ ++ switch (intCmdType) { ++ case P2P_FIND_PHASE_WK: ++ find_phase_handler(padapter); ++ break; ++ case P2P_RESTORE_STATE_WK: ++ restore_p2p_state_handler(padapter); ++ break; ++ case P2P_PRE_TX_PROVDISC_PROCESS_WK: ++ pre_tx_provdisc_handler(padapter); ++ break; ++ case P2P_PRE_TX_INVITEREQ_PROCESS_WK: ++ pre_tx_invitereq_handler(padapter); ++ break; ++ case P2P_PRE_TX_NEGOREQ_PROCESS_WK: ++ pre_tx_negoreq_handler(padapter); ++ break; ++ } ++ ++} ++ ++void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength) ++{ ++ u8 *ies; ++ u32 ies_len; ++ u8 *p2p_ie; ++ u32 p2p_ielen = 0; ++ u8 noa_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */ ++ u32 attr_contentlen = 0; ++ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 find_p2p = false, find_p2p_ps = false; ++ u8 noa_offset, noa_num, noa_index; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ if (IELength <= _BEACON_IE_OFFSET_) ++ return; ++ ++ ies = IEs + _BEACON_IE_OFFSET_; ++ ies_len = IELength - _BEACON_IE_OFFSET_; ++ ++ p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); ++ ++ while (p2p_ie) { ++ find_p2p = true; ++ /* Get Notice of Absence IE. */ ++ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen)) { ++ find_p2p_ps = true; ++ noa_index = noa_attr[0]; ++ ++ if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) || ++ (noa_index != pwdinfo->noa_index)) { /* if index change, driver should reconfigure related setting. */ ++ pwdinfo->noa_index = noa_index; ++ pwdinfo->opp_ps = noa_attr[1] >> 7; ++ pwdinfo->ctwindow = noa_attr[1] & 0x7F; ++ ++ noa_offset = 2; ++ noa_num = 0; ++ /* NoA length should be n*(13) + 2 */ ++ if (attr_contentlen > 2) { ++ while (noa_offset < attr_contentlen) { ++ /* memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */ ++ pwdinfo->noa_count[noa_num] = noa_attr[noa_offset]; ++ noa_offset += 1; ++ ++ memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4); ++ noa_offset += 4; ++ ++ memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4); ++ noa_offset += 4; ++ ++ memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4); ++ noa_offset += 4; ++ ++ noa_num++; ++ } ++ } ++ pwdinfo->noa_num = noa_num; ++ ++ if (pwdinfo->opp_ps == 1) { ++ pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW; ++ /* driver should wait LPS for entering CTWindow */ ++ if (padapter->pwrctrlpriv.bFwCurrentInPSMode) ++ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1); ++ } else if (pwdinfo->noa_num > 0) { ++ pwdinfo->p2p_ps_mode = P2P_PS_NOA; ++ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1); ++ } else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { ++ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); ++ } ++ } ++ ++ break; /* find target, just break. */ ++ } ++ ++ /* Get the next P2P IE */ ++ p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); ++ } ++ ++ if (find_p2p) { ++ if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && !find_p2p_ps) ++ p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); ++ } ++ ++} ++ ++void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ /* Pre action for p2p state */ ++ switch (p2p_ps_state) { ++ case P2P_PS_DISABLE: ++ pwdinfo->p2p_ps_state = p2p_ps_state; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); ++ ++ pwdinfo->noa_index = 0; ++ pwdinfo->ctwindow = 0; ++ pwdinfo->opp_ps = 0; ++ pwdinfo->noa_num = 0; ++ pwdinfo->p2p_ps_mode = P2P_PS_NONE; ++ if (padapter->pwrctrlpriv.bFwCurrentInPSMode) { ++ if (pwrpriv->smart_ps == 0) { ++ pwrpriv->smart_ps = 2; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&padapter->pwrctrlpriv.pwr_mode)); ++ } ++ } ++ break; ++ case P2P_PS_ENABLE: ++ if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { ++ pwdinfo->p2p_ps_state = p2p_ps_state; ++ ++ if (pwdinfo->ctwindow > 0) { ++ if (pwrpriv->smart_ps != 0) { ++ pwrpriv->smart_ps = 0; ++ DBG_88E("%s(): Enter CTW, change SmartPS\n", __func__); ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&padapter->pwrctrlpriv.pwr_mode)); ++ } ++ } ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); ++ } ++ break; ++ case P2P_PS_SCAN: ++ case P2P_PS_SCAN_DONE: ++ case P2P_PS_ALLSTASLEEP: ++ if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { ++ pwdinfo->p2p_ps_state = p2p_ps_state; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); ++ } ++ break; ++ default: ++ break; ++ } ++ ++} ++ ++u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue) ++{ ++ struct cmd_obj *ph2c; ++ struct drvextra_cmd_parm *pdrvextra_cmd_parm; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct cmd_priv *pcmdpriv = &padapter->cmdpriv; ++ u8 res = _SUCCESS; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return res; ++ ++ if (enqueue) { ++ ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); ++ if (!ph2c) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); ++ if (!pdrvextra_cmd_parm) { ++ kfree(ph2c); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID; ++ pdrvextra_cmd_parm->type_size = p2p_ps_state; ++ pdrvextra_cmd_parm->pbuf = NULL; ++ ++ init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); ++ ++ res = rtw_enqueue_cmd(pcmdpriv, ph2c); ++ } else { ++ p2p_ps_wk_hdl(padapter, p2p_ps_state); ++ } ++ ++exit: ++ ++ return res; ++} ++ ++static void reset_ch_sitesurvey_timer_process(struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, pwrctrlpriv.pwr_state_check_timer); ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ DBG_88E("[%s] In\n", __func__); ++ /* Reset the operation channel information */ ++ pwdinfo->rx_invitereq_info.operation_ch[0] = 0; ++ pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; ++} ++ ++static void reset_ch_sitesurvey_timer_process2(struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, pwrctrlpriv.pwr_state_check_timer); ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ DBG_88E("[%s] In\n", __func__); ++ /* Reset the operation channel information */ ++ pwdinfo->p2p_info.operation_ch[0] = 0; ++ pwdinfo->p2p_info.scan_op_ch_only = 0; ++} ++ ++static void restore_p2p_state_timer_process(struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, wdinfo.restore_p2p_state_timer); ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ p2p_protocol_wk_cmd(adapter, P2P_RESTORE_STATE_WK); ++} ++ ++static void pre_tx_scan_timer_process(struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, wdinfo.pre_tx_scan_timer); ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { ++ if (pwdinfo->tx_prov_disc_info.benable) { /* the provision discovery request frame is trigger to send or not */ ++ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK); ++ /* issue_probereq_p2p(adapter, NULL); */ ++ /* _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); */ ++ } ++ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { ++ if (pwdinfo->nego_req_info.benable) ++ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK); ++ } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) { ++ if (pwdinfo->invitereq_info.benable) ++ p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK); ++ } else { ++ DBG_88E("[%s] p2p_state is %d, ignore!!\n", __func__, rtw_p2p_state(pwdinfo)); ++ } ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++static void find_phase_timer_process(struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, wdinfo.find_phase_timer); ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++ ++ adapter->wdinfo.find_phase_state_exchange_cnt++; ++ ++ p2p_protocol_wk_cmd(adapter, P2P_FIND_PHASE_WK); ++} ++ ++void reset_global_wifidirect_info(struct adapter *padapter) ++{ ++ struct wifidirect_info *pwdinfo; ++ ++ pwdinfo = &padapter->wdinfo; ++ pwdinfo->persistent_supported = 0; ++ pwdinfo->session_available = true; ++ pwdinfo->wfd_tdls_enable = 0; ++ pwdinfo->wfd_tdls_weaksec = 0; ++} ++ ++void rtw_init_wifidirect_timers(struct adapter *padapter) ++{ ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ timer_setup(&pwdinfo->find_phase_timer, find_phase_timer_process, 0); ++ timer_setup(&pwdinfo->restore_p2p_state_timer, restore_p2p_state_timer_process, 0); ++ timer_setup(&pwdinfo->pre_tx_scan_timer, pre_tx_scan_timer_process, 0); ++ timer_setup(&pwdinfo->reset_ch_sitesurvey, reset_ch_sitesurvey_timer_process, 0); ++ timer_setup(&pwdinfo->reset_ch_sitesurvey2, reset_ch_sitesurvey_timer_process2, 0); ++} ++ ++void rtw_init_wifidirect_addrs(struct adapter *padapter, u8 *dev_addr, u8 *iface_addr) ++{ ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ /*init device&interface address */ ++ if (dev_addr) ++ memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN); ++ if (iface_addr) ++ memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN); ++#endif ++} ++ ++void init_wifidirect_info(struct adapter *padapter, enum P2P_ROLE role) ++{ ++ struct wifidirect_info *pwdinfo; ++ ++ pwdinfo = &padapter->wdinfo; ++ pwdinfo->padapter = padapter; ++ ++ /* 1, 6, 11 are the social channel defined in the WiFi Direct specification. */ ++ pwdinfo->social_chan[0] = 1; ++ pwdinfo->social_chan[1] = 6; ++ pwdinfo->social_chan[2] = 11; ++ pwdinfo->social_chan[3] = 0; /* channel 0 for scanning ending in site survey function. */ ++ ++ /* Use the channel 11 as the listen channel */ ++ pwdinfo->listen_channel = 11; ++ ++ if (role == P2P_ROLE_DEVICE) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); ++ pwdinfo->intent = 1; ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN); ++ } else if (role == P2P_ROLE_CLIENT) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ pwdinfo->intent = 1; ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ } else if (role == P2P_ROLE_GO) { ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ pwdinfo->intent = 15; ++ rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); ++ } ++ ++/* Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */ ++ pwdinfo->support_rate[0] = 0x8c; /* 6(B) */ ++ pwdinfo->support_rate[1] = 0x92; /* 9(B) */ ++ pwdinfo->support_rate[2] = 0x18; /* 12 */ ++ pwdinfo->support_rate[3] = 0x24; /* 18 */ ++ pwdinfo->support_rate[4] = 0x30; /* 24 */ ++ pwdinfo->support_rate[5] = 0x48; /* 36 */ ++ pwdinfo->support_rate[6] = 0x60; /* 48 */ ++ pwdinfo->support_rate[7] = 0x6c; /* 54 */ ++ ++ memcpy(pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7); ++ ++ memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN); ++ pwdinfo->device_name_len = 0; ++ ++ memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info)); ++ pwdinfo->invitereq_info.token = 3; /* Token used for P2P invitation request frame. */ ++ ++ memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info)); ++ pwdinfo->inviteresp_info.token = 0; ++ ++ pwdinfo->profileindex = 0; ++ memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM); ++ ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); ++ ++ pwdinfo->listen_dwell = (u8)((jiffies % 3) + 1); ++ ++ memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info)); ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE; ++ ++ memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info)); ++ ++ pwdinfo->device_password_id_for_nego = WPS_DPID_PBC; ++ pwdinfo->negotiation_dialog_token = 1; ++ ++ memset(pwdinfo->nego_ssid, 0x00, WLAN_SSID_MAXLEN); ++ pwdinfo->nego_ssidlen = 0; ++ ++ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; ++ pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD; ++ pwdinfo->channel_list_attr_len = 0; ++ memset(pwdinfo->channel_list_attr, 0x00, 100); ++ ++ memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4); ++ memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3); ++ memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); ++ pwdinfo->wfd_tdls_enable = 0; ++ memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); ++ memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN); ++ ++ pwdinfo->rx_invitereq_info.operation_ch[0] = 0; ++ pwdinfo->rx_invitereq_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ ++ pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; ++ pwdinfo->p2p_info.operation_ch[0] = 0; ++ pwdinfo->p2p_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ ++ pwdinfo->p2p_info.scan_op_ch_only = 0; ++} ++ ++int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role) ++{ ++ int ret = _SUCCESS; ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || role == P2P_ROLE_GO) { ++ /* leave IPS/Autosuspend */ ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* Added by Albert 2011/03/22 */ ++ /* In the P2P mode, the driver should not support the b mode. */ ++ /* So, the Tx packet shouldn't use the CCK rate */ ++ update_tx_basic_rate(padapter, (WIRELESS_11G | WIRELESS_11_24N)); ++ ++ /* Enable P2P function */ ++ init_wifidirect_info(padapter, role); ++ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, true); ++ } else if (role == P2P_ROLE_DISABLE) { ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* Disable P2P function */ ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { ++ _cancel_timer_ex(&pwdinfo->find_phase_timer); ++ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); ++ _cancel_timer_ex(&pwdinfo->pre_tx_scan_timer); ++ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); ++ _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey2); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); ++ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE); ++ memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info)); ++ } ++ ++ rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, false); ++ ++ /* Restore to initial setting. */ ++ update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); ++ } ++ ++exit: ++ return ret; ++} ++ ++#else ++u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue) ++{ ++ return _FAIL; ++} ++ ++void process_p2p_ps_ie(struct adapter *padapter, u8 *IEs, u32 IELength) ++{ ++} ++ ++#endif /* CONFIG_88EU_P2P */ +diff --git a/drivers/staging/r8188eu/core/rtw_pwrctrl.c b/drivers/staging/r8188eu/core/rtw_pwrctrl.c +new file mode 100644 +index 000000000000..c3897b29121c +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_pwrctrl.c +@@ -0,0 +1,605 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_PWRCTRL_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/osdep_intf.h" ++#include "../include/linux/usb.h" ++ ++void ips_enter(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ struct xmit_priv *pxmit_priv = &padapter->xmitpriv; ++ ++ if (padapter->registrypriv.mp_mode == 1) ++ return; ++ ++ if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || ++ pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { ++ DBG_88E_LEVEL(_drv_info_, "There are some pkts to transmit\n"); ++ DBG_88E_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", ++ pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt); ++ return; ++ } ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ ++ pwrpriv->bips_processing = true; ++ ++ /* syn ips_mode with request */ ++ pwrpriv->ips_mode = pwrpriv->ips_mode_req; ++ ++ pwrpriv->ips_enter_cnts++; ++ DBG_88E("==>ips_enter cnts:%d\n", pwrpriv->ips_enter_cnts); ++ if (rf_off == pwrpriv->change_rfpwrstate) { ++ pwrpriv->bpower_saving = true; ++ DBG_88E_LEVEL(_drv_info_, "nolinked power save enter\n"); ++ ++ if (pwrpriv->ips_mode == IPS_LEVEL_2) ++ pwrpriv->bkeepfwalive = true; ++ ++ rtw_ips_pwr_down(padapter); ++ pwrpriv->rf_pwrstate = rf_off; ++ } ++ pwrpriv->bips_processing = false; ++ ++ _exit_pwrlock(&pwrpriv->lock); ++} ++ ++int ips_leave(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ int result = _SUCCESS; ++ int keyid; ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ ++ if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) { ++ pwrpriv->bips_processing = true; ++ pwrpriv->change_rfpwrstate = rf_on; ++ pwrpriv->ips_leave_cnts++; ++ DBG_88E("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts); ++ ++ result = rtw_ips_pwr_up(padapter); ++ if (result == _SUCCESS) { ++ pwrpriv->rf_pwrstate = rf_on; ++ } ++ DBG_88E_LEVEL(_drv_info_, "nolinked power save leave\n"); ++ ++ if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) || (_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm)) { ++ DBG_88E("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing); ++ set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ for (keyid = 0; keyid < 4; keyid++) { ++ if (pmlmepriv->key_mask & BIT(keyid)) { ++ if (keyid == psecuritypriv->dot11PrivacyKeyIndex) ++ result = rtw_set_key(padapter, psecuritypriv, keyid, 1); ++ else ++ result = rtw_set_key(padapter, psecuritypriv, keyid, 0); ++ } ++ } ++ } ++ ++ DBG_88E("==> ips_leave.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c)); ++ pwrpriv->bips_processing = false; ++ ++ pwrpriv->bkeepfwalive = false; ++ pwrpriv->bpower_saving = false; ++ } ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ return result; ++} ++ ++static bool rtw_pwr_unassociated_idle(struct adapter *adapter) ++{ ++ struct adapter *buddy = adapter->pbuddy_adapter; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &adapter->wdinfo; ++#endif ++ ++ bool ret = false; ++ ++ if (adapter->pwrctrlpriv.ips_deny_time >= jiffies) ++ goto exit; ++ ++ if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE | WIFI_SITE_MONITOR) || ++ check_fwstate(pmlmepriv, WIFI_UNDER_LINKING | WIFI_UNDER_WPS) || ++ check_fwstate(pmlmepriv, WIFI_UNDER_WPS) || ++ check_fwstate(pmlmepriv, WIFI_AP_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE) || ++#if defined(CONFIG_88EU_P2P) ++ !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++#else ++ 0) ++#endif ++ goto exit; ++ ++ /* consider buddy, if exist */ ++ if (buddy) { ++ struct mlme_priv *b_pmlmepriv = &buddy->mlmepriv; ++ #ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *b_pwdinfo = &buddy->wdinfo; ++ #endif ++ ++ if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE | WIFI_SITE_MONITOR) || ++ check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING | WIFI_UNDER_WPS) || ++ check_fwstate(b_pmlmepriv, WIFI_AP_STATE) || ++ check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE) || ++#if defined(CONFIG_88EU_P2P) ++ !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE)) ++#else ++ 0) ++#endif ++ goto exit; ++ } ++ ret = true; ++ ++exit: ++ return ret; ++} ++ ++void rtw_ps_processor(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ enum rt_rf_power_state rfpwrstate; ++ ++ pwrpriv->ps_processing = true; ++ ++ if (pwrpriv->bips_processing) ++ goto exit; ++ ++ if (padapter->pwrctrlpriv.bHWPwrPindetect) { ++ rfpwrstate = RfOnOffDetect(padapter); ++ DBG_88E("@@@@- #2 %s==> rfstate:%s\n", __func__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off"); ++ ++ if (rfpwrstate != pwrpriv->rf_pwrstate) { ++ if (rfpwrstate == rf_off) { ++ pwrpriv->change_rfpwrstate = rf_off; ++ pwrpriv->brfoffbyhw = true; ++ padapter->bCardDisableWOHSM = true; ++ rtw_hw_suspend(padapter); ++ } else { ++ pwrpriv->change_rfpwrstate = rf_on; ++ rtw_hw_resume(padapter); ++ } ++ DBG_88E("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off) ? "rf_off" : "rf_on"); ++ } ++ pwrpriv->pwr_state_check_cnts++; ++ } ++ ++ if (pwrpriv->ips_mode_req == IPS_NONE) ++ goto exit; ++ ++ if (!rtw_pwr_unassociated_idle(padapter)) ++ goto exit; ++ ++ if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts % 4) == 0)) { ++ DBG_88E("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv)); ++ pwrpriv->change_rfpwrstate = rf_off; ++ ++ ips_enter(padapter); ++ } ++exit: ++ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); ++ pwrpriv->ps_processing = false; ++} ++ ++static void pwr_state_check_handler(struct timer_list *t) ++{ ++ struct adapter *padapter = ++ from_timer(padapter, t, ++ pwrctrlpriv.pwr_state_check_timer); ++ rtw_ps_cmd(padapter); ++} ++ ++/* ++ * ++ * Parameters ++ * padapter ++ * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 ++ * ++ */ ++void rtw_set_rpwm(struct adapter *padapter, u8 pslv) ++{ ++ u8 rpwm; ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ ++ pslv = PS_STATE(pslv); ++ ++ if (pwrpriv->btcoex_rfon) { ++ if (pslv < PS_STATE_S4) ++ pslv = PS_STATE_S3; ++ } ++ ++ if (pwrpriv->rpwm == pslv) ++ return; ++ ++ if ((padapter->bSurpriseRemoved) || ++ (!padapter->hw_init_completed)) { ++ pwrpriv->cpwm = PS_STATE_S4; ++ ++ return; ++ } ++ ++ if (padapter->bDriverStopped) { ++ if (pslv < PS_STATE_S2) ++ return; ++ } ++ ++ rpwm = pslv | pwrpriv->tog; ++ ++ pwrpriv->rpwm = pslv; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); ++ ++ pwrpriv->tog += 0x80; ++ pwrpriv->cpwm = pslv; ++ ++} ++ ++static u8 PS_RDY_CHECK(struct adapter *padapter) ++{ ++ u32 curr_time, delta_time; ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ curr_time = jiffies; ++ delta_time = curr_time - pwrpriv->DelayLPSLastTimeStamp; ++ ++ if (delta_time < LPS_DELAY_TIME) ++ return false; ++ ++ if (!check_fwstate(pmlmepriv, _FW_LINKED) || ++ check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) || ++ check_fwstate(pmlmepriv, WIFI_AP_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) ++ return false; ++ if (pwrpriv->bInSuspend) ++ return false; ++ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && !padapter->securitypriv.binstallGrpkey) { ++ DBG_88E("Group handshake still in progress !!!\n"); ++ return false; ++ } ++ return true; ++} ++ ++void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ if (ps_mode > PM_Card_Disable) ++ return; ++ ++ if (pwrpriv->pwr_mode == ps_mode) { ++ if (PS_MODE_ACTIVE == ps_mode) ++ return; ++ ++ if ((pwrpriv->smart_ps == smart_ps) && ++ (pwrpriv->bcn_ant_mode == bcn_ant_mode)) ++ return; ++ } ++ ++ /* if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) */ ++ if (ps_mode == PS_MODE_ACTIVE) { ++#ifdef CONFIG_88EU_P2P ++ if (pwdinfo->opp_ps == 0) { ++ DBG_88E("rtw_set_ps_mode: Leave 802.11 power save\n"); ++ pwrpriv->pwr_mode = ps_mode; ++ rtw_set_rpwm(padapter, PS_STATE_S4); ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); ++ pwrpriv->bFwCurrentInPSMode = false; ++ } ++ } else { ++#endif /* CONFIG_88EU_P2P */ ++ if (PS_RDY_CHECK(padapter)) { ++ DBG_88E("%s: Enter 802.11 power save\n", __func__); ++ pwrpriv->bFwCurrentInPSMode = true; ++ pwrpriv->pwr_mode = ps_mode; ++ pwrpriv->smart_ps = smart_ps; ++ pwrpriv->bcn_ant_mode = bcn_ant_mode; ++ rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); ++ ++#ifdef CONFIG_88EU_P2P ++ /* Set CTWindow after LPS */ ++ if (pwdinfo->opp_ps == 1) ++ p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 0); ++#endif /* CONFIG_88EU_P2P */ ++ ++ rtw_set_rpwm(padapter, PS_STATE_S2); ++ } ++ } ++ ++} ++ ++/* ++ * Return: ++ * 0: Leave OK ++ * -1: Timeout ++ * -2: Other error ++ */ ++s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms) ++{ ++ u32 start_time; ++ u8 bAwake = false; ++ s32 err = 0; ++ ++ start_time = jiffies; ++ while (1) { ++ rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); ++ if (bAwake) ++ break; ++ ++ if (padapter->bSurpriseRemoved) { ++ err = -2; ++ DBG_88E("%s: device surprise removed!!\n", __func__); ++ break; ++ } ++ ++ if (rtw_get_passing_time_ms(start_time) > delay_ms) { ++ err = -1; ++ DBG_88E("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms); ++ break; ++ } ++ rtw_usleep_os(100); ++ } ++ ++ return err; ++} ++ ++/* */ ++/* Description: */ ++/* Enter the leisure power save mode. */ ++/* */ ++void LPS_Enter(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ ++ if (!PS_RDY_CHECK(padapter)) ++ return; ++ ++ if (pwrpriv->bLeisurePs) { ++ /* Idle for a while if we connect to AP a while ago. */ ++ if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */ ++ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { ++ pwrpriv->bpower_saving = true; ++ DBG_88E("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps); ++ /* For Tenda W311R IOT issue */ ++ rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, ++ pwrpriv->smart_ps, 0x40); ++ } ++ } else { ++ pwrpriv->LpsIdleCount++; ++ } ++ } ++ ++} ++ ++#define LPS_LEAVE_TIMEOUT_MS 100 ++ ++/* Description: */ ++/* Leave the leisure power save mode. */ ++void LPS_Leave(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ ++ if (pwrpriv->bLeisurePs) { ++ if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { ++ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0x40); ++ ++ if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) ++ LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS); ++ } ++ } ++ ++ pwrpriv->bpower_saving = false; ++ ++} ++ ++/* */ ++/* Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */ ++/* Move code to function by tynli. 2010.03.26. */ ++/* */ ++void LeaveAllPowerSaveMode(struct adapter *Adapter) ++{ ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ u8 enqueue = 0; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { /* connect */ ++ p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, enqueue); ++ ++ rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue); ++ } ++ ++} ++ ++void rtw_init_pwrctrl_priv(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; ++ ++ _init_pwrlock(&pwrctrlpriv->lock); ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ pwrctrlpriv->ips_enter_cnts = 0; ++ pwrctrlpriv->ips_leave_cnts = 0; ++ pwrctrlpriv->bips_processing = false; ++ ++ pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; ++ pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; ++ ++ pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; ++ pwrctrlpriv->pwr_state_check_cnts = 0; ++ pwrctrlpriv->bInternalAutoSuspend = false; ++ pwrctrlpriv->bInSuspend = false; ++ pwrctrlpriv->bkeepfwalive = false; ++ ++ pwrctrlpriv->LpsIdleCount = 0; ++ if (padapter->registrypriv.mp_mode == 1) ++ pwrctrlpriv->power_mgnt = PS_MODE_ACTIVE; ++ else ++ pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */ ++ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false; ++ ++ pwrctrlpriv->bFwCurrentInPSMode = false; ++ ++ pwrctrlpriv->rpwm = 0; ++ pwrctrlpriv->cpwm = PS_STATE_S4; ++ ++ pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; ++ pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; ++ pwrctrlpriv->bcn_ant_mode = 0; ++ ++ pwrctrlpriv->tog = 0x80; ++ ++ pwrctrlpriv->btcoex_rfon = false; ++ ++ timer_setup(&pwrctrlpriv->pwr_state_check_timer, pwr_state_check_handler, 0); ++} ++ ++void rtw_free_pwrctrl_priv(struct adapter *adapter) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = &adapter->pwrctrlpriv; ++ ++ _free_pwrlock(&pwrctrlpriv->lock); ++ ++} ++ ++u8 rtw_interface_ps_func(struct adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val) ++{ ++ u8 bResult = true; ++ rtw_hal_intf_ps_func(padapter, efunc_id, val); ++ ++ return bResult; ++} ++ ++inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ms); ++} ++ ++/* ++* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend ++* @adapter: pointer to struct adapter structure ++* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup ++* Return _SUCCESS or _FAIL ++*/ ++ ++int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *caller) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ int ret = _SUCCESS; ++ u32 start = jiffies; ++ ++ if (pwrpriv->ips_deny_time < jiffies + rtw_ms_to_systime(ips_deffer_ms)) ++ pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ips_deffer_ms); ++ ++ if (pwrpriv->ps_processing) { ++ DBG_88E("%s wait ps_processing...\n", __func__); ++ while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000) ++ msleep(10); ++ if (pwrpriv->ps_processing) ++ DBG_88E("%s wait ps_processing timeout\n", __func__); ++ else ++ DBG_88E("%s wait ps_processing done\n", __func__); ++ } ++ ++ /* System suspend is not allowed to wakeup */ ++ if ((!pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) { ++ while (pwrpriv->bInSuspend && ++ (rtw_get_passing_time_ms(start) <= 3000 || ++ (rtw_get_passing_time_ms(start) <= 500))) ++ msleep(10); ++ if (pwrpriv->bInSuspend) ++ DBG_88E("%s wait bInSuspend timeout\n", __func__); ++ else ++ DBG_88E("%s wait bInSuspend done\n", __func__); ++ } ++ ++ /* block??? */ ++ if ((pwrpriv->bInternalAutoSuspend) && (padapter->net_closed)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* I think this should be check in IPS, LPS, autosuspend functions... */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ ret = _SUCCESS; ++ goto exit; ++ } ++ if (rf_off == pwrpriv->rf_pwrstate) { ++ DBG_88E("%s call ips_leave....\n", __func__); ++ if (_FAIL == ips_leave(padapter)) { ++ DBG_88E("======> ips_leave fail.............\n"); ++ ret = _FAIL; ++ goto exit; ++ } ++ } ++ ++ /* TODO: the following checking need to be merged... */ ++ if (padapter->bDriverStopped || !padapter->bup || ++ !padapter->hw_init_completed) { ++ DBG_88E("%s: bDriverStopped=%d, bup=%d, hw_init_completed =%u\n" ++ , caller ++ , padapter->bDriverStopped ++ , padapter->bup ++ , padapter->hw_init_completed); ++ ret = false; ++ goto exit; ++ } ++ ++exit: ++ if (pwrpriv->ips_deny_time < jiffies + rtw_ms_to_systime(ips_deffer_ms)) ++ pwrpriv->ips_deny_time = jiffies + rtw_ms_to_systime(ips_deffer_ms); ++ return ret; ++} ++ ++int rtw_pm_set_lps(struct adapter *padapter, u8 mode) ++{ ++ int ret = 0; ++ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; ++ ++ if (mode < PS_MODE_NUM) { ++ if (pwrctrlpriv->power_mgnt != mode) { ++ if (PS_MODE_ACTIVE == mode) ++ LeaveAllPowerSaveMode(padapter); ++ else ++ pwrctrlpriv->LpsIdleCount = 2; ++ pwrctrlpriv->power_mgnt = mode; ++ pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? true : false; ++ } ++ } else { ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++int rtw_pm_set_ips(struct adapter *padapter, u8 mode) ++{ ++ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; ++ ++ if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) { ++ rtw_ips_mode_req(pwrctrlpriv, mode); ++ DBG_88E("%s %s\n", __func__, mode == IPS_NORMAL ? "IPS_NORMAL" : "IPS_LEVEL_2"); ++ return 0; ++ } else if (mode == IPS_NONE) { ++ rtw_ips_mode_req(pwrctrlpriv, mode); ++ DBG_88E("%s %s\n", __func__, "IPS_NONE"); ++ if ((padapter->bSurpriseRemoved == 0) && (_FAIL == rtw_pwr_wakeup(padapter))) ++ return -EFAULT; ++ } else { ++ return -EINVAL; ++ } ++ return 0; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c +new file mode 100644 +index 000000000000..e082edfbaad8 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_recv.c +@@ -0,0 +1,2058 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_RECV_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/mlme_osdep.h" ++#include "../include/usb_ops.h" ++#include "../include/wifi.h" ++ ++static u8 SNAP_ETH_TYPE_IPX[2] = {0x81, 0x37}; ++static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3}; ++ ++/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ ++static u8 rtw_bridge_tunnel_header[] = { ++ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 ++}; ++ ++static u8 rtw_rfc1042_header[] = { ++ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 ++}; ++ ++void rtw_signal_stat_timer_hdl(struct timer_list *); ++ ++void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) ++{ ++ ++ memset((u8 *)psta_recvpriv, 0, sizeof(struct sta_recv_priv)); ++ ++ spin_lock_init(&psta_recvpriv->lock); ++ ++ _rtw_init_queue(&psta_recvpriv->defrag_q); ++ ++} ++ ++int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) ++{ ++ int i; ++ ++ struct recv_frame *precvframe; ++ ++ int res = _SUCCESS; ++ ++ spin_lock_init(&precvpriv->lock); ++ ++ _rtw_init_queue(&precvpriv->free_recv_queue); ++ _rtw_init_queue(&precvpriv->recv_pending_queue); ++ _rtw_init_queue(&precvpriv->uc_swdec_pending_queue); ++ ++ precvpriv->adapter = padapter; ++ ++ precvpriv->free_recvframe_cnt = NR_RECVFRAME; ++ ++ rtw_os_recv_resource_init(precvpriv, padapter); ++ ++ precvpriv->pallocated_frame_buf = vzalloc(NR_RECVFRAME * sizeof(struct recv_frame) + RXFRAME_ALIGN_SZ); ++ ++ if (!precvpriv->pallocated_frame_buf) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); ++ ++ precvframe = (struct recv_frame *)precvpriv->precv_frame_buf; ++ ++ for (i = 0; i < NR_RECVFRAME; i++) { ++ INIT_LIST_HEAD(&precvframe->list); ++ ++ list_add_tail(&precvframe->list, &precvpriv->free_recv_queue.queue); ++ ++ res = rtw_os_recv_resource_alloc(padapter, precvframe); ++ ++ precvframe->len = 0; ++ ++ precvframe->adapter = padapter; ++ precvframe++; ++ } ++ precvpriv->rx_pending_cnt = 1; ++ ++ sema_init(&precvpriv->allrxreturnevt, 0); ++ ++ res = rtw_hal_init_recv_priv(padapter); ++ ++ timer_setup(&precvpriv->signal_stat_timer, rtw_signal_stat_timer_hdl, 0); ++ precvpriv->signal_stat_sampling_interval = 1000; /* ms */ ++ ++ rtw_set_signal_stat_timer(precvpriv); ++exit: ++ ++ return res; ++} ++ ++void _rtw_free_recv_priv(struct recv_priv *precvpriv) ++{ ++ struct adapter *padapter = precvpriv->adapter; ++ ++ rtw_free_uc_swdec_pending_queue(padapter); ++ ++ rtw_os_recv_resource_free(precvpriv); ++ ++ vfree(precvpriv->pallocated_frame_buf); ++ ++ rtw_hal_free_recv_priv(padapter); ++} ++ ++struct recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue) ++{ ++ struct recv_frame *hdr; ++ struct list_head *plist, *phead; ++ struct adapter *padapter; ++ struct recv_priv *precvpriv; ++ ++ if (list_empty(&pfree_recv_queue->queue)) { ++ hdr = NULL; ++ } else { ++ phead = get_list_head(pfree_recv_queue); ++ ++ plist = phead->next; ++ ++ hdr = container_of(plist, struct recv_frame, list); ++ ++ list_del_init(&hdr->list); ++ padapter = hdr->adapter; ++ if (padapter) { ++ precvpriv = &padapter->recvpriv; ++ if (pfree_recv_queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt--; ++ } ++ } ++ ++ return (struct recv_frame *)hdr; ++} ++ ++struct recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue) ++{ ++ struct recv_frame *precvframe; ++ ++ spin_lock_bh(&pfree_recv_queue->lock); ++ ++ precvframe = _rtw_alloc_recvframe(pfree_recv_queue); ++ ++ spin_unlock_bh(&pfree_recv_queue->lock); ++ ++ return precvframe; ++} ++ ++void rtw_init_recvframe(struct recv_frame *precvframe, struct recv_priv *precvpriv) ++{ ++ /* Perry: This can be removed */ ++ INIT_LIST_HEAD(&precvframe->list); ++ ++ precvframe->len = 0; ++} ++ ++int rtw_free_recvframe(struct recv_frame *precvframe, struct __queue *pfree_recv_queue) ++{ ++ struct adapter *padapter; ++ struct recv_priv *precvpriv; ++ ++ if (!precvframe) ++ return _FAIL; ++ padapter = precvframe->adapter; ++ precvpriv = &padapter->recvpriv; ++ if (precvframe->pkt) { ++ dev_kfree_skb_any(precvframe->pkt);/* free skb by driver */ ++ precvframe->pkt = NULL; ++ } ++ ++ spin_lock_bh(&pfree_recv_queue->lock); ++ ++ list_del_init(&precvframe->list); ++ ++ precvframe->len = 0; ++ ++ list_add_tail(&precvframe->list, get_list_head(pfree_recv_queue)); ++ ++ if (padapter) { ++ if (pfree_recv_queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt++; ++ } ++ ++ spin_unlock_bh(&pfree_recv_queue->lock); ++ ++ return _SUCCESS; ++} ++ ++int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) ++{ ++ struct adapter *padapter = precvframe->adapter; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ list_del_init(&precvframe->list); ++ list_add_tail(&precvframe->list, get_list_head(queue)); ++ ++ if (padapter) { ++ if (queue == &precvpriv->free_recv_queue) ++ precvpriv->free_recvframe_cnt++; ++ } ++ ++ return _SUCCESS; ++} ++ ++int rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) ++{ ++ int ret; ++ ++ spin_lock_bh(&queue->lock); ++ ret = _rtw_enqueue_recvframe(precvframe, queue); ++ spin_unlock_bh(&queue->lock); ++ ++ return ret; ++} ++ ++/* ++caller : defrag ; recvframe_chk_defrag in recv_thread (passive) ++pframequeue: defrag_queue : will be accessed in recv_thread (passive) ++ ++using spinlock to protect ++ ++*/ ++ ++void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue) ++{ ++ struct recv_frame *hdr; ++ struct list_head *plist, *phead; ++ ++ spin_lock(&pframequeue->lock); ++ ++ phead = get_list_head(pframequeue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ hdr = container_of(plist, struct recv_frame, list); ++ ++ plist = plist->next; ++ ++ rtw_free_recvframe((struct recv_frame *)hdr, pfree_recv_queue); ++ } ++ ++ spin_unlock(&pframequeue->lock); ++ ++} ++ ++u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter) ++{ ++ u32 cnt = 0; ++ struct recv_frame *pending_frame; ++ while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) { ++ rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue); ++ DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__); ++ cnt++; ++ } ++ ++ return cnt; ++} ++ ++int rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue) ++{ ++ spin_lock_bh(&queue->lock); ++ ++ list_del_init(&precvbuf->list); ++ list_add(&precvbuf->list, get_list_head(queue)); ++ ++ spin_unlock_bh(&queue->lock); ++ ++ return _SUCCESS; ++} ++ ++int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&queue->lock, flags); ++ ++ list_del_init(&precvbuf->list); ++ ++ list_add_tail(&precvbuf->list, get_list_head(queue)); ++ spin_unlock_irqrestore(&queue->lock, flags); ++ return _SUCCESS; ++} ++ ++struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue) ++{ ++ struct recv_buf *precvbuf; ++ struct list_head *plist, *phead; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&queue->lock, flags); ++ ++ if (list_empty(&queue->queue)) { ++ precvbuf = NULL; ++ } else { ++ phead = get_list_head(queue); ++ ++ plist = phead->next; ++ ++ precvbuf = container_of(plist, struct recv_buf, list); ++ ++ list_del_init(&precvbuf->list); ++ } ++ ++ spin_unlock_irqrestore(&queue->lock, flags); ++ ++ return precvbuf; ++} ++ ++static int recvframe_chkmic(struct adapter *adapter, struct recv_frame *precvframe) ++{ ++ int i, res = _SUCCESS; ++ u32 datalen; ++ u8 miccode[8]; ++ u8 bmic_err = false, brpt_micerror = true; ++ u8 *pframe, *payload, *pframemic; ++ u8 *mickey; ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib = &precvframe->attrib; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]); ++ ++ if (prxattrib->encrypt == _TKIP_) { ++ /* calculate mic code */ ++ if (stainfo) { ++ if (is_multicast_ether_addr(prxattrib->ra)) { ++ mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; ++ ++ if (!psecuritypriv) { ++ res = _FAIL; ++ DBG_88E("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"); ++ goto exit; ++ } ++ } else { ++ mickey = &stainfo->dot11tkiprxmickey.skey[0]; ++ } ++ ++ datalen = precvframe->len - prxattrib->hdrlen - prxattrib->iv_len - prxattrib->icv_len - 8;/* icv_len included the mic code */ ++ pframe = precvframe->rx_data; ++ payload = pframe + prxattrib->hdrlen + prxattrib->iv_len; ++ ++ rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0], ++ (unsigned char)prxattrib->priority); /* care the length of the data */ ++ ++ pframemic = payload + datalen; ++ ++ bmic_err = false; ++ ++ for (i = 0; i < 8; i++) { ++ if (miccode[i] != *(pframemic + i)) ++ bmic_err = true; ++ } ++ ++ if (bmic_err) { ++ /* double check key_index for some timing issue , */ ++ /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */ ++ if (is_multicast_ether_addr(prxattrib->ra) && prxattrib->key_index != pmlmeinfo->key_index) ++ brpt_micerror = false; ++ ++ if ((prxattrib->bdecrypted) && (brpt_micerror)) { ++ rtw_handle_tkip_mic_err(adapter, (u8)is_multicast_ether_addr(prxattrib->ra)); ++ DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); ++ } else { ++ DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); ++ } ++ res = _FAIL; ++ } else { ++ /* mic checked ok */ ++ if (!psecuritypriv->bcheck_grpkey && is_multicast_ether_addr(prxattrib->ra)) ++ psecuritypriv->bcheck_grpkey = true; ++ } ++ } ++ ++ recvframe_pull_tail(precvframe, 8); ++ } ++ ++exit: ++ ++ return res; ++} ++ ++/* decrypt and set the ivlen, icvlen of the recv_frame */ ++static struct recv_frame *decryptor(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ struct rx_pkt_attrib *prxattrib = &precv_frame->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct recv_frame *return_packet = precv_frame; ++ u32 res = _SUCCESS; ++ ++ if (prxattrib->encrypt > 0) { ++ u8 *iv = precv_frame->rx_data + prxattrib->hdrlen; ++ prxattrib->key_index = (((iv[3]) >> 6) & 0x3); ++ ++ if (prxattrib->key_index > WEP_KEYS) { ++ DBG_88E("prxattrib->key_index(%d)>WEP_KEYS\n", prxattrib->key_index); ++ ++ switch (prxattrib->encrypt) { ++ case _WEP40_: ++ case _WEP104_: ++ prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex; ++ break; ++ case _TKIP_: ++ case _AES_: ++ default: ++ prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid; ++ break; ++ } ++ } ++ } ++ ++ if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || (psecuritypriv->sw_decrypt))) { ++ psecuritypriv->hw_decrypted = false; ++ ++ switch (prxattrib->encrypt) { ++ case _WEP40_: ++ case _WEP104_: ++ rtw_wep_decrypt(padapter, (u8 *)precv_frame); ++ break; ++ case _TKIP_: ++ res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame); ++ break; ++ case _AES_: ++ res = rtw_aes_decrypt(padapter, (u8 *)precv_frame); ++ break; ++ default: ++ break; ++ } ++ } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 && ++ (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_)) ++ psecuritypriv->hw_decrypted = true; ++ ++ if (res == _FAIL) { ++ rtw_free_recvframe(return_packet, &padapter->recvpriv.free_recv_queue); ++ return_packet = NULL; ++ } else { ++ prxattrib->bdecrypted = true; ++ } ++ ++ return return_packet; ++} ++ ++/* set the security information in the recv_frame */ ++static struct recv_frame *portctrl(struct adapter *adapter, struct recv_frame *precv_frame) ++{ ++ u8 *psta_addr, *ptr; ++ uint auth_alg; ++ struct recv_frame *pfhdr; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv; ++ struct recv_frame *prtnframe; ++ u16 ether_type = 0; ++ u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */ ++ struct rx_pkt_attrib *pattrib; ++ __be16 be_tmp; ++ ++ pstapriv = &adapter->stapriv; ++ ++ auth_alg = adapter->securitypriv.dot11AuthAlgrthm; ++ ++ ptr = precv_frame->rx_data; ++ pfhdr = precv_frame; ++ pattrib = &pfhdr->attrib; ++ psta_addr = pattrib->ta; ++ ++ prtnframe = NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, psta_addr); ++ ++ if (auth_alg == 2) { ++ if (psta && psta->ieee8021x_blocked) { ++ /* blocked */ ++ /* only accept EAPOL frame */ ++ prtnframe = precv_frame; ++ ++ /* get ether_type */ ++ ptr = ptr + pfhdr->attrib.hdrlen + pfhdr->attrib.iv_len + LLC_HEADER_SIZE; ++ memcpy(&be_tmp, ptr, 2); ++ ether_type = ntohs(be_tmp); ++ ++ if (ether_type == eapol_type) { ++ prtnframe = precv_frame; ++ } else { ++ /* free this frame */ ++ rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue); ++ prtnframe = NULL; ++ } ++ } else { ++ /* allowed */ ++ /* check decryption status, and decrypt the frame if needed */ ++ prtnframe = precv_frame; ++ } ++ } else { ++ prtnframe = precv_frame; ++ } ++ ++ return prtnframe; ++} ++ ++static int recv_decache(struct recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache) ++{ ++ int tid = precv_frame->attrib.priority; ++ ++ u16 seq_ctrl = ((precv_frame->attrib.seq_num & 0xffff) << 4) | ++ (precv_frame->attrib.frag_num & 0xf); ++ ++ if (tid > 15) ++ return _FAIL; ++ ++ if (1) {/* if (bretry) */ ++ if (seq_ctrl == prxcache->tid_rxseq[tid]) ++ return _FAIL; ++ } ++ ++ prxcache->tid_rxseq[tid] = seq_ctrl; ++ ++ return _SUCCESS; ++} ++ ++void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame); ++void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++#ifdef CONFIG_88EU_AP_MODE ++ unsigned char pwrbit; ++ u8 *ptr = precv_frame->rx_data; ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta = NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ ++ pwrbit = GetPwrMgt(ptr); ++ ++ if (psta) { ++ if (pwrbit) { ++ if (!(psta->state & WIFI_SLEEP_STATE)) ++ stop_sta_xmit(padapter, psta); ++ } else { ++ if (psta->state & WIFI_SLEEP_STATE) ++ wakeup_sta_to_xmit(padapter, psta); ++ } ++ } ++ ++#endif ++} ++ ++static void process_wmmps_data(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++#ifdef CONFIG_88EU_AP_MODE ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *psta = NULL; ++ ++ psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ ++ if (!psta) ++ return; ++ ++ if (!psta->qos_option) ++ return; ++ ++ if (!(psta->qos_info & 0xf)) ++ return; ++ ++ if (psta->state & WIFI_SLEEP_STATE) { ++ u8 wmmps_ac = 0; ++ ++ switch (pattrib->priority) { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk & BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi & BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo & BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be & BIT(1); ++ break; ++ } ++ ++ if (wmmps_ac) { ++ if (psta->sleepq_ac_len > 0) { ++ /* process received triggered frame */ ++ xmit_delivery_enabled_frames(padapter, psta); ++ } else { ++ /* issue one qos null frame with More data bit = 0 and the EOSP bit set (= 1) */ ++ issue_qos_nulldata(padapter, psta->hwaddr, (u16)pattrib->priority, 0, 0); ++ } ++ } ++ } ++ ++#endif ++} ++ ++static void count_rx_stats(struct adapter *padapter, struct recv_frame *prframe, struct sta_info *sta) ++{ ++ int sz; ++ struct sta_info *psta = NULL; ++ struct stainfo_stats *pstats = NULL; ++ struct rx_pkt_attrib *pattrib = &prframe->attrib; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ sz = get_recvframe_len(prframe); ++ precvpriv->rx_bytes += sz; ++ ++ padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++; ++ ++ if (!is_broadcast_ether_addr(pattrib->dst) && !is_multicast_ether_addr(pattrib->dst)) ++ padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++; ++ ++ if (sta) ++ psta = sta; ++ else ++ psta = prframe->psta; ++ ++ if (psta) { ++ pstats = &psta->sta_stats; ++ ++ pstats->rx_data_pkts++; ++ pstats->rx_bytes += sz; ++ } ++} ++ ++int sta2sta_data_frame( ++ struct adapter *adapter, ++ struct recv_frame *precv_frame, ++ struct sta_info **psta ++); ++ ++int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame, struct sta_info **psta) ++{ ++ u8 *ptr = precv_frame->rx_data; ++ int ret = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 *mybssid = get_bssid(pmlmepriv); ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ u8 *sta_addr = NULL; ++ bool bmcast = is_multicast_ether_addr(pattrib->dst); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { ++ /* filter packets that SA is myself or multicast or broadcast */ ++ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ memcmp(pattrib->bssid, mybssid, ETH_ALEN)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ sta_addr = pattrib->src; ++ } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ /* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */ ++ if (memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ sta_addr = pattrib->bssid; ++ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ if (bmcast) { ++ /* For AP mode, if DA == MCAST, then BSSID should be also MCAST */ ++ if (!is_multicast_ether_addr(pattrib->bssid)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ } else { /* not mc-frame */ ++ /* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */ ++ if (memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ sta_addr = pattrib->src; ++ } ++ } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { ++ memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ sta_addr = mybssid; ++ } else { ++ ret = _FAIL; ++ } ++ ++ if (bmcast) ++ *psta = rtw_get_bcmc_stainfo(adapter); ++ else ++ *psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */ ++ ++ if (!*psta) { ++ if (adapter->registrypriv.mp_mode == 1) { ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) ++ adapter->mppriv.rx_pktloss++; ++ } ++ ret = _FAIL; ++ goto exit; ++ } ++ ++exit: ++ ++ return ret; ++} ++ ++static int ap2sta_data_frame( ++ struct adapter *adapter, ++ struct recv_frame *precv_frame, ++ struct sta_info **psta) ++{ ++ u8 *ptr = precv_frame->rx_data; ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ int ret = _SUCCESS; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 *mybssid = get_bssid(pmlmepriv); ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ bool bmcast = is_multicast_ether_addr(pattrib->dst); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && ++ (check_fwstate(pmlmepriv, _FW_LINKED) || ++ check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) { ++ /* filter packets that SA is myself or multicast or broadcast */ ++ if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* da should be for me */ ++ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* check BSSID */ ++ if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || ++ (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { ++ if (!bmcast) { ++ DBG_88E("issue_deauth to the nonassociated ap=%pM for the reason(7)\n", (pattrib->bssid)); ++ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ } ++ ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if (bmcast) ++ *psta = rtw_get_bcmc_stainfo(adapter); ++ else ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */ ++ ++ if (!*psta) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { */ ++ /* */ ++ ++ if (GetFrameSubType(ptr) & BIT(6)) { ++ /* No data, will not indicate to upper layer, temporily count it here */ ++ count_rx_stats(adapter, precv_frame, *psta); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && ++ check_fwstate(pmlmepriv, _FW_LINKED)) { ++ memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ ++ /* */ ++ memcpy(pattrib->bssid, mybssid, ETH_ALEN); ++ ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ ++ if (!*psta) { ++ ret = _FAIL; ++ goto exit; ++ } ++ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ /* Special case */ ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } else { ++ if (!memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) { ++ *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ ++ if (!*psta) { ++ DBG_88E("issue_deauth to the ap =%pM for the reason(7)\n", (pattrib->bssid)); ++ ++ issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ } ++ } ++ ++ ret = _FAIL; ++ } ++ ++exit: ++ ++ return ret; ++} ++ ++static int sta2ap_data_frame(struct adapter *adapter, ++ struct recv_frame *precv_frame, ++ struct sta_info **psta) ++{ ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ struct sta_priv *pstapriv = &adapter->stapriv; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ u8 *ptr = precv_frame->rx_data; ++ unsigned char *mybssid = get_bssid(pmlmepriv); ++ int ret = _SUCCESS; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ /* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */ ++ if (memcmp(pattrib->bssid, mybssid, ETH_ALEN)) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ *psta = rtw_get_stainfo(pstapriv, pattrib->src); ++ if (!*psta) { ++ DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src)); ++ ++ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ ++ process_pwrbit_data(adapter, precv_frame); ++ ++ if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { ++ process_wmmps_data(adapter, precv_frame); ++ } ++ ++ if (GetFrameSubType(ptr) & BIT(6)) { ++ /* No data, will not indicate to upper layer, temporily count it here */ ++ count_rx_stats(adapter, precv_frame, *psta); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ } else { ++ u8 *myhwaddr = myid(&adapter->eeprompriv); ++ if (memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) { ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ DBG_88E("issue_deauth to sta=%pM for the reason(7)\n", (pattrib->src)); ++ issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ++ ret = RTW_RX_HANDLED; ++ goto exit; ++ } ++ ++exit: ++ ++ return ret; ++} ++ ++static int validate_recv_ctrl_frame(struct adapter *padapter, ++ struct recv_frame *precv_frame) ++{ ++#ifdef CONFIG_88EU_AP_MODE ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 *pframe = precv_frame->rx_data; ++ /* uint len = precv_frame->len; */ ++ ++ if (GetFrameType(pframe) != WIFI_CTRL_TYPE) ++ return _FAIL; ++ ++ /* receive the frames that ra(a1) is my address */ ++ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN)) ++ return _FAIL; ++ ++ /* only handle ps-poll */ ++ if (GetFrameSubType(pframe) == WIFI_PSPOLL) { ++ u16 aid; ++ u8 wmmps_ac = 0; ++ struct sta_info *psta = NULL; ++ ++ aid = GetAid(pframe); ++ psta = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); ++ ++ if (!psta || psta->aid != aid) ++ return _FAIL; ++ ++ /* for rx pkt statistics */ ++ psta->sta_stats.rx_ctrl_pkts++; ++ ++ switch (pattrib->priority) { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk & BIT(0); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi & BIT(0); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo & BIT(0); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be & BIT(0); ++ break; ++ } ++ ++ if (wmmps_ac) ++ return _FAIL; ++ ++ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { ++ DBG_88E("%s alive check-rx ps-poll\n", __func__); ++ psta->expire_to = pstapriv->expire_to; ++ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; ++ } ++ ++ if ((psta->state & WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap & BIT(psta->aid))) { ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = xmitframe_phead->next; ++ ++ if (xmitframe_phead != xmitframe_plist) { ++ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = xmitframe_plist->next; ++ ++ list_del_init(&pxmitframe->list); ++ ++ psta->sleepq_len--; ++ ++ if (psta->sleepq_len > 0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ pxmitframe->attrib.triggered = 1; ++ ++ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); ++ ++ if (psta->sleepq_len == 0) { ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ /* upate BCN for TIM IE */ ++ /* update_BCNTIM(padapter); */ ++ update_beacon(padapter, _TIM_IE_, NULL, false); ++ } ++ } else { ++ if (pstapriv->tim_bitmap & BIT(psta->aid)) { ++ if (psta->sleepq_len == 0) { ++ DBG_88E("no buffered packets to xmit\n"); ++ ++ /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */ ++ issue_nulldata(padapter, psta->hwaddr, 0, 0, 0); ++ } else { ++ DBG_88E("error!psta->sleepq_len=%d\n", psta->sleepq_len); ++ psta->sleepq_len = 0; ++ } ++ ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ /* upate BCN for TIM IE */ ++ /* update_BCNTIM(padapter); */ ++ update_beacon(padapter, _TIM_IE_, NULL, false); ++ } ++ } ++ spin_unlock_bh(&pxmitpriv->lock); ++ } ++ } ++ ++#endif ++ ++ return _FAIL; ++} ++ ++struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, struct recv_frame *precv_frame); ++ ++static int validate_recv_mgnt_frame(struct adapter *padapter, ++ struct recv_frame *precv_frame) ++{ ++ struct sta_info *psta; ++ ++ precv_frame = recvframe_chk_defrag(padapter, precv_frame); ++ if (!precv_frame) ++ return _SUCCESS; ++ ++ /* for rx pkt statistics */ ++ psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(precv_frame->rx_data)); ++ if (psta) { ++ psta->sta_stats.rx_mgnt_pkts++; ++ if (GetFrameSubType(precv_frame->rx_data) == WIFI_BEACON) { ++ psta->sta_stats.rx_beacon_pkts++; ++ } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBEREQ) { ++ psta->sta_stats.rx_probereq_pkts++; ++ } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBERSP) { ++ if (!memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->rx_data), ETH_ALEN)) ++ psta->sta_stats.rx_probersp_pkts++; ++ else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->rx_data)) || ++ is_multicast_mac_addr(GetAddr1Ptr(precv_frame->rx_data))) ++ psta->sta_stats.rx_probersp_bm_pkts++; ++ else ++ psta->sta_stats.rx_probersp_uo_pkts++; ++ } ++ } ++ ++ mgt_dispatcher(padapter, precv_frame); ++ ++ return _SUCCESS; ++} ++ ++static int validate_recv_data_frame(struct adapter *adapter, ++ struct recv_frame *precv_frame) ++{ ++ u8 bretry; ++ u8 *psa, *pda, *pbssid; ++ struct sta_info *psta = NULL; ++ u8 *ptr = precv_frame->rx_data; ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ struct security_priv *psecuritypriv = &adapter->securitypriv; ++ int ret = _SUCCESS; ++ ++ bretry = GetRetry(ptr); ++ pda = get_da(ptr); ++ psa = get_sa(ptr); ++ pbssid = get_hdr_bssid(ptr); ++ ++ if (!pbssid) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ memcpy(pattrib->dst, pda, ETH_ALEN); ++ memcpy(pattrib->src, psa, ETH_ALEN); ++ ++ memcpy(pattrib->bssid, pbssid, ETH_ALEN); ++ ++ switch (pattrib->to_fr_ds) { ++ case 0: ++ memcpy(pattrib->ra, pda, ETH_ALEN); ++ memcpy(pattrib->ta, psa, ETH_ALEN); ++ ret = sta2sta_data_frame(adapter, precv_frame, &psta); ++ break; ++ case 1: ++ memcpy(pattrib->ra, pda, ETH_ALEN); ++ memcpy(pattrib->ta, pbssid, ETH_ALEN); ++ ret = ap2sta_data_frame(adapter, precv_frame, &psta); ++ break; ++ case 2: ++ memcpy(pattrib->ra, pbssid, ETH_ALEN); ++ memcpy(pattrib->ta, psa, ETH_ALEN); ++ ret = sta2ap_data_frame(adapter, precv_frame, &psta); ++ break; ++ case 3: ++ memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); ++ memcpy(pattrib->ta, GetAddr2Ptr(ptr), ETH_ALEN); ++ ret = _FAIL; ++ break; ++ default: ++ ret = _FAIL; ++ break; ++ } ++ ++ if (ret == _FAIL) { ++ goto exit; ++ } else if (ret == RTW_RX_HANDLED) { ++ goto exit; ++ } ++ ++ if (!psta) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ /* psta->rssi = prxcmd->rssi; */ ++ /* psta->signal_quality = prxcmd->sq; */ ++ precv_frame->psta = psta; ++ ++ pattrib->amsdu = 0; ++ pattrib->ack_policy = 0; ++ /* parsing QC field */ ++ if (pattrib->qos == 1) { ++ pattrib->priority = GetPriority((ptr + 24)); ++ pattrib->ack_policy = GetAckpolicy((ptr + 24)); ++ pattrib->amsdu = GetAMsdu((ptr + 24)); ++ pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26; ++ ++ if (pattrib->priority != 0 && pattrib->priority != 3) ++ adapter->recvpriv.bIsAnyNonBEPkts = true; ++ } else { ++ pattrib->priority = 0; ++ pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 30 : 24; ++ } ++ ++ if (pattrib->order)/* HT-CTRL 11n */ ++ pattrib->hdrlen += 4; ++ ++ precv_frame->preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority]; ++ ++ /* decache, drop duplicate recv packets */ ++ if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) { ++ ret = _FAIL; ++ goto exit; ++ } ++ ++ if (pattrib->privacy) { ++ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, is_multicast_ether_addr(pattrib->ra)); ++ ++ SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); ++ } else { ++ pattrib->encrypt = 0; ++ pattrib->iv_len = 0; ++ pattrib->icv_len = 0; ++ } ++ ++exit: ++ ++ return ret; ++} ++ ++static int validate_recv_frame(struct adapter *adapter, struct recv_frame *precv_frame) ++{ ++ /* shall check frame subtype, to / from ds, da, bssid */ ++ ++ /* then call check if rx seq/frag. duplicated. */ ++ ++ u8 type; ++ u8 subtype; ++ int retval = _SUCCESS; ++ u8 bDumpRxPkt; ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ u8 *ptr = precv_frame->rx_data; ++ u8 ver = (unsigned char)(*ptr) & 0x3; ++ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { ++ int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter)); ++ if (ch_set_idx >= 0) ++ pmlmeext->channel_set[ch_set_idx].rx_count++; ++ } ++ ++ /* add version chk */ ++ if (ver != 0) { ++ retval = _FAIL; ++ goto exit; ++ } ++ ++ type = GetFrameType(ptr); ++ subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */ ++ ++ pattrib->to_fr_ds = get_tofr_ds(ptr); ++ ++ pattrib->frag_num = GetFragNum(ptr); ++ pattrib->seq_num = GetSequence(ptr); ++ ++ pattrib->pw_save = GetPwrMgt(ptr); ++ pattrib->mfrag = GetMFrag(ptr); ++ pattrib->mdata = GetMData(ptr); ++ pattrib->privacy = GetPrivacy(ptr); ++ pattrib->order = GetOrder(ptr); ++ ++ /* Dump rx packets */ ++ rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); ++ if (bDumpRxPkt == 1) {/* dump all rx packets */ ++ int i; ++ DBG_88E("#############################\n"); ++ ++ for (i = 0; i < 64; i = i + 8) ++ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr + i), ++ *(ptr + i + 1), *(ptr + i + 2), *(ptr + i + 3), *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7)); ++ DBG_88E("#############################\n"); ++ } else if (bDumpRxPkt == 2) { ++ if (type == WIFI_MGT_TYPE) { ++ int i; ++ DBG_88E("#############################\n"); ++ ++ for (i = 0; i < 64; i = i + 8) ++ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr + i), ++ *(ptr + i + 1), *(ptr + i + 2), *(ptr + i + 3), *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7)); ++ DBG_88E("#############################\n"); ++ } ++ } else if (bDumpRxPkt == 3) { ++ if (type == WIFI_DATA_TYPE) { ++ int i; ++ DBG_88E("#############################\n"); ++ ++ for (i = 0; i < 64; i = i + 8) ++ DBG_88E("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr + i), ++ *(ptr + i + 1), *(ptr + i + 2), *(ptr + i + 3), *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7)); ++ DBG_88E("#############################\n"); ++ } ++ } ++ switch (type) { ++ case WIFI_MGT_TYPE: /* mgnt */ ++ validate_recv_mgnt_frame(adapter, precv_frame); ++ retval = _FAIL; /* only data frame return _SUCCESS */ ++ break; ++ case WIFI_CTRL_TYPE: /* ctrl */ ++ validate_recv_ctrl_frame(adapter, precv_frame); ++ retval = _FAIL; /* only data frame return _SUCCESS */ ++ break; ++ case WIFI_DATA_TYPE: /* data */ ++ rtw_led_control(adapter, LED_CTL_RX); ++ pattrib->qos = (subtype & BIT(7)) ? 1 : 0; ++ retval = validate_recv_data_frame(adapter, precv_frame); ++ if (retval == _FAIL) { ++ struct recv_priv *precvpriv = &adapter->recvpriv; ++ precvpriv->rx_drop++; ++ } ++ break; ++ default: ++ retval = _FAIL; ++ break; ++ } ++ ++exit: ++ ++ return retval; ++} ++ ++/* remove the wlanhdr and add the eth_hdr */ ++ ++static int wlanhdr_to_ethhdr(struct recv_frame *precvframe) ++{ ++ int rmv_len; ++ u16 eth_type, len; ++ __be16 be_tmp; ++ u8 bsnaphdr; ++ u8 *psnap_type; ++ struct ieee80211_snap_hdr *psnap; ++ ++ int ret = _SUCCESS; ++ struct adapter *adapter = precvframe->adapter; ++ struct mlme_priv *pmlmepriv = &adapter->mlmepriv; ++ ++ u8 *ptr = get_recvframe_data(precvframe); /* point to frame_ctrl field */ ++ struct rx_pkt_attrib *pattrib = &precvframe->attrib; ++ ++ if (pattrib->encrypt) ++ recvframe_pull_tail(precvframe, pattrib->icv_len); ++ ++ psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + pattrib->iv_len); ++ psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ if ((!memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) && ++ memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) && ++ memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2)) || ++ !memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ ++ bsnaphdr = true; ++ } else { ++ /* Leave Ethernet header part of hdr and full payload */ ++ bsnaphdr = false; ++ } ++ ++ rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0); ++ len = precvframe->len - rmv_len; ++ ++ memcpy(&be_tmp, ptr + rmv_len, 2); ++ eth_type = ntohs(be_tmp); /* pattrib->ether_type */ ++ pattrib->eth_type = eth_type; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE))) { ++ ptr += rmv_len; ++ *ptr = 0x87; ++ *(ptr + 1) = 0x12; ++ ++ eth_type = 0x8712; ++ /* append rx status for mp test packets */ ++ ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2) - 24); ++ memcpy(ptr, get_rxmem(precvframe), 24); ++ ptr += 24; ++ } else { ++ ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); ++ } ++ ++ memcpy(ptr, pattrib->dst, ETH_ALEN); ++ memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN); ++ ++ if (!bsnaphdr) { ++ be_tmp = htons(len); ++ memcpy(ptr + 12, &be_tmp, 2); ++ } ++ ++ return ret; ++} ++ ++/* perform defrag */ ++static struct recv_frame *recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q) ++{ ++ struct list_head *plist, *phead; ++ u8 wlanhdr_offset; ++ u8 curfragnum; ++ struct recv_frame *pfhdr, *pnfhdr; ++ struct recv_frame *prframe, *pnextrframe; ++ struct __queue *pfree_recv_queue; ++ ++ curfragnum = 0; ++ pfree_recv_queue = &adapter->recvpriv.free_recv_queue; ++ ++ phead = get_list_head(defrag_q); ++ plist = phead->next; ++ pfhdr = container_of(plist, struct recv_frame, list); ++ prframe = (struct recv_frame *)pfhdr; ++ list_del_init(&prframe->list); ++ ++ if (curfragnum != pfhdr->attrib.frag_num) { ++ /* the first fragment number must be 0 */ ++ /* free the whole queue */ ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ ++ return NULL; ++ } ++ ++ curfragnum++; ++ ++ plist = get_list_head(defrag_q); ++ plist = phead->next; ++ pfhdr = container_of(plist, struct recv_frame, list); ++ prframe = (struct recv_frame *)pfhdr; ++ list_del_init(&prframe->list); ++ ++ plist = plist->next; ++ ++ while (phead != plist) { ++ pnfhdr = container_of(plist, struct recv_frame, list); ++ pnextrframe = (struct recv_frame *)pnfhdr; ++ ++ /* check the fragment sequence (2nd ~n fragment frame) */ ++ ++ if (curfragnum != pnfhdr->attrib.frag_num) { ++ /* the fragment number must be increasing (after decache) */ ++ /* release the defrag_q & prframe */ ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ return NULL; ++ } ++ ++ curfragnum++; ++ ++ /* copy the 2nd~n fragment frame's payload to the first fragment */ ++ /* get the 2nd~last fragment frame's payload */ ++ ++ wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; ++ ++ recvframe_pull(pnextrframe, wlanhdr_offset); ++ ++ /* append to first fragment frame's tail (if privacy frame, pull the ICV) */ ++ recvframe_pull_tail(prframe, pfhdr->attrib.icv_len); ++ ++ /* memcpy */ ++ memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); ++ ++ recvframe_put(prframe, pnfhdr->len); ++ ++ pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; ++ plist = plist->next; ++ } ++ ++ /* free the defrag_q queue and return the prframe */ ++ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); ++ ++ return prframe; ++} ++ ++/* check if need to defrag, if needed queue the frame to defrag_q */ ++struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, struct recv_frame *precv_frame) ++{ ++ u8 ismfrag; ++ u8 fragnum; ++ u8 *psta_addr; ++ struct recv_frame *pfhdr; ++ struct sta_info *psta; ++ struct sta_priv *pstapriv; ++ struct list_head *phead; ++ struct recv_frame *prtnframe = NULL; ++ struct __queue *pfree_recv_queue, *pdefrag_q; ++ ++ pstapriv = &padapter->stapriv; ++ ++ pfhdr = precv_frame; ++ ++ pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ /* need to define struct of wlan header frame ctrl */ ++ ismfrag = pfhdr->attrib.mfrag; ++ fragnum = pfhdr->attrib.frag_num; ++ ++ psta_addr = pfhdr->attrib.ta; ++ psta = rtw_get_stainfo(pstapriv, psta_addr); ++ if (!psta) { ++ u8 type = GetFrameType(pfhdr->rx_data); ++ if (type != WIFI_DATA_TYPE) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ pdefrag_q = &psta->sta_recvpriv.defrag_q; ++ } else { ++ pdefrag_q = NULL; ++ } ++ } else { ++ pdefrag_q = &psta->sta_recvpriv.defrag_q; ++ } ++ ++ if ((ismfrag == 0) && (fragnum == 0)) ++ prtnframe = precv_frame;/* isn't a fragment frame */ ++ ++ if (ismfrag == 1) { ++ /* 0~(n-1) fragment frame */ ++ /* enqueue to defraf_g */ ++ if (pdefrag_q) { ++ if (fragnum == 0) { ++ /* the first fragment */ ++ if (!list_empty(&pdefrag_q->queue)) { ++ /* free current defrag_q */ ++ rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue); ++ } ++ } ++ ++ /* Then enqueue the 0~(n-1) fragment into the defrag_q */ ++ ++ phead = get_list_head(pdefrag_q); ++ list_add_tail(&pfhdr->list, phead); ++ ++ prtnframe = NULL; ++ } else { ++ /* can't find this ta's defrag_queue, so free this recv_frame */ ++ if (precv_frame && pfree_recv_queue) ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ prtnframe = NULL; ++ } ++ } ++ ++ if ((ismfrag == 0) && (fragnum != 0)) { ++ /* the last fragment frame */ ++ /* enqueue the last fragment */ ++ if (pdefrag_q) { ++ phead = get_list_head(pdefrag_q); ++ list_add_tail(&pfhdr->list, phead); ++ ++ /* call recvframe_defrag to defrag */ ++ precv_frame = recvframe_defrag(padapter, pdefrag_q); ++ prtnframe = precv_frame; ++ } else { ++ /* can't find this ta's defrag_queue, so free this recv_frame */ ++ if (precv_frame && pfree_recv_queue) ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ prtnframe = NULL; ++ } ++ } ++ ++ if (prtnframe && prtnframe->attrib.privacy) { ++ /* after defrag we must check tkip mic code */ ++ if (recvframe_chkmic(padapter, prtnframe) == _FAIL) { ++ if (precv_frame && pfree_recv_queue) ++ rtw_free_recvframe(prtnframe, pfree_recv_queue); ++ prtnframe = NULL; ++ } ++ } ++ ++ return prtnframe; ++} ++ ++static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) ++{ ++ int a_len, padding_len; ++ u16 eth_type, nSubframe_Length; ++ u8 nr_subframes, i; ++ unsigned char *pdata; ++ struct rx_pkt_attrib *pattrib; ++ unsigned char *data_ptr; ++ struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT]; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct __queue *pfree_recv_queue = &precvpriv->free_recv_queue; ++ int ret = _SUCCESS; ++ nr_subframes = 0; ++ ++ pattrib = &prframe->attrib; ++ ++ recvframe_pull(prframe, prframe->attrib.hdrlen); ++ ++ if (prframe->attrib.iv_len > 0) ++ recvframe_pull(prframe, prframe->attrib.iv_len); ++ ++ a_len = prframe->len; ++ ++ pdata = prframe->rx_data; ++ ++ while (a_len > ETH_HLEN) { ++ /* Offset 12 denote 2 mac address */ ++ nSubframe_Length = RTW_GET_BE16(pdata + 12); ++ ++ if (a_len < ETH_HLEN + nSubframe_Length) { ++ DBG_88E("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length); ++ goto exit; ++ } ++ ++ /* move the data point to data content */ ++ pdata += ETH_HLEN; ++ a_len -= ETH_HLEN; ++ ++ /* Allocate new skb for releasing to upper layer */ ++ sub_skb = dev_alloc_skb(nSubframe_Length + 12); ++ if (sub_skb) { ++ skb_reserve(sub_skb, 12); ++ data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); ++ memcpy(data_ptr, pdata, nSubframe_Length); ++ } else { ++ sub_skb = skb_clone(prframe->pkt, GFP_ATOMIC); ++ if (sub_skb) { ++ sub_skb->data = pdata; ++ sub_skb->len = nSubframe_Length; ++ skb_set_tail_pointer(sub_skb, nSubframe_Length); ++ } else { ++ DBG_88E("skb_clone() Fail!!! , nr_subframes=%d\n", nr_subframes); ++ break; ++ } ++ } ++ ++ subframes[nr_subframes++] = sub_skb; ++ ++ if (nr_subframes >= MAX_SUBFRAME_COUNT) { ++ DBG_88E("ParseSubframe(): Too many Subframes! Packets dropped!\n"); ++ break; ++ } ++ ++ pdata += nSubframe_Length; ++ a_len -= nSubframe_Length; ++ if (a_len != 0) { ++ padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4 - 1)); ++ if (padding_len == 4) { ++ padding_len = 0; ++ } ++ ++ if (a_len < padding_len) { ++ goto exit; ++ } ++ pdata += padding_len; ++ a_len -= padding_len; ++ } ++ } ++ ++ for (i = 0; i < nr_subframes; i++) { ++ sub_skb = subframes[i]; ++ /* convert hdr + possible LLC headers into Ethernet header */ ++ eth_type = RTW_GET_BE16(&sub_skb->data[6]); ++ if (sub_skb->len >= 8 && ++ ((!memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) && ++ eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || ++ !memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) { ++ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ ++ skb_pull(sub_skb, SNAP_SIZE); ++ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); ++ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); ++ } else { ++ __be16 len; ++ /* Leave Ethernet header part of hdr and full payload */ ++ len = htons(sub_skb->len); ++ memcpy(skb_push(sub_skb, 2), &len, 2); ++ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN); ++ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN); ++ } ++ ++ /* Indicate the packets to upper layer */ ++ /* Insert NAT2.5 RX here! */ ++ sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev); ++ sub_skb->dev = padapter->pnetdev; ++ ++ sub_skb->ip_summed = CHECKSUM_NONE; ++ ++ netif_rx(sub_skb); ++ } ++ ++exit: ++ ++ prframe->len = 0; ++ rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */ ++ ++ return ret; ++} ++ ++static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) ++{ ++ u8 wsize = preorder_ctrl->wsize_b; ++ u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF;/* 4096; */ ++ ++ /* Rx Reorder initialize condition. */ ++ if (preorder_ctrl->indicate_seq == 0xFFFF) ++ preorder_ctrl->indicate_seq = seq_num; ++ ++ /* Drop out the packet which SeqNum is smaller than WinStart */ ++ if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) ++ return false; ++ ++ /* */ ++ /* Sliding window manipulation. Conditions includes: */ ++ /* 1. Incoming SeqNum is equal to WinStart =>Window shift 1 */ ++ /* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */ ++ /* */ ++ if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) { ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; ++ } else if (SN_LESS(wend, seq_num)) { ++ if (seq_num >= (wsize - 1)) ++ preorder_ctrl->indicate_seq = seq_num + 1 - wsize; ++ else ++ preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1; ++ } ++ ++ return true; ++} ++ ++int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, struct recv_frame *prframe); ++int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, struct recv_frame *prframe) ++{ ++ struct rx_pkt_attrib *pattrib = &prframe->attrib; ++ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ struct list_head *phead, *plist; ++ struct recv_frame *hdr; ++ struct rx_pkt_attrib *pnextattrib; ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ hdr = container_of(plist, struct recv_frame, list); ++ pnextattrib = &hdr->attrib; ++ ++ if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) ++ plist = plist->next; ++ else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) ++ return false; ++ else ++ break; ++ } ++ ++ list_del_init(&prframe->list); ++ ++ list_add_tail(&prframe->list, plist); ++ return true; ++} ++ ++static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) ++{ ++ struct list_head *phead, *plist; ++ struct recv_frame *prframe; ++ struct rx_pkt_attrib *pattrib; ++ int bPktInBuf = false; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = phead->next; ++ ++ /* Handling some condition for forced indicate case. */ ++ if (bforced) { ++ if (list_empty(phead)) ++ return true; ++ ++ prframe = container_of(plist, struct recv_frame, list); ++ pattrib = &prframe->attrib; ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ } ++ ++ /* Prepare indication list and indication. */ ++ /* Check if there is any packet need indicate. */ ++ while (!list_empty(phead)) { ++ prframe = container_of(plist, struct recv_frame, list); ++ pattrib = &prframe->attrib; ++ ++ if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { ++ plist = plist->next; ++ list_del_init(&prframe->list); ++ ++ if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; ++ ++ /* Set this as a lock to make sure that only one thread is indicating packet. */ ++ ++ /* indicate this recv_frame */ ++ if (!pattrib->amsdu) { ++ if ((!padapter->bDriverStopped) && ++ (!padapter->bSurpriseRemoved)) ++ rtw_recv_indicatepkt(padapter, prframe);/* indicate this recv_frame */ ++ } else if (pattrib->amsdu == 1) { ++ if (amsdu_to_msdu(padapter, prframe) != _SUCCESS) ++ rtw_free_recvframe(prframe, &precvpriv->free_recv_queue); ++ } else { ++ /* error condition; */ ++ } ++ ++ /* Update local variables. */ ++ bPktInBuf = false; ++ } else { ++ bPktInBuf = true; ++ break; ++ } ++ } ++ return bPktInBuf; ++} ++ ++static int recv_indicatepkt_reorder(struct adapter *padapter, struct recv_frame *prframe) ++{ ++ int retval = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = &prframe->attrib; ++ struct recv_reorder_ctrl *preorder_ctrl = prframe->preorder_ctrl; ++ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ if (!pattrib->amsdu) { ++ /* s1. */ ++ wlanhdr_to_ethhdr(prframe); ++ ++ if (pattrib->qos != 1) { ++ if (!padapter->bDriverStopped && ++ !padapter->bSurpriseRemoved) { ++ rtw_recv_indicatepkt(padapter, prframe); ++ return _SUCCESS; ++ } ++ ++ return _FAIL; ++ } ++ ++ if (!preorder_ctrl->enable) { ++ /* indicate this recv_frame */ ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ rtw_recv_indicatepkt(padapter, prframe); ++ ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096; ++ return _SUCCESS; ++ } ++ } else if (pattrib->amsdu == 1) { /* temp filter -> means didn't support A-MSDUs in a A-MPDU */ ++ if (!preorder_ctrl->enable) { ++ preorder_ctrl->indicate_seq = pattrib->seq_num; ++ retval = amsdu_to_msdu(padapter, prframe); ++ ++ preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096; ++ return retval; ++ } ++ } ++ ++ spin_lock_bh(&ppending_recvframe_queue->lock); ++ ++ /* s2. check if winstart_b(indicate_seq) needs to been updated */ ++ if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) ++ goto _err_exit; ++ ++ /* s3. Insert all packet into Reorder Queue to maintain its ordering. */ ++ if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) ++ goto _err_exit; ++ ++ /* s4. */ ++ /* Indication process. */ ++ /* After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets */ ++ /* with the SeqNum smaller than latest WinStart and buffer other packets. */ ++ /* */ ++ /* For Rx Reorder condition: */ ++ /* 1. All packets with SeqNum smaller than WinStart => Indicate */ ++ /* 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. */ ++ /* */ ++ ++ /* recv_indicatepkts_in_order(padapter, preorder_ctrl, true); */ ++ if (recv_indicatepkts_in_order(padapter, preorder_ctrl, false)) { ++ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ } else { ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); ++ } ++ ++ return _SUCCESS; ++ ++_err_exit: ++ ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ ++ return _FAIL; ++} ++ ++void rtw_reordering_ctrl_timeout_handler(void *pcontext) ++{ ++ struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext; ++ struct adapter *padapter = preorder_ctrl->padapter; ++ struct __queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ if (padapter->bDriverStopped || padapter->bSurpriseRemoved) ++ return; ++ ++ spin_lock_bh(&ppending_recvframe_queue->lock); ++ ++ if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true)) ++ _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); ++ ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++} ++ ++static int process_recv_indicatepkts(struct adapter *padapter, struct recv_frame *prframe) ++{ ++ int retval = _SUCCESS; ++ /* struct recv_priv *precvpriv = &padapter->recvpriv; */ ++ /* struct rx_pkt_attrib *pattrib = &prframe->attrib; */ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ if (phtpriv->ht_option) { /* B/G/N Mode */ ++ /* prframe->preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */ ++ ++ if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) { ++ /* including perform A-MPDU Rx Ordering Buffer Control */ ++ if ((!padapter->bDriverStopped) && ++ (!padapter->bSurpriseRemoved)) { ++ retval = _FAIL; ++ return retval; ++ } ++ } ++ } else { /* B/G mode */ ++ retval = wlanhdr_to_ethhdr(prframe); ++ if (retval != _SUCCESS) ++ return retval; ++ ++ if ((!padapter->bDriverStopped) && ++ (!padapter->bSurpriseRemoved)) { ++ /* indicate this recv_frame */ ++ rtw_recv_indicatepkt(padapter, prframe); ++ } else { ++ retval = _FAIL; ++ return retval; ++ } ++ } ++ ++ return retval; ++} ++ ++static int recv_func_prehandle(struct adapter *padapter, struct recv_frame *rframe) ++{ ++ int ret = _SUCCESS; ++ struct rx_pkt_attrib *pattrib = &rframe->attrib; ++ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (padapter->registrypriv.mp_mode == 1) { ++ if (pattrib->crc_err == 1) ++ padapter->mppriv.rx_crcerrpktcount++; ++ else ++ padapter->mppriv.rx_pktcount++; ++ ++ if (!check_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE)) { ++ ret = _FAIL; ++ rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ ++ goto exit; ++ } ++ } ++ ++ /* check the frame crtl field and decache */ ++ ret = validate_recv_frame(padapter, rframe); ++ if (ret != _SUCCESS) { ++ rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ ++ goto exit; ++ } ++ ++exit: ++ return ret; ++} ++ ++static int recv_func_posthandle(struct adapter *padapter, struct recv_frame *prframe) ++{ ++ int ret = _SUCCESS; ++ struct recv_frame *orig_prframe = prframe; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ /* DATA FRAME */ ++ rtw_led_control(padapter, LED_CTL_RX); ++ ++ prframe = decryptor(padapter, prframe); ++ if (!prframe) { ++ ret = _FAIL; ++ goto _recv_data_drop; ++ } ++ ++ prframe = recvframe_chk_defrag(padapter, prframe); ++ if (!prframe) ++ goto _recv_data_drop; ++ ++ prframe = portctrl(padapter, prframe); ++ if (!prframe) { ++ ret = _FAIL; ++ goto _recv_data_drop; ++ } ++ ++ count_rx_stats(padapter, prframe, NULL); ++ ++ ret = process_recv_indicatepkts(padapter, prframe); ++ if (ret != _SUCCESS) { ++ rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */ ++ goto _recv_data_drop; ++ } ++ return ret; ++ ++_recv_data_drop: ++ precvpriv->rx_drop++; ++ return ret; ++} ++ ++static int recv_func(struct adapter *padapter, struct recv_frame *rframe) ++{ ++ int ret; ++ struct rx_pkt_attrib *prxattrib = &rframe->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *mlmepriv = &padapter->mlmepriv; ++ struct recv_priv *recvpriv = &padapter->recvpriv; ++ ++ /* check if need to handle uc_swdec_pending_queue*/ ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && ++ psecuritypriv->busetkipkey) { ++ struct recv_frame *pending_frame; ++ int cnt = 0; ++ ++ pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); ++ while (pending_frame) { ++ cnt++; ++ recv_func_posthandle(padapter, pending_frame); ++ } ++ } ++ ++ ret = recv_func_prehandle(padapter, rframe); ++ ++ if (ret == _SUCCESS) { ++ /* check if need to enqueue into uc_swdec_pending_queue*/ ++ if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && ++ !is_multicast_ether_addr(prxattrib->ra) && prxattrib->encrypt > 0 && ++ (prxattrib->bdecrypted == 0 || psecuritypriv->sw_decrypt) && ++ psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPAPSK && ++ !psecuritypriv->busetkipkey) { ++ rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); ++ DBG_88E("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); ++ if (recvpriv->free_recvframe_cnt < NR_RECVFRAME / 4) { ++ /* to prevent from recvframe starvation, ++ * get recvframe from uc_swdec_pending_queue to ++ * free_recvframe_cnt */ ++ rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); ++ if (rframe) ++ goto do_posthandle; ++ } ++ goto exit; ++ } ++do_posthandle: ++ ret = recv_func_posthandle(padapter, rframe); ++ } ++ ++exit: ++ return ret; ++} ++ ++s32 rtw_recv_entry(struct recv_frame *precvframe) ++{ ++ struct adapter *padapter; ++ struct recv_priv *precvpriv; ++ s32 ret = _SUCCESS; ++ ++ padapter = precvframe->adapter; ++ ++ precvpriv = &padapter->recvpriv; ++ ++ ret = recv_func(padapter, precvframe); ++ if (ret == _FAIL) ++ goto _recv_entry_drop; ++ ++ precvpriv->rx_pkts++; ++ ++ return ret; ++ ++_recv_entry_drop: ++ ++ if (padapter->registrypriv.mp_mode == 1) ++ padapter->mppriv.rx_pktloss = precvpriv->rx_drop; ++ ++ return ret; ++} ++ ++void rtw_signal_stat_timer_hdl(struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, recvpriv.signal_stat_timer); ++ struct recv_priv *recvpriv = &adapter->recvpriv; ++ ++ u32 tmp_s, tmp_q; ++ u8 avg_signal_strength = 0; ++ u8 avg_signal_qual = 0; ++ u8 _alpha = 3; /* this value is based on converging_constant = 5000 and sampling_interval = 1000 */ ++ ++ if (adapter->recvpriv.is_signal_dbg) { ++ /* update the user specific value, signal_strength_dbg, to signal_strength, rssi */ ++ adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg; ++ adapter->recvpriv.rssi = (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg); ++ } else { ++ if (recvpriv->signal_strength_data.update_req == 0) {/* update_req is clear, means we got rx */ ++ avg_signal_strength = recvpriv->signal_strength_data.avg_val; ++ /* after avg_vals are accquired, we can re-stat the signal values */ ++ recvpriv->signal_strength_data.update_req = 1; ++ } ++ ++ if (recvpriv->signal_qual_data.update_req == 0) {/* update_req is clear, means we got rx */ ++ avg_signal_qual = recvpriv->signal_qual_data.avg_val; ++ /* after avg_vals are accquired, we can re-stat the signal values */ ++ recvpriv->signal_qual_data.update_req = 1; ++ } ++ ++ /* update value of signal_strength, rssi, signal_qual */ ++ if (!check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY)) { ++ tmp_s = (avg_signal_strength + (_alpha - 1) * recvpriv->signal_strength); ++ if (tmp_s % _alpha) ++ tmp_s = tmp_s / _alpha + 1; ++ else ++ tmp_s = tmp_s / _alpha; ++ if (tmp_s > 100) ++ tmp_s = 100; ++ ++ tmp_q = (avg_signal_qual + (_alpha - 1) * recvpriv->signal_qual); ++ if (tmp_q % _alpha) ++ tmp_q = tmp_q / _alpha + 1; ++ else ++ tmp_q = tmp_q / _alpha; ++ if (tmp_q > 100) ++ tmp_q = 100; ++ ++ recvpriv->signal_strength = tmp_s; ++ recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s); ++ recvpriv->signal_qual = tmp_q; ++ } ++ } ++ rtw_set_signal_stat_timer(recvpriv); ++} +diff --git a/drivers/staging/r8188eu/core/rtw_rf.c b/drivers/staging/r8188eu/core/rtw_rf.c +new file mode 100644 +index 000000000000..321546c40446 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_rf.c +@@ -0,0 +1,72 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTW_RF_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/xmit_osdep.h" ++ ++struct ch_freq { ++ u32 channel; ++ u32 frequency; ++}; ++ ++static struct ch_freq ch_freq_map[] = { ++ {1, 2412}, {2, 2417}, {3, 2422}, {4, 2427}, {5, 2432}, ++ {6, 2437}, {7, 2442}, {8, 2447}, {9, 2452}, {10, 2457}, ++ {11, 2462}, {12, 2467}, {13, 2472}, {14, 2484}, ++ /* UNII */ ++ {36, 5180}, {40, 5200}, {44, 5220}, {48, 5240}, {52, 5260}, ++ {56, 5280}, {60, 5300}, {64, 5320}, {149, 5745}, {153, 5765}, ++ {157, 5785}, {161, 5805}, {165, 5825}, {167, 5835}, {169, 5845}, ++ {171, 5855}, {173, 5865}, ++ /* HiperLAN2 */ ++ {100, 5500}, {104, 5520}, {108, 5540}, {112, 5560}, {116, 5580}, ++ {120, 5600}, {124, 5620}, {128, 5640}, {132, 5660}, {136, 5680}, ++ {140, 5700}, ++ /* Japan MMAC */ ++ {34, 5170}, {38, 5190}, {42, 5210}, {46, 5230}, ++ /* Japan */ ++ {184, 4920}, {188, 4940}, {192, 4960}, {196, 4980}, ++ {208, 5040},/* Japan, means J08 */ ++ {212, 5060},/* Japan, means J12 */ ++ {216, 5080},/* Japan, means J16 */ ++}; ++ ++static int ch_freq_map_num = (sizeof(ch_freq_map) / sizeof(struct ch_freq)); ++ ++u32 rtw_ch2freq(u32 channel) ++{ ++ u8 i; ++ u32 freq = 0; ++ ++ for (i = 0; i < ch_freq_map_num; i++) { ++ if (channel == ch_freq_map[i].channel) { ++ freq = ch_freq_map[i].frequency; ++ break; ++ } ++ } ++ if (i == ch_freq_map_num) ++ freq = 2412; ++ ++ return freq; ++} ++ ++u32 rtw_freq2ch(u32 freq) ++{ ++ u8 i; ++ u32 ch = 0; ++ ++ for (i = 0; i < ch_freq_map_num; i++) { ++ if (freq == ch_freq_map[i].frequency) { ++ ch = ch_freq_map[i].channel; ++ break; ++ } ++ } ++ if (i == ch_freq_map_num) ++ ch = 1; ++ ++ return ch; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_security.c b/drivers/staging/r8188eu/core/rtw_security.c +new file mode 100644 +index 000000000000..5aa893ab46e9 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_security.c +@@ -0,0 +1,1656 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTW_SECURITY_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/wifi.h" ++#include "../include/osdep_intf.h" ++ ++/* WEP related ===== */ ++ ++#define CRC32_POLY 0x04c11db7 ++ ++struct arc4context { ++ u32 x; ++ u32 y; ++ u8 state[256]; ++}; ++ ++static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len) ++{ ++ u32 t, u; ++ u32 keyindex; ++ u32 stateindex; ++ u8 *state; ++ u32 counter; ++ ++ state = parc4ctx->state; ++ parc4ctx->x = 0; ++ parc4ctx->y = 0; ++ for (counter = 0; counter < 256; counter++) ++ state[counter] = (u8)counter; ++ keyindex = 0; ++ stateindex = 0; ++ for (counter = 0; counter < 256; counter++) { ++ t = state[counter]; ++ stateindex = (stateindex + key[keyindex] + t) & 0xff; ++ u = state[stateindex]; ++ state[stateindex] = (u8)t; ++ state[counter] = (u8)u; ++ if (++keyindex >= key_len) ++ keyindex = 0; ++ } ++ ++} ++ ++static u32 arcfour_byte(struct arc4context *parc4ctx) ++{ ++ u32 x; ++ u32 y; ++ u32 sx, sy; ++ u8 *state; ++ ++ state = parc4ctx->state; ++ x = (parc4ctx->x + 1) & 0xff; ++ sx = state[x]; ++ y = (sx + parc4ctx->y) & 0xff; ++ sy = state[y]; ++ parc4ctx->x = x; ++ parc4ctx->y = y; ++ state[y] = (u8)sx; ++ state[x] = (u8)sy; ++ ++ return state[(sx + sy) & 0xff]; ++} ++ ++static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 len) ++{ ++ u32 i; ++ ++ for (i = 0; i < len; i++) ++ dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); ++ ++} ++ ++/* ++ Need to consider the fragment situation ++*/ ++void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe) ++{ /* exclude ICV */ ++ union { ++ __le32 f0; ++ u8 f1[4]; ++ } crc; ++ struct arc4context mycontext; ++ ++ int curfragnum, length; ++ u32 keylength; ++ ++ u8 *pframe, *payload, *iv; /* wepkey */ ++ u8 wepkey[16]; ++ u8 hw_hdr_offset = 0; ++ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ if (!((struct xmit_frame *)pxmitframe)->buf_addr) ++ return; ++ ++ hw_hdr_offset = TXDESC_SIZE + ++ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); ++ ++ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; ++ ++ /* start to encrypt each fragment */ ++ if ((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) { ++ keylength = psecuritypriv->dot11DefKeylen[psecuritypriv->dot11PrivacyKeyIndex]; ++ ++ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { ++ iv = pframe + pattrib->hdrlen; ++ memcpy(&wepkey[0], iv, 3); ++ memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength); ++ payload = pframe + pattrib->iv_len + pattrib->hdrlen; ++ ++ if ((curfragnum + 1) == pattrib->nr_frags) { /* the last fragment */ ++ length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; ++ ++ crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length)); ++ ++ arcfour_init(&mycontext, wepkey, 3 + keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload + length, crc.f1, 4); ++ } else { ++ length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; ++ crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length)); ++ arcfour_init(&mycontext, wepkey, 3 + keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload + length, crc.f1, 4); ++ ++ pframe += pxmitpriv->frag_len; ++ pframe = (u8 *)RND4((size_t)(pframe)); ++ } ++ } ++ } ++ ++} ++ ++void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) ++{ ++ /* exclude ICV */ ++ struct arc4context mycontext; ++ int length; ++ u32 keylength; ++ u8 *pframe, *payload, *iv, wepkey[16]; ++ u8 keyindex; ++ struct rx_pkt_attrib *prxattrib = &(((struct recv_frame *)precvframe)->attrib); ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data; ++ ++ /* start to decrypt recvframe */ ++ if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) { ++ iv = pframe + prxattrib->hdrlen; ++ keyindex = prxattrib->key_index; ++ keylength = psecuritypriv->dot11DefKeylen[keyindex]; ++ memcpy(&wepkey[0], iv, 3); ++ memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength); ++ length = ((struct recv_frame *)precvframe)->len - prxattrib->hdrlen - prxattrib->iv_len; ++ ++ payload = pframe + prxattrib->iv_len + prxattrib->hdrlen; ++ ++ /* decrypt payload include icv */ ++ arcfour_init(&mycontext, wepkey, 3 + keylength); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ } ++} ++ ++/* 3 ===== TKIP related ===== */ ++ ++static u32 secmicgetuint32(u8 *p) ++/* Convert from Byte[] to Us3232 in a portable way */ ++{ ++ s32 i; ++ u32 res = 0; ++ ++ for (i = 0; i < 4; i++) ++ res |= ((u32)(*p++)) << (8 * i); ++ ++ return res; ++} ++ ++static void secmicputuint32(u8 *p, u32 val) ++/* Convert from Us3232 to Byte[] in a portable way */ ++{ ++ long i; ++ ++ for (i = 0; i < 4; i++) { ++ *p++ = (u8)(val & 0xff); ++ val >>= 8; ++ } ++ ++} ++ ++static void secmicclear(struct mic_data *pmicdata) ++{ ++/* Reset the state to the empty message. */ ++ ++ pmicdata->L = pmicdata->K0; ++ pmicdata->R = pmicdata->K1; ++ pmicdata->nBytesInM = 0; ++ pmicdata->M = 0; ++ ++} ++ ++void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key) ++{ ++ /* Set the key */ ++ ++ pmicdata->K0 = secmicgetuint32(key); ++ pmicdata->K1 = secmicgetuint32(key + 4); ++ /* and reset the message */ ++ secmicclear(pmicdata); ++ ++} ++ ++void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b) ++{ ++ ++ /* Append the byte to our word-sized buffer */ ++ pmicdata->M |= ((unsigned long)b) << (8 * pmicdata->nBytesInM); ++ pmicdata->nBytesInM++; ++ /* Process the word if it is full. */ ++ if (pmicdata->nBytesInM >= 4) { ++ pmicdata->L ^= pmicdata->M; ++ pmicdata->R ^= ROL32(pmicdata->L, 17); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ROL32(pmicdata->L, 3); ++ pmicdata->L += pmicdata->R; ++ pmicdata->R ^= ROR32(pmicdata->L, 2); ++ pmicdata->L += pmicdata->R; ++ /* Clear the buffer */ ++ pmicdata->M = 0; ++ pmicdata->nBytesInM = 0; ++ } ++ ++} ++ ++void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes) ++{ ++ ++ /* This is simple */ ++ while (nbytes > 0) { ++ rtw_secmicappendbyte(pmicdata, *src++); ++ nbytes--; ++ } ++ ++} ++ ++void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst) ++{ ++ ++ /* Append the minimum padding */ ++ rtw_secmicappendbyte(pmicdata, 0x5a); ++ rtw_secmicappendbyte(pmicdata, 0); ++ rtw_secmicappendbyte(pmicdata, 0); ++ rtw_secmicappendbyte(pmicdata, 0); ++ rtw_secmicappendbyte(pmicdata, 0); ++ /* and then zeroes until the length is a multiple of 4 */ ++ while (pmicdata->nBytesInM != 0) ++ rtw_secmicappendbyte(pmicdata, 0); ++ /* The appendByte function has already computed the result. */ ++ secmicputuint32(dst, pmicdata->L); ++ secmicputuint32(dst + 4, pmicdata->R); ++ /* Reset to the empty message. */ ++ secmicclear(pmicdata); ++ ++} ++ ++void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri) ++{ ++ struct mic_data micdata; ++ u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; ++ ++ rtw_secmicsetkey(&micdata, key); ++ priority[0] = pri; ++ ++ /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ ++ if (header[1] & 1) { /* ToDS == 1 */ ++ rtw_secmicappend(&micdata, &header[16], 6); /* DA */ ++ if (header[1] & 2) /* From Ds == 1 */ ++ rtw_secmicappend(&micdata, &header[24], 6); ++ else ++ rtw_secmicappend(&micdata, &header[10], 6); ++ } else { /* ToDS == 0 */ ++ rtw_secmicappend(&micdata, &header[4], 6); /* DA */ ++ if (header[1] & 2) /* From Ds == 1 */ ++ rtw_secmicappend(&micdata, &header[16], 6); ++ else ++ rtw_secmicappend(&micdata, &header[10], 6); ++ } ++ rtw_secmicappend(&micdata, &priority[0], 4); ++ ++ rtw_secmicappend(&micdata, data, data_len); ++ ++ rtw_secgetmic(&micdata, mic_code); ++ ++} ++ ++/* macros for extraction/creation of unsigned char/unsigned short values */ ++#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) ++#define Lo8(v16) ((u8)((v16) & 0x00FF)) ++#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF)) ++#define Lo16(v32) ((u16)((v32) & 0xFFFF)) ++#define Hi16(v32) ((u16)(((v32) >> 16) & 0xFFFF)) ++#define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8)) ++ ++/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */ ++#define TK16(N) Mk16(tk[2 * (N) + 1], tk[2 * (N)]) ++ ++/* S-box lookup: 16 bits --> 16 bits */ ++#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)]) ++ ++/* fixed algorithm "parameters" */ ++#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ ++#define TA_SIZE 6 /* 48-bit transmitter address */ ++#define TK_SIZE 16 /* 128-bit temporal key */ ++#define P1K_SIZE 10 /* 80-bit Phase1 key */ ++#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ ++ ++/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */ ++static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM) */ ++{ ++ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, ++ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, ++ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, ++ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, ++ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, ++ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, ++ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, ++ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, ++ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, ++ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, ++ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, ++ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, ++ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, ++ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, ++ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, ++ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, ++ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, ++ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, ++ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, ++ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, ++ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, ++ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, ++ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, ++ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, ++ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, ++ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, ++ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, ++ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, ++ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, ++ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, ++ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, ++ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, ++ }, ++ ++ { /* second half of table is unsigned char-reversed version of first! */ ++ 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, ++ 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, ++ 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, ++ 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, ++ 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83, ++ 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A, ++ 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F, ++ 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA, ++ 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, ++ 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, ++ 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, ++ 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, ++ 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, ++ 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B, ++ 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1, ++ 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF, ++ 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E, ++ 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, ++ 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, ++ 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, ++ 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, ++ 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, ++ 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049, ++ 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810, ++ 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197, ++ 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F, ++ 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, ++ 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, ++ 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, ++ 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, ++ 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, ++ 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C, ++ } ++}; ++ ++ /* ++********************************************************************** ++* Routine: Phase 1 -- generate P1K, given TA, TK, IV32 ++* ++* Inputs: ++* tk[] = temporal key [128 bits] ++* ta[] = transmitter's MAC address [ 48 bits] ++* iv32 = upper 32 bits of IV [ 32 bits] ++* Output: ++* p1k[] = Phase 1 key [ 80 bits] ++* ++* Note: ++* This function only needs to be called every 2**16 packets, ++* although in theory it could be called every packet. ++* ++********************************************************************** ++*/ ++static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) ++{ ++ int i; ++ ++ /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ ++ p1k[0] = Lo16(iv32); ++ p1k[1] = Hi16(iv32); ++ p1k[2] = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */ ++ p1k[3] = Mk16(ta[3], ta[2]); ++ p1k[4] = Mk16(ta[5], ta[4]); ++ ++ /* Now compute an unbalanced Feistel cipher with 80-bit block */ ++ /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ ++ for (i = 0; i < PHASE1_LOOP_CNT; i++) { /* Each add operation here is mod 2**16 */ ++ p1k[0] += _S_(p1k[4] ^ TK16((i & 1) + 0)); ++ p1k[1] += _S_(p1k[0] ^ TK16((i & 1) + 2)); ++ p1k[2] += _S_(p1k[1] ^ TK16((i & 1) + 4)); ++ p1k[3] += _S_(p1k[2] ^ TK16((i & 1) + 6)); ++ p1k[4] += _S_(p1k[3] ^ TK16((i & 1) + 0)); ++ p1k[4] += (unsigned short)i; /* avoid "slide attacks" */ ++ } ++ ++} ++ ++/* ++********************************************************************** ++* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 ++* ++* Inputs: ++* tk[] = Temporal key [128 bits] ++* p1k[] = Phase 1 output key [ 80 bits] ++* iv16 = low 16 bits of IV counter [ 16 bits] ++* Output: ++* rc4key[] = the key used to encrypt the packet [128 bits] ++* ++* Note: ++* The value {TA, IV32, IV16} for Phase1/Phase2 must be unique ++* across all packets using the same key TK value. Then, for a ++* given value of TK[], this TKIP48 construction guarantees that ++* the final RC4KEY value is unique across all packets. ++* ++* Suggested implementation optimization: if PPK[] is "overlaid" ++* appropriately on RC4KEY[], there is no need for the final ++* for loop below that copies the PPK[] result into RC4KEY[]. ++* ++********************************************************************** ++*/ ++static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) ++{ ++ int i; ++ u16 PPK[6]; /* temporary key for mixing */ ++ ++ /* Note: all adds in the PPK[] equations below are mod 2**16 */ ++ for (i = 0; i < 5; i++) ++ PPK[i] = p1k[i]; /* first, copy P1K to PPK */ ++ PPK[5] = p1k[4] + iv16; /* next, add in IV16 */ ++ ++ /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ ++ PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ ++ PPK[1] += _S_(PPK[0] ^ TK16(1)); ++ PPK[2] += _S_(PPK[1] ^ TK16(2)); ++ PPK[3] += _S_(PPK[2] ^ TK16(3)); ++ PPK[4] += _S_(PPK[3] ^ TK16(4)); ++ PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ ++ ++ /* Final sweep: bijective, "linear". Rotates kill LSB correlations */ ++ PPK[0] += RotR1(PPK[5] ^ TK16(6)); ++ PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ ++ PPK[2] += RotR1(PPK[1]); ++ PPK[3] += RotR1(PPK[2]); ++ PPK[4] += RotR1(PPK[3]); ++ PPK[5] += RotR1(PPK[4]); ++ /* Note: At this point, for a given key TK[0..15], the 96-bit output */ ++ /* value PPK[0..5] is guaranteed to be unique, as a function */ ++ /* of the 96-bit "input" value {TA, IV32, IV16}. That is, P1K */ ++ /* is now a keyed permutation of {TA, IV32, IV16}. */ ++ ++ /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */ ++ rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */ ++ rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */ ++ rc4key[2] = Lo8(iv16); ++ rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); ++ ++ /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ ++ for (i = 0; i < 6; i++) { ++ rc4key[4 + 2 * i] = Lo8(PPK[i]); ++ rc4key[5 + 2 * i] = Hi8(PPK[i]); ++ } ++ ++} ++ ++/* The hlen isn't include the IV */ ++u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) ++{ /* exclude ICV */ ++ u16 pnl; ++ u32 pnh; ++ u8 rc4key[16]; ++ u8 ttkey[16]; ++ union { ++ __le32 f0; ++ u8 f1[4]; ++ } crc; ++ u8 hw_hdr_offset = 0; ++ struct arc4context mycontext; ++ int curfragnum, length; ++ ++ u8 *pframe, *payload, *iv, *prwskey; ++ union pn48 dot11txpn; ++ struct sta_info *stainfo; ++ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ u32 res = _SUCCESS; ++ ++ if (!((struct xmit_frame *)pxmitframe)->buf_addr) ++ return _FAIL; ++ ++ hw_hdr_offset = TXDESC_SIZE + ++ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); ++ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; ++ /* 4 start to encrypt each fragment */ ++ if (pattrib->encrypt == _TKIP_) { ++ if (pattrib->psta) ++ stainfo = pattrib->psta; ++ else ++ stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]); ++ ++ if (stainfo) { ++ if (is_multicast_ether_addr(pattrib->ra)) ++ prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; ++ else ++ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; ++ ++ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { ++ iv = pframe + pattrib->hdrlen; ++ payload = pframe + pattrib->iv_len + pattrib->hdrlen; ++ ++ GET_TKIP_PN(iv, dot11txpn); ++ ++ pnl = (u16)(dot11txpn.val); ++ pnh = (u32)(dot11txpn.val >> 16); ++ phase1((u16 *)&ttkey[0], prwskey, &pattrib->ta[0], pnh); ++ phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl); ++ ++ if ((curfragnum + 1) == pattrib->nr_frags) { /* 4 the last fragment */ ++ length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; ++ crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length)); ++ ++ arcfour_init(&mycontext, rc4key, 16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload + length, crc.f1, 4); ++ } else { ++ length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; ++ crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length)); ++ ++ arcfour_init(&mycontext, rc4key, 16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ arcfour_encrypt(&mycontext, payload + length, crc.f1, 4); ++ ++ pframe += pxmitpriv->frag_len; ++ pframe = (u8 *)RND4((size_t)(pframe)); ++ } ++ } ++ } else { ++ res = _FAIL; ++ } ++ } ++ ++ return res; ++} ++ ++/* The hlen isn't include the IV */ ++u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) ++{ /* exclude ICV */ ++ u16 pnl; ++ u32 pnh; ++ u8 rc4key[16]; ++ u8 ttkey[16]; ++ union { ++ __le32 f0; ++ u8 f1[4]; ++ } crc; ++ struct arc4context mycontext; ++ int length; ++ ++ u8 *pframe, *payload, *iv, *prwskey; ++ union pn48 dot11txpn; ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u32 res = _SUCCESS; ++ ++ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data; ++ ++ /* 4 start to decrypt recvframe */ ++ if (prxattrib->encrypt == _TKIP_) { ++ stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); ++ if (stainfo) { ++ if (is_multicast_ether_addr(prxattrib->ra)) { ++ if (!psecuritypriv->binstallGrpkey) { ++ res = _FAIL; ++ DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); ++ goto exit; ++ } ++ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; ++ } else { ++ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; ++ } ++ ++ iv = pframe + prxattrib->hdrlen; ++ payload = pframe + prxattrib->iv_len + prxattrib->hdrlen; ++ length = ((struct recv_frame *)precvframe)->len - prxattrib->hdrlen - prxattrib->iv_len; ++ ++ GET_TKIP_PN(iv, dot11txpn); ++ ++ pnl = (u16)(dot11txpn.val); ++ pnh = (u32)(dot11txpn.val >> 16); ++ ++ phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh); ++ phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl); ++ ++ /* 4 decrypt payload include icv */ ++ ++ arcfour_init(&mycontext, rc4key, 16); ++ arcfour_encrypt(&mycontext, payload, payload, length); ++ ++ crc.f0 = cpu_to_le32(~crc32_le(~0, payload, length)); ++ ++ if (crc.f1[3] != payload[length - 1] || ++ crc.f1[2] != payload[length - 2] || ++ crc.f1[1] != payload[length - 3] || ++ crc.f1[0] != payload[length - 4]) ++ res = _FAIL; ++ } else { ++ res = _FAIL; ++ } ++ } ++ ++exit: ++ return res; ++} ++ ++/* 3 ===== AES related ===== */ ++ ++#define MAX_MSG_SIZE 2048 ++/*****************************/ ++/******** SBOX Table *********/ ++/*****************************/ ++ ++static u8 sbox_table[256] = { ++ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, ++ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, ++ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, ++ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, ++ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, ++ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, ++ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, ++ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, ++ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, ++ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, ++ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, ++ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, ++ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, ++ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, ++ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, ++ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, ++ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, ++ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, ++ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, ++ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, ++ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, ++ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, ++ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, ++ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, ++ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, ++ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, ++ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, ++ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, ++ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, ++ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, ++ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, ++ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ++}; ++ ++/*****************************/ ++/**** Function Prototypes ****/ ++/*****************************/ ++ ++static void bitwise_xor(u8 *ina, u8 *inb, u8 *out); ++static void construct_mic_iv(u8 *mic_header1, int qc_exists, int a4_exists, u8 *mpdu, uint payload_length, u8 *pn_vector); ++static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu); ++static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists); ++static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c); ++static void xor_128(u8 *a, u8 *b, u8 *out); ++static void xor_32(u8 *a, u8 *b, u8 *out); ++static u8 sbox(u8 a); ++static void next_key(u8 *key, int round); ++static void byte_sub(u8 *in, u8 *out); ++static void shift_row(u8 *in, u8 *out); ++static void mix_column(u8 *in, u8 *out); ++static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext); ++ ++/****************************************/ ++/* aes128k128d() */ ++/* Performs a 128 bit AES encrypt with */ ++/* 128 bit data. */ ++/****************************************/ ++static void xor_128(u8 *a, u8 *b, u8 *out) ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) ++ out[i] = a[i] ^ b[i]; ++ ++} ++ ++static void xor_32(u8 *a, u8 *b, u8 *out) ++{ ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ out[i] = a[i] ^ b[i]; ++ ++} ++ ++static u8 sbox(u8 a) ++{ ++ return sbox_table[(int)a]; ++} ++ ++static void next_key(u8 *key, int round) ++{ ++ u8 rcon; ++ u8 sbox_key[4]; ++ u8 rcon_table[12] = { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, ++ 0x1b, 0x36, 0x36, 0x36 ++ }; ++ ++ sbox_key[0] = sbox(key[13]); ++ sbox_key[1] = sbox(key[14]); ++ sbox_key[2] = sbox(key[15]); ++ sbox_key[3] = sbox(key[12]); ++ ++ rcon = rcon_table[round]; ++ ++ xor_32(&key[0], sbox_key, &key[0]); ++ key[0] = key[0] ^ rcon; ++ ++ xor_32(&key[4], &key[0], &key[4]); ++ xor_32(&key[8], &key[4], &key[8]); ++ xor_32(&key[12], &key[8], &key[12]); ++ ++} ++ ++static void byte_sub(u8 *in, u8 *out) ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) ++ out[i] = sbox(in[i]); ++ ++} ++ ++static void shift_row(u8 *in, u8 *out) ++{ ++ ++ out[0] = in[0]; ++ out[1] = in[5]; ++ out[2] = in[10]; ++ out[3] = in[15]; ++ out[4] = in[4]; ++ out[5] = in[9]; ++ out[6] = in[14]; ++ out[7] = in[3]; ++ out[8] = in[8]; ++ out[9] = in[13]; ++ out[10] = in[2]; ++ out[11] = in[7]; ++ out[12] = in[12]; ++ out[13] = in[1]; ++ out[14] = in[6]; ++ out[15] = in[11]; ++ ++} ++ ++static void mix_column(u8 *in, u8 *out) ++{ ++ int i; ++ u8 add1b[4]; ++ u8 add1bf7[4]; ++ u8 rotl[4]; ++ u8 swap_halfs[4]; ++ u8 andf7[4]; ++ u8 rotr[4]; ++ u8 temp[4]; ++ u8 tempb[4]; ++ ++ for (i = 0 ; i < 4; i++) { ++ if ((in[i] & 0x80) == 0x80) ++ add1b[i] = 0x1b; ++ else ++ add1b[i] = 0x00; ++ } ++ ++ swap_halfs[0] = in[2]; /* Swap halves */ ++ swap_halfs[1] = in[3]; ++ swap_halfs[2] = in[0]; ++ swap_halfs[3] = in[1]; ++ ++ rotl[0] = in[3]; /* Rotate left 8 bits */ ++ rotl[1] = in[0]; ++ rotl[2] = in[1]; ++ rotl[3] = in[2]; ++ ++ andf7[0] = in[0] & 0x7f; ++ andf7[1] = in[1] & 0x7f; ++ andf7[2] = in[2] & 0x7f; ++ andf7[3] = in[3] & 0x7f; ++ ++ for (i = 3; i > 0; i--) { /* logical shift left 1 bit */ ++ andf7[i] = andf7[i] << 1; ++ if ((andf7[i - 1] & 0x80) == 0x80) ++ andf7[i] = (andf7[i] | 0x01); ++ } ++ andf7[0] = andf7[0] << 1; ++ andf7[0] = andf7[0] & 0xfe; ++ ++ xor_32(add1b, andf7, add1bf7); ++ ++ xor_32(in, add1bf7, rotr); ++ ++ temp[0] = rotr[0]; /* Rotate right 8 bits */ ++ rotr[0] = rotr[1]; ++ rotr[1] = rotr[2]; ++ rotr[2] = rotr[3]; ++ rotr[3] = temp[0]; ++ ++ xor_32(add1bf7, rotr, temp); ++ xor_32(swap_halfs, rotl, tempb); ++ xor_32(temp, tempb, out); ++ ++} ++ ++static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) ++{ ++ int round; ++ int i; ++ u8 intermediatea[16]; ++ u8 intermediateb[16]; ++ u8 round_key[16]; ++ ++ for (i = 0; i < 16; i++) ++ round_key[i] = key[i]; ++ for (round = 0; round < 11; round++) { ++ if (round == 0) { ++ xor_128(round_key, data, ciphertext); ++ next_key(round_key, round); ++ } else if (round == 10) { ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ xor_128(intermediateb, round_key, ciphertext); ++ } else { /* 1 - 9 */ ++ byte_sub(ciphertext, intermediatea); ++ shift_row(intermediatea, intermediateb); ++ mix_column(&intermediateb[0], &intermediatea[0]); ++ mix_column(&intermediateb[4], &intermediatea[4]); ++ mix_column(&intermediateb[8], &intermediatea[8]); ++ mix_column(&intermediateb[12], &intermediatea[12]); ++ xor_128(intermediatea, round_key, ciphertext); ++ next_key(round_key, round); ++ } ++ } ++ ++} ++ ++/************************************************/ ++/* construct_mic_iv() */ ++/* Builds the MIC IV from header fields and PN */ ++/************************************************/ ++static void construct_mic_iv(u8 *mic_iv, int qc_exists, int a4_exists, u8 *mpdu, ++ uint payload_length, u8 *pn_vector) ++{ ++ int i; ++ ++ mic_iv[0] = 0x59; ++ if (qc_exists && a4_exists) ++ mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ ++ if (qc_exists && !a4_exists) ++ mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ ++ if (!qc_exists) ++ mic_iv[1] = 0x00; ++ for (i = 2; i < 8; i++) ++ mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ ++ for (i = 8; i < 14; i++) ++ mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ ++ mic_iv[14] = (unsigned char)(payload_length / 256); ++ mic_iv[15] = (unsigned char)(payload_length % 256); ++ ++} ++ ++/************************************************/ ++/* construct_mic_header1() */ ++/* Builds the first MIC header block from */ ++/* header fields. */ ++/************************************************/ ++static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu) ++{ ++ ++ mic_header1[0] = (u8)((header_length - 2) / 256); ++ mic_header1[1] = (u8)((header_length - 2) % 256); ++ mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ ++ mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ ++ mic_header1[4] = mpdu[4]; /* A1 */ ++ mic_header1[5] = mpdu[5]; ++ mic_header1[6] = mpdu[6]; ++ mic_header1[7] = mpdu[7]; ++ mic_header1[8] = mpdu[8]; ++ mic_header1[9] = mpdu[9]; ++ mic_header1[10] = mpdu[10]; /* A2 */ ++ mic_header1[11] = mpdu[11]; ++ mic_header1[12] = mpdu[12]; ++ mic_header1[13] = mpdu[13]; ++ mic_header1[14] = mpdu[14]; ++ mic_header1[15] = mpdu[15]; ++ ++} ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/************************************************/ ++static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists) ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) ++ mic_header2[i] = 0x00; ++ ++ mic_header2[0] = mpdu[16]; /* A3 */ ++ mic_header2[1] = mpdu[17]; ++ mic_header2[2] = mpdu[18]; ++ mic_header2[3] = mpdu[19]; ++ mic_header2[4] = mpdu[20]; ++ mic_header2[5] = mpdu[21]; ++ ++ mic_header2[6] = 0x00; ++ mic_header2[7] = 0x00; /* mpdu[23]; */ ++ ++ if (!qc_exists && a4_exists) { ++ for (i = 0; i < 6; i++) ++ mic_header2[8 + i] = mpdu[24 + i]; /* A4 */ ++ } ++ ++ if (qc_exists && !a4_exists) { ++ mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ ++ mic_header2[9] = mpdu[25] & 0x00; ++ } ++ ++ if (qc_exists && a4_exists) { ++ for (i = 0; i < 6; i++) ++ mic_header2[8 + i] = mpdu[24 + i]; /* A4 */ ++ ++ mic_header2[14] = mpdu[30] & 0x0f; ++ mic_header2[15] = mpdu[31] & 0x00; ++ } ++ ++} ++ ++/************************************************/ ++/* construct_mic_header2() */ ++/* Builds the last MIC header block from */ ++/* header fields. */ ++/************************************************/ ++static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c) ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) ++ ctr_preload[i] = 0x00; ++ i = 0; ++ ++ ctr_preload[0] = 0x01; /* flag */ ++ if (qc_exists && a4_exists) ++ ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ ++ if (qc_exists && !a4_exists) ++ ctr_preload[1] = mpdu[24] & 0x0f; ++ ++ for (i = 2; i < 8; i++) ++ ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ ++ for (i = 8; i < 14; i++) ++ ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ ++ ctr_preload[14] = (unsigned char)(c / 256); /* Ctr */ ++ ctr_preload[15] = (unsigned char)(c % 256); ++ ++} ++ ++/************************************/ ++/* bitwise_xor() */ ++/* A 128 bit, bitwise exclusive or */ ++/************************************/ ++static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) ++ out[i] = ina[i] ^ inb[i]; ++ ++} ++ ++static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen) ++{ ++ uint qc_exists, a4_exists, i, j, payload_remainder, ++ num_blocks, payload_index; ++ ++ u8 pn_vector[6]; ++ u8 mic_iv[16]; ++ u8 mic_header1[16]; ++ u8 mic_header2[16]; ++ u8 ctr_preload[16]; ++ ++ /* Intermediate Buffers */ ++ u8 chain_buffer[16]; ++ u8 aes_out[16]; ++ u8 padded_buffer[16]; ++ u8 mic[8]; ++ uint frtype = GetFrameType(pframe); ++ uint frsubtype = GetFrameSubType(pframe); ++ ++ frsubtype = frsubtype >> 4; ++ ++ memset((void *)mic_iv, 0, 16); ++ memset((void *)mic_header1, 0, 16); ++ memset((void *)mic_header2, 0, 16); ++ memset((void *)ctr_preload, 0, 16); ++ memset((void *)chain_buffer, 0, 16); ++ memset((void *)aes_out, 0, 16); ++ memset((void *)padded_buffer, 0, 16); ++ ++ if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) ++ a4_exists = 0; ++ else ++ a4_exists = 1; ++ ++ if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) || (frtype == WIFI_DATA_CFACKPOLL)) { ++ qc_exists = 1; ++ if (hdrlen != WLAN_HDR_A3_QOS_LEN) ++ hdrlen += 2; ++ } else if ((frsubtype == 0x08) || (frsubtype == 0x09) || (frsubtype == 0x0a) || (frsubtype == 0x0b)) { ++ if (hdrlen != WLAN_HDR_A3_QOS_LEN) ++ hdrlen += 2; ++ qc_exists = 1; ++ } else { ++ qc_exists = 0; ++ } ++ ++ pn_vector[0] = pframe[hdrlen]; ++ pn_vector[1] = pframe[hdrlen + 1]; ++ pn_vector[2] = pframe[hdrlen + 4]; ++ pn_vector[3] = pframe[hdrlen + 5]; ++ pn_vector[4] = pframe[hdrlen + 6]; ++ pn_vector[5] = pframe[hdrlen + 7]; ++ ++ construct_mic_iv(mic_iv, qc_exists, a4_exists, pframe, plen, pn_vector); ++ ++ construct_mic_header1(mic_header1, hdrlen, pframe); ++ construct_mic_header2(mic_header2, pframe, a4_exists, qc_exists); ++ ++ payload_remainder = plen % 16; ++ num_blocks = plen / 16; ++ ++ /* Find start of payload */ ++ payload_index = (hdrlen + 8); ++ ++ /* Calculate MIC */ ++ aes128k128d(key, mic_iv, aes_out); ++ bitwise_xor(aes_out, mic_header1, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ bitwise_xor(aes_out, mic_header2, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ ++ for (i = 0; i < num_blocks; i++) { ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */ ++ ++ payload_index += 16; ++ aes128k128d(key, chain_buffer, aes_out); ++ } ++ ++ /* Add on the final payload block if it needs padding */ ++ if (payload_remainder > 0) { ++ for (j = 0; j < 16; j++) ++ padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ padded_buffer[j] = pframe[payload_index++];/* padded_buffer[j] = message[payload_index++]; */ ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ } ++ ++ for (j = 0; j < 8; j++) ++ mic[j] = aes_out[j]; ++ ++ /* Insert MIC into payload */ ++ for (j = 0; j < 8; j++) ++ pframe[payload_index + j] = mic[j]; /* message[payload_index+j] = mic[j]; */ ++ ++ payload_index = hdrlen + 8; ++ for (i = 0; i < num_blocks; i++) { ++ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i + 1); ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); ++ for (j = 0; j < 16; j++) ++ pframe[payload_index++] = chain_buffer[j]; ++ } ++ ++ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ ++ /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks + 1); ++ ++ for (j = 0; j < 16; j++) ++ padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ padded_buffer[j] = pframe[payload_index + j]; ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j = 0; j < payload_remainder; j++) ++ pframe[payload_index++] = chain_buffer[j]; ++ } ++ /* Encrypt the MIC */ ++ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, 0); ++ ++ for (j = 0; j < 16; j++) ++ padded_buffer[j] = 0x00; ++ for (j = 0; j < 8; j++) ++ padded_buffer[j] = pframe[j + hdrlen + 8 + plen]; ++ ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j = 0; j < 8; j++) ++ pframe[payload_index++] = chain_buffer[j]; ++ ++ return _SUCCESS; ++} ++ ++u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) ++{ /* exclude ICV */ ++ ++ /*static*/ ++/* unsigned char message[MAX_MSG_SIZE]; */ ++ ++ /* Intermediate Buffers */ ++ int curfragnum, length; ++ u8 *pframe, *prwskey; /* *payload,*iv */ ++ u8 hw_hdr_offset = 0; ++ struct sta_info *stainfo; ++ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++/* uint offset = 0; */ ++ u32 res = _SUCCESS; ++ ++ if (!((struct xmit_frame *)pxmitframe)->buf_addr) ++ return _FAIL; ++ ++ hw_hdr_offset = TXDESC_SIZE + ++ (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); ++ ++ pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; ++ ++ /* 4 start to encrypt each fragment */ ++ if (pattrib->encrypt == _AES_) { ++ if (pattrib->psta) ++ stainfo = pattrib->psta; ++ else ++ stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]); ++ ++ if (stainfo) { ++ if (is_multicast_ether_addr(pattrib->ra)) ++ prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; ++ else ++ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; ++ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { ++ if ((curfragnum + 1) == pattrib->nr_frags) { /* 4 the last fragment */ ++ length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; ++ ++ aes_cipher(prwskey, pattrib->hdrlen, pframe, length); ++ } else { ++ length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; ++ ++ aes_cipher(prwskey, pattrib->hdrlen, pframe, length); ++ pframe += pxmitpriv->frag_len; ++ pframe = (u8 *)RND4((size_t)(pframe)); ++ } ++ } ++ } else { ++ res = _FAIL; ++ } ++ } ++ ++ return res; ++} ++ ++static int aes_decipher(u8 *key, uint hdrlen, ++ u8 *pframe, uint plen) ++{ ++ static u8 message[MAX_MSG_SIZE]; ++ uint qc_exists, a4_exists, i, j, payload_remainder, ++ num_blocks, payload_index; ++ int res = _SUCCESS; ++ u8 pn_vector[6]; ++ u8 mic_iv[16]; ++ u8 mic_header1[16]; ++ u8 mic_header2[16]; ++ u8 ctr_preload[16]; ++ ++ /* Intermediate Buffers */ ++ u8 chain_buffer[16]; ++ u8 aes_out[16]; ++ u8 padded_buffer[16]; ++ u8 mic[8]; ++ ++/* uint offset = 0; */ ++ uint frtype = GetFrameType(pframe); ++ uint frsubtype = GetFrameSubType(pframe); ++ ++ frsubtype = frsubtype >> 4; ++ ++ memset((void *)mic_iv, 0, 16); ++ memset((void *)mic_header1, 0, 16); ++ memset((void *)mic_header2, 0, 16); ++ memset((void *)ctr_preload, 0, 16); ++ memset((void *)chain_buffer, 0, 16); ++ memset((void *)aes_out, 0, 16); ++ memset((void *)padded_buffer, 0, 16); ++ ++ /* start to decrypt the payload */ ++ ++ num_blocks = (plen - 8) / 16; /* plen including llc, payload_length and mic) */ ++ ++ payload_remainder = (plen - 8) % 16; ++ ++ pn_vector[0] = pframe[hdrlen]; ++ pn_vector[1] = pframe[hdrlen + 1]; ++ pn_vector[2] = pframe[hdrlen + 4]; ++ pn_vector[3] = pframe[hdrlen + 5]; ++ pn_vector[4] = pframe[hdrlen + 6]; ++ pn_vector[5] = pframe[hdrlen + 7]; ++ ++ if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) ++ a4_exists = 0; ++ else ++ a4_exists = 1; ++ ++ if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) || ++ (frtype == WIFI_DATA_CFACKPOLL)) { ++ qc_exists = 1; ++ if (hdrlen != WLAN_HDR_A3_QOS_LEN) ++ hdrlen += 2; ++ } else if ((frsubtype == 0x08) || (frsubtype == 0x09) || ++ (frsubtype == 0x0a) || (frsubtype == 0x0b)) { ++ if (hdrlen != WLAN_HDR_A3_QOS_LEN) ++ hdrlen += 2; ++ qc_exists = 1; ++ } else { ++ qc_exists = 0; ++ } ++ ++ /* now, decrypt pframe with hdrlen offset and plen long */ ++ ++ payload_index = hdrlen + 8; /* 8 is for extiv */ ++ ++ for (i = 0; i < num_blocks; i++) { ++ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i + 1); ++ ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); ++ ++ for (j = 0; j < 16; j++) ++ pframe[payload_index++] = chain_buffer[j]; ++ } ++ ++ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ ++ /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks + 1); ++ ++ for (j = 0; j < 16; j++) ++ padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ padded_buffer[j] = pframe[payload_index + j]; ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j = 0; j < payload_remainder; j++) ++ pframe[payload_index++] = chain_buffer[j]; ++ } ++ ++ /* start to calculate the mic */ ++ if ((hdrlen + plen + 8) <= MAX_MSG_SIZE) ++ memcpy(message, pframe, (hdrlen + plen + 8)); /* 8 is for ext iv len */ ++ ++ pn_vector[0] = pframe[hdrlen]; ++ pn_vector[1] = pframe[hdrlen + 1]; ++ pn_vector[2] = pframe[hdrlen + 4]; ++ pn_vector[3] = pframe[hdrlen + 5]; ++ pn_vector[4] = pframe[hdrlen + 6]; ++ pn_vector[5] = pframe[hdrlen + 7]; ++ construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen - 8, pn_vector); ++ ++ construct_mic_header1(mic_header1, hdrlen, message); ++ construct_mic_header2(mic_header2, message, a4_exists, qc_exists); ++ ++ payload_remainder = (plen - 8) % 16; ++ num_blocks = (plen - 8) / 16; ++ ++ /* Find start of payload */ ++ payload_index = (hdrlen + 8); ++ ++ /* Calculate MIC */ ++ aes128k128d(key, mic_iv, aes_out); ++ bitwise_xor(aes_out, mic_header1, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ bitwise_xor(aes_out, mic_header2, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ ++ for (i = 0; i < num_blocks; i++) { ++ bitwise_xor(aes_out, &message[payload_index], chain_buffer); ++ ++ payload_index += 16; ++ aes128k128d(key, chain_buffer, aes_out); ++ } ++ ++ /* Add on the final payload block if it needs padding */ ++ if (payload_remainder > 0) { ++ for (j = 0; j < 16; j++) ++ padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ padded_buffer[j] = message[payload_index++]; ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ aes128k128d(key, chain_buffer, aes_out); ++ } ++ ++ for (j = 0 ; j < 8; j++) ++ mic[j] = aes_out[j]; ++ ++ /* Insert MIC into payload */ ++ for (j = 0; j < 8; j++) ++ message[payload_index + j] = mic[j]; ++ ++ payload_index = hdrlen + 8; ++ for (i = 0; i < num_blocks; i++) { ++ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i + 1); ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, &message[payload_index], chain_buffer); ++ for (j = 0; j < 16; j++) ++ message[payload_index++] = chain_buffer[j]; ++ } ++ ++ if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ ++ /* encrypt it and copy the unpadded part back */ ++ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, num_blocks + 1); ++ ++ for (j = 0; j < 16; j++) ++ padded_buffer[j] = 0x00; ++ for (j = 0; j < payload_remainder; j++) ++ padded_buffer[j] = message[payload_index + j]; ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j = 0; j < payload_remainder; j++) ++ message[payload_index++] = chain_buffer[j]; ++ } ++ ++ /* Encrypt the MIC */ ++ construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0); ++ ++ for (j = 0; j < 16; j++) ++ padded_buffer[j] = 0x00; ++ for (j = 0; j < 8; j++) ++ padded_buffer[j] = message[j + hdrlen + 8 + plen - 8]; ++ ++ aes128k128d(key, ctr_preload, aes_out); ++ bitwise_xor(aes_out, padded_buffer, chain_buffer); ++ for (j = 0; j < 8; j++) ++ message[payload_index++] = chain_buffer[j]; ++ ++ /* compare the mic */ ++ for (i = 0; i < 8; i++) { ++ if (pframe[hdrlen + 8 + plen - 8 + i] != message[hdrlen + 8 + plen - 8 + i]) { ++ DBG_88E("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n", ++ i, pframe[hdrlen + 8 + plen - 8 + i], message[hdrlen + 8 + plen - 8 + i]); ++ res = _FAIL; ++ } ++ } ++ ++ return res; ++} ++ ++u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) ++{ /* exclude ICV */ ++ /* Intermediate Buffers */ ++ int length; ++ u8 *pframe, *prwskey; /* *payload,*iv */ ++ struct sta_info *stainfo; ++ struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u32 res = _SUCCESS; ++ ++ pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data; ++ /* 4 start to encrypt each fragment */ ++ if (prxattrib->encrypt == _AES_) { ++ stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); ++ if (stainfo) { ++ if (is_multicast_ether_addr(prxattrib->ra)) { ++ /* in concurrent we should use sw descrypt in group key, so we remove this message */ ++ if (!psecuritypriv->binstallGrpkey) { ++ res = _FAIL; ++ DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); ++ goto exit; ++ } ++ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; ++ if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) { ++ DBG_88E("not match packet_index=%d, install_index=%d\n", ++ prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid); ++ res = _FAIL; ++ goto exit; ++ } ++ } else { ++ prwskey = &stainfo->dot118021x_UncstKey.skey[0]; ++ } ++ length = ((struct recv_frame *)precvframe)->len - prxattrib->hdrlen - prxattrib->iv_len; ++ res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); ++ } else { ++ res = _FAIL; ++ } ++ } ++ ++exit: ++ return res; ++} ++ ++/* AES tables*/ ++const u32 Te0[256] = { ++ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, ++ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, ++ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, ++ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, ++ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, ++ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, ++ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, ++ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, ++ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, ++ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, ++ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, ++ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, ++ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, ++ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, ++ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, ++ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, ++ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, ++ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, ++ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, ++ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, ++ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, ++ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, ++ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, ++ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, ++ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, ++ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, ++ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, ++ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, ++ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, ++ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, ++ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, ++ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, ++ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, ++ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, ++ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, ++ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, ++ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, ++ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, ++ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, ++ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, ++ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, ++ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, ++ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, ++ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, ++ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, ++ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, ++ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, ++ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, ++ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, ++ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, ++ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, ++ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, ++ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, ++ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, ++ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, ++ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, ++ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, ++ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, ++ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, ++ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, ++ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, ++ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, ++ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, ++ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, ++}; ++ ++const u32 Td0[256] = { ++ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, ++ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, ++ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, ++ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, ++ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, ++ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, ++ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, ++ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, ++ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, ++ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, ++ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, ++ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, ++ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, ++ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, ++ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, ++ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, ++ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, ++ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, ++ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, ++ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, ++ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, ++ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, ++ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, ++ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, ++ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, ++ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, ++ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, ++ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, ++ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, ++ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, ++ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, ++ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, ++ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, ++ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, ++ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, ++ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, ++ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, ++ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, ++ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, ++ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, ++ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, ++ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, ++ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, ++ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, ++ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, ++ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, ++ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, ++ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, ++ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, ++ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, ++ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, ++ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, ++ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, ++ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, ++ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, ++ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, ++ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, ++ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, ++ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, ++ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, ++ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, ++ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, ++ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, ++ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, ++}; ++ ++const u8 Td4s[256] = { ++ 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, ++ 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, ++ 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, ++ 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, ++ 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, ++ 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, ++ 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, ++ 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, ++ 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, ++ 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, ++ 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, ++ 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, ++ 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, ++ 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, ++ 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, ++ 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, ++ 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, ++ 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, ++ 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, ++ 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, ++ 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, ++ 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, ++ 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, ++ 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, ++ 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, ++ 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, ++ 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, ++ 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, ++ 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, ++ 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, ++ 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, ++ 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, ++}; ++const u8 rcons[] = { ++ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 ++ /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ ++}; ++ ++/** ++ * Expand the cipher key into the encryption key schedule. ++ * ++ * @return the number of rounds for the given cipher key size. ++ */ ++#define ROUND(i, d, s) \ ++do { \ ++ d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ ++ d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ ++ d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ ++ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]; \ ++} while (0); ++ ++/** ++ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) ++ * @key: 128-bit key for the hash operation ++ * @data: Data buffer for which a MAC is determined ++ * @data_len: Length of data buffer in bytes ++ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) ++ * Returns: 0 on success, -1 on failure ++ * ++ * This is a mode for using block cipher (AES in this case) for authentication. ++ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication ++ * (SP) 800-38B. ++ */ ++void rtw_use_tkipkey_handler(void *FunctionContext) ++{ ++ struct adapter *padapter = (struct adapter *)FunctionContext; ++ ++ padapter->securitypriv.busetkipkey = true; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_sreset.c b/drivers/staging/r8188eu/core/rtw_sreset.c +new file mode 100644 +index 000000000000..c831033d20a9 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_sreset.c +@@ -0,0 +1,62 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#include "../include/rtw_sreset.h" ++ ++void sreset_init_value(struct adapter *padapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ _rtw_mutex_init(&psrtpriv->silentreset_mutex); ++ psrtpriv->silent_reset_inprogress = false; ++ psrtpriv->wifi_error_status = WIFI_STATUS_SUCCESS; ++ psrtpriv->last_tx_time = 0; ++ psrtpriv->last_tx_complete_time = 0; ++} ++void sreset_reset_value(struct adapter *padapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ psrtpriv->silent_reset_inprogress = false; ++ psrtpriv->wifi_error_status = WIFI_STATUS_SUCCESS; ++ psrtpriv->last_tx_time = 0; ++ psrtpriv->last_tx_complete_time = 0; ++} ++ ++u8 sreset_get_wifi_status(struct adapter *padapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ u8 status = WIFI_STATUS_SUCCESS; ++ u32 val32 = 0; ++ ++ if (psrtpriv->silent_reset_inprogress) ++ return status; ++ val32 = rtw_read32(padapter, REG_TXDMA_STATUS); ++ if (val32 == 0xeaeaeaea) { ++ psrtpriv->wifi_error_status = WIFI_IF_NOT_EXIST; ++ } else if (val32 != 0) { ++ DBG_88E("txdmastatu(%x)\n", val32); ++ psrtpriv->wifi_error_status = WIFI_MAC_TXDMA_ERROR; ++ } ++ ++ if (WIFI_STATUS_SUCCESS != psrtpriv->wifi_error_status) { ++ DBG_88E("==>%s error_status(0x%x)\n", __func__, psrtpriv->wifi_error_status); ++ status = (psrtpriv->wifi_error_status & (~(USB_READ_PORT_FAIL | USB_WRITE_PORT_FAIL))); ++ } ++ DBG_88E("==> %s wifi_status(0x%x)\n", __func__, status); ++ ++ /* status restore */ ++ psrtpriv->wifi_error_status = WIFI_STATUS_SUCCESS; ++ ++ return status; ++} ++ ++void sreset_set_wifi_error_status(struct adapter *padapter, u32 status) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ pHalData->srestpriv.wifi_error_status = status; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_sta_mgt.c b/drivers/staging/r8188eu/core/rtw_sta_mgt.c +new file mode 100644 +index 000000000000..f6dffed53a60 +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_sta_mgt.c +@@ -0,0 +1,508 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTW_STA_MGT_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/xmit_osdep.h" ++#include "../include/mlme_osdep.h" ++#include "../include/sta_info.h" ++ ++static void _rtw_init_stainfo(struct sta_info *psta) ++{ ++ ++ memset((u8 *)psta, 0, sizeof(struct sta_info)); ++ ++ spin_lock_init(&psta->lock); ++ INIT_LIST_HEAD(&psta->list); ++ INIT_LIST_HEAD(&psta->hash_list); ++ _rtw_init_queue(&psta->sleep_q); ++ psta->sleepq_len = 0; ++ ++ _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); ++ _rtw_init_sta_recv_priv(&psta->sta_recvpriv); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++ INIT_LIST_HEAD(&psta->asoc_list); ++ ++ INIT_LIST_HEAD(&psta->auth_list); ++ ++ psta->expire_to = 0; ++ ++ psta->flags = 0; ++ ++ psta->capability = 0; ++ ++ psta->bpairwise_key_installed = false; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ psta->nonerp_set = 0; ++ psta->no_short_slot_time_set = 0; ++ psta->no_short_preamble_set = 0; ++ psta->no_ht_gf_set = 0; ++ psta->no_ht_set = 0; ++ psta->ht_20mhz_set = 0; ++#endif ++ ++ psta->under_exist_checking = 0; ++ ++ psta->keep_alive_trycnt = 0; ++ ++#endif /* CONFIG_88EU_AP_MODE */ ++ ++} ++ ++u32 _rtw_init_sta_priv(struct sta_priv *pstapriv) ++{ ++ struct sta_info *psta; ++ s32 i; ++ ++ pstapriv->pallocated_stainfo_buf = vzalloc(sizeof(struct sta_info) * NUM_STA + 4); ++ ++ if (!pstapriv->pallocated_stainfo_buf) ++ return _FAIL; ++ ++ pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - ++ ((size_t)(pstapriv->pallocated_stainfo_buf) & 3); ++ ++ _rtw_init_queue(&pstapriv->free_sta_queue); ++ ++ spin_lock_init(&pstapriv->sta_hash_lock); ++ ++ pstapriv->asoc_sta_count = 0; ++ _rtw_init_queue(&pstapriv->sleep_q); ++ _rtw_init_queue(&pstapriv->wakeup_q); ++ ++ psta = (struct sta_info *)(pstapriv->pstainfo_buf); ++ ++ for (i = 0; i < NUM_STA; i++) { ++ _rtw_init_stainfo(psta); ++ ++ INIT_LIST_HEAD(&pstapriv->sta_hash[i]); ++ ++ list_add_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue)); ++ ++ psta++; ++ } ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++ pstapriv->sta_dz_bitmap = 0; ++ pstapriv->tim_bitmap = 0; ++ ++ INIT_LIST_HEAD(&pstapriv->asoc_list); ++ INIT_LIST_HEAD(&pstapriv->auth_list); ++ spin_lock_init(&pstapriv->asoc_list_lock); ++ spin_lock_init(&pstapriv->auth_list_lock); ++ pstapriv->asoc_list_cnt = 0; ++ pstapriv->auth_list_cnt = 0; ++ ++ pstapriv->auth_to = 3; /* 3*2 = 6 sec */ ++ pstapriv->assoc_to = 3; ++ pstapriv->expire_to = 3; /* 3*2 = 6 sec */ ++ pstapriv->max_num_sta = NUM_STA; ++#endif ++ ++ return _SUCCESS; ++} ++ ++inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta) ++{ ++ int offset = (((u8 *)sta) - stapriv->pstainfo_buf) / sizeof(struct sta_info); ++ ++ if (!stainfo_offset_valid(offset)) ++ DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset); ++ ++ return offset; ++} ++ ++inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset) ++{ ++ if (!stainfo_offset_valid(offset)) ++ DBG_88E("%s invalid offset(%d), out of range!!!", __func__, offset); ++ ++ return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info)); ++} ++ ++u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) ++{ ++ struct list_head *phead, *plist; ++ struct sta_info *psta = NULL; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ int index; ++ ++ if (pstapriv) { ++ /* delete all reordering_ctrl_timer */ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ for (index = 0; index < NUM_STA; index++) { ++ phead = &pstapriv->sta_hash[index]; ++ plist = phead->next; ++ ++ while (phead != plist) { ++ int i; ++ psta = container_of(plist, struct sta_info, hash_list); ++ plist = plist->next; ++ ++ for (i = 0; i < 16; i++) { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); ++ } ++ } ++ } ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ /*===============================*/ ++ ++ if (pstapriv->pallocated_stainfo_buf) ++ vfree(pstapriv->pallocated_stainfo_buf); ++ } ++ ++ return _SUCCESS; ++} ++ ++struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) ++{ ++ s32 index; ++ struct list_head *phash_list; ++ struct sta_info *psta; ++ struct __queue *pfree_sta_queue; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ int i = 0; ++ u16 wRxSeqInitialValue = 0xffff; ++ ++ pfree_sta_queue = &pstapriv->free_sta_queue; ++ ++ spin_lock_bh(&pfree_sta_queue->lock); ++ ++ if (list_empty(&pfree_sta_queue->queue)) { ++ spin_unlock_bh(&pfree_sta_queue->lock); ++ psta = NULL; ++ } else { ++ psta = container_of((&pfree_sta_queue->queue)->next, struct sta_info, list); ++ list_del_init(&psta->list); ++ spin_unlock_bh(&pfree_sta_queue->lock); ++ _rtw_init_stainfo(psta); ++ memcpy(psta->hwaddr, hwaddr, ETH_ALEN); ++ index = wifi_mac_hash(hwaddr); ++ if (index >= NUM_STA) { ++ psta = NULL; ++ goto exit; ++ } ++ phash_list = &pstapriv->sta_hash[index]; ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ list_add_tail(&psta->hash_list, phash_list); ++ ++ pstapriv->asoc_sta_count++; ++ ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++/* Commented by Albert 2009/08/13 */ ++/* For the SMC router, the sequence number of first packet of WPS handshake will be 0. */ ++/* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */ ++/* So, we initialize the tid_rxseq variable as the 0xffff. */ ++ ++ for (i = 0; i < 16; i++) ++ memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); ++ ++ init_addba_retry_timer(pstapriv->padapter, psta); ++ ++ /* for A-MPDU Rx reordering buffer control */ ++ for (i = 0; i < 16; i++) { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ ++ preorder_ctrl->padapter = pstapriv->padapter; ++ ++ preorder_ctrl->enable = false; ++ ++ preorder_ctrl->indicate_seq = 0xffff; ++ preorder_ctrl->wend_b = 0xffff; ++ preorder_ctrl->wsize_b = 64;/* 64; */ ++ ++ _rtw_init_queue(&preorder_ctrl->pending_recvframe_queue); ++ ++ rtw_init_recv_timer(preorder_ctrl); ++ } ++ ++ /* init for DM */ ++ psta->rssi_stat.UndecoratedSmoothedPWDB = (-1); ++ psta->rssi_stat.UndecoratedSmoothedCCK = (-1); ++ ++ /* init for the sequence number of received management frame */ ++ psta->RxMgmtFrameSeqNum = 0xffff; ++ } ++ ++exit: ++ ++ return psta; ++} ++ ++/* using pstapriv->sta_hash_lock to protect */ ++u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) ++{ ++ int i; ++ struct __queue *pfree_sta_queue; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_xmit_priv *pstaxmitpriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if (!psta) ++ goto exit; ++ ++ pfree_sta_queue = &pstapriv->free_sta_queue; ++ ++ pstaxmitpriv = &psta->sta_xmitpriv; ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q); ++ psta->sleepq_len = 0; ++ ++ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); ++ ++ list_del_init(&pstaxmitpriv->vo_q.tx_pending); ++ ++ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); ++ ++ list_del_init(&pstaxmitpriv->vi_q.tx_pending); ++ ++ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); ++ ++ list_del_init(&pstaxmitpriv->bk_q.tx_pending); ++ ++ rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); ++ ++ list_del_init(&pstaxmitpriv->be_q.tx_pending); ++ ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ list_del_init(&psta->hash_list); ++ pstapriv->asoc_sta_count--; ++ ++ /* re-init sta_info; 20061114 */ ++ _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); ++ _rtw_init_sta_recv_priv(&psta->sta_recvpriv); ++ ++ _cancel_timer_ex(&psta->addba_retry_timer); ++ ++ /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */ ++ for (i = 0; i < 16 ; i++) { ++ struct list_head *phead, *plist; ++ struct recv_frame *prframe; ++ struct __queue *ppending_recvframe_queue; ++ struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; ++ ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ ++ _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); ++ ++ ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; ++ ++ spin_lock_bh(&ppending_recvframe_queue->lock); ++ ++ phead = get_list_head(ppending_recvframe_queue); ++ plist = phead->next; ++ ++ while (!list_empty(phead)) { ++ prframe = container_of(plist, struct recv_frame, list); ++ ++ plist = plist->next; ++ ++ list_del_init(&prframe->list); ++ ++ rtw_free_recvframe(prframe, pfree_recv_queue); ++ } ++ ++ spin_unlock_bh(&ppending_recvframe_queue->lock); ++ } ++ ++ if (!(psta->state & WIFI_AP_STATE)) ++ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, false); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++ spin_lock_bh(&pstapriv->auth_list_lock); ++ if (!list_empty(&psta->auth_list)) { ++ list_del_init(&psta->auth_list); ++ pstapriv->auth_list_cnt--; ++ } ++ spin_unlock_bh(&pstapriv->auth_list_lock); ++ ++ psta->expire_to = 0; ++ ++ psta->sleepq_ac_len = 0; ++ psta->qos_info = 0; ++ ++ psta->max_sp_len = 0; ++ psta->uapsd_bk = 0; ++ psta->uapsd_be = 0; ++ psta->uapsd_vi = 0; ++ psta->uapsd_vo = 0; ++ psta->has_legacy_ac = 0; ++ ++ pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ if ((psta->aid > 0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) { ++ pstapriv->sta_aid[psta->aid - 1] = NULL; ++ psta->aid = 0; ++ } ++ ++ psta->under_exist_checking = 0; ++ ++#endif /* CONFIG_88EU_AP_MODE */ ++ ++ spin_lock_bh(&pfree_sta_queue->lock); ++ list_add_tail(&psta->list, get_list_head(pfree_sta_queue)); ++ spin_unlock_bh(&pfree_sta_queue->lock); ++ ++exit: ++ ++ return _SUCCESS; ++} ++ ++/* free all stainfo which in sta_hash[all] */ ++void rtw_free_all_stainfo(struct adapter *padapter) ++{ ++ struct list_head *plist, *phead; ++ s32 index; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter); ++ ++ if (pstapriv->asoc_sta_count == 1) ++ return; ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ for (index = 0; index < NUM_STA; index++) { ++ phead = &pstapriv->sta_hash[index]; ++ plist = phead->next; ++ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, hash_list); ++ ++ plist = plist->next; ++ ++ if (pbcmc_stainfo != psta) ++ rtw_free_stainfo(padapter, psta); ++ } ++ } ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++} ++ ++/* any station allocated can be searched by hash list */ ++struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) ++{ ++ struct list_head *plist, *phead; ++ struct sta_info *psta = NULL; ++ u32 index; ++ u8 *addr; ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ if (!hwaddr) ++ return NULL; ++ ++ if (IS_MCAST(hwaddr)) ++ addr = bc_addr; ++ else ++ addr = hwaddr; ++ ++ index = wifi_mac_hash(addr); ++ ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ phead = &pstapriv->sta_hash[index]; ++ plist = phead->next; ++ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, hash_list); ++ ++ if ((!memcmp(psta->hwaddr, addr, ETH_ALEN))) { ++ /* if found the matched address */ ++ break; ++ } ++ psta = NULL; ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ ++ return psta; ++} ++ ++u32 rtw_init_bcmc_stainfo(struct adapter *padapter) ++{ ++ struct sta_info *psta; ++ u32 res = _SUCCESS; ++ unsigned char bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ psta = rtw_alloc_stainfo(pstapriv, bcast_addr); ++ ++ if (!psta) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ /* default broadcast & multicast use macid 1 */ ++ psta->mac_id = 1; ++ ++exit: ++ ++ return res; ++} ++ ++struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter) ++{ ++ struct sta_info *psta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ psta = rtw_get_stainfo(pstapriv, bc_addr); ++ ++ return psta; ++} ++ ++u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr) ++{ ++ u8 res = true; ++#ifdef CONFIG_88EU_AP_MODE ++ struct list_head *plist, *phead; ++ struct rtw_wlan_acl_node *paclnode; ++ u8 match = false; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; ++ struct __queue *pacl_node_q = &pacl_list->acl_node_q; ++ ++ spin_lock_bh(&pacl_node_q->lock); ++ phead = get_list_head(pacl_node_q); ++ plist = phead->next; ++ while (phead != plist) { ++ paclnode = container_of(plist, struct rtw_wlan_acl_node, list); ++ plist = plist->next; ++ ++ if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN)) { ++ if (paclnode->valid) { ++ match = true; ++ break; ++ } ++ } ++ } ++ spin_unlock_bh(&pacl_node_q->lock); ++ ++ if (pacl_list->mode == 1)/* accept unless in deny list */ ++ res = (match) ? false : true; ++ else if (pacl_list->mode == 2)/* deny unless in accept list */ ++ res = (match) ? true : false; ++ else ++ res = true; ++ ++#endif ++ ++ return res; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c +new file mode 100644 +index 000000000000..a3a5e1c64c4a +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c +@@ -0,0 +1,1643 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_WLAN_UTIL_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/wifi.h" ++ ++static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f}; ++static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74}; ++ ++static unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18}; ++static unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7}; ++ ++static unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96}; ++static unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43}; ++static unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43}; ++static unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c}; ++static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5}; ++static unsigned char EPIGRAM_OUI[] = {0x00, 0x90, 0x4c}; ++ ++unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20}; ++ ++#define R2T_PHY_DELAY (0) ++ ++/* define WAIT_FOR_BCN_TO_M (3000) */ ++#define WAIT_FOR_BCN_TO_MIN (6000) ++#define WAIT_FOR_BCN_TO_MAX (20000) ++ ++static u8 rtw_basic_rate_cck[4] = { ++ IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK ++}; ++ ++static u8 rtw_basic_rate_ofdm[3] = { ++ IEEE80211_OFDM_RATE_6MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB | IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_OFDM_RATE_24MB | IEEE80211_BASIC_RATE_MASK ++}; ++ ++static u8 rtw_basic_rate_mix[7] = { ++ IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_OFDM_RATE_6MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB | IEEE80211_BASIC_RATE_MASK, ++ IEEE80211_OFDM_RATE_24MB | IEEE80211_BASIC_RATE_MASK ++}; ++ ++int cckrates_included(unsigned char *rate, int ratelen) ++{ ++ int i; ++ ++ for (i = 0; i < ratelen; i++) { ++ if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || ++ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) ++ return true; ++ } ++ return false; ++} ++ ++int cckratesonly_included(unsigned char *rate, int ratelen) ++{ ++ int i; ++ ++ for (i = 0; i < ratelen; i++) { ++ if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && ++ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) ++ return false; ++ } ++ ++ return true; ++} ++ ++unsigned char networktype_to_raid(unsigned char network_type) ++{ ++ unsigned char raid; ++ ++ switch (network_type) { ++ case WIRELESS_11B: ++ raid = RATR_INX_WIRELESS_B; ++ break; ++ case WIRELESS_11G: ++ raid = RATR_INX_WIRELESS_G; ++ break; ++ case WIRELESS_11BG: ++ raid = RATR_INX_WIRELESS_GB; ++ break; ++ case WIRELESS_11_24N: ++ raid = RATR_INX_WIRELESS_N; ++ break; ++ case WIRELESS_11G_24N: ++ raid = RATR_INX_WIRELESS_NG; ++ break; ++ case WIRELESS_11BG_24N: ++ raid = RATR_INX_WIRELESS_NGB; ++ break; ++ default: ++ raid = RATR_INX_WIRELESS_GB; ++ break; ++ } ++ return raid; ++} ++ ++u8 judge_network_type(struct adapter *padapter, unsigned char *rate, int ratelen) ++{ ++ u8 network_type = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (pmlmeext->cur_channel > 14) { ++ network_type |= WIRELESS_INVALID; ++ } else { ++ if (pmlmeinfo->HT_enable) ++ network_type = WIRELESS_11_24N; ++ ++ if (cckratesonly_included(rate, ratelen)) ++ network_type |= WIRELESS_11B; ++ else if (cckrates_included(rate, ratelen)) ++ network_type |= WIRELESS_11BG; ++ else ++ network_type |= WIRELESS_11G; ++ } ++ return network_type; ++} ++ ++static unsigned char ratetbl_val_2wifirate(unsigned char rate) ++{ ++ unsigned char val = 0; ++ ++ switch (rate & 0x7f) { ++ case 0: ++ val = IEEE80211_CCK_RATE_1MB; ++ break; ++ case 1: ++ val = IEEE80211_CCK_RATE_2MB; ++ break; ++ case 2: ++ val = IEEE80211_CCK_RATE_5MB; ++ break; ++ case 3: ++ val = IEEE80211_CCK_RATE_11MB; ++ break; ++ case 4: ++ val = IEEE80211_OFDM_RATE_6MB; ++ break; ++ case 5: ++ val = IEEE80211_OFDM_RATE_9MB; ++ break; ++ case 6: ++ val = IEEE80211_OFDM_RATE_12MB; ++ break; ++ case 7: ++ val = IEEE80211_OFDM_RATE_18MB; ++ break; ++ case 8: ++ val = IEEE80211_OFDM_RATE_24MB; ++ break; ++ case 9: ++ val = IEEE80211_OFDM_RATE_36MB; ++ break; ++ case 10: ++ val = IEEE80211_OFDM_RATE_48MB; ++ break; ++ case 11: ++ val = IEEE80211_OFDM_RATE_54MB; ++ break; ++ } ++ return val; ++} ++ ++static int is_basicrate(struct adapter *padapter, unsigned char rate) ++{ ++ int i; ++ unsigned char val; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ for (i = 0; i < NumRates; i++) { ++ val = pmlmeext->basicrate[i]; ++ ++ if ((val != 0xff) && (val != 0xfe)) { ++ if (rate == ratetbl_val_2wifirate(val)) ++ return true; ++ } ++ } ++ return false; ++} ++ ++static unsigned int ratetbl2rateset(struct adapter *padapter, unsigned char *rateset) ++{ ++ int i; ++ unsigned char rate; ++ unsigned int len = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ for (i = 0; i < NumRates; i++) { ++ rate = pmlmeext->datarate[i]; ++ ++ switch (rate) { ++ case 0xff: ++ return len; ++ case 0xfe: ++ continue; ++ default: ++ rate = ratetbl_val_2wifirate(rate); ++ ++ if (is_basicrate(padapter, rate)) ++ rate |= IEEE80211_BASIC_RATE_MASK; ++ ++ rateset[len] = rate; ++ len++; ++ break; ++ } ++ } ++ return len; ++} ++ ++void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *bssrate_len) ++{ ++ unsigned char supportedrates[NumRates]; ++ ++ memset(supportedrates, 0, NumRates); ++ *bssrate_len = ratetbl2rateset(padapter, supportedrates); ++ memcpy(pbssrate, supportedrates, *bssrate_len); ++} ++ ++void UpdateBrateTbl(struct adapter *Adapter, u8 *mbrate) ++{ ++ u8 i; ++ u8 rate; ++ ++ /* 1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */ ++ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ rate = mbrate[i] & 0x7f; ++ switch (rate) { ++ case IEEE80211_CCK_RATE_1MB: ++ case IEEE80211_CCK_RATE_2MB: ++ case IEEE80211_CCK_RATE_5MB: ++ case IEEE80211_CCK_RATE_11MB: ++ case IEEE80211_OFDM_RATE_6MB: ++ case IEEE80211_OFDM_RATE_12MB: ++ case IEEE80211_OFDM_RATE_24MB: ++ mbrate[i] |= IEEE80211_BASIC_RATE_MASK; ++ break; ++ } ++ } ++} ++ ++void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen) ++{ ++ u8 i; ++ u8 rate; ++ ++ for (i = 0; i < bssratelen; i++) { ++ rate = bssrateset[i] & 0x7f; ++ switch (rate) { ++ case IEEE80211_CCK_RATE_1MB: ++ case IEEE80211_CCK_RATE_2MB: ++ case IEEE80211_CCK_RATE_5MB: ++ case IEEE80211_CCK_RATE_11MB: ++ bssrateset[i] |= IEEE80211_BASIC_RATE_MASK; ++ break; ++ } ++ } ++} ++ ++void Save_DM_Func_Flag(struct adapter *padapter) ++{ ++ u8 saveflag = true; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag)); ++} ++ ++void Restore_DM_Func_Flag(struct adapter *padapter) ++{ ++ u8 saveflag = false; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag)); ++} ++ ++void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable) ++{ ++ if (enable) ++ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_SET, (u8 *)(&mode)); ++ else ++ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode)); ++} ++ ++static void Set_NETYPE0_MSR(struct adapter *padapter, u8 type) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type)); ++} ++ ++void Set_MSR(struct adapter *padapter, u8 type) ++{ ++ Set_NETYPE0_MSR(padapter, type); ++} ++ ++inline u8 rtw_get_oper_ch(struct adapter *adapter) ++{ ++ return adapter->mlmeextpriv.oper_channel; ++} ++ ++inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch) ++{ ++ adapter->mlmeextpriv.oper_channel = ch; ++} ++ ++inline u8 rtw_get_oper_bw(struct adapter *adapter) ++{ ++ return adapter->mlmeextpriv.oper_bwmode; ++} ++ ++inline void rtw_set_oper_bw(struct adapter *adapter, u8 bw) ++{ ++ adapter->mlmeextpriv.oper_bwmode = bw; ++} ++ ++inline u8 rtw_get_oper_choffset(struct adapter *adapter) ++{ ++ return adapter->mlmeextpriv.oper_ch_offset; ++} ++ ++inline void rtw_set_oper_choffset(struct adapter *adapter, u8 offset) ++{ ++ adapter->mlmeextpriv.oper_ch_offset = offset; ++} ++ ++void SelectChannel(struct adapter *padapter, unsigned char channel) ++{ ++ /* saved channel info */ ++ rtw_set_oper_ch(padapter, channel); ++ rtw_hal_set_chan(padapter, channel); ++} ++ ++void SetBWMode(struct adapter *padapter, unsigned short bwmode, ++ unsigned char channel_offset) ++{ ++ /* saved bw info */ ++ rtw_set_oper_bw(padapter, bwmode); ++ rtw_set_oper_choffset(padapter, channel_offset); ++ ++ rtw_hal_set_bwmode(padapter, (enum ht_channel_width)bwmode, channel_offset); ++} ++ ++void set_channel_bwmode(struct adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode) ++{ ++ u8 center_ch; ++ ++ if (padapter->bNotifyChannelChange) ++ DBG_88E("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode); ++ ++ if ((bwmode == HT_CHANNEL_WIDTH_20) || ++ (channel_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)) { ++ /* SelectChannel(padapter, channel); */ ++ center_ch = channel; ++ } else { ++ /* switch to the proper channel */ ++ if (channel_offset == HAL_PRIME_CHNL_OFFSET_LOWER) { ++ /* SelectChannel(padapter, channel + 2); */ ++ center_ch = channel + 2; ++ } else { ++ /* SelectChannel(padapter, channel - 2); */ ++ center_ch = channel - 2; ++ } ++ } ++ ++ /* set Channel */ ++ /* saved channel/bw info */ ++ rtw_set_oper_ch(padapter, channel); ++ rtw_set_oper_bw(padapter, bwmode); ++ rtw_set_oper_choffset(padapter, channel_offset); ++ ++ rtw_hal_set_chan(padapter, center_ch); /* set center channel */ ++ SetBWMode(padapter, bwmode, channel_offset); ++} ++ ++int get_bsstype(unsigned short capability) ++{ ++ if (capability & BIT(0)) ++ return WIFI_FW_AP_STATE; ++ else if (capability & BIT(1)) ++ return WIFI_FW_ADHOC_STATE; ++ else ++ return 0; ++} ++ ++__inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork) ++{ ++ return pnetwork->MacAddress; ++} ++ ++u16 get_beacon_interval(struct wlan_bssid_ex *bss) ++{ ++ __le16 val; ++ memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2); ++ ++ return le16_to_cpu(val); ++} ++ ++int is_client_associated_to_ap(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ ++ if (!padapter) ++ return _FAIL; ++ ++ pmlmeext = &padapter->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE)) ++ return true; ++ else ++ return _FAIL; ++} ++ ++int is_client_associated_to_ibss(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) ++ return true; ++ else ++ return _FAIL; ++} ++ ++int is_IBSS_empty(struct adapter *padapter) ++{ ++ unsigned int i; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) { ++ if (pmlmeinfo->FW_sta_info[i].status == 1) ++ return _FAIL; ++ } ++ return true; ++} ++ ++unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval) ++{ ++ if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN) ++ return WAIT_FOR_BCN_TO_MIN; ++ else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX) ++ return WAIT_FOR_BCN_TO_MAX; ++ else ++ return bcn_interval << 2; ++} ++ ++void CAM_empty_entry(struct adapter *Adapter, u8 ucIndex) ++{ ++ rtw_hal_set_hwreg(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex)); ++} ++ ++void invalidate_cam_all(struct adapter *padapter) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL); ++} ++ ++void write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key) ++{ ++ unsigned int i, val, addr; ++ int j; ++ u32 cam_val[2]; ++ ++ addr = entry << 3; ++ ++ for (j = 5; j >= 0; j--) { ++ switch (j) { ++ case 0: ++ val = (ctrl | (mac[0] << 16) | (mac[1] << 24)); ++ break; ++ case 1: ++ val = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24)); ++ break; ++ default: ++ i = (j - 2) << 2; ++ val = (key[i] | (key[i + 1] << 8) | (key[i + 2] << 16) | (key[i + 3] << 24)); ++ break; ++ } ++ ++ cam_val[0] = val; ++ cam_val[1] = addr + (unsigned int)j; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val); ++ } ++} ++ ++void clear_cam_entry(struct adapter *padapter, u8 entry) ++{ ++ unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ++ ++ write_cam(padapter, entry, 0, null_sta, null_key); ++} ++ ++int allocate_fw_sta_entry(struct adapter *padapter) ++{ ++ unsigned int mac_id; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) { ++ if (pmlmeinfo->FW_sta_info[mac_id].status == 0) { ++ pmlmeinfo->FW_sta_info[mac_id].status = 1; ++ pmlmeinfo->FW_sta_info[mac_id].retry = 0; ++ break; ++ } ++ } ++ ++ return mac_id; ++} ++ ++void flush_all_cam_entry(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, NULL); ++ ++ memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info)); ++} ++ ++int WMM_param_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) ++{ ++ /* struct registry_priv *pregpriv = &padapter->registrypriv; */ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (pmlmepriv->qospriv.qos_option == 0) { ++ pmlmeinfo->WMM_enable = 0; ++ return _FAIL; ++ } ++ ++ pmlmeinfo->WMM_enable = 1; ++ memcpy(&pmlmeinfo->WMM_param, pIE->data + 6, sizeof(struct WMM_para_element)); ++ return true; ++} ++ ++void WMMOnAssocRsp(struct adapter *padapter) ++{ ++ u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime; ++ u8 acm_mask; ++ u16 TXOP; ++ u32 acParm, i; ++ u32 edca[4], inx[4]; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ ++ if (pmlmeinfo->WMM_enable == 0) { ++ padapter->mlmepriv.acm_mask = 0; ++ return; ++ } ++ ++ acm_mask = 0; ++ ++ if (pmlmeext->cur_wireless_mode == WIRELESS_11B) ++ aSifsTime = 10; ++ else ++ aSifsTime = 16; ++ ++ for (i = 0; i < 4; i++) { ++ ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03; ++ ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01; ++ ++ /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */ ++ AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime; ++ ++ ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f); ++ ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4; ++ TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit); ++ ++ acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); ++ ++ switch (ACI) { ++ case 0x0: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); ++ acm_mask |= (ACM ? BIT(1) : 0); ++ edca[XMIT_BE_QUEUE] = acParm; ++ break; ++ case 0x1: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); ++ edca[XMIT_BK_QUEUE] = acParm; ++ break; ++ case 0x2: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); ++ acm_mask |= (ACM ? BIT(2) : 0); ++ edca[XMIT_VI_QUEUE] = acParm; ++ break; ++ case 0x3: ++ rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); ++ acm_mask |= (ACM ? BIT(3) : 0); ++ edca[XMIT_VO_QUEUE] = acParm; ++ break; ++ } ++ ++ DBG_88E("WMM(%x): %x, %x\n", ACI, ACM, acParm); ++ } ++ ++ if (padapter->registrypriv.acm_method == 1) ++ rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask)); ++ else ++ padapter->mlmepriv.acm_mask = acm_mask; ++ ++ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; ++ ++ if (pregpriv->wifi_spec == 1) { ++ u32 j, tmp, change_inx = false; ++ ++ /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */ ++ for (i = 0; i < 4; i++) { ++ for (j = i + 1; j < 4; j++) { ++ /* compare CW and AIFS */ ++ if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) { ++ change_inx = true; ++ } else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) { ++ /* compare TXOP */ ++ if ((edca[j] >> 16) > (edca[i] >> 16)) ++ change_inx = true; ++ } ++ ++ if (change_inx) { ++ tmp = edca[i]; ++ edca[i] = edca[j]; ++ edca[j] = tmp; ++ ++ tmp = inx[i]; ++ inx[i] = inx[j]; ++ inx[j] = tmp; ++ ++ change_inx = false; ++ } ++ } ++ } ++ } ++ ++ for (i = 0; i < 4; i++) { ++ pxmitpriv->wmm_para_seq[i] = inx[i]; ++ DBG_88E("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]); ++ } ++} ++ ++static void bwmode_update_check(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) ++{ ++ unsigned char new_bwmode; ++ unsigned char new_ch_offset; ++ struct HT_info_element *pHT_info; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ if (!pIE) ++ return; ++ ++ if (!phtpriv) ++ return; ++ ++ if (pIE->Length > sizeof(struct HT_info_element)) ++ return; ++ ++ pHT_info = (struct HT_info_element *)pIE->data; ++ ++ if ((pHT_info->infos[0] & BIT(2)) && pregistrypriv->cbw40_enable) { ++ new_bwmode = HT_CHANNEL_WIDTH_40; ++ ++ switch (pHT_info->infos[0] & 0x3) { ++ case 1: ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; ++ break; ++ case 3: ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; ++ break; ++ default: ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ break; ++ } ++ } else { ++ new_bwmode = HT_CHANNEL_WIDTH_20; ++ new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ ++ if ((new_bwmode != pmlmeext->cur_bwmode) || ++ (new_ch_offset != pmlmeext->cur_ch_offset)) { ++ pmlmeinfo->bwmode_updated = true; ++ ++ pmlmeext->cur_bwmode = new_bwmode; ++ pmlmeext->cur_ch_offset = new_ch_offset; ++ ++ /* update HT info also */ ++ HT_info_handler(padapter, pIE); ++ } else { ++ pmlmeinfo->bwmode_updated = false; ++ } ++ ++ if (pmlmeinfo->bwmode_updated) { ++ struct sta_info *psta; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ /* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ ++ ++ /* update ap's stainfo */ ++ psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); ++ if (psta) { ++ struct ht_priv *phtpriv_sta = &psta->htpriv; ++ ++ if (phtpriv_sta->ht_option) { ++ /* bwmode */ ++ phtpriv_sta->bwmode = pmlmeext->cur_bwmode; ++ phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; ++ } else { ++ phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20; ++ phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ } ++ } ++ } ++} ++ ++void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) ++{ ++ unsigned int i; ++ u8 rf_type; ++ u8 max_AMPDU_len, min_MPDU_spacing; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ if (!pIE) ++ return; ++ ++ if (!phtpriv->ht_option) ++ return; ++ ++ pmlmeinfo->HT_caps_enable = 1; ++ ++ for (i = 0; i < (pIE->Length); i++) { ++ if (i != 2) { ++ /* Got the endian issue here. */ ++ pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]); ++ } else { ++ /* modify from fw by Thomas 2010/11/17 */ ++ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3)) ++ max_AMPDU_len = (pIE->data[i] & 0x3); ++ else ++ max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3); ++ ++ if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c)) ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c); ++ else ++ min_MPDU_spacing = (pIE->data[i] & 0x1c); ++ ++ pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing; ++ } ++ } ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ /* update the MCS rates */ ++ for (i = 0; i < 16; i++) { ++ if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R)) ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; ++ else ++ pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R[i]; ++ } ++} ++ ++void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ht_priv *phtpriv = &pmlmepriv->htpriv; ++ ++ if (!pIE) ++ return; ++ ++ if (!phtpriv->ht_option) ++ return; ++ ++ if (pIE->Length > sizeof(struct HT_info_element)) ++ return; ++ ++ pmlmeinfo->HT_info_enable = 1; ++ memcpy(&pmlmeinfo->HT_info, pIE->data, pIE->Length); ++} ++ ++void HTOnAssocRsp(struct adapter *padapter) ++{ ++ unsigned char max_AMPDU_len; ++ unsigned char min_MPDU_spacing; ++ /* struct registry_priv *pregpriv = &padapter->registrypriv; */ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ DBG_88E("%s\n", __func__); ++ ++ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) { ++ pmlmeinfo->HT_enable = 1; ++ } else { ++ pmlmeinfo->HT_enable = 0; ++ return; ++ } ++ ++ /* handle A-MPDU parameter field */ ++ /* ++ AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k ++ AMPDU_para [4:2]:Min MPDU Start Spacing ++ */ ++ max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; ++ ++ min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); ++} ++ ++void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (pIE->Length > 1) ++ return; ++ ++ pmlmeinfo->ERP_enable = 1; ++ memcpy(&pmlmeinfo->ERP_IE, pIE->data, pIE->Length); ++} ++ ++void VCS_update(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ switch (pregpriv->vrtl_carrier_sense) { /* 0:off 1:on 2:auto */ ++ case 0: /* off */ ++ psta->rtsen = 0; ++ psta->cts2self = 0; ++ break; ++ case 1: /* on */ ++ if (pregpriv->vcs_type == 1) { /* 1:RTS/CTS 2:CTS to self */ ++ psta->rtsen = 1; ++ psta->cts2self = 0; ++ } else { ++ psta->rtsen = 0; ++ psta->cts2self = 1; ++ } ++ break; ++ case 2: /* auto */ ++ default: ++ if ((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) { ++ if (pregpriv->vcs_type == 1) { ++ psta->rtsen = 1; ++ psta->cts2self = 0; ++ } else { ++ psta->rtsen = 0; ++ psta->cts2self = 1; ++ } ++ } else { ++ psta->rtsen = 0; ++ psta->cts2self = 0; ++ } ++ break; ++ } ++} ++ ++int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) ++{ ++ unsigned int len; ++ unsigned char *p; ++ unsigned short val16, subtype; ++ struct wlan_network *cur_network = &Adapter->mlmepriv.cur_network; ++ /* u8 wpa_ie[255], rsn_ie[255]; */ ++ u16 wpa_len = 0, rsn_len = 0; ++ u8 encryp_protocol = 0; ++ struct wlan_bssid_ex *bssid; ++ int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0; ++ unsigned char *pbuf; ++ u32 wpa_ielen = 0; ++ u8 *pbssid = GetAddr3Ptr(pframe); ++ u32 hidden_ssid = 0; ++ struct HT_info_element *pht_info = NULL; ++ struct ieee80211_ht_cap *pht_cap = NULL; ++ u32 bcn_channel; ++ unsigned short ht_cap_info; ++ unsigned char ht_info_infos_0; ++ ++ if (!is_client_associated_to_ap(Adapter)) ++ return true; ++ ++ len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ if (len > MAX_IE_SZ) { ++ DBG_88E("%s IE too long for survey event\n", __func__); ++ return _FAIL; ++ } ++ ++ if (memcmp(cur_network->network.MacAddress, pbssid, 6)) { ++ DBG_88E("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n%pM %pM\n", ++ (pbssid), (cur_network->network.MacAddress)); ++ return true; ++ } ++ ++ bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC); ++ if (!bssid) ++ return _FAIL; ++ ++ subtype = GetFrameSubType(pframe) >> 4; ++ ++ if (subtype == WIFI_BEACON) ++ bssid->Reserved[0] = 1; ++ ++ bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len; ++ ++ /* below is to copy the information element */ ++ bssid->IELength = len; ++ memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); ++ ++ /* check bw and channel offset */ ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (p && len > 0) { ++ pht_cap = (struct ieee80211_ht_cap *)(p + 2); ++ ht_cap_info = le16_to_cpu(pht_cap->cap_info); ++ } else { ++ ht_cap_info = 0; ++ } ++ /* parsing HT_INFO_IE */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (p && len > 0) { ++ pht_info = (struct HT_info_element *)(p + 2); ++ ht_info_infos_0 = pht_info->infos[0]; ++ } else { ++ ht_info_infos_0 = 0; ++ } ++ if (ht_cap_info != cur_network->BcnInfo.ht_cap_info || ++ ((ht_info_infos_0 & 0x03) != (cur_network->BcnInfo.ht_info_infos_0 & 0x03))) { ++ DBG_88E("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, ++ ht_cap_info, ht_info_infos_0); ++ DBG_88E("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, ++ cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0); ++ DBG_88E("%s bw mode change, disconnect\n", __func__); ++ /* bcn_info_update */ ++ cur_network->BcnInfo.ht_cap_info = ht_cap_info; ++ cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0; ++ /* to do : need to check that whether modify related register of BB or not */ ++ /* goto _mismatch; */ ++ } ++ ++ /* Checking for channel */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (p) { ++ bcn_channel = *(p + 2); ++ } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (pht_info) { ++ bcn_channel = pht_info->primary_channel; ++ } else { /* we don't find channel IE, so don't check it */ ++ DBG_88E("Oops: %s we don't find channel IE, so don't check it\n", __func__); ++ bcn_channel = Adapter->mlmeextpriv.cur_channel; ++ } ++ } ++ if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { ++ DBG_88E("%s beacon channel:%d cur channel:%d disconnect\n", __func__, ++ bcn_channel, Adapter->mlmeextpriv.cur_channel); ++ goto _mismatch; ++ } ++ ++ /* checking SSID */ ++ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); ++ if (!p) { ++ DBG_88E("%s marc: cannot find SSID for survey event\n", __func__); ++ hidden_ssid = true; ++ } else { ++ hidden_ssid = false; ++ } ++ ++ if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) { ++ memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); ++ bssid->Ssid.SsidLength = *(p + 1); ++ } else { ++ bssid->Ssid.SsidLength = 0; ++ bssid->Ssid.Ssid[0] = '\0'; ++ } ++ ++ if (memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) || ++ bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) { ++ if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */ ++ DBG_88E("%s(), SSID is not match return FAIL\n", __func__); ++ goto _mismatch; ++ } ++ } ++ ++ /* check encryption info */ ++ val16 = rtw_get_capability((struct wlan_bssid_ex *)bssid); ++ ++ if (val16 & BIT(4)) ++ bssid->Privacy = 1; ++ else ++ bssid->Privacy = 0; ++ ++ if (cur_network->network.Privacy != bssid->Privacy) { ++ DBG_88E("%s(), privacy is not match return FAIL\n", __func__); ++ goto _mismatch; ++ } ++ ++ rtw_get_sec_ie(bssid->IEs, bssid->IELength, NULL, &rsn_len, NULL, &wpa_len); ++ ++ if (rsn_len > 0) { ++ encryp_protocol = ENCRYP_PROTOCOL_WPA2; ++ } else if (wpa_len > 0) { ++ encryp_protocol = ENCRYP_PROTOCOL_WPA; ++ } else { ++ if (bssid->Privacy) ++ encryp_protocol = ENCRYP_PROTOCOL_WEP; ++ } ++ ++ if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { ++ DBG_88E("%s(): enctyp is not match , return FAIL\n", __func__); ++ goto _mismatch; ++ } ++ ++ if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { ++ pbuf = rtw_get_wpa_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength - 12); ++ if (pbuf && (wpa_ielen > 0)) { ++ rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is_8021x); ++ } else { ++ pbuf = rtw_get_wpa2_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength - 12); ++ ++ if (pbuf && (wpa_ielen > 0)) ++ rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is_8021x); ++ } ++ ++ if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) { ++ DBG_88E("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match , return FAIL\n", __func__, ++ pairwise_cipher, cur_network->BcnInfo.pairwise_cipher, ++ group_cipher, cur_network->BcnInfo.group_cipher); ++ goto _mismatch; ++ } ++ ++ if (is_8021x != cur_network->BcnInfo.is_8021x) { ++ DBG_88E("%s authentication is not match , return FAIL\n", __func__); ++ goto _mismatch; ++ } ++ } ++ ++ kfree(bssid); ++ ++ return _SUCCESS; ++ ++_mismatch: ++ kfree(bssid); ++ ++ return _FAIL; ++} ++ ++void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta) ++{ ++ unsigned int i; ++ unsigned int len; ++ struct ndis_802_11_var_ie *pIE; ++ ++ len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN); ++ ++ for (i = 0; i < len;) { ++ pIE = (struct ndis_802_11_var_ie *)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i); ++ ++ switch (pIE->ElementID) { ++ case _HT_EXTRA_INFO_IE_: /* HT info */ ++ /* HT_info_handler(padapter, pIE); */ ++ bwmode_update_check(padapter, pIE); ++ break; ++ case _ERPINFO_IE_: ++ ERP_IE_handler(padapter, pIE); ++ VCS_update(padapter, psta); ++ break; ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++} ++ ++unsigned int is_ap_in_tkip(struct adapter *padapter) ++{ ++ u32 i; ++ struct ndis_802_11_var_ie *pIE; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ ++ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { ++ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) { ++ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i); ++ ++ switch (pIE->ElementID) { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((!memcmp(pIE->data, RTW_WPA_OUI, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4))) ++ return true; ++ break; ++ case _RSN_IE_2_: ++ if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4)) ++ return true; ++ break; ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ return false; ++ } else { ++ return false; ++ } ++} ++ ++unsigned int should_forbid_n_rate(struct adapter *padapter) ++{ ++ u32 i; ++ struct ndis_802_11_var_ie *pIE; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *cur_network = &pmlmepriv->cur_network.network; ++ ++ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { ++ for (i = sizeof(struct ndis_802_11_fixed_ie); i < cur_network->IELength;) { ++ pIE = (struct ndis_802_11_var_ie *)(cur_network->IEs + i); ++ ++ switch (pIE->ElementID) { ++ case _VENDOR_SPECIFIC_IE_: ++ if (!memcmp(pIE->data, RTW_WPA_OUI, 4) && ++ ((!memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP, 4)) || ++ (!memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP, 4)))) ++ return false; ++ break; ++ case _RSN_IE_2_: ++ if ((!memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4)) || ++ (!memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4))) ++ return false; ++ break; ++ default: ++ break; ++ } ++ ++ i += (pIE->Length + 2); ++ } ++ ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++unsigned int is_ap_in_wep(struct adapter *padapter) ++{ ++ u32 i; ++ struct ndis_802_11_var_ie *pIE; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ ++ if (rtw_get_capability((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) { ++ for (i = sizeof(struct ndis_802_11_fixed_ie); i < pmlmeinfo->network.IELength;) { ++ pIE = (struct ndis_802_11_var_ie *)(pmlmeinfo->network.IEs + i); ++ ++ switch (pIE->ElementID) { ++ case _VENDOR_SPECIFIC_IE_: ++ if (!memcmp(pIE->data, RTW_WPA_OUI, 4)) ++ return false; ++ break; ++ case _RSN_IE_2_: ++ return false; ++ default: ++ break; ++ } ++ i += (pIE->Length + 2); ++ } ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++int wifirate2_ratetbl_inx(unsigned char rate) ++{ ++ int inx = 0; ++ rate = rate & 0x7f; ++ ++ switch (rate) { ++ case 54 * 2: ++ inx = 11; ++ break; ++ case 48 * 2: ++ inx = 10; ++ break; ++ case 36 * 2: ++ inx = 9; ++ break; ++ case 24 * 2: ++ inx = 8; ++ break; ++ case 18 * 2: ++ inx = 7; ++ break; ++ case 12 * 2: ++ inx = 6; ++ break; ++ case 9 * 2: ++ inx = 5; ++ break; ++ case 6 * 2: ++ inx = 4; ++ break; ++ case 11 * 2: ++ inx = 3; ++ break; ++ case 11: ++ inx = 2; ++ break; ++ case 2 * 2: ++ inx = 1; ++ break; ++ case 1 * 2: ++ inx = 0; ++ break; ++ } ++ return inx; ++} ++ ++unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz) ++{ ++ unsigned int i, num_of_rate; ++ unsigned int mask = 0; ++ ++ num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz; ++ ++ for (i = 0; i < num_of_rate; i++) { ++ if ((*(ptn + i)) & 0x80) ++ mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i)); ++ } ++ return mask; ++} ++ ++unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz) ++{ ++ unsigned int i, num_of_rate; ++ unsigned int mask = 0; ++ ++ num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz; ++ ++ for (i = 0; i < num_of_rate; i++) ++ mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i)); ++ return mask; ++} ++ ++unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps) ++{ ++ unsigned int mask = 0; ++ ++ mask = ((pHT_caps->u.HT_cap_element.MCS_rate[0] << 12) | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 20)); ++ ++ return mask; ++} ++ ++int support_short_GI(struct adapter *padapter, struct HT_caps_element *pHT_caps) ++{ ++ unsigned char bit_offset; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (!(pmlmeinfo->HT_enable)) ++ return _FAIL; ++ ++ if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) ++ return _FAIL; ++ ++ bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40) ? 6 : 5; ++ ++ if (__le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & (0x1 << bit_offset)) ++ return _SUCCESS; ++ else ++ return _FAIL; ++} ++ ++unsigned char get_highest_rate_idx(u32 mask) ++{ ++ int i; ++ unsigned char rate_idx = 0; ++ ++ for (i = 27; i >= 0; i--) { ++ if (mask & BIT(i)) { ++ rate_idx = i; ++ break; ++ } ++ } ++ return rate_idx; ++} ++ ++void Update_RA_Entry(struct adapter *padapter, u32 mac_id) ++{ ++ rtw_hal_update_ra_mask(padapter, mac_id, 0); ++} ++ ++static void enable_rate_adaptive(struct adapter *padapter, u32 mac_id) ++{ ++ Update_RA_Entry(padapter, mac_id); ++} ++ ++void set_sta_rate(struct adapter *padapter, struct sta_info *psta) ++{ ++ /* rate adaptive */ ++ enable_rate_adaptive(padapter, psta->mac_id); ++} ++ ++/* Update RRSR and Rate for USERATE */ ++void update_tx_basic_rate(struct adapter *padapter, u8 wirelessmode) ++{ ++ unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX]; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ /* Added by Albert 2011/03/22 */ ++ /* In the P2P mode, the driver should not support the b mode. */ ++ /* So, the Tx packet shouldn't use the CCK rate */ ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) ++ return; ++#endif /* CONFIG_88EU_P2P */ ++ memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); ++ ++ if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) ++ memcpy(supported_rates, rtw_basic_rate_cck, 4); ++ else if (wirelessmode & WIRELESS_11B) ++ memcpy(supported_rates, rtw_basic_rate_mix, 7); ++ else ++ memcpy(supported_rates, rtw_basic_rate_ofdm, 3); ++ ++ if (wirelessmode & WIRELESS_11B) ++ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); ++ else ++ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, supported_rates); ++} ++ ++unsigned char check_assoc_AP(u8 *pframe, uint len) ++{ ++ unsigned int i; ++ struct ndis_802_11_var_ie *pIE; ++ u8 epigram_vendor_flag; ++ u8 ralink_vendor_flag; ++ epigram_vendor_flag = 0; ++ ralink_vendor_flag = 0; ++ ++ for (i = sizeof(struct ndis_802_11_fixed_ie); i < len;) { ++ pIE = (struct ndis_802_11_var_ie *)(pframe + i); ++ ++ switch (pIE->ElementID) { ++ case _VENDOR_SPECIFIC_IE_: ++ if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || ++ (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) { ++ DBG_88E("link to Artheros AP\n"); ++ return HT_IOT_PEER_ATHEROS; ++ } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) || ++ (!memcmp(pIE->data, BROADCOM_OUI2, 3)) || ++ (!memcmp(pIE->data, BROADCOM_OUI2, 3))) { ++ DBG_88E("link to Broadcom AP\n"); ++ return HT_IOT_PEER_BROADCOM; ++ } else if (!memcmp(pIE->data, MARVELL_OUI, 3)) { ++ DBG_88E("link to Marvell AP\n"); ++ return HT_IOT_PEER_MARVELL; ++ } else if (!memcmp(pIE->data, RALINK_OUI, 3)) { ++ if (!ralink_vendor_flag) { ++ ralink_vendor_flag = 1; ++ } else { ++ DBG_88E("link to Ralink AP\n"); ++ return HT_IOT_PEER_RALINK; ++ } ++ } else if (!memcmp(pIE->data, CISCO_OUI, 3)) { ++ DBG_88E("link to Cisco AP\n"); ++ return HT_IOT_PEER_CISCO; ++ } else if (!memcmp(pIE->data, REALTEK_OUI, 3)) { ++ DBG_88E("link to Realtek 96B\n"); ++ return HT_IOT_PEER_REALTEK; ++ } else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) { ++ DBG_88E("link to Airgo Cap\n"); ++ return HT_IOT_PEER_AIRGO; ++ } else if (!memcmp(pIE->data, EPIGRAM_OUI, 3)) { ++ epigram_vendor_flag = 1; ++ if (ralink_vendor_flag) { ++ DBG_88E("link to Tenda W311R AP\n"); ++ return HT_IOT_PEER_TENDA; ++ } else { ++ DBG_88E("Capture EPIGRAM_OUI\n"); ++ } ++ } else { ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ i += (pIE->Length + 2); ++ } ++ ++ if (ralink_vendor_flag && !epigram_vendor_flag) { ++ DBG_88E("link to Ralink AP\n"); ++ return HT_IOT_PEER_RALINK; ++ } else if (ralink_vendor_flag && epigram_vendor_flag) { ++ DBG_88E("link to Tenda W311R AP\n"); ++ return HT_IOT_PEER_TENDA; ++ } else { ++ DBG_88E("link to new AP\n"); ++ return HT_IOT_PEER_UNKNOWN; ++ } ++} ++ ++void update_IOT_info(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ switch (pmlmeinfo->assoc_AP_vendor) { ++ case HT_IOT_PEER_MARVELL: ++ pmlmeinfo->turboMode_cts2self = 1; ++ pmlmeinfo->turboMode_rtsen = 0; ++ break; ++ case HT_IOT_PEER_RALINK: ++ pmlmeinfo->turboMode_cts2self = 0; ++ pmlmeinfo->turboMode_rtsen = 1; ++ /* disable high power */ ++ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false); ++ break; ++ case HT_IOT_PEER_REALTEK: ++ /* rtw_write16(padapter, 0x4cc, 0xffff); */ ++ /* rtw_write16(padapter, 0x546, 0x01c0); */ ++ /* disable high power */ ++ Switch_DM_Func(padapter, (~DYNAMIC_BB_DYNAMIC_TXPWR), false); ++ break; ++ default: ++ pmlmeinfo->turboMode_cts2self = 0; ++ pmlmeinfo->turboMode_rtsen = 1; ++ break; ++ } ++} ++ ++void update_capinfo(struct adapter *Adapter, u16 updateCap) ++{ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ bool ShortPreamble; ++ ++ /* Check preamble mode, 2005.01.06, by rcnjko. */ ++ /* Mark to update preamble value forever, 2008.03.18 by lanhsin */ ++ ++ if (updateCap & cShortPreamble) { /* Short Preamble */ ++ if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { /* PREAMBLE_LONG or PREAMBLE_AUTO */ ++ ShortPreamble = true; ++ pmlmeinfo->preamble_mode = PREAMBLE_SHORT; ++ rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); ++ } ++ } else { /* Long Preamble */ ++ if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) { /* PREAMBLE_SHORT or PREAMBLE_AUTO */ ++ ShortPreamble = false; ++ pmlmeinfo->preamble_mode = PREAMBLE_LONG; ++ rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); ++ } ++ } ++ ++ if (updateCap & cIBSS) { ++ /* Filen: See 802.11-2007 p.91 */ ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } else { /* Filen: See 802.11-2007 p.90 */ ++ if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11_24N)) { ++ if (updateCap & cShortSlotTime) { /* Short Slot Time */ ++ if (pmlmeinfo->slotTime != SHORT_SLOT_TIME) ++ pmlmeinfo->slotTime = SHORT_SLOT_TIME; ++ } else { /* Long Slot Time */ ++ if (pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME) ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } ++ } else { ++ /* B Mode */ ++ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; ++ } ++ } ++ ++ rtw_hal_set_hwreg(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime); ++} ++ ++void update_wireless_mode(struct adapter *padapter) ++{ ++ int ratelen, network_type = 0; ++ u32 SIFS_Timer; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ unsigned char *rate = cur_network->SupportedRates; ++ ++ ratelen = rtw_get_rateset_len(cur_network->SupportedRates); ++ ++ if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) ++ pmlmeinfo->HT_enable = 1; ++ ++ if (pmlmeext->cur_channel > 14) { ++ network_type |= WIRELESS_INVALID; ++ } else { ++ if (pmlmeinfo->HT_enable) ++ network_type = WIRELESS_11_24N; ++ ++ if (cckratesonly_included(rate, ratelen)) ++ network_type |= WIRELESS_11B; ++ else if (cckrates_included(rate, ratelen)) ++ network_type |= WIRELESS_11BG; ++ else ++ network_type |= WIRELESS_11G; ++ } ++ ++ pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode; ++ ++ SIFS_Timer = 0x0a0a0808;/* 0x0808 -> for CCK, 0x0a0a -> for OFDM */ ++ /* change this value if having IOT issues. */ ++ ++ padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); ++ ++ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); ++ else ++ update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); ++} ++ ++void update_bmc_sta_support_rate(struct adapter *padapter, u32 mac_id) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { ++ /* Only B, B/G, and B/G/N AP could use CCK rate */ ++ memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_cck, 4); ++ } else { ++ memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_ofdm, 3); ++ } ++} ++ ++int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx) ++{ ++ unsigned int ie_len; ++ struct ndis_802_11_var_ie *pIE; ++ int supportRateNum = 0; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len); ++ if (!pIE) ++ return _FAIL; ++ ++ memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len); ++ supportRateNum = ie_len; ++ ++ pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len); ++ if (pIE) ++ memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len); ++ ++ return _SUCCESS; ++} ++ ++void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr) ++{ ++ struct sta_info *psta; ++ u16 tid; ++ u16 param; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct ADDBA_request *preq = (struct ADDBA_request *)paddba_req; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ psta = rtw_get_stainfo(pstapriv, addr); ++ ++ if (psta) { ++ param = le16_to_cpu(preq->BA_para_set); ++ tid = (param >> 2) & 0x0f; ++ preorder_ctrl = &psta->recvreorder_ctrl[tid]; ++ preorder_ctrl->indicate_seq = 0xffff; ++ preorder_ctrl->enable = (pmlmeinfo->bAcceptAddbaReq) ? true : false; ++ } ++} ++ ++void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) ++{ ++ u8 *pIE; ++ __le32 *pbuf; ++ ++ pIE = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); ++ pbuf = (__le32 *)pIE; ++ ++ pmlmeext->TSFValue = le32_to_cpu(*(pbuf + 1)); ++ ++ pmlmeext->TSFValue = pmlmeext->TSFValue << 32; ++ ++ pmlmeext->TSFValue |= le32_to_cpu(*pbuf); ++} ++ ++void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext) ++{ ++ rtw_hal_set_hwreg(padapter, HW_VAR_CORRECT_TSF, NULL); ++} ++ ++void beacon_timing_control(struct adapter *padapter) ++{ ++ rtw_hal_bcn_related_reg_setting(padapter); ++} ++ ++static struct adapter *pbuddy_padapter; ++ ++int rtw_handle_dualmac(struct adapter *adapter, bool init) ++{ ++ int status = _SUCCESS; ++ ++ if (init) { ++ if (!pbuddy_padapter) { ++ pbuddy_padapter = adapter; ++ DBG_88E("%s(): pbuddy_padapter == NULL, Set pbuddy_padapter\n", __func__); ++ } else { ++ adapter->pbuddy_adapter = pbuddy_padapter; ++ pbuddy_padapter->pbuddy_adapter = adapter; ++ /* clear global value */ ++ pbuddy_padapter = NULL; ++ DBG_88E("%s(): pbuddy_padapter exist, Exchange Information\n", __func__); ++ } ++ } else { ++ pbuddy_padapter = NULL; ++ } ++ return status; ++} +diff --git a/drivers/staging/r8188eu/core/rtw_xmit.c b/drivers/staging/r8188eu/core/rtw_xmit.c +new file mode 100644 +index 000000000000..46fe62c7c32c +--- /dev/null ++++ b/drivers/staging/r8188eu/core/rtw_xmit.c +@@ -0,0 +1,2240 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _RTW_XMIT_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/wifi.h" ++#include "../include/osdep_intf.h" ++#include "../include/usb_ops.h" ++#include "../include/usb_osintf.h" ++ ++static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; ++static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; ++ ++static void _init_txservq(struct tx_servq *ptxservq) ++{ ++ ++ INIT_LIST_HEAD(&ptxservq->tx_pending); ++ _rtw_init_queue(&ptxservq->sta_pending); ++ ptxservq->qcnt = 0; ++ ++} ++ ++void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) ++{ ++ ++ memset((unsigned char *)psta_xmitpriv, 0, sizeof(struct sta_xmit_priv)); ++ spin_lock_init(&psta_xmitpriv->lock); ++ _init_txservq(&psta_xmitpriv->be_q); ++ _init_txservq(&psta_xmitpriv->bk_q); ++ _init_txservq(&psta_xmitpriv->vi_q); ++ _init_txservq(&psta_xmitpriv->vo_q); ++ INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); ++ INIT_LIST_HEAD(&psta_xmitpriv->apsd); ++ ++} ++ ++s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) ++{ ++ int i; ++ struct xmit_buf *pxmitbuf; ++ struct xmit_frame *pxframe; ++ int res = _SUCCESS; ++ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ ++ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by vzalloc(). */ ++ ++ spin_lock_init(&pxmitpriv->lock); ++ sema_init(&pxmitpriv->xmit_sema, 0); ++ sema_init(&pxmitpriv->terminate_xmitthread_sema, 0); ++ ++ /* ++ Please insert all the queue initializaiton using _rtw_init_queue below ++ */ ++ ++ pxmitpriv->adapter = padapter; ++ ++ _rtw_init_queue(&pxmitpriv->be_pending); ++ _rtw_init_queue(&pxmitpriv->bk_pending); ++ _rtw_init_queue(&pxmitpriv->vi_pending); ++ _rtw_init_queue(&pxmitpriv->vo_pending); ++ _rtw_init_queue(&pxmitpriv->bm_pending); ++ ++ _rtw_init_queue(&pxmitpriv->free_xmit_queue); ++ ++ /* ++ Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, ++ and initialize free_xmit_frame below. ++ Please also apply free_txobj to link_up all the xmit_frames... ++ */ ++ ++ pxmitpriv->pallocated_frame_buf = vzalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); ++ ++ if (!pxmitpriv->pallocated_frame_buf) { ++ pxmitpriv->pxmit_frame_buf = NULL; ++ res = _FAIL; ++ goto exit; ++ } ++ pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_frame_buf), 4); ++ /* pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - */ ++ /* ((size_t) (pxmitpriv->pallocated_frame_buf) &3); */ ++ ++ pxframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf; ++ ++ for (i = 0; i < NR_XMITFRAME; i++) { ++ INIT_LIST_HEAD(&pxframe->list); ++ ++ pxframe->padapter = padapter; ++ pxframe->frame_tag = NULL_FRAMETAG; ++ ++ pxframe->pkt = NULL; ++ ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ list_add_tail(&pxframe->list, &pxmitpriv->free_xmit_queue.queue); ++ ++ pxframe++; ++ } ++ ++ pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; ++ ++ pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; ++ ++ /* init xmit_buf */ ++ _rtw_init_queue(&pxmitpriv->free_xmitbuf_queue); ++ _rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue); ++ ++ pxmitpriv->pallocated_xmitbuf = vzalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4); ++ ++ if (!pxmitpriv->pallocated_xmitbuf) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmitbuf), 4); ++ /* pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - */ ++ /* ((size_t) (pxmitpriv->pallocated_xmitbuf) &3); */ ++ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; ++ ++ for (i = 0; i < NR_XMITBUFF; i++) { ++ INIT_LIST_HEAD(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->ext_tag = false; ++ ++ /* Tx buf allocation may fail sometimes, so sleep and retry. */ ++ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); ++ if (res == _FAIL) { ++ msleep(10); ++ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); ++ if (res == _FAIL) { ++ goto exit; ++ } ++ } ++ ++ pxmitbuf->flags = XMIT_VO_QUEUE; ++ ++ list_add_tail(&pxmitbuf->list, &pxmitpriv->free_xmitbuf_queue.queue); ++ pxmitbuf++; ++ } ++ ++ pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; ++ ++ /* Init xmit extension buff */ ++ _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); ++ ++ pxmitpriv->pallocated_xmit_extbuf = vzalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4); ++ ++ if (!pxmitpriv->pallocated_xmit_extbuf) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4); ++ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; ++ ++ for (i = 0; i < num_xmit_extbuf; i++) { ++ INIT_LIST_HEAD(&pxmitbuf->list); ++ ++ pxmitbuf->priv_data = NULL; ++ pxmitbuf->padapter = padapter; ++ pxmitbuf->ext_tag = true; ++ ++ res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ); ++ if (res == _FAIL) { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ list_add_tail(&pxmitbuf->list, &pxmitpriv->free_xmit_extbuf_queue.queue); ++ pxmitbuf++; ++ } ++ ++ pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; ++ ++ rtw_alloc_hwxmits(padapter); ++ rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); ++ ++ for (i = 0; i < 4; i++) ++ pxmitpriv->wmm_para_seq[i] = i; ++ ++ pxmitpriv->txirp_cnt = 1; ++ ++ sema_init(&pxmitpriv->tx_retevt, 0); ++ ++ /* per AC pending irp */ ++ pxmitpriv->beq_cnt = 0; ++ pxmitpriv->bkq_cnt = 0; ++ pxmitpriv->viq_cnt = 0; ++ pxmitpriv->voq_cnt = 0; ++ ++ pxmitpriv->ack_tx = false; ++ _rtw_mutex_init(&pxmitpriv->ack_tx_mutex); ++ rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0); ++ ++ rtw_hal_init_xmit_priv(padapter); ++ ++exit: ++ ++ return res; ++} ++ ++void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv) ++{ ++ int i; ++ struct adapter *padapter = pxmitpriv->adapter; ++ struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitpriv->pxmit_frame_buf; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; ++ u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; ++ u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; ++ ++ if (!pxmitpriv->pxmit_frame_buf) ++ return; ++ ++ for (i = 0; i < NR_XMITFRAME; i++) { ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ ++ pxmitframe++; ++ } ++ ++ for (i = 0; i < NR_XMITBUFF; i++) { ++ rtw_os_xmit_resource_free(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ)); ++ pxmitbuf++; ++ } ++ ++ vfree(pxmitpriv->pallocated_frame_buf); ++ ++ vfree(pxmitpriv->pallocated_xmitbuf); ++ ++ pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; ++ for (i = 0; i < num_xmit_extbuf; i++) { ++ rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ)); ++ pxmitbuf++; ++ } ++ ++ vfree(pxmitpriv->pallocated_xmit_extbuf); ++ ++ rtw_free_hwxmits(padapter); ++ ++ _rtw_mutex_free(&pxmitpriv->ack_tx_mutex); ++} ++ ++static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ u32 sz; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct sta_info *psta = pattrib->psta; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (pattrib->nr_frags != 1) ++ sz = padapter->xmitpriv.frag_len; ++ else /* no frag */ ++ sz = pattrib->last_txcmdsz; ++ ++ /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */ ++ /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */ ++ /* Other fragments are protected by previous fragment. */ ++ /* So we only need to check the length of first fragment. */ ++ if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) { ++ if (sz > padapter->registrypriv.rts_thresh) { ++ pattrib->vcs_mode = RTS_CTS; ++ } else { ++ if (psta->rtsen) ++ pattrib->vcs_mode = RTS_CTS; ++ else if (psta->cts2self) ++ pattrib->vcs_mode = CTS_TO_SELF; ++ else ++ pattrib->vcs_mode = NONE_VCS; ++ } ++ } else { ++ while (true) { ++ /* IOT action */ ++ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && pattrib->ampdu_en && ++ (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { ++ pattrib->vcs_mode = CTS_TO_SELF; ++ break; ++ } ++ ++ /* check ERP protection */ ++ if (psta->rtsen || psta->cts2self) { ++ if (psta->rtsen) ++ pattrib->vcs_mode = RTS_CTS; ++ else if (psta->cts2self) ++ pattrib->vcs_mode = CTS_TO_SELF; ++ ++ break; ++ } ++ ++ /* check HT op mode */ ++ if (pattrib->ht_en) { ++ u8 htopmode = pmlmeinfo->HT_protection; ++ if ((pmlmeext->cur_bwmode && (htopmode == 2 || htopmode == 3)) || ++ (!pmlmeext->cur_bwmode && htopmode == 3)) { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ } ++ ++ /* check rts */ ++ if (sz > padapter->registrypriv.rts_thresh) { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ ++ /* to do list: check MIMO power save condition. */ ++ ++ /* check AMPDU aggregation for TXOP */ ++ if (pattrib->ampdu_en) { ++ pattrib->vcs_mode = RTS_CTS; ++ break; ++ } ++ ++ pattrib->vcs_mode = NONE_VCS; ++ break; ++ } ++ } ++} ++ ++static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta) ++{ ++ /*if (psta->rtsen) ++ pattrib->vcs_mode = RTS_CTS; ++ else if (psta->cts2self) ++ pattrib->vcs_mode = CTS_TO_SELF; ++ else ++ pattrib->vcs_mode = NONE_VCS;*/ ++ ++ pattrib->mdata = 0; ++ pattrib->eosp = 0; ++ pattrib->triggered = 0; ++ ++ /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */ ++ pattrib->qos_en = psta->qos_option; ++ ++ pattrib->raid = psta->raid; ++ pattrib->ht_en = psta->htpriv.ht_option; ++ pattrib->bwmode = psta->htpriv.bwmode; ++ pattrib->ch_offset = psta->htpriv.ch_offset; ++ pattrib->sgi = psta->htpriv.sgi; ++ pattrib->ampdu_en = false; ++ pattrib->retry_ctrl = false; ++} ++ ++u8 qos_acm(u8 acm_mask, u8 priority) ++{ ++ u8 change_priority = priority; ++ ++ switch (priority) { ++ case 0: ++ case 3: ++ if (acm_mask & BIT(1)) ++ change_priority = 1; ++ break; ++ case 1: ++ case 2: ++ break; ++ case 4: ++ case 5: ++ if (acm_mask & BIT(2)) ++ change_priority = 0; ++ break; ++ case 6: ++ case 7: ++ if (acm_mask & BIT(3)) ++ change_priority = 5; ++ break; ++ default: ++ DBG_88E("qos_acm(): invalid pattrib->priority: %d!!!\n", priority); ++ break; ++ } ++ ++ return change_priority; ++} ++ ++static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) ++{ ++ struct ethhdr etherhdr; ++ struct iphdr ip_hdr; ++ s32 user_prio = 0; ++ ++ _rtw_open_pktfile(ppktfile->pkt, ppktfile); ++ _rtw_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); ++ ++ /* get user_prio from IP hdr */ ++ if (pattrib->ether_type == 0x0800) { ++ _rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); ++/* user_prio = (ntohs(ip_hdr.tos) >> 5) & 0x3; */ ++ user_prio = ip_hdr.tos >> 5; ++ } else if (pattrib->ether_type == 0x888e) { ++ /* "When priority processing of data frames is supported, */ ++ /* a STA's SME should send EAPOL-Key frames at the highest priority." */ ++ user_prio = 7; ++ } ++ ++ pattrib->priority = user_prio; ++ pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; ++ pattrib->subtype = WIFI_QOS_DATA_TYPE; ++} ++ ++static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib) ++{ ++ struct pkt_file pktfile; ++ struct sta_info *psta = NULL; ++ struct ethhdr etherhdr; ++ ++ bool bmcast; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ int res = _SUCCESS; ++ ++ ++ ++ _rtw_open_pktfile(pkt, &pktfile); ++ _rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN); ++ ++ pattrib->ether_type = ntohs(etherhdr.h_proto); ++ ++ memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); ++ memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); ++ ++ pattrib->pctrl = 0; ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); ++ memcpy(pattrib->ta, pattrib->src, ETH_ALEN); ++ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); ++ memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); ++ } ++ ++ pattrib->pktlen = pktfile.pkt_len; ++ ++ if (ETH_P_IP == pattrib->ether_type) { ++ /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */ ++ /* to prevent DHCP protocol fail */ ++ u8 tmp[24]; ++ _rtw_pktfile_read(&pktfile, &tmp[0], 24); ++ pattrib->dhcp_pkt = 0; ++ if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ ++ if (ETH_P_IP == pattrib->ether_type) {/* IP header */ ++ if (((tmp[21] == 68) && (tmp[23] == 67)) || ++ ((tmp[21] == 67) && (tmp[23] == 68))) { ++ /* 68 : UDP BOOTP client */ ++ /* 67 : UDP BOOTP server */ ++ /* Use low rate to send DHCP packet. */ ++ pattrib->dhcp_pkt = 1; ++ } ++ } ++ } ++ } else if (0x888e == pattrib->ether_type) { ++ DBG_88E_LEVEL(_drv_info_, "send eapol packet\n"); ++ } ++ ++ if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) ++ rtw_set_scan_deny(padapter, 3000); ++ ++ /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ ++ if ((pattrib->ether_type == 0x0806) || (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1); ++ ++ bmcast = is_multicast_ether_addr(pattrib->ra); ++ ++ /* get sta_info */ ++ if (bmcast) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ if (!psta) { /* if we cannot get psta => drrp the pkt */ ++ res = _FAIL; ++ goto exit; ++ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) && !(psta->state & _FW_LINKED)) { ++ res = _FAIL; ++ goto exit; ++ } ++ } ++ ++ if (psta) { ++ pattrib->mac_id = psta->mac_id; ++ /* DBG_88E("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */ ++ pattrib->psta = psta; ++ } else { ++ /* if we cannot get psta => drop the pkt */ ++ res = _FAIL; ++ goto exit; ++ } ++ ++ pattrib->ack_policy = 0; ++ /* get ether_hdr_len */ ++ pattrib->pkt_hdrlen = ETH_HLEN;/* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */ ++ ++ pattrib->hdrlen = WLAN_HDR_A3_LEN; ++ pattrib->subtype = WIFI_DATA_TYPE; ++ pattrib->priority = 0; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE | WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { ++ if (psta->qos_option) ++ set_qos(&pktfile, pattrib); ++ } else { ++ if (pqospriv->qos_option) { ++ set_qos(&pktfile, pattrib); ++ ++ if (pmlmepriv->acm_mask != 0) ++ pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority); ++ } ++ } ++ ++ if (psta->ieee8021x_blocked) { ++ pattrib->encrypt = 0; ++ ++ if ((pattrib->ether_type != 0x888e) && !check_fwstate(pmlmepriv, WIFI_MP_STATE)) { ++ res = _FAIL; ++ goto exit; ++ } ++ } else { ++ GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); ++ ++ switch (psecuritypriv->dot11AuthAlgrthm) { ++ case dot11AuthAlgrthm_Open: ++ case dot11AuthAlgrthm_Shared: ++ case dot11AuthAlgrthm_Auto: ++ pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex; ++ break; ++ case dot11AuthAlgrthm_8021X: ++ if (bmcast) ++ pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid; ++ else ++ pattrib->key_idx = 0; ++ break; ++ default: ++ pattrib->key_idx = 0; ++ break; ++ } ++ } ++ ++ switch (pattrib->encrypt) { ++ case _WEP40_: ++ case _WEP104_: ++ pattrib->iv_len = 4; ++ pattrib->icv_len = 4; ++ break; ++ case _TKIP_: ++ pattrib->iv_len = 8; ++ pattrib->icv_len = 4; ++ ++ if (padapter->securitypriv.busetkipkey == _FAIL) { ++ res = _FAIL; ++ goto exit; ++ } ++ break; ++ case _AES_: ++ pattrib->iv_len = 8; ++ pattrib->icv_len = 8; ++ break; ++ default: ++ pattrib->iv_len = 0; ++ pattrib->icv_len = 0; ++ break; ++ } ++ ++ if (pattrib->encrypt && ++ (padapter->securitypriv.sw_encrypt || !psecuritypriv->hw_decrypted)) ++ pattrib->bswenc = true; ++ else ++ pattrib->bswenc = false; ++ ++ rtw_set_tx_chksum_offload(pkt, pattrib); ++ ++ update_attrib_phy_info(pattrib, psta); ++ ++exit: ++ ++ return res; ++} ++ ++static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ int curfragnum, length; ++ u8 *pframe, *payload, mic[8]; ++ struct mic_data micdata; ++ struct sta_info *stainfo; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; ++ u8 hw_hdr_offset = 0; ++ ++ if (pattrib->psta) ++ stainfo = pattrib->psta; ++ else ++ stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]); ++ ++ hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); ++ ++ if (pattrib->encrypt == _TKIP_) {/* if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_PRIVACY_) */ ++ /* encode mic code */ ++ if (stainfo) { ++ u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ++ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ++ 0x0, 0x0}; ++ ++ pframe = pxmitframe->buf_addr + hw_hdr_offset; ++ ++ if (is_multicast_ether_addr(pattrib->ra)) { ++ if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16)) ++ return _FAIL; ++ /* start to calculate the mic code */ ++ rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey); ++ } else { ++ if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0], null_key, 16)) { ++ /* msleep(10); */ ++ return _FAIL; ++ } ++ /* start to calculate the mic code */ ++ rtw_secmicsetkey(&micdata, &stainfo->dot11tkiptxmickey.skey[0]); ++ } ++ ++ if (pframe[1] & 1) { /* ToDS == 1 */ ++ rtw_secmicappend(&micdata, &pframe[16], 6); /* DA */ ++ if (pframe[1] & 2) /* From Ds == 1 */ ++ rtw_secmicappend(&micdata, &pframe[24], 6); ++ else ++ rtw_secmicappend(&micdata, &pframe[10], 6); ++ } else { /* ToDS == 0 */ ++ rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */ ++ if (pframe[1] & 2) /* From Ds == 1 */ ++ rtw_secmicappend(&micdata, &pframe[16], 6); ++ else ++ rtw_secmicappend(&micdata, &pframe[10], 6); ++ } ++ ++ if (pattrib->qos_en) ++ priority[0] = (u8)pxmitframe->attrib.priority; ++ ++ rtw_secmicappend(&micdata, &priority[0], 4); ++ ++ payload = pframe; ++ ++ for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { ++ payload = (u8 *)RND4((size_t)(payload)); ++ ++ payload = payload + pattrib->hdrlen + pattrib->iv_len; ++ if ((curfragnum + 1) == pattrib->nr_frags) { ++ length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - ((pattrib->bswenc) ? pattrib->icv_len : 0); ++ rtw_secmicappend(&micdata, payload, length); ++ payload = payload + length; ++ } else { ++ length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - ((pattrib->bswenc) ? pattrib->icv_len : 0); ++ rtw_secmicappend(&micdata, payload, length); ++ payload = payload + length + pattrib->icv_len; ++ } ++ } ++ rtw_secgetmic(&micdata, &mic[0]); ++ /* add mic code and add the mic code length in last_txcmdsz */ ++ ++ memcpy(payload, &mic[0], 8); ++ pattrib->last_txcmdsz += 8; ++ ++ payload = payload - pattrib->last_txcmdsz + 8; ++ } ++ } ++ ++ return _SUCCESS; ++} ++ ++static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ if (pattrib->bswenc) { ++ switch (pattrib->encrypt) { ++ case _WEP40_: ++ case _WEP104_: ++ rtw_wep_encrypt(padapter, (u8 *)pxmitframe); ++ break; ++ case _TKIP_: ++ rtw_tkip_encrypt(padapter, (u8 *)pxmitframe); ++ break; ++ case _AES_: ++ rtw_aes_encrypt(padapter, (u8 *)pxmitframe); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return _SUCCESS; ++} ++ ++s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattrib) ++{ ++ u16 *qc; ++ ++ struct rtw_ieee80211_hdr *pwlanhdr = (struct rtw_ieee80211_hdr *)hdr; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct qos_priv *pqospriv = &pmlmepriv->qospriv; ++ u8 qos_option = false; ++ ++ int res = _SUCCESS; ++ __le16 *fctrl = &pwlanhdr->frame_ctl; ++ ++ struct sta_info *psta; ++ ++ if (pattrib->psta) { ++ psta = pattrib->psta; ++ } else { ++ if (is_multicast_ether_addr(pattrib->ra)) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ } else { ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ } ++ } ++ ++ memset(hdr, 0, WLANHDR_OFFSET); ++ ++ SetFrameSubType(fctrl, pattrib->subtype); ++ ++ if (pattrib->subtype & WIFI_DATA_TYPE) { ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { ++ /* to_ds = 1, fr_ds = 0; */ ++ /* Data transfer to AP */ ++ SetToDs(fctrl); ++ memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); ++ ++ if (pqospriv->qos_option) ++ qos_option = true; ++ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ /* to_ds = 0, fr_ds = 1; */ ++ SetFrDs(fctrl); ++ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); ++ ++ if (psta->qos_option) ++ qos_option = true; ++ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { ++ memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); ++ ++ if (psta->qos_option) ++ qos_option = true; ++ } else { ++ res = _FAIL; ++ goto exit; ++ } ++ ++ if (pattrib->mdata) ++ SetMData(fctrl); ++ ++ if (pattrib->encrypt) ++ SetPrivacy(fctrl); ++ ++ if (qos_option) { ++ qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); ++ ++ if (pattrib->priority) ++ SetPriority(qc, pattrib->priority); ++ ++ SetEOSP(qc, pattrib->eosp); ++ ++ SetAckpolicy(qc, pattrib->ack_policy); ++ } ++ ++ /* TODO: fill HT Control Field */ ++ ++ /* Update Seq Num will be handled by f/w */ ++ if (psta) { ++ psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; ++ psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; ++ ++ pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; ++ ++ SetSeqNum(hdr, pattrib->seqnum); ++ ++ /* check if enable ampdu */ ++ if (pattrib->ht_en && psta->htpriv.ampdu_enable) { ++ if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) ++ pattrib->ampdu_en = true; ++ } ++ ++ /* re-check if enable ampdu by BA_starting_seqctrl */ ++ if (pattrib->ampdu_en) { ++ u16 tx_seq; ++ ++ tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f]; ++ ++ /* check BA_starting_seqctrl */ ++ if (SN_LESS(pattrib->seqnum, tx_seq)) { ++ pattrib->ampdu_en = false;/* AGG BK */ ++ } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) { ++ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq + 1) & 0xfff; ++ ++ pattrib->ampdu_en = true;/* AGG EN */ ++ } else { ++ psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum + 1) & 0xfff; ++ pattrib->ampdu_en = true;/* AGG EN */ ++ } ++ } ++ } ++ } ++exit: ++ ++ return res; ++} ++ ++s32 rtw_txframes_pending(struct adapter *padapter) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ return (!list_empty(&pxmitpriv->be_pending.queue) || ++ !list_empty(&pxmitpriv->bk_pending.queue) || ++ !list_empty(&pxmitpriv->vi_pending.queue) || ++ !list_empty(&pxmitpriv->vo_pending.queue)); ++} ++ ++s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ struct sta_info *psta; ++ struct tx_servq *ptxservq; ++ int priority = pattrib->priority; ++ ++ psta = pattrib->psta; ++ ++ switch (priority) { ++ case 1: ++ case 2: ++ ptxservq = &psta->sta_xmitpriv.bk_q; ++ break; ++ case 4: ++ case 5: ++ ptxservq = &psta->sta_xmitpriv.vi_q; ++ break; ++ case 6: ++ case 7: ++ ptxservq = &psta->sta_xmitpriv.vo_q; ++ break; ++ case 0: ++ case 3: ++ default: ++ ptxservq = &psta->sta_xmitpriv.be_q; ++ break; ++ } ++ ++ if (ptxservq) ++ return ptxservq->qcnt; ++ return 0; ++} ++ ++/* ++ * Calculate wlan 802.11 packet MAX size from pkt_attrib ++ * This function doesn't consider fragment case ++ */ ++u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib) ++{ ++ u32 len = 0; ++ ++ len = pattrib->hdrlen + pattrib->iv_len; /* WLAN Header and IV */ ++ len += SNAP_SIZE + sizeof(u16); /* LLC */ ++ len += pattrib->pktlen; ++ if (pattrib->encrypt == _TKIP_) ++ len += 8; /* MIC */ ++ len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /* ICV */ ++ ++ return len; ++} ++ ++/* ++ ++This sub-routine will perform all the following: ++ ++1. remove 802.3 header. ++2. create wlan_header, based on the info in pxmitframe ++3. append sta's iv/ext-iv ++4. append LLC ++5. move frag chunk from pframe to pxmitframe->mem ++6. apply sw-encrypt, if necessary. ++ ++*/ ++s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe) ++{ ++ struct pkt_file pktfile; ++ s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; ++ size_t addr; ++ u8 *pframe, *mem_start; ++ u8 hw_hdr_offset; ++ struct sta_info *psta; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ u8 *pbuf_start; ++ bool bmcst = is_multicast_ether_addr(pattrib->ra); ++ s32 res = _SUCCESS; ++ ++ if (!pkt) ++ return _FAIL; ++ ++ psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); ++ ++ if (!psta) ++ return _FAIL; ++ ++ if (!pxmitframe->buf_addr) { ++ DBG_88E("==> %s buf_addr == NULL\n", __func__); ++ return _FAIL; ++ } ++ ++ pbuf_start = pxmitframe->buf_addr; ++ ++ hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); ++ ++ mem_start = pbuf_start + hw_hdr_offset; ++ ++ if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { ++ DBG_88E("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ _rtw_open_pktfile(pkt, &pktfile); ++ _rtw_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen); ++ ++ frg_inx = 0; ++ frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ ++ ++ while (1) { ++ llc_sz = 0; ++ ++ mpdu_len = frg_len; ++ ++ pframe = mem_start; ++ ++ SetMFrag(mem_start); ++ ++ pframe += pattrib->hdrlen; ++ mpdu_len -= pattrib->hdrlen; ++ ++ /* adding icv, if necessary... */ ++ if (pattrib->iv_len) { ++ if (psta) { ++ switch (pattrib->encrypt) { ++ case _WEP40_: ++ case _WEP104_: ++ WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ break; ++ case _TKIP_: ++ if (bmcst) ++ TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ else ++ TKIP_IV(pattrib->iv, psta->dot11txpn, 0); ++ break; ++ case _AES_: ++ if (bmcst) ++ AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); ++ else ++ AES_IV(pattrib->iv, psta->dot11txpn, 0); ++ break; ++ } ++ } ++ ++ memcpy(pframe, pattrib->iv, pattrib->iv_len); ++ ++ pframe += pattrib->iv_len; ++ ++ mpdu_len -= pattrib->iv_len; ++ } ++ ++ if (frg_inx == 0) { ++ llc_sz = rtw_put_snap(pframe, pattrib->ether_type); ++ pframe += llc_sz; ++ mpdu_len -= llc_sz; ++ } ++ ++ if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { ++ mpdu_len -= pattrib->icv_len; ++ } ++ ++ if (bmcst) { ++ /* don't do fragment to broadcat/multicast packets */ ++ mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen); ++ } else { ++ mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len); ++ } ++ ++ pframe += mem_sz; ++ ++ if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { ++ memcpy(pframe, pattrib->icv, pattrib->icv_len); ++ pframe += pattrib->icv_len; ++ } ++ ++ frg_inx++; ++ ++ if (bmcst || rtw_endofpktfile(&pktfile)) { ++ pattrib->nr_frags = frg_inx; ++ ++ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) + ++ ((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz; ++ ++ ClearMFrag(mem_start); ++ ++ break; ++ } ++ ++ addr = (size_t)(pframe); ++ ++ mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset; ++ memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); ++ } ++ ++ if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { ++ DBG_88E("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"); ++ res = _FAIL; ++ goto exit; ++ } ++ ++ xmitframe_swencrypt(padapter, pxmitframe); ++ ++ if (!bmcst) ++ update_attrib_vcs_info(padapter, pxmitframe); ++ else ++ pattrib->vcs_mode = NONE_VCS; ++ ++exit: ++ ++ return res; ++} ++ ++/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header ++ * IEEE LLC/SNAP header contains 8 octets ++ * First 3 octets comprise the LLC portion ++ * SNAP portion, 5 octets, is divided into two fields: ++ * Organizationally Unique Identifier(OUI), 3 octets, ++ * type, defined by that organization, 2 octets. ++ */ ++s32 rtw_put_snap(u8 *data, u16 h_proto) ++{ ++ struct ieee80211_snap_hdr *snap; ++ u8 *oui; ++ ++ snap = (struct ieee80211_snap_hdr *)data; ++ snap->dsap = 0xaa; ++ snap->ssap = 0xaa; ++ snap->ctrl = 0x03; ++ ++ if (h_proto == 0x8137 || h_proto == 0x80f3) ++ oui = P802_1H_OUI; ++ else ++ oui = RFC1042_OUI; ++ ++ snap->oui[0] = oui[0]; ++ snap->oui[1] = oui[1]; ++ snap->oui[2] = oui[2]; ++ ++ *(__be16 *)(data + SNAP_SIZE) = htons(h_proto); ++ ++ return SNAP_SIZE + sizeof(u16); ++} ++ ++void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) ++{ ++ uint protection; ++ u8 *perp; ++ int erp_len; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ ++ switch (pxmitpriv->vcs_setting) { ++ case DISABLE_VCS: ++ pxmitpriv->vcs = NONE_VCS; ++ break; ++ case ENABLE_VCS: ++ break; ++ case AUTO_VCS: ++ default: ++ perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); ++ if (!perp) { ++ pxmitpriv->vcs = NONE_VCS; ++ } else { ++ protection = (*(perp + 2)) & BIT(1); ++ if (protection) { ++ if (pregistrypriv->vcs_type == RTS_CTS) ++ pxmitpriv->vcs = RTS_CTS; ++ else ++ pxmitpriv->vcs = CTS_TO_SELF; ++ } else { ++ pxmitpriv->vcs = NONE_VCS; ++ } ++ } ++ break; ++ } ++ ++} ++ ++void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz) ++{ ++ struct sta_info *psta = NULL; ++ struct stainfo_stats *pstats = NULL; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) { ++ pxmitpriv->tx_bytes += sz; ++ pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pxmitframe->agg_num; ++ ++ psta = pxmitframe->attrib.psta; ++ if (psta) { ++ pstats = &psta->sta_stats; ++ pstats->tx_pkts += pxmitframe->agg_num; ++ pstats->tx_bytes += sz; ++ } ++ } ++} ++ ++struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_buf *pxmitbuf = NULL; ++ struct list_head *plist, *phead; ++ struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pfree_queue->lock, flags); ++ ++ if (list_empty(&pfree_queue->queue)) { ++ pxmitbuf = NULL; ++ } else { ++ phead = get_list_head(pfree_queue); ++ ++ plist = phead->next; ++ ++ pxmitbuf = container_of(plist, struct xmit_buf, list); ++ ++ list_del_init(&pxmitbuf->list); ++ } ++ ++ if (pxmitbuf) { ++ pxmitpriv->free_xmit_extbuf_cnt--; ++ ++ pxmitbuf->priv_data = NULL; ++ /* pxmitbuf->ext_tag = true; */ ++ ++ if (pxmitbuf->sctx) { ++ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); ++ } ++ } ++ ++ spin_unlock_irqrestore(&pfree_queue->lock, flags); ++ ++ return pxmitbuf; ++} ++ ++s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; ++ unsigned long flags; ++ ++ if (!pxmitbuf) ++ return _FAIL; ++ ++ spin_lock_irqsave(&pfree_queue->lock, flags); ++ ++ list_del_init(&pxmitbuf->list); ++ ++ list_add_tail(&pxmitbuf->list, get_list_head(pfree_queue)); ++ pxmitpriv->free_xmit_extbuf_cnt++; ++ ++ spin_unlock_irqrestore(&pfree_queue->lock, flags); ++ ++ return _SUCCESS; ++} ++ ++struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) ++{ ++ struct xmit_buf *pxmitbuf = NULL; ++ struct list_head *plist, *phead; ++ struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; ++ unsigned long flags; ++ ++ /* DBG_88E("+rtw_alloc_xmitbuf\n"); */ ++ ++ spin_lock_irqsave(&pfree_xmitbuf_queue->lock, flags); ++ ++ if (list_empty(&pfree_xmitbuf_queue->queue)) { ++ pxmitbuf = NULL; ++ } else { ++ phead = get_list_head(pfree_xmitbuf_queue); ++ ++ plist = phead->next; ++ ++ pxmitbuf = container_of(plist, struct xmit_buf, list); ++ ++ list_del_init(&pxmitbuf->list); ++ } ++ ++ if (pxmitbuf) { ++ pxmitpriv->free_xmitbuf_cnt--; ++ pxmitbuf->priv_data = NULL; ++ if (pxmitbuf->sctx) { ++ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); ++ } ++ } ++ spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, flags); ++ ++ return pxmitbuf; ++} ++ ++s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; ++ unsigned long flags; ++ ++ if (!pxmitbuf) ++ return _FAIL; ++ ++ if (pxmitbuf->sctx) { ++ DBG_88E("%s pxmitbuf->sctx is not NULL\n", __func__); ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE); ++ } ++ ++ if (pxmitbuf->ext_tag) { ++ rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf); ++ } else { ++ spin_lock_irqsave(&pfree_xmitbuf_queue->lock, flags); ++ ++ list_del_init(&pxmitbuf->list); ++ ++ list_add_tail(&pxmitbuf->list, get_list_head(pfree_xmitbuf_queue)); ++ ++ pxmitpriv->free_xmitbuf_cnt++; ++ spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, flags); ++ } ++ ++ return _SUCCESS; ++} ++ ++/* ++Calling context: ++1. OS_TXENTRY ++2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) ++ ++If we turn on USE_RXTHREAD, then, no need for critical section. ++Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... ++ ++Must be very very cautious... ++ ++*/ ++ ++struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */ ++{ ++ /* ++ Please remember to use all the osdep_service api, ++ and lock/unlock or _enter/_exit critical to protect ++ pfree_xmit_queue ++ */ ++ ++ struct xmit_frame *pxframe = NULL; ++ struct list_head *plist, *phead; ++ struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; ++ ++ spin_lock_bh(&pfree_xmit_queue->lock); ++ ++ if (list_empty(&pfree_xmit_queue->queue)) { ++ pxframe = NULL; ++ } else { ++ phead = get_list_head(pfree_xmit_queue); ++ ++ plist = phead->next; ++ ++ pxframe = container_of(plist, struct xmit_frame, list); ++ ++ list_del_init(&pxframe->list); ++ } ++ ++ if (pxframe) { /* default value setting */ ++ pxmitpriv->free_xmitframe_cnt--; ++ ++ pxframe->buf_addr = NULL; ++ pxframe->pxmitbuf = NULL; ++ ++ memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib)); ++ /* pxframe->attrib.psta = NULL; */ ++ ++ pxframe->frame_tag = DATA_FRAMETAG; ++ ++ pxframe->pkt = NULL; ++ pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */ ++ ++ pxframe->agg_num = 1; ++ pxframe->ack_report = 0; ++ } ++ ++ spin_unlock_bh(&pfree_xmit_queue->lock); ++ ++ return pxframe; ++} ++ ++s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe) ++{ ++ struct __queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; ++ struct adapter *padapter = pxmitpriv->adapter; ++ struct sk_buff *pndis_pkt = NULL; ++ ++ if (!pxmitframe) ++ goto exit; ++ ++ spin_lock_bh(&pfree_xmit_queue->lock); ++ ++ list_del_init(&pxmitframe->list); ++ ++ if (pxmitframe->pkt) { ++ pndis_pkt = pxmitframe->pkt; ++ pxmitframe->pkt = NULL; ++ } ++ ++ list_add_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue)); ++ ++ pxmitpriv->free_xmitframe_cnt++; ++ ++ spin_unlock_bh(&pfree_xmit_queue->lock); ++ ++ if (pndis_pkt) ++ rtw_os_pkt_complete(padapter, pndis_pkt); ++ ++exit: ++ ++ return _SUCCESS; ++} ++ ++void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pframequeue) ++{ ++ struct list_head *plist, *phead; ++ struct xmit_frame *pxmitframe; ++ ++ spin_lock_bh(&pframequeue->lock); ++ ++ phead = get_list_head(pframequeue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pxmitframe = container_of(plist, struct xmit_frame, list); ++ ++ plist = plist->next; ++ ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ } ++ spin_unlock_bh(&pframequeue->lock); ++ ++} ++ ++s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) { ++/* pxmitframe->pkt = NULL; */ ++ return _FAIL; ++ } ++ ++ return _SUCCESS; ++} ++ ++static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, struct __queue *pframe_queue) ++{ ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ ++ xmitframe_phead = get_list_head(pframe_queue); ++ xmitframe_plist = xmitframe_phead->next; ++ ++ if (xmitframe_phead != xmitframe_plist) { ++ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = xmitframe_plist->next; ++ ++ list_del_init(&pxmitframe->list); ++ ++ ptxservq->qcnt--; ++ } ++ return pxmitframe; ++} ++ ++struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, int entry) ++{ ++ struct list_head *sta_plist, *sta_phead; ++ struct hw_xmit *phwxmit; ++ struct tx_servq *ptxservq = NULL; ++ struct __queue *pframe_queue = NULL; ++ struct xmit_frame *pxmitframe = NULL; ++ struct adapter *padapter = pxmitpriv->adapter; ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ int i, inx[4]; ++ ++ inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; ++ ++ if (pregpriv->wifi_spec == 1) { ++ int j; ++ ++ for (j = 0; j < 4; j++) ++ inx[j] = pxmitpriv->wmm_para_seq[j]; ++ } ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ for (i = 0; i < entry; i++) { ++ phwxmit = phwxmit_i + inx[i]; ++ ++ sta_phead = get_list_head(phwxmit->sta_queue); ++ sta_plist = sta_phead->next; ++ ++ while (sta_phead != sta_plist) { ++ ptxservq = container_of(sta_plist, struct tx_servq, tx_pending); ++ ++ pframe_queue = &ptxservq->sta_pending; ++ ++ pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue); ++ ++ if (pxmitframe) { ++ phwxmit->accnt--; ++ ++ /* Remove sta node when there are no pending packets. */ ++ if (list_empty(&pframe_queue->queue)) /* must be done after get_next and before break */ ++ list_del_init(&ptxservq->tx_pending); ++ goto exit; ++ } ++ ++ sta_plist = sta_plist->next; ++ } ++ } ++exit: ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ return pxmitframe; ++} ++ ++struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info *psta, int up, u8 *ac) ++{ ++ struct tx_servq *ptxservq; ++ ++ switch (up) { ++ case 1: ++ case 2: ++ ptxservq = &psta->sta_xmitpriv.bk_q; ++ *(ac) = 3; ++ break; ++ case 4: ++ case 5: ++ ptxservq = &psta->sta_xmitpriv.vi_q; ++ *(ac) = 1; ++ break; ++ case 6: ++ case 7: ++ ptxservq = &psta->sta_xmitpriv.vo_q; ++ *(ac) = 0; ++ break; ++ case 0: ++ case 3: ++ default: ++ ptxservq = &psta->sta_xmitpriv.be_q; ++ *(ac) = 2; ++ break; ++ } ++ ++ return ptxservq; ++} ++ ++/* ++ * Will enqueue pxmitframe to the proper queue, ++ * and indicate it to xx_pending list..... ++ */ ++s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ u8 ac_index; ++ struct sta_info *psta; ++ struct tx_servq *ptxservq; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; ++ int res = _SUCCESS; ++ ++ if (pattrib->psta) { ++ psta = pattrib->psta; ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ } ++ ++ if (!psta) { ++ res = _FAIL; ++ DBG_88E("rtw_xmit_classifier: psta == NULL\n"); ++ goto exit; ++ } ++ ++ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); ++ ++ if (list_empty(&ptxservq->tx_pending)) ++ list_add_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue)); ++ ++ list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending)); ++ ptxservq->qcnt++; ++ phwxmits[ac_index].accnt++; ++exit: ++ ++ return res; ++} ++ ++void rtw_alloc_hwxmits(struct adapter *padapter) ++{ ++ struct hw_xmit *hwxmits; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; ++ ++ pxmitpriv->hwxmits = kzalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry, GFP_KERNEL); ++ ++ hwxmits = pxmitpriv->hwxmits; ++ ++ if (pxmitpriv->hwxmit_entry == 5) { ++ hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; ++ hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; ++ hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; ++ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; ++ hwxmits[4] .sta_queue = &pxmitpriv->be_pending; ++ } else if (pxmitpriv->hwxmit_entry == 4) { ++ hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; ++ hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; ++ hwxmits[2] .sta_queue = &pxmitpriv->be_pending; ++ hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; ++ } else { ++ } ++} ++ ++void rtw_free_hwxmits(struct adapter *padapter) ++{ ++ struct hw_xmit *hwxmits; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ hwxmits = pxmitpriv->hwxmits; ++ kfree(hwxmits); ++} ++ ++void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry) ++{ ++ int i; ++ ++ for (i = 0; i < entry; i++, phwxmit++) ++ phwxmit->accnt = 0; ++ ++} ++ ++static int rtw_br_client_tx(struct adapter *padapter, struct sk_buff **pskb) ++{ ++ struct sk_buff *skb = *pskb; ++ int res, is_vlan_tag = 0, i, do_nat25 = 1; ++ unsigned short vlan_hdr = 0; ++ void *br_port = NULL; ++ ++ rcu_read_lock(); ++ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); ++ rcu_read_unlock(); ++ spin_lock_bh(&padapter->br_ext_lock); ++ if (!(skb->data[0] & 1) && br_port && ++ memcmp(skb->data + MACADDRLEN, padapter->br_mac, MACADDRLEN) && ++ *((__be16 *)(skb->data + MACADDRLEN * 2)) != __constant_htons(ETH_P_8021Q) && ++ *((__be16 *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_IP) && ++ !memcmp(padapter->scdb_mac, skb->data + MACADDRLEN, MACADDRLEN) && padapter->scdb_entry) { ++ memcpy(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); ++ padapter->scdb_entry->ageing_timer = jiffies; ++ spin_unlock_bh(&padapter->br_ext_lock); ++ } else { ++ if (*((__be16 *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_8021Q)) { ++ is_vlan_tag = 1; ++ vlan_hdr = *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2)); ++ for (i = 0; i < 6; i++) ++ *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2 - i * 2)) = *((unsigned short *)(skb->data + MACADDRLEN * 2 - 2 - i * 2)); ++ skb_pull(skb, 4); ++ } ++ if (!memcmp(skb->data + MACADDRLEN, padapter->br_mac, MACADDRLEN) && ++ (*((__be16 *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_IP))) ++ memcpy(padapter->br_ip, skb->data + WLAN_ETHHDR_LEN + 12, 4); ++ ++ if (*((__be16 *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_IP)) { ++ if (memcmp(padapter->scdb_mac, skb->data + MACADDRLEN, MACADDRLEN)) { ++ padapter->scdb_entry = (struct nat25_network_db_entry *)scdb_findEntry(padapter, ++ skb->data + MACADDRLEN, skb->data + WLAN_ETHHDR_LEN + 12); ++ if (padapter->scdb_entry) { ++ memcpy(padapter->scdb_mac, skb->data + MACADDRLEN, MACADDRLEN); ++ memcpy(padapter->scdb_ip, skb->data + WLAN_ETHHDR_LEN + 12, 4); ++ padapter->scdb_entry->ageing_timer = jiffies; ++ do_nat25 = 0; ++ } ++ } else { ++ if (padapter->scdb_entry) { ++ padapter->scdb_entry->ageing_timer = jiffies; ++ do_nat25 = 0; ++ } else { ++ memset(padapter->scdb_mac, 0, MACADDRLEN); ++ memset(padapter->scdb_ip, 0, 4); ++ } ++ } ++ } ++ spin_unlock_bh(&padapter->br_ext_lock); ++ if (do_nat25) { ++ if (nat25_db_handle(padapter, skb, NAT25_CHECK) == 0) { ++ struct sk_buff *newskb; ++ ++ if (is_vlan_tag) { ++ skb_push(skb, 4); ++ for (i = 0; i < 6; i++) ++ *((unsigned short *)(skb->data + i * 2)) = *((unsigned short *)(skb->data + 4 + i * 2)); ++ *((__be16 *)(skb->data + MACADDRLEN * 2)) = __constant_htons(ETH_P_8021Q); ++ *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2)) = vlan_hdr; ++ } ++ ++ newskb = skb_copy(skb, GFP_ATOMIC); ++ if (!newskb) { ++ DEBUG_ERR("TX DROP: skb_copy fail!\n"); ++ return -1; ++ } ++ dev_kfree_skb_any(skb); ++ ++ *pskb = skb = newskb; ++ if (is_vlan_tag) { ++ vlan_hdr = *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2)); ++ for (i = 0; i < 6; i++) ++ *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2 - i * 2)) = *((unsigned short *)(skb->data + MACADDRLEN * 2 - 2 - i * 2)); ++ skb_pull(skb, 4); ++ } ++ } ++ ++ if (skb_is_nonlinear(skb)) ++ DEBUG_ERR("%s(): skb_is_nonlinear!!\n", __func__); ++ ++ res = skb_linearize(skb); ++ if (res < 0) { ++ DEBUG_ERR("TX DROP: skb_linearize fail!\n"); ++ return -1; ++ } ++ ++ res = nat25_db_handle(padapter, skb, NAT25_INSERT); ++ if (res < 0) { ++ if (res == -2) { ++ DEBUG_ERR("TX DROP: nat25_db_handle fail!\n"); ++ return -1; ++ } ++ return 0; ++ } ++ } ++ ++ memcpy(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); ++ ++ dhcp_flag_bcast(padapter, skb); ++ ++ if (is_vlan_tag) { ++ skb_push(skb, 4); ++ for (i = 0; i < 6; i++) ++ *((unsigned short *)(skb->data + i * 2)) = *((unsigned short *)(skb->data + 4 + i * 2)); ++ *((__be16 *)(skb->data + MACADDRLEN * 2)) = __constant_htons(ETH_P_8021Q); ++ *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2)) = vlan_hdr; ++ } ++ } ++ ++ /* check if SA is equal to our MAC */ ++ if (memcmp(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN)) { ++ DEBUG_ERR("TX DROP: untransformed frame SA:%02X%02X%02X%02X%02X%02X!\n", ++ skb->data[6], skb->data[7], skb->data[8], skb->data[9], skb->data[10], skb->data[11]); ++ return -1; ++ } ++ return 0; ++} ++ ++u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe) ++{ ++ u32 addr; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ switch (pattrib->qsel) { ++ case 0: ++ case 3: ++ addr = BE_QUEUE_INX; ++ break; ++ case 1: ++ case 2: ++ addr = BK_QUEUE_INX; ++ break; ++ case 4: ++ case 5: ++ addr = VI_QUEUE_INX; ++ break; ++ case 6: ++ case 7: ++ addr = VO_QUEUE_INX; ++ break; ++ case 0x10: ++ addr = BCN_QUEUE_INX; ++ break; ++ case 0x11:/* BC/MC in PS (HIQ) */ ++ addr = HIGH_QUEUE_INX; ++ break; ++ case 0x12: ++ default: ++ addr = MGT_QUEUE_INX; ++ break; ++ } ++ ++ return addr; ++} ++ ++static void do_queue_select(struct adapter *padapter, struct pkt_attrib *pattrib) ++{ ++ u8 qsel; ++ ++ qsel = pattrib->priority; ++ ++ pattrib->qsel = qsel; ++} ++ ++/* ++ * The main transmit(tx) entry ++ * ++ * Return ++ * 1 enqueue ++ * 0 success, hardware will handle this xmit frame(packet) ++ * <0 fail ++ */ ++s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct xmit_frame *pxmitframe = NULL; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ void *br_port = NULL; ++ s32 res; ++ ++ pxmitframe = rtw_alloc_xmitframe(pxmitpriv); ++ if (!pxmitframe) { ++ DBG_88E("DBG_TX_DROP_FRAME %s no more pxmitframe\n", __func__); ++ return -1; ++ } ++ ++ rcu_read_lock(); ++ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); ++ rcu_read_unlock(); ++ ++ if (br_port && check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE)) { ++ res = rtw_br_client_tx(padapter, ppkt); ++ if (res == -1) { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ return -1; ++ } ++ } ++ ++ res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); ++ ++ if (res == _FAIL) { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ return -1; ++ } ++ pxmitframe->pkt = *ppkt; ++ ++ rtw_led_control(padapter, LED_CTL_TX); ++ ++ do_queue_select(padapter, &pxmitframe->attrib); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ spin_lock_bh(&pxmitpriv->lock); ++ if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe)) { ++ spin_unlock_bh(&pxmitpriv->lock); ++ return 1; ++ } ++ spin_unlock_bh(&pxmitpriv->lock); ++#endif ++ ++ if (!rtw_hal_xmit(padapter, pxmitframe)) ++ return 1; ++ ++ return 0; ++} ++ ++#if defined(CONFIG_88EU_AP_MODE) ++ ++int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe) ++{ ++ int ret = false; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ bool bmcst = is_multicast_ether_addr(pattrib->ra); ++ ++ if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ return ret; ++ ++ if (pattrib->psta) ++ psta = pattrib->psta; ++ else ++ psta = rtw_get_stainfo(pstapriv, pattrib->ra); ++ ++ if (!psta) ++ return ret; ++ ++ if (pattrib->triggered == 1) { ++ if (bmcst) ++ pattrib->qsel = 0x11;/* HIQ */ ++ return ret; ++ } ++ ++ if (bmcst) { ++ spin_lock_bh(&psta->sleep_q.lock); ++ ++ if (pstapriv->sta_dz_bitmap) {/* if any one sta is in ps mode */ ++ list_del_init(&pxmitframe->list); ++ ++ list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); ++ ++ psta->sleepq_len++; ++ ++ pstapriv->tim_bitmap |= BIT(0);/* */ ++ pstapriv->sta_dz_bitmap |= BIT(0); ++ ++ update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */ ++ ++ ret = true; ++ } ++ ++ spin_unlock_bh(&psta->sleep_q.lock); ++ ++ return ret; ++ } ++ ++ spin_lock_bh(&psta->sleep_q.lock); ++ ++ if (psta->state & WIFI_SLEEP_STATE) { ++ u8 wmmps_ac = 0; ++ ++ if (pstapriv->sta_dz_bitmap & BIT(psta->aid)) { ++ list_del_init(&pxmitframe->list); ++ ++ list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); ++ ++ psta->sleepq_len++; ++ ++ switch (pattrib->priority) { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk & BIT(0); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi & BIT(0); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo & BIT(0); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be & BIT(0); ++ break; ++ } ++ ++ if (wmmps_ac) ++ psta->sleepq_ac_len++; ++ ++ if (((psta->has_legacy_ac) && (!wmmps_ac)) || ++ ((!psta->has_legacy_ac) && (wmmps_ac))) { ++ pstapriv->tim_bitmap |= BIT(psta->aid); ++ ++ if (psta->sleepq_len == 1) { ++ /* upate BCN for TIM IE */ ++ update_beacon(padapter, _TIM_IE_, NULL, false); ++ } ++ } ++ ret = true; ++ } ++ } ++ ++ spin_unlock_bh(&psta->sleep_q.lock); ++ ++ return ret; ++} ++ ++static void dequeue_xmitframes_to_sleeping_queue(struct adapter *padapter, struct sta_info *psta, struct __queue *pframequeue) ++{ ++ struct list_head *plist, *phead; ++ u8 ac_index; ++ struct tx_servq *ptxservq; ++ struct pkt_attrib *pattrib; ++ struct xmit_frame *pxmitframe; ++ struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; ++ ++ phead = get_list_head(pframequeue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pxmitframe = container_of(plist, struct xmit_frame, list); ++ ++ plist = plist->next; ++ ++ xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe); ++ ++ pattrib = &pxmitframe->attrib; ++ ++ ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); ++ ++ ptxservq->qcnt--; ++ phwxmits[ac_index].accnt--; ++ } ++} ++ ++void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta) ++{ ++ struct sta_info *psta_bmc; ++ struct sta_xmit_priv *pstaxmitpriv; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ pstaxmitpriv = &psta->sta_xmitpriv; ++ ++ /* for BC/MC Frames */ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ psta->state |= WIFI_SLEEP_STATE; ++ ++ pstapriv->sta_dz_bitmap |= BIT(psta->aid); ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending); ++ list_del_init(&pstaxmitpriv->vo_q.tx_pending); ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending); ++ list_del_init(&pstaxmitpriv->vi_q.tx_pending); ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending); ++ list_del_init(&pstaxmitpriv->be_q.tx_pending); ++ ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending); ++ list_del_init(&pstaxmitpriv->bk_q.tx_pending); ++ ++ /* for BC/MC Frames */ ++ pstaxmitpriv = &psta_bmc->sta_xmitpriv; ++ dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending); ++ list_del_init(&pstaxmitpriv->be_q.tx_pending); ++ ++ spin_unlock_bh(&pxmitpriv->lock); ++} ++ ++void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 update_mask = 0, wmmps_ac = 0; ++ struct sta_info *psta_bmc; ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ spin_lock_bh(&psta->sleep_q.lock); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = xmitframe_phead->next; ++ ++ while (xmitframe_phead != xmitframe_plist) { ++ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = xmitframe_plist->next; ++ ++ list_del_init(&pxmitframe->list); ++ ++ switch (pxmitframe->attrib.priority) { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk & BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi & BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo & BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be & BIT(1); ++ break; ++ } ++ ++ psta->sleepq_len--; ++ if (psta->sleepq_len > 0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ if (wmmps_ac) { ++ psta->sleepq_ac_len--; ++ if (psta->sleepq_ac_len > 0) { ++ pxmitframe->attrib.mdata = 1; ++ pxmitframe->attrib.eosp = 0; ++ } else { ++ pxmitframe->attrib.mdata = 0; ++ pxmitframe->attrib.eosp = 1; ++ } ++ } ++ ++ pxmitframe->attrib.triggered = 1; ++ ++ spin_unlock_bh(&psta->sleep_q.lock); ++ if (rtw_hal_xmit(padapter, pxmitframe)) ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ spin_lock_bh(&psta->sleep_q.lock); ++ } ++ ++ if (psta->sleepq_len == 0) { ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ update_mask = BIT(0); ++ ++ if (psta->state & WIFI_SLEEP_STATE) ++ psta->state ^= WIFI_SLEEP_STATE; ++ ++ if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { ++ psta->expire_to = pstapriv->expire_to; ++ psta->state ^= WIFI_STA_ALIVE_CHK_STATE; ++ } ++ ++ pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); ++ } ++ ++ spin_unlock_bh(&psta->sleep_q.lock); ++ ++ /* for BC/MC Frames */ ++ psta_bmc = rtw_get_bcmc_stainfo(padapter); ++ if (!psta_bmc) ++ return; ++ ++ if ((pstapriv->sta_dz_bitmap & 0xfffe) == 0x0) { /* no any sta in ps mode */ ++ spin_lock_bh(&psta_bmc->sleep_q.lock); ++ ++ xmitframe_phead = get_list_head(&psta_bmc->sleep_q); ++ xmitframe_plist = xmitframe_phead->next; ++ ++ while (xmitframe_phead != xmitframe_plist) { ++ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = xmitframe_plist->next; ++ ++ list_del_init(&pxmitframe->list); ++ ++ psta_bmc->sleepq_len--; ++ if (psta_bmc->sleepq_len > 0) ++ pxmitframe->attrib.mdata = 1; ++ else ++ pxmitframe->attrib.mdata = 0; ++ ++ pxmitframe->attrib.triggered = 1; ++ ++ spin_unlock_bh(&psta_bmc->sleep_q.lock); ++ if (rtw_hal_xmit(padapter, pxmitframe)) ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ spin_lock_bh(&psta_bmc->sleep_q.lock); ++ } ++ ++ if (psta_bmc->sleepq_len == 0) { ++ pstapriv->tim_bitmap &= ~BIT(0); ++ pstapriv->sta_dz_bitmap &= ~BIT(0); ++ ++ update_mask |= BIT(1); ++ } ++ ++ spin_unlock_bh(&psta_bmc->sleep_q.lock); ++ } ++ ++ if (update_mask) ++ update_beacon(padapter, _TIM_IE_, NULL, false); ++} ++ ++void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta) ++{ ++ u8 wmmps_ac = 0; ++ struct list_head *xmitframe_plist, *xmitframe_phead; ++ struct xmit_frame *pxmitframe = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ spin_lock_bh(&psta->sleep_q.lock); ++ ++ xmitframe_phead = get_list_head(&psta->sleep_q); ++ xmitframe_plist = xmitframe_phead->next; ++ ++ while (xmitframe_phead != xmitframe_plist) { ++ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); ++ ++ xmitframe_plist = xmitframe_plist->next; ++ ++ switch (pxmitframe->attrib.priority) { ++ case 1: ++ case 2: ++ wmmps_ac = psta->uapsd_bk & BIT(1); ++ break; ++ case 4: ++ case 5: ++ wmmps_ac = psta->uapsd_vi & BIT(1); ++ break; ++ case 6: ++ case 7: ++ wmmps_ac = psta->uapsd_vo & BIT(1); ++ break; ++ case 0: ++ case 3: ++ default: ++ wmmps_ac = psta->uapsd_be & BIT(1); ++ break; ++ } ++ ++ if (!wmmps_ac) ++ continue; ++ ++ list_del_init(&pxmitframe->list); ++ ++ psta->sleepq_len--; ++ psta->sleepq_ac_len--; ++ ++ if (psta->sleepq_ac_len > 0) { ++ pxmitframe->attrib.mdata = 1; ++ pxmitframe->attrib.eosp = 0; ++ } else { ++ pxmitframe->attrib.mdata = 0; ++ pxmitframe->attrib.eosp = 1; ++ } ++ ++ pxmitframe->attrib.triggered = 1; ++ ++ if (rtw_hal_xmit(padapter, pxmitframe)) ++ rtw_os_xmit_complete(padapter, pxmitframe); ++ ++ if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) { ++ pstapriv->tim_bitmap &= ~BIT(psta->aid); ++ ++ /* upate BCN for TIM IE */ ++ update_beacon(padapter, _TIM_IE_, NULL, false); ++ } ++ } ++ ++ spin_unlock_bh(&psta->sleep_q.lock); ++} ++ ++#endif ++ ++void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms) ++{ ++ sctx->timeout_ms = timeout_ms; ++ sctx->submit_time = jiffies; ++ init_completion(&sctx->done); ++ sctx->status = RTW_SCTX_SUBMITTED; ++} ++ ++int rtw_sctx_wait(struct submit_ctx *sctx) ++{ ++ int ret = _FAIL; ++ unsigned long expire; ++ int status = 0; ++ ++ expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT; ++ if (!wait_for_completion_timeout(&sctx->done, expire)) { ++ /* timeout, do something?? */ ++ status = RTW_SCTX_DONE_TIMEOUT; ++ DBG_88E("%s timeout\n", __func__); ++ } else { ++ status = sctx->status; ++ } ++ ++ if (status == RTW_SCTX_DONE_SUCCESS) ++ ret = _SUCCESS; ++ ++ return ret; ++} ++ ++static bool rtw_sctx_chk_waring_status(int status) ++{ ++ switch (status) { ++ case RTW_SCTX_DONE_UNKNOWN: ++ case RTW_SCTX_DONE_BUF_ALLOC: ++ case RTW_SCTX_DONE_BUF_FREE: ++ ++ case RTW_SCTX_DONE_DRV_STOP: ++ case RTW_SCTX_DONE_DEV_REMOVE: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++void rtw_sctx_done_err(struct submit_ctx **sctx, int status) ++{ ++ if (*sctx) { ++ if (rtw_sctx_chk_waring_status(status)) ++ DBG_88E("%s status:%d\n", __func__, status); ++ (*sctx)->status = status; ++ complete(&((*sctx)->done)); ++ *sctx = NULL; ++ } ++} ++ ++void rtw_sctx_done(struct submit_ctx **sctx) ++{ ++ rtw_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS); ++} ++ ++int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms) ++{ ++ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; ++ ++ pack_tx_ops->submit_time = jiffies; ++ pack_tx_ops->timeout_ms = timeout_ms; ++ pack_tx_ops->status = RTW_SCTX_SUBMITTED; ++ ++ return rtw_sctx_wait(pack_tx_ops); ++} ++ ++void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) ++{ ++ struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; ++ ++ if (pxmitpriv->ack_tx) ++ rtw_sctx_done_err(&pack_tx_ops, status); ++ else ++ DBG_88E("%s ack_tx not set\n", __func__); ++} +diff --git a/drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c b/drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c +new file mode 100644 +index 000000000000..48ede610cd28 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c +@@ -0,0 +1,69 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/Hal8188EPwrSeq.h" ++#include "../include/rtl8188e_hal.h" ++ ++/* ++ drivers should parse below arrays and do the corresponding actions ++*/ ++/* 3 Power on Array */ ++struct wl_pwr_cfg rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ RTL8188E_TRANS_CARDEMU_TO_ACT ++ RTL8188E_TRANS_END ++}; ++ ++/* 3Radio off Array */ ++struct wl_pwr_cfg rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ RTL8188E_TRANS_ACT_TO_CARDEMU ++ RTL8188E_TRANS_END ++}; ++ ++/* 3Card Disable Array */ ++struct wl_pwr_cfg rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ RTL8188E_TRANS_ACT_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_CARDDIS ++ RTL8188E_TRANS_END ++}; ++ ++/* 3 Card Enable Array */ ++struct wl_pwr_cfg rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ RTL8188E_TRANS_CARDDIS_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_ACT ++ RTL8188E_TRANS_END ++}; ++ ++/* 3Suspend Array */ ++struct wl_pwr_cfg rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ RTL8188E_TRANS_ACT_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_SUS ++ RTL8188E_TRANS_END ++}; ++ ++/* 3 Resume Array */ ++struct wl_pwr_cfg rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ RTL8188E_TRANS_SUS_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_ACT ++ RTL8188E_TRANS_END ++}; ++ ++/* 3HWPDN Array */ ++struct wl_pwr_cfg rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ RTL8188E_TRANS_ACT_TO_CARDEMU ++ RTL8188E_TRANS_CARDEMU_TO_PDN ++ RTL8188E_TRANS_END ++}; ++ ++/* 3 Enter LPS */ ++struct wl_pwr_cfg rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ /* FW behavior */ ++ RTL8188E_TRANS_ACT_TO_LPS ++ RTL8188E_TRANS_END ++}; ++ ++/* 3 Leave LPS */ ++struct wl_pwr_cfg rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS + RTL8188E_TRANS_END_STEPS] = { ++ /* FW behavior */ ++ RTL8188E_TRANS_LPS_TO_ACT ++ RTL8188E_TRANS_END ++}; +diff --git a/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c b/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c +new file mode 100644 +index 000000000000..d873672feb27 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c +@@ -0,0 +1,664 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (c) Realtek Semiconductor Corp. ++Module Name: ++ RateAdaptive.c ++ ++Abstract: ++ Implement Rate Adaptive functions for common operations. ++ ++Major Change History: ++ When Who What ++ ---------- --------------- ------------------------------- ++ 2011-08-12 Page Create. ++ ++--*/ ++#include "../include/odm_precomp.h" ++ ++/* Rate adaptive parameters */ ++ ++static u8 RETRY_PENALTY[PERENTRY][RETRYSIZE + 1] = { ++ {5, 4, 3, 2, 0, 3}, /* 92 , idx = 0 */ ++ {6, 5, 4, 3, 0, 4}, /* 86 , idx = 1 */ ++ {6, 5, 4, 2, 0, 4}, /* 81 , idx = 2 */ ++ {8, 7, 6, 4, 0, 6}, /* 75 , idx = 3 */ ++ {10, 9, 8, 6, 0, 8}, /* 71 , idx = 4 */ ++ {10, 9, 8, 4, 0, 8}, /* 66 , idx = 5 */ ++ {10, 9, 8, 2, 0, 8}, /* 62 , idx = 6 */ ++ {10, 9, 8, 0, 0, 8}, /* 59 , idx = 7 */ ++ {18, 17, 16, 8, 0, 16}, /* 53 , idx = 8 */ ++ {26, 25, 24, 16, 0, 24}, /* 50 , idx = 9 */ ++ {34, 33, 32, 24, 0, 32}, /* 47 , idx = 0x0a */ ++ {34, 31, 28, 20, 0, 32}, /* 43 , idx = 0x0b */ ++ {34, 31, 27, 18, 0, 32}, /* 40 , idx = 0x0c */ ++ {34, 31, 26, 16, 0, 32}, /* 37 , idx = 0x0d */ ++ {34, 30, 22, 16, 0, 32}, /* 32 , idx = 0x0e */ ++ {34, 30, 24, 16, 0, 32}, /* 26 , idx = 0x0f */ ++ {49, 46, 40, 16, 0, 48}, /* 20 , idx = 0x10 */ ++ {49, 45, 32, 0, 0, 48}, /* 17 , idx = 0x11 */ ++ {49, 45, 22, 18, 0, 48}, /* 15 , idx = 0x12 */ ++ {49, 40, 24, 16, 0, 48}, /* 12 , idx = 0x13 */ ++ {49, 32, 18, 12, 0, 48}, /* 9 , idx = 0x14 */ ++ {49, 22, 18, 14, 0, 48}, /* 6 , idx = 0x15 */ ++ {49, 16, 16, 0, 0, 48} ++ }; /* 3, idx = 0x16 */ ++ ++static u8 PT_PENALTY[RETRYSIZE + 1] = {34, 31, 30, 24, 0, 32}; ++ ++/* wilson modify */ ++static u8 RETRY_PENALTY_IDX[2][RATESIZE] = { ++ {4, 4, 4, 5, 4, 4, 5, 7, 7, 7, 8, 0x0a, /* SS>TH */ ++ 4, 4, 4, 4, 6, 0x0a, 0x0b, 0x0d, ++ 5, 5, 7, 7, 8, 0x0b, 0x0d, 0x0f}, /* 0329 R01 */ ++ {0x0a, 0x0a, 0x0b, 0x0c, 0x0a, ++ 0x0a, 0x0b, 0x0c, 0x0d, 0x10, 0x13, 0x14, /* SSTH */ ++ 0x0f, 0x10, 0x10, 0x12, 0x12, 0x13, 0x14, 0x15, ++ 0x11, 0x11, 0x12, 0x13, 0x13, 0x13, 0x14, 0x15}; ++ ++static u8 RSSI_THRESHOLD[RATESIZE] = { ++ 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0x24, 0x26, 0x2a, ++ 0x18, 0x1a, 0x1d, 0x1f, 0x21, 0x27, 0x29, 0x2a, ++ 0, 0, 0, 0x1f, 0x23, 0x28, 0x2a, 0x2c}; ++ ++static u16 N_THRESHOLD_HIGH[RATESIZE] = { ++ 4, 4, 8, 16, ++ 24, 36, 48, 72, 96, 144, 192, 216, ++ 60, 80, 100, 160, 240, 400, 560, 640, ++ 300, 320, 480, 720, 1000, 1200, 1600, 2000}; ++static u16 N_THRESHOLD_LOW[RATESIZE] = { ++ 2, 2, 4, 8, ++ 12, 18, 24, 36, 48, 72, 96, 108, ++ 30, 40, 50, 80, 120, 200, 280, 320, ++ 150, 160, 240, 360, 500, 600, 800, 1000}; ++ ++static u8 DROPING_NECESSARY[RATESIZE] = { ++ 1, 1, 1, 1, ++ 1, 2, 3, 4, 5, 6, 7, 8, ++ 1, 2, 3, 4, 5, 6, 7, 8, ++ 5, 6, 7, 8, 9, 10, 11, 12}; ++ ++static u8 PendingForRateUpFail[5] = {2, 10, 24, 40, 60}; ++static u16 DynamicTxRPTTiming[6] = { ++ 0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12, 0x927c}; /* 200ms-1200ms */ ++ ++/* End Rate adaptive parameters */ ++ ++static void odm_SetTxRPTTiming_8188E( ++ struct odm_dm_struct *dm_odm, ++ struct odm_ra_info *pRaInfo, ++ u8 extend ++ ) ++{ ++ u8 idx = 0; ++ ++ for (idx = 0; idx < 5; idx++) ++ if (DynamicTxRPTTiming[idx] == pRaInfo->RptTime) ++ break; ++ ++ if (extend == 0) { /* back to default timing */ ++ idx = 0; /* 200ms */ ++ } else if (extend == 1) {/* increase the timing */ ++ idx += 1; ++ if (idx > 5) ++ idx = 5; ++ } else if (extend == 2) {/* decrease the timing */ ++ if (idx != 0) ++ idx -= 1; ++ } ++ pRaInfo->RptTime = DynamicTxRPTTiming[idx]; ++} ++ ++static int odm_RateDown_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo) ++{ ++ u8 RateID, LowestRate, HighestRate; ++ u8 i; ++ ++ if (NULL == pRaInfo) ++ return -1; ++ RateID = pRaInfo->PreRate; ++ LowestRate = pRaInfo->LowestRate; ++ HighestRate = pRaInfo->HighestRate; ++ ++ if (RateID > HighestRate) { ++ RateID = HighestRate; ++ } else if (pRaInfo->RateSGI) { ++ pRaInfo->RateSGI = 0; ++ } else if (RateID > LowestRate) { ++ if (RateID > 0) { ++ for (i = RateID - 1; i > LowestRate; i--) { ++ if (pRaInfo->RAUseRate & BIT(i)) { ++ RateID = i; ++ goto RateDownFinish; ++ } ++ } ++ } ++ } else if (RateID <= LowestRate) { ++ RateID = LowestRate; ++ } ++RateDownFinish: ++ if (pRaInfo->RAWaitingCounter == 1) { ++ pRaInfo->RAWaitingCounter += 1; ++ pRaInfo->RAPendingCounter += 1; ++ } else if (pRaInfo->RAWaitingCounter == 0) { ++ ; ++ } else { ++ pRaInfo->RAWaitingCounter = 0; ++ pRaInfo->RAPendingCounter = 0; ++ } ++ ++ if (pRaInfo->RAPendingCounter >= 4) ++ pRaInfo->RAPendingCounter = 4; ++ ++ pRaInfo->DecisionRate = RateID; ++ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 2); ++ return 0; ++} ++ ++static int odm_RateUp_8188E( ++ struct odm_dm_struct *dm_odm, ++ struct odm_ra_info *pRaInfo ++ ) ++{ ++ u8 RateID, HighestRate; ++ u8 i; ++ ++ if (NULL == pRaInfo) ++ return -1; ++ RateID = pRaInfo->PreRate; ++ HighestRate = pRaInfo->HighestRate; ++ if (pRaInfo->RAWaitingCounter == 1) { ++ pRaInfo->RAWaitingCounter = 0; ++ pRaInfo->RAPendingCounter = 0; ++ } else if (pRaInfo->RAWaitingCounter > 1) { ++ pRaInfo->PreRssiStaRA = pRaInfo->RssiStaRA; ++ goto RateUpfinish; ++ } ++ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 0); ++ ++ if (RateID < HighestRate) { ++ for (i = RateID + 1; i <= HighestRate; i++) { ++ if (pRaInfo->RAUseRate & BIT(i)) { ++ RateID = i; ++ goto RateUpfinish; ++ } ++ } ++ } else if (RateID == HighestRate) { ++ if (pRaInfo->SGIEnable && (pRaInfo->RateSGI != 1)) ++ pRaInfo->RateSGI = 1; ++ else if ((pRaInfo->SGIEnable) != 1) ++ pRaInfo->RateSGI = 0; ++ } else { ++ RateID = HighestRate; ++ } ++RateUpfinish: ++ if (pRaInfo->RAWaitingCounter == (4 + PendingForRateUpFail[pRaInfo->RAPendingCounter])) ++ pRaInfo->RAWaitingCounter = 0; ++ else ++ pRaInfo->RAWaitingCounter++; ++ ++ pRaInfo->DecisionRate = RateID; ++ return 0; ++} ++ ++static void odm_ResetRaCounter_8188E(struct odm_ra_info *pRaInfo) ++{ ++ u8 RateID; ++ ++ RateID = pRaInfo->DecisionRate; ++ pRaInfo->NscUp = (N_THRESHOLD_HIGH[RateID] + N_THRESHOLD_LOW[RateID]) >> 1; ++ pRaInfo->NscDown = (N_THRESHOLD_HIGH[RateID] + N_THRESHOLD_LOW[RateID]) >> 1; ++} ++ ++static void odm_RateDecision_8188E(struct odm_dm_struct *dm_odm, ++ struct odm_ra_info *pRaInfo ++ ) ++{ ++ u8 RateID = 0, RtyPtID = 0, PenaltyID1 = 0, PenaltyID2 = 0; ++ /* u32 pool_retry; */ ++ static u8 DynamicTxRPTTimingCounter; ++ ++ if (pRaInfo->Active && (pRaInfo->TOTAL > 0)) { /* STA used and data packet exits */ ++ if ((pRaInfo->RssiStaRA < (pRaInfo->PreRssiStaRA - 3)) || ++ (pRaInfo->RssiStaRA > (pRaInfo->PreRssiStaRA + 3))) { ++ pRaInfo->RAWaitingCounter = 0; ++ pRaInfo->RAPendingCounter = 0; ++ } ++ /* Start RA decision */ ++ if (pRaInfo->PreRate > pRaInfo->HighestRate) ++ RateID = pRaInfo->HighestRate; ++ else ++ RateID = pRaInfo->PreRate; ++ if (pRaInfo->RssiStaRA > RSSI_THRESHOLD[RateID]) ++ RtyPtID = 0; ++ else ++ RtyPtID = 1; ++ PenaltyID1 = RETRY_PENALTY_IDX[RtyPtID][RateID]; /* TODO by page */ ++ ++ pRaInfo->NscDown += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID1][0]; ++ pRaInfo->NscDown += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID1][1]; ++ pRaInfo->NscDown += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID1][2]; ++ pRaInfo->NscDown += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID1][3]; ++ pRaInfo->NscDown += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID1][4]; ++ if (pRaInfo->NscDown > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5])) ++ pRaInfo->NscDown -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]; ++ else ++ pRaInfo->NscDown = 0; ++ ++ /* rate up */ ++ PenaltyID2 = RETRY_PENALTY_UP_IDX[RateID]; ++ pRaInfo->NscUp += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID2][0]; ++ pRaInfo->NscUp += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID2][1]; ++ pRaInfo->NscUp += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID2][2]; ++ pRaInfo->NscUp += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID2][3]; ++ pRaInfo->NscUp += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID2][4]; ++ if (pRaInfo->NscUp > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5])) ++ pRaInfo->NscUp -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]; ++ else ++ pRaInfo->NscUp = 0; ++ ++ if ((pRaInfo->NscDown < N_THRESHOLD_LOW[RateID]) || ++ (pRaInfo->DROP > DROPING_NECESSARY[RateID])) ++ odm_RateDown_8188E(dm_odm, pRaInfo); ++ else if (pRaInfo->NscUp > N_THRESHOLD_HIGH[RateID]) ++ odm_RateUp_8188E(dm_odm, pRaInfo); ++ ++ if (pRaInfo->DecisionRate > pRaInfo->HighestRate) ++ pRaInfo->DecisionRate = pRaInfo->HighestRate; ++ ++ if ((pRaInfo->DecisionRate) == (pRaInfo->PreRate)) ++ DynamicTxRPTTimingCounter += 1; ++ else ++ DynamicTxRPTTimingCounter = 0; ++ ++ if (DynamicTxRPTTimingCounter >= 4) { ++ odm_SetTxRPTTiming_8188E(dm_odm, pRaInfo, 1); ++ DynamicTxRPTTimingCounter = 0; ++ } ++ ++ pRaInfo->PreRate = pRaInfo->DecisionRate; /* YJ, add, 120120 */ ++ ++ odm_ResetRaCounter_8188E(pRaInfo); ++ } ++} ++ ++static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_info *pRaInfo) ++{ /* Wilson 2011/10/26 */ ++ u32 MaskFromReg; ++ s8 i; ++ ++ switch (pRaInfo->RateID) { ++ case RATR_INX_WIRELESS_NGB: ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & 0x0f8ff015; ++ break; ++ case RATR_INX_WIRELESS_NG: ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & 0x0f8ff010; ++ break; ++ case RATR_INX_WIRELESS_NB: ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & 0x0f8ff005; ++ break; ++ case RATR_INX_WIRELESS_N: ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & 0x0f8ff000; ++ break; ++ case RATR_INX_WIRELESS_GB: ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & 0x00000ff5; ++ break; ++ case RATR_INX_WIRELESS_G: ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & 0x00000ff0; ++ break; ++ case RATR_INX_WIRELESS_B: ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & 0x0000000d; ++ break; ++ case 12: ++ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR0); ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & MaskFromReg; ++ break; ++ case 13: ++ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR1); ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & MaskFromReg; ++ break; ++ case 14: ++ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR2); ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & MaskFromReg; ++ break; ++ case 15: ++ MaskFromReg = ODM_Read4Byte(dm_odm, REG_ARFR3); ++ pRaInfo->RAUseRate = (pRaInfo->RateMask) & MaskFromReg; ++ break; ++ default: ++ pRaInfo->RAUseRate = (pRaInfo->RateMask); ++ break; ++ } ++ /* Highest rate */ ++ if (pRaInfo->RAUseRate) { ++ for (i = RATESIZE; i >= 0; i--) { ++ if ((pRaInfo->RAUseRate) & BIT(i)) { ++ pRaInfo->HighestRate = i; ++ break; ++ } ++ } ++ } else { ++ pRaInfo->HighestRate = 0; ++ } ++ /* Lowest rate */ ++ if (pRaInfo->RAUseRate) { ++ for (i = 0; i < RATESIZE; i++) { ++ if ((pRaInfo->RAUseRate) & BIT(i)) { ++ pRaInfo->LowestRate = i; ++ break; ++ } ++ } ++ } else { ++ pRaInfo->LowestRate = 0; ++ } ++ if (pRaInfo->HighestRate > 0x13) ++ pRaInfo->PTModeSS = 3; ++ else if (pRaInfo->HighestRate > 0x0b) ++ pRaInfo->PTModeSS = 2; ++ else if (pRaInfo->HighestRate > 0x03) ++ pRaInfo->PTModeSS = 1; ++ else ++ pRaInfo->PTModeSS = 0; ++ ++ if (pRaInfo->DecisionRate > pRaInfo->HighestRate) ++ pRaInfo->DecisionRate = pRaInfo->HighestRate; ++ ++ return 0; ++} ++ ++static void odm_PTTryState_8188E(struct odm_ra_info *pRaInfo) ++{ ++ pRaInfo->PTTryState = 0; ++ switch (pRaInfo->PTModeSS) { ++ case 3: ++ if (pRaInfo->DecisionRate >= 0x19) ++ pRaInfo->PTTryState = 1; ++ break; ++ case 2: ++ if (pRaInfo->DecisionRate >= 0x11) ++ pRaInfo->PTTryState = 1; ++ break; ++ case 1: ++ if (pRaInfo->DecisionRate >= 0x0a) ++ pRaInfo->PTTryState = 1; ++ break; ++ case 0: ++ if (pRaInfo->DecisionRate >= 0x03) ++ pRaInfo->PTTryState = 1; ++ break; ++ default: ++ pRaInfo->PTTryState = 0; ++ break; ++ } ++ ++ if (pRaInfo->RssiStaRA < 48) { ++ pRaInfo->PTStage = 0; ++ } else if (pRaInfo->PTTryState == 1) { ++ if ((pRaInfo->PTStopCount >= 10) || ++ (pRaInfo->PTPreRssi > pRaInfo->RssiStaRA + 5) || ++ (pRaInfo->PTPreRssi < pRaInfo->RssiStaRA - 5) || ++ (pRaInfo->DecisionRate != pRaInfo->PTPreRate)) { ++ if (pRaInfo->PTStage == 0) ++ pRaInfo->PTStage = 1; ++ else if (pRaInfo->PTStage == 1) ++ pRaInfo->PTStage = 3; ++ else ++ pRaInfo->PTStage = 5; ++ ++ pRaInfo->PTPreRssi = pRaInfo->RssiStaRA; ++ pRaInfo->PTStopCount = 0; ++ } else { ++ pRaInfo->RAstage = 0; ++ pRaInfo->PTStopCount++; ++ } ++ } else { ++ pRaInfo->PTStage = 0; ++ pRaInfo->RAstage = 0; ++ } ++ pRaInfo->PTPreRate = pRaInfo->DecisionRate; ++} ++ ++static void odm_PTDecision_8188E(struct odm_ra_info *pRaInfo) ++{ ++ u8 j; ++ u8 temp_stage; ++ u32 numsc; ++ u32 num_total; ++ u8 stage_id; ++ ++ numsc = 0; ++ num_total = pRaInfo->TOTAL * PT_PENALTY[5]; ++ for (j = 0; j <= 4; j++) { ++ numsc += pRaInfo->RTY[j] * PT_PENALTY[j]; ++ if (numsc > num_total) ++ break; ++ } ++ ++ j = j >> 1; ++ temp_stage = (pRaInfo->PTStage + 1) >> 1; ++ if (temp_stage > j) ++ stage_id = temp_stage - j; ++ else ++ stage_id = 0; ++ ++ pRaInfo->PTSmoothFactor = (pRaInfo->PTSmoothFactor >> 1) + (pRaInfo->PTSmoothFactor >> 2) + stage_id * 16 + 2; ++ if (pRaInfo->PTSmoothFactor > 192) ++ pRaInfo->PTSmoothFactor = 192; ++ stage_id = pRaInfo->PTSmoothFactor >> 6; ++ temp_stage = stage_id * 2; ++ if (temp_stage != 0) ++ temp_stage -= 1; ++ if (pRaInfo->DROP > 3) ++ temp_stage = 0; ++ pRaInfo->PTStage = temp_stage; ++} ++ ++static void ++odm_RATxRPTTimerSetting( ++ struct odm_dm_struct *dm_odm, ++ u16 minRptTime ++) ++{ ++ if (dm_odm->CurrminRptTime != minRptTime) { ++ rtw_rpt_timer_cfg_cmd(dm_odm->Adapter, minRptTime); ++ dm_odm->CurrminRptTime = minRptTime; ++ } ++} ++ ++void ++ODM_RASupport_Init( ++ struct odm_dm_struct *dm_odm ++ ) ++{ ++ /* 2012/02/14 MH Be noticed, the init must be after IC type is recognized!!!!! */ ++ if (dm_odm->SupportICType == ODM_RTL8188E) ++ dm_odm->RaSupport88E = true; ++} ++ ++int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 macid) ++{ ++ struct odm_ra_info *pRaInfo = &dm_odm->RAInfo[macid]; ++ u8 WirelessMode = 0xFF; /* invalid value */ ++ u8 max_rate_idx = 0x13; /* MCS7 */ ++ if (dm_odm->pWirelessMode) ++ WirelessMode = *dm_odm->pWirelessMode; ++ ++ if (WirelessMode != 0xFF) { ++ if (WirelessMode & ODM_WM_N24G) ++ max_rate_idx = 0x13; ++ else if (WirelessMode & ODM_WM_G) ++ max_rate_idx = 0x0b; ++ else if (WirelessMode & ODM_WM_B) ++ max_rate_idx = 0x03; ++ } ++ ++ pRaInfo->DecisionRate = max_rate_idx; ++ pRaInfo->PreRate = max_rate_idx; ++ pRaInfo->HighestRate = max_rate_idx; ++ pRaInfo->LowestRate = 0; ++ pRaInfo->RateID = 0; ++ pRaInfo->RateMask = 0xffffffff; ++ pRaInfo->RssiStaRA = 0; ++ pRaInfo->PreRssiStaRA = 0; ++ pRaInfo->SGIEnable = 0; ++ pRaInfo->RAUseRate = 0xffffffff; ++ pRaInfo->NscDown = (N_THRESHOLD_HIGH[0x13] + N_THRESHOLD_LOW[0x13]) / 2; ++ pRaInfo->NscUp = (N_THRESHOLD_HIGH[0x13] + N_THRESHOLD_LOW[0x13]) / 2; ++ pRaInfo->RateSGI = 0; ++ pRaInfo->Active = 1; /* Active is not used at present. by page, 110819 */ ++ pRaInfo->RptTime = 0x927c; ++ pRaInfo->DROP = 0; ++ pRaInfo->RTY[0] = 0; ++ pRaInfo->RTY[1] = 0; ++ pRaInfo->RTY[2] = 0; ++ pRaInfo->RTY[3] = 0; ++ pRaInfo->RTY[4] = 0; ++ pRaInfo->TOTAL = 0; ++ pRaInfo->RAWaitingCounter = 0; ++ pRaInfo->RAPendingCounter = 0; ++ pRaInfo->PTActive = 1; /* Active when this STA is use */ ++ pRaInfo->PTTryState = 0; ++ pRaInfo->PTStage = 5; /* Need to fill into HW_PWR_STATUS */ ++ pRaInfo->PTSmoothFactor = 192; ++ pRaInfo->PTStopCount = 0; ++ pRaInfo->PTPreRate = 0; ++ pRaInfo->PTPreRssi = 0; ++ pRaInfo->PTModeSS = 0; ++ pRaInfo->RAstage = 0; ++ return 0; ++} ++ ++int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm) ++{ ++ u8 macid = 0; ++ ++ dm_odm->CurrminRptTime = 0; ++ ++ for (macid = 0; macid < ODM_ASSOCIATE_ENTRY_NUM; macid++) ++ ODM_RAInfo_Init(dm_odm, macid); ++ ++ return 0; ++} ++ ++u8 ODM_RA_GetShortGI_8188E(struct odm_dm_struct *dm_odm, u8 macid) ++{ ++ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) ++ return 0; ++ return dm_odm->RAInfo[macid].RateSGI; ++} ++ ++u8 ODM_RA_GetDecisionRate_8188E(struct odm_dm_struct *dm_odm, u8 macid) ++{ ++ u8 DecisionRate = 0; ++ ++ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) ++ return 0; ++ DecisionRate = (dm_odm->RAInfo[macid].DecisionRate); ++ return DecisionRate; ++} ++ ++u8 ODM_RA_GetHwPwrStatus_8188E(struct odm_dm_struct *dm_odm, u8 macid) ++{ ++ u8 PTStage = 5; ++ ++ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) ++ return 0; ++ PTStage = (dm_odm->RAInfo[macid].PTStage); ++ return PTStage; ++} ++ ++void ODM_RA_UpdateRateInfo_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 RateID, u32 RateMask, u8 SGIEnable) ++{ ++ struct odm_ra_info *pRaInfo = NULL; ++ ++ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) ++ return; ++ ++ pRaInfo = &dm_odm->RAInfo[macid]; ++ pRaInfo->RateID = RateID; ++ pRaInfo->RateMask = RateMask; ++ pRaInfo->SGIEnable = SGIEnable; ++ odm_ARFBRefresh_8188E(dm_odm, pRaInfo); ++} ++ ++void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid, u8 Rssi) ++{ ++ struct odm_ra_info *pRaInfo = NULL; ++ ++ if ((NULL == dm_odm) || (macid >= ASSOCIATE_ENTRY_NUM)) ++ return; ++ ++ pRaInfo = &dm_odm->RAInfo[macid]; ++ pRaInfo->RssiStaRA = Rssi; ++} ++ ++void ODM_RA_Set_TxRPT_Time(struct odm_dm_struct *dm_odm, u16 minRptTime) ++{ ++ ODM_Write2Byte(dm_odm, REG_TX_RPT_TIME, minRptTime); ++} ++ ++void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16 TxRPT_Len, u32 macid_entry0, u32 macid_entry1) ++{ ++ struct odm_ra_info *pRAInfo = NULL; ++ u8 MacId = 0; ++ u8 *pBuffer = NULL; ++ u32 valid = 0, ItemNum = 0; ++ u16 minRptTime = 0x927c; ++ ++ ItemNum = TxRPT_Len >> 3; ++ pBuffer = TxRPT_Buf; ++ ++ do { ++ if (MacId >= ASSOCIATE_ENTRY_NUM) ++ valid = 0; ++ else if (MacId >= 32) ++ valid = (1 << (MacId - 32)) & macid_entry1; ++ else ++ valid = (1 << MacId) & macid_entry0; ++ ++ pRAInfo = &dm_odm->RAInfo[MacId]; ++ if (valid) { ++ pRAInfo->RTY[0] = (u16)GET_TX_REPORT_TYPE1_RERTY_0(pBuffer); ++ pRAInfo->RTY[1] = (u16)GET_TX_REPORT_TYPE1_RERTY_1(pBuffer); ++ pRAInfo->RTY[2] = (u16)GET_TX_REPORT_TYPE1_RERTY_2((u8 *)pBuffer); ++ pRAInfo->RTY[3] = (u16)GET_TX_REPORT_TYPE1_RERTY_3(pBuffer); ++ pRAInfo->RTY[4] = (u16)GET_TX_REPORT_TYPE1_RERTY_4(pBuffer); ++ pRAInfo->DROP = (u16)GET_TX_REPORT_TYPE1_DROP_0(pBuffer); ++ pRAInfo->TOTAL = pRAInfo->RTY[0] + pRAInfo->RTY[1] + ++ pRAInfo->RTY[2] + pRAInfo->RTY[3] + ++ pRAInfo->RTY[4] + pRAInfo->DROP; ++ if (pRAInfo->TOTAL != 0) { ++ if (pRAInfo->PTActive) { ++ if (pRAInfo->RAstage < 5) ++ odm_RateDecision_8188E(dm_odm, pRAInfo); ++ else if (pRAInfo->RAstage == 5) /* Power training try state */ ++ odm_PTTryState_8188E(pRAInfo); ++ else /* RAstage == 6 */ ++ odm_PTDecision_8188E(pRAInfo); ++ ++ /* Stage_RA counter */ ++ if (pRAInfo->RAstage <= 5) ++ pRAInfo->RAstage++; ++ else ++ pRAInfo->RAstage = 0; ++ } else { ++ odm_RateDecision_8188E(dm_odm, pRAInfo); ++ } ++ } ++ } ++ ++ if (minRptTime > pRAInfo->RptTime) ++ minRptTime = pRAInfo->RptTime; ++ ++ pBuffer += TX_RPT2_ITEM_SIZE; ++ MacId++; ++ } while (MacId < ItemNum); ++ ++ odm_RATxRPTTimerSetting(dm_odm, minRptTime); ++} +diff --git a/drivers/staging/r8188eu/hal/HalHWImg8188E_BB.c b/drivers/staging/r8188eu/hal/HalHWImg8188E_BB.c +new file mode 100644 +index 000000000000..55aa20a30342 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/HalHWImg8188E_BB.c +@@ -0,0 +1,702 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++#include "../include/rtw_iol.h" ++ ++#define read_next_pair(array, v1, v2, i) \ ++ do { \ ++ i += 2; \ ++ v1 = array[i]; \ ++ v2 = array[i + 1]; \ ++ } while (0) ++ ++static bool CheckCondition(const u32 condition, const u32 hex) ++{ ++ u32 _board = (hex & 0x000000FF); ++ u32 _interface = (hex & 0x0000FF00) >> 8; ++ u32 _platform = (hex & 0x00FF0000) >> 16; ++ u32 cond = condition; ++ ++ if (condition == 0xCDCDCDCD) ++ return true; ++ ++ cond = condition & 0x000000FF; ++ if ((_board == cond) && cond != 0x00) ++ return false; ++ ++ cond = condition & 0x0000FF00; ++ cond = cond >> 8; ++ if ((_interface & cond) == 0 && cond != 0x07) ++ return false; ++ ++ cond = condition & 0x00FF0000; ++ cond = cond >> 16; ++ if ((_platform & cond) == 0 && cond != 0x0F) ++ return false; ++ return true; ++} ++ ++/****************************************************************************** ++* AGC_TAB_1T.TXT ++******************************************************************************/ ++ ++static u32 array_agc_tab_1t_8188e[] = { ++ 0xC78, 0xFB000001, ++ 0xC78, 0xFB010001, ++ 0xC78, 0xFB020001, ++ 0xC78, 0xFB030001, ++ 0xC78, 0xFB040001, ++ 0xC78, 0xFB050001, ++ 0xC78, 0xFA060001, ++ 0xC78, 0xF9070001, ++ 0xC78, 0xF8080001, ++ 0xC78, 0xF7090001, ++ 0xC78, 0xF60A0001, ++ 0xC78, 0xF50B0001, ++ 0xC78, 0xF40C0001, ++ 0xC78, 0xF30D0001, ++ 0xC78, 0xF20E0001, ++ 0xC78, 0xF10F0001, ++ 0xC78, 0xF0100001, ++ 0xC78, 0xEF110001, ++ 0xC78, 0xEE120001, ++ 0xC78, 0xED130001, ++ 0xC78, 0xEC140001, ++ 0xC78, 0xEB150001, ++ 0xC78, 0xEA160001, ++ 0xC78, 0xE9170001, ++ 0xC78, 0xE8180001, ++ 0xC78, 0xE7190001, ++ 0xC78, 0xE61A0001, ++ 0xC78, 0xE51B0001, ++ 0xC78, 0xE41C0001, ++ 0xC78, 0xE31D0001, ++ 0xC78, 0xE21E0001, ++ 0xC78, 0xE11F0001, ++ 0xC78, 0x8A200001, ++ 0xC78, 0x89210001, ++ 0xC78, 0x88220001, ++ 0xC78, 0x87230001, ++ 0xC78, 0x86240001, ++ 0xC78, 0x85250001, ++ 0xC78, 0x84260001, ++ 0xC78, 0x83270001, ++ 0xC78, 0x82280001, ++ 0xC78, 0x6B290001, ++ 0xC78, 0x6A2A0001, ++ 0xC78, 0x692B0001, ++ 0xC78, 0x682C0001, ++ 0xC78, 0x672D0001, ++ 0xC78, 0x662E0001, ++ 0xC78, 0x652F0001, ++ 0xC78, 0x64300001, ++ 0xC78, 0x63310001, ++ 0xC78, 0x62320001, ++ 0xC78, 0x61330001, ++ 0xC78, 0x46340001, ++ 0xC78, 0x45350001, ++ 0xC78, 0x44360001, ++ 0xC78, 0x43370001, ++ 0xC78, 0x42380001, ++ 0xC78, 0x41390001, ++ 0xC78, 0x403A0001, ++ 0xC78, 0x403B0001, ++ 0xC78, 0x403C0001, ++ 0xC78, 0x403D0001, ++ 0xC78, 0x403E0001, ++ 0xC78, 0x403F0001, ++ 0xC78, 0xFB400001, ++ 0xC78, 0xFB410001, ++ 0xC78, 0xFB420001, ++ 0xC78, 0xFB430001, ++ 0xC78, 0xFB440001, ++ 0xC78, 0xFB450001, ++ 0xC78, 0xFB460001, ++ 0xC78, 0xFB470001, ++ 0xC78, 0xFB480001, ++ 0xC78, 0xFA490001, ++ 0xC78, 0xF94A0001, ++ 0xC78, 0xF84B0001, ++ 0xC78, 0xF74C0001, ++ 0xC78, 0xF64D0001, ++ 0xC78, 0xF54E0001, ++ 0xC78, 0xF44F0001, ++ 0xC78, 0xF3500001, ++ 0xC78, 0xF2510001, ++ 0xC78, 0xF1520001, ++ 0xC78, 0xF0530001, ++ 0xC78, 0xEF540001, ++ 0xC78, 0xEE550001, ++ 0xC78, 0xED560001, ++ 0xC78, 0xEC570001, ++ 0xC78, 0xEB580001, ++ 0xC78, 0xEA590001, ++ 0xC78, 0xE95A0001, ++ 0xC78, 0xE85B0001, ++ 0xC78, 0xE75C0001, ++ 0xC78, 0xE65D0001, ++ 0xC78, 0xE55E0001, ++ 0xC78, 0xE45F0001, ++ 0xC78, 0xE3600001, ++ 0xC78, 0xE2610001, ++ 0xC78, 0xC3620001, ++ 0xC78, 0xC2630001, ++ 0xC78, 0xC1640001, ++ 0xC78, 0x8B650001, ++ 0xC78, 0x8A660001, ++ 0xC78, 0x89670001, ++ 0xC78, 0x88680001, ++ 0xC78, 0x87690001, ++ 0xC78, 0x866A0001, ++ 0xC78, 0x856B0001, ++ 0xC78, 0x846C0001, ++ 0xC78, 0x676D0001, ++ 0xC78, 0x666E0001, ++ 0xC78, 0x656F0001, ++ 0xC78, 0x64700001, ++ 0xC78, 0x63710001, ++ 0xC78, 0x62720001, ++ 0xC78, 0x61730001, ++ 0xC78, 0x60740001, ++ 0xC78, 0x46750001, ++ 0xC78, 0x45760001, ++ 0xC78, 0x44770001, ++ 0xC78, 0x43780001, ++ 0xC78, 0x42790001, ++ 0xC78, 0x417A0001, ++ 0xC78, 0x407B0001, ++ 0xC78, 0x407C0001, ++ 0xC78, 0x407D0001, ++ 0xC78, 0x407E0001, ++ 0xC78, 0x407F0001, ++}; ++ ++enum HAL_STATUS ODM_ReadAndConfig_AGC_TAB_1T_8188E(struct odm_dm_struct *dm_odm) ++{ ++ u32 hex = 0; ++ u32 i = 0; ++ u8 platform = dm_odm->SupportPlatform; ++ u8 interfaceValue = dm_odm->SupportInterface; ++ u8 board = dm_odm->BoardType; ++ u32 arraylen = sizeof(array_agc_tab_1t_8188e) / sizeof(u32); ++ u32 *array = array_agc_tab_1t_8188e; ++ bool biol = false; ++ struct adapter *adapter = dm_odm->Adapter; ++ struct xmit_frame *pxmit_frame = NULL; ++ u8 bndy_cnt = 1; ++ enum HAL_STATUS rst = HAL_STATUS_SUCCESS; ++ ++ hex += board; ++ hex += interfaceValue << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ biol = rtw_IOL_applied(adapter); ++ ++ if (biol) { ++ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapter); ++ if (!pxmit_frame) { ++ pr_info("rtw_IOL_accquire_xmit_frame failed\n"); ++ return HAL_STATUS_FAILURE; ++ } ++ } ++ ++ for (i = 0; i < arraylen; i += 2) { ++ u32 v1 = array[i]; ++ u32 v2 = array[i + 1]; ++ ++ /* This (offset, data) pair meets the condition. */ ++ if (v1 < 0xCDCDCDCD) { ++ if (biol) { ++ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord); ++ } else { ++ odm_ConfigBB_AGC_8188E(dm_odm, v1, bMaskDWord, v2); ++ } ++ continue; ++ } else { ++ /* This line is the start line of branch. */ ++ if (!CheckCondition(array[i], hex)) { ++ /* Discard the following (offset, data) pairs. */ ++ read_next_pair(array, v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < arraylen - 2) ++ read_next_pair(array, v1, v2, i); ++ i -= 2; /* prevent from for-loop += 2 */ ++ } else { /* Configure matched pairs and skip to end of if-else. */ ++ read_next_pair(array, v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < arraylen - 2) { ++ if (biol) { ++ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord); ++ } else { ++ odm_ConfigBB_AGC_8188E(dm_odm, v1, bMaskDWord, v2); ++ } ++ read_next_pair(array, v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < arraylen - 2) ++ read_next_pair(array, v1, v2, i); ++ } ++ } ++ } ++ if (biol) { ++ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) { ++ printk("~~~ %s IOL_exec_cmds Failed !!!\n", __func__); ++ rst = HAL_STATUS_FAILURE; ++ } ++ } ++ return rst; ++} ++ ++/****************************************************************************** ++* PHY_REG_1T.TXT ++******************************************************************************/ ++ ++static u32 array_phy_reg_1t_8188e[] = { ++ 0x800, 0x80040000, ++ 0x804, 0x00000003, ++ 0x808, 0x0000FC00, ++ 0x80C, 0x0000000A, ++ 0x810, 0x10001331, ++ 0x814, 0x020C3D10, ++ 0x818, 0x02200385, ++ 0x81C, 0x00000000, ++ 0x820, 0x01000100, ++ 0x824, 0x00390204, ++ 0x828, 0x00000000, ++ 0x82C, 0x00000000, ++ 0x830, 0x00000000, ++ 0x834, 0x00000000, ++ 0x838, 0x00000000, ++ 0x83C, 0x00000000, ++ 0x840, 0x00010000, ++ 0x844, 0x00000000, ++ 0x848, 0x00000000, ++ 0x84C, 0x00000000, ++ 0x850, 0x00000000, ++ 0x854, 0x00000000, ++ 0x858, 0x569A11A9, ++ 0x85C, 0x01000014, ++ 0x860, 0x66F60110, ++ 0x864, 0x061F0649, ++ 0x868, 0x00000000, ++ 0x86C, 0x27272700, ++ 0x870, 0x07000760, ++ 0x874, 0x25004000, ++ 0x878, 0x00000808, ++ 0x87C, 0x00000000, ++ 0x880, 0xB0000C1C, ++ 0x884, 0x00000001, ++ 0x888, 0x00000000, ++ 0x88C, 0xCCC000C0, ++ 0x890, 0x00000800, ++ 0x894, 0xFFFFFFFE, ++ 0x898, 0x40302010, ++ 0x89C, 0x00706050, ++ 0x900, 0x00000000, ++ 0x904, 0x00000023, ++ 0x908, 0x00000000, ++ 0x90C, 0x81121111, ++ 0x910, 0x00000002, ++ 0x914, 0x00000201, ++ 0xA00, 0x00D047C8, ++ 0xA04, 0x80FF000C, ++ 0xA08, 0x8C838300, ++ 0xA0C, 0x2E7F120F, ++ 0xA10, 0x9500BB78, ++ 0xA14, 0x1114D028, ++ 0xA18, 0x00881117, ++ 0xA1C, 0x89140F00, ++ 0xA20, 0x1A1B0000, ++ 0xA24, 0x090E1317, ++ 0xA28, 0x00000204, ++ 0xA2C, 0x00D30000, ++ 0xA70, 0x101FBF00, ++ 0xA74, 0x00000007, ++ 0xA78, 0x00000900, ++ 0xA7C, 0x225B0606, ++ 0xA80, 0x218075B1, ++ 0xB2C, 0x80000000, ++ 0xC00, 0x48071D40, ++ 0xC04, 0x03A05611, ++ 0xC08, 0x000000E4, ++ 0xC0C, 0x6C6C6C6C, ++ 0xC10, 0x08800000, ++ 0xC14, 0x40000100, ++ 0xC18, 0x08800000, ++ 0xC1C, 0x40000100, ++ 0xC20, 0x00000000, ++ 0xC24, 0x00000000, ++ 0xC28, 0x00000000, ++ 0xC2C, 0x00000000, ++ 0xC30, 0x69E9AC47, ++ 0xC34, 0x469652AF, ++ 0xC38, 0x49795994, ++ 0xC3C, 0x0A97971C, ++ 0xC40, 0x1F7C403F, ++ 0xC44, 0x000100B7, ++ 0xC48, 0xEC020107, ++ 0xC4C, 0x007F037F, ++ 0xC50, 0x69553420, ++ 0xC54, 0x43BC0094, ++ 0xC58, 0x00013169, ++ 0xC5C, 0x00250492, ++ 0xC60, 0x00000000, ++ 0xC64, 0x7112848B, ++ 0xC68, 0x47C00BFF, ++ 0xC6C, 0x00000036, ++ 0xC70, 0x2C7F000D, ++ 0xC74, 0x020610DB, ++ 0xC78, 0x0000001F, ++ 0xC7C, 0x00B91612, ++ 0xC80, 0x390000E4, ++ 0xC84, 0x20F60000, ++ 0xC88, 0x40000100, ++ 0xC8C, 0x20200000, ++ 0xC90, 0x00091521, ++ 0xC94, 0x00000000, ++ 0xC98, 0x00121820, ++ 0xC9C, 0x00007F7F, ++ 0xCA0, 0x00000000, ++ 0xCA4, 0x000300A0, ++ 0xCA8, 0x00000000, ++ 0xCAC, 0x00000000, ++ 0xCB0, 0x00000000, ++ 0xCB4, 0x00000000, ++ 0xCB8, 0x00000000, ++ 0xCBC, 0x28000000, ++ 0xCC0, 0x00000000, ++ 0xCC4, 0x00000000, ++ 0xCC8, 0x00000000, ++ 0xCCC, 0x00000000, ++ 0xCD0, 0x00000000, ++ 0xCD4, 0x00000000, ++ 0xCD8, 0x64B22427, ++ 0xCDC, 0x00766932, ++ 0xCE0, 0x00222222, ++ 0xCE4, 0x00000000, ++ 0xCE8, 0x37644302, ++ 0xCEC, 0x2F97D40C, ++ 0xD00, 0x00000740, ++ 0xD04, 0x00020401, ++ 0xD08, 0x0000907F, ++ 0xD0C, 0x20010201, ++ 0xD10, 0xA0633333, ++ 0xD14, 0x3333BC43, ++ 0xD18, 0x7A8F5B6F, ++ 0xD2C, 0xCC979975, ++ 0xD30, 0x00000000, ++ 0xD34, 0x80608000, ++ 0xD38, 0x00000000, ++ 0xD3C, 0x00127353, ++ 0xD40, 0x00000000, ++ 0xD44, 0x00000000, ++ 0xD48, 0x00000000, ++ 0xD4C, 0x00000000, ++ 0xD50, 0x6437140A, ++ 0xD54, 0x00000000, ++ 0xD58, 0x00000282, ++ 0xD5C, 0x30032064, ++ 0xD60, 0x4653DE68, ++ 0xD64, 0x04518A3C, ++ 0xD68, 0x00002101, ++ 0xD6C, 0x2A201C16, ++ 0xD70, 0x1812362E, ++ 0xD74, 0x322C2220, ++ 0xD78, 0x000E3C24, ++ 0xE00, 0x2D2D2D2D, ++ 0xE04, 0x2D2D2D2D, ++ 0xE08, 0x0390272D, ++ 0xE10, 0x2D2D2D2D, ++ 0xE14, 0x2D2D2D2D, ++ 0xE18, 0x2D2D2D2D, ++ 0xE1C, 0x2D2D2D2D, ++ 0xE28, 0x00000000, ++ 0xE30, 0x1000DC1F, ++ 0xE34, 0x10008C1F, ++ 0xE38, 0x02140102, ++ 0xE3C, 0x681604C2, ++ 0xE40, 0x01007C00, ++ 0xE44, 0x01004800, ++ 0xE48, 0xFB000000, ++ 0xE4C, 0x000028D1, ++ 0xE50, 0x1000DC1F, ++ 0xE54, 0x10008C1F, ++ 0xE58, 0x02140102, ++ 0xE5C, 0x28160D05, ++ 0xE60, 0x00000008, ++ 0xE68, 0x001B25A4, ++ 0xE6C, 0x00C00014, ++ 0xE70, 0x00C00014, ++ 0xE74, 0x01000014, ++ 0xE78, 0x01000014, ++ 0xE7C, 0x01000014, ++ 0xE80, 0x01000014, ++ 0xE84, 0x00C00014, ++ 0xE88, 0x01000014, ++ 0xE8C, 0x00C00014, ++ 0xED0, 0x00C00014, ++ 0xED4, 0x00C00014, ++ 0xED8, 0x00C00014, ++ 0xEDC, 0x00000014, ++ 0xEE0, 0x00000014, ++ 0xEEC, 0x01C00014, ++ 0xF14, 0x00000003, ++ 0xF4C, 0x00000000, ++ 0xF00, 0x00000300, ++}; ++ ++enum HAL_STATUS ODM_ReadAndConfig_PHY_REG_1T_8188E(struct odm_dm_struct *dm_odm) ++{ ++ u32 hex = 0; ++ u32 i = 0; ++ u8 platform = dm_odm->SupportPlatform; ++ u8 interfaceValue = dm_odm->SupportInterface; ++ u8 board = dm_odm->BoardType; ++ u32 arraylen = sizeof(array_phy_reg_1t_8188e) / sizeof(u32); ++ u32 *array = array_phy_reg_1t_8188e; ++ bool biol = false; ++ struct adapter *adapter = dm_odm->Adapter; ++ struct xmit_frame *pxmit_frame = NULL; ++ u8 bndy_cnt = 1; ++ enum HAL_STATUS rst = HAL_STATUS_SUCCESS; ++ hex += board; ++ hex += interfaceValue << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ biol = rtw_IOL_applied(adapter); ++ ++ if (biol) { ++ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapter); ++ if (!pxmit_frame) { ++ pr_info("rtw_IOL_accquire_xmit_frame failed\n"); ++ return HAL_STATUS_FAILURE; ++ } ++ } ++ ++ for (i = 0; i < arraylen; i += 2) { ++ u32 v1 = array[i]; ++ u32 v2 = array[i + 1]; ++ ++ /* This (offset, data) pair meets the condition. */ ++ if (v1 < 0xCDCDCDCD) { ++ if (biol) { ++ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ if (v1 == 0xfe) { ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50); ++ } else if (v1 == 0xfd) { ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5); ++ } else if (v1 == 0xfc) { ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1); ++ } else if (v1 == 0xfb) { ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50); ++ } else if (v1 == 0xfa) { ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); ++ } else if (v1 == 0xf9) { ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1); ++ } else { ++ if (v1 == 0xa24) ++ dm_odm->RFCalibrateInfo.RegA24 = v2; ++ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord); ++ } ++ } else { ++ odm_ConfigBB_PHY_8188E(dm_odm, v1, bMaskDWord, v2); ++ } ++ continue; ++ } else { /* This line is the start line of branch. */ ++ if (!CheckCondition(array[i], hex)) { ++ /* Discard the following (offset, data) pairs. */ ++ read_next_pair(array, v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < arraylen - 2) ++ read_next_pair(array, v1, v2, i); ++ i -= 2; /* prevent from for-loop += 2 */ ++ } else { /* Configure matched pairs and skip to end of if-else. */ ++ read_next_pair(array, v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < arraylen - 2) { ++ if (biol) { ++ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ if (v1 == 0xfe) { ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50); ++ } else if (v1 == 0xfd) { ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5); ++ } else if (v1 == 0xfc) { ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1); ++ } else if (v1 == 0xfb) { ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50); ++ } else if (v1 == 0xfa) { ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); ++ } else if (v1 == 0xf9) { ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1); ++ } else { ++ if (v1 == 0xa24) ++ dm_odm->RFCalibrateInfo.RegA24 = v2; ++ ++ rtw_IOL_append_WD_cmd(pxmit_frame, (u16)v1, v2, bMaskDWord); ++ } ++ } else { ++ odm_ConfigBB_PHY_8188E(dm_odm, v1, bMaskDWord, v2); ++ } ++ read_next_pair(array, v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < arraylen - 2) ++ read_next_pair(array, v1, v2, i); ++ } ++ } ++ } ++ if (biol) { ++ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) { ++ rst = HAL_STATUS_FAILURE; ++ pr_info("~~~ IOL Config %s Failed !!!\n", __func__); ++ } ++ } ++ return rst; ++} ++ ++/****************************************************************************** ++* PHY_REG_PG.TXT ++******************************************************************************/ ++ ++static u32 array_phy_reg_pg_8188e[] = { ++ 0xE00, 0xFFFFFFFF, 0x06070809, ++ 0xE04, 0xFFFFFFFF, 0x02020405, ++ 0xE08, 0x0000FF00, 0x00000006, ++ 0x86C, 0xFFFFFF00, 0x00020400, ++ 0xE10, 0xFFFFFFFF, 0x08090A0B, ++ 0xE14, 0xFFFFFFFF, 0x01030607, ++ 0xE18, 0xFFFFFFFF, 0x08090A0B, ++ 0xE1C, 0xFFFFFFFF, 0x01030607, ++ 0xE00, 0xFFFFFFFF, 0x00000000, ++ 0xE04, 0xFFFFFFFF, 0x00000000, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x00000000, ++ 0xE14, 0xFFFFFFFF, 0x00000000, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x02020202, ++ 0xE04, 0xFFFFFFFF, 0x00020202, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x04040404, ++ 0xE14, 0xFFFFFFFF, 0x00020404, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x02020202, ++ 0xE04, 0xFFFFFFFF, 0x00020202, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x04040404, ++ 0xE14, 0xFFFFFFFF, 0x00020404, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x00000000, ++ 0xE04, 0xFFFFFFFF, 0x00000000, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x00000000, ++ 0xE14, 0xFFFFFFFF, 0x00000000, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x02020202, ++ 0xE04, 0xFFFFFFFF, 0x00020202, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x04040404, ++ 0xE14, 0xFFFFFFFF, 0x00020404, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x00000000, ++ 0xE04, 0xFFFFFFFF, 0x00000000, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x00000000, ++ 0xE14, 0xFFFFFFFF, 0x00000000, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x00000000, ++ 0xE04, 0xFFFFFFFF, 0x00000000, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x00000000, ++ 0xE14, 0xFFFFFFFF, 0x00000000, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x00000000, ++ 0xE04, 0xFFFFFFFF, 0x00000000, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x00000000, ++ 0xE14, 0xFFFFFFFF, 0x00000000, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x00000000, ++ 0xE04, 0xFFFFFFFF, 0x00000000, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x00000000, ++ 0xE14, 0xFFFFFFFF, 0x00000000, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ 0xE00, 0xFFFFFFFF, 0x00000000, ++ 0xE04, 0xFFFFFFFF, 0x00000000, ++ 0xE08, 0x0000FF00, 0x00000000, ++ 0x86C, 0xFFFFFF00, 0x00000000, ++ 0xE10, 0xFFFFFFFF, 0x00000000, ++ 0xE14, 0xFFFFFFFF, 0x00000000, ++ 0xE18, 0xFFFFFFFF, 0x00000000, ++ 0xE1C, 0xFFFFFFFF, 0x00000000, ++ ++}; ++ ++void ODM_ReadAndConfig_PHY_REG_PG_8188E(struct odm_dm_struct *dm_odm) ++{ ++ u32 hex; ++ u32 i = 0; ++ u8 platform = dm_odm->SupportPlatform; ++ u8 interfaceValue = dm_odm->SupportInterface; ++ u8 board = dm_odm->BoardType; ++ u32 arraylen = sizeof(array_phy_reg_pg_8188e) / sizeof(u32); ++ u32 *array = array_phy_reg_pg_8188e; ++ ++ hex = board + (interfaceValue << 8); ++ hex += (platform << 16) + 0xFF000000; ++ ++ for (i = 0; i < arraylen; i += 3) { ++ u32 v1 = array[i]; ++ u32 v2 = array[i + 1]; ++ u32 v3 = array[i + 2]; ++ ++ /* this line is a line of pure_body */ ++ if (v1 < 0xCDCDCDCD) { ++ odm_ConfigBB_PHY_REG_PG_8188E(dm_odm, v1, v2, v3); ++ continue; ++ } else { /* this line is the start of branch */ ++ if (!CheckCondition(array[i], hex)) { ++ /* don't need the hw_body */ ++ i += 2; /* skip the pair of expression */ ++ v1 = array[i]; ++ v2 = array[i + 1]; ++ v3 = array[i + 2]; ++ while (v2 != 0xDEAD) { ++ i += 3; ++ v1 = array[i]; ++ v2 = array[i + 1]; ++ v3 = array[i + 1]; ++ } ++ } ++ } ++ } ++} +diff --git a/drivers/staging/r8188eu/hal/HalHWImg8188E_MAC.c b/drivers/staging/r8188eu/hal/HalHWImg8188E_MAC.c +new file mode 100644 +index 000000000000..0ff2609c26bb +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/HalHWImg8188E_MAC.c +@@ -0,0 +1,213 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++#include "../include/rtw_iol.h" ++ ++static bool Checkcondition(const u32 condition, const u32 hex) ++{ ++ u32 _board = (hex & 0x000000FF); ++ u32 _interface = (hex & 0x0000FF00) >> 8; ++ u32 _platform = (hex & 0x00FF0000) >> 16; ++ u32 cond = condition; ++ ++ if (condition == 0xCDCDCDCD) ++ return true; ++ ++ cond = condition & 0x000000FF; ++ if ((_board == cond) && cond != 0x00) ++ return false; ++ ++ cond = condition & 0x0000FF00; ++ cond = cond >> 8; ++ if ((_interface & cond) == 0 && cond != 0x07) ++ return false; ++ ++ cond = condition & 0x00FF0000; ++ cond = cond >> 16; ++ if ((_platform & cond) == 0 && cond != 0x0F) ++ return false; ++ return true; ++} ++ ++/****************************************************************************** ++* MAC_REG.TXT ++******************************************************************************/ ++ ++static u32 array_MAC_REG_8188E[] = { ++ 0x026, 0x00000041, ++ 0x027, 0x00000035, ++ 0x428, 0x0000000A, ++ 0x429, 0x00000010, ++ 0x430, 0x00000000, ++ 0x431, 0x00000001, ++ 0x432, 0x00000002, ++ 0x433, 0x00000004, ++ 0x434, 0x00000005, ++ 0x435, 0x00000006, ++ 0x436, 0x00000007, ++ 0x437, 0x00000008, ++ 0x438, 0x00000000, ++ 0x439, 0x00000000, ++ 0x43A, 0x00000001, ++ 0x43B, 0x00000002, ++ 0x43C, 0x00000004, ++ 0x43D, 0x00000005, ++ 0x43E, 0x00000006, ++ 0x43F, 0x00000007, ++ 0x440, 0x0000005D, ++ 0x441, 0x00000001, ++ 0x442, 0x00000000, ++ 0x444, 0x00000015, ++ 0x445, 0x000000F0, ++ 0x446, 0x0000000F, ++ 0x447, 0x00000000, ++ 0x458, 0x00000041, ++ 0x459, 0x000000A8, ++ 0x45A, 0x00000072, ++ 0x45B, 0x000000B9, ++ 0x460, 0x00000066, ++ 0x461, 0x00000066, ++ 0x480, 0x00000008, ++ 0x4C8, 0x000000FF, ++ 0x4C9, 0x00000008, ++ 0x4CC, 0x000000FF, ++ 0x4CD, 0x000000FF, ++ 0x4CE, 0x00000001, ++ 0x4D3, 0x00000001, ++ 0x500, 0x00000026, ++ 0x501, 0x000000A2, ++ 0x502, 0x0000002F, ++ 0x503, 0x00000000, ++ 0x504, 0x00000028, ++ 0x505, 0x000000A3, ++ 0x506, 0x0000005E, ++ 0x507, 0x00000000, ++ 0x508, 0x0000002B, ++ 0x509, 0x000000A4, ++ 0x50A, 0x0000005E, ++ 0x50B, 0x00000000, ++ 0x50C, 0x0000004F, ++ 0x50D, 0x000000A4, ++ 0x50E, 0x00000000, ++ 0x50F, 0x00000000, ++ 0x512, 0x0000001C, ++ 0x514, 0x0000000A, ++ 0x516, 0x0000000A, ++ 0x525, 0x0000004F, ++ 0x550, 0x00000010, ++ 0x551, 0x00000010, ++ 0x559, 0x00000002, ++ 0x55D, 0x000000FF, ++ 0x605, 0x00000030, ++ 0x608, 0x0000000E, ++ 0x609, 0x0000002A, ++ 0x620, 0x000000FF, ++ 0x621, 0x000000FF, ++ 0x622, 0x000000FF, ++ 0x623, 0x000000FF, ++ 0x624, 0x000000FF, ++ 0x625, 0x000000FF, ++ 0x626, 0x000000FF, ++ 0x627, 0x000000FF, ++ 0x652, 0x00000020, ++ 0x63C, 0x0000000A, ++ 0x63D, 0x0000000A, ++ 0x63E, 0x0000000E, ++ 0x63F, 0x0000000E, ++ 0x640, 0x00000040, ++ 0x66E, 0x00000005, ++ 0x700, 0x00000021, ++ 0x701, 0x00000043, ++ 0x702, 0x00000065, ++ 0x703, 0x00000087, ++ 0x708, 0x00000021, ++ 0x709, 0x00000043, ++ 0x70A, 0x00000065, ++ 0x70B, 0x00000087, ++}; ++ ++enum HAL_STATUS ODM_ReadAndConfig_MAC_REG_8188E(struct odm_dm_struct *dm_odm) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = array[i]; v2 = array[i + 1]; } while (0) ++ ++ u32 hex = 0; ++ u32 i; ++ u8 platform = dm_odm->SupportPlatform; ++ u8 interface_val = dm_odm->SupportInterface; ++ u8 board = dm_odm->BoardType; ++ u32 array_len = sizeof(array_MAC_REG_8188E) / sizeof(u32); ++ u32 *array = array_MAC_REG_8188E; ++ bool biol = false; ++ ++ struct adapter *adapt = dm_odm->Adapter; ++ struct xmit_frame *pxmit_frame = NULL; ++ u8 bndy_cnt = 1; ++ enum HAL_STATUS rst = HAL_STATUS_SUCCESS; ++ hex += board; ++ hex += interface_val << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ ++ biol = rtw_IOL_applied(adapt); ++ ++ if (biol) { ++ pxmit_frame = rtw_IOL_accquire_xmit_frame(adapt); ++ if (!pxmit_frame) { ++ pr_info("rtw_IOL_accquire_xmit_frame failed\n"); ++ return HAL_STATUS_FAILURE; ++ } ++ } ++ ++ for (i = 0; i < array_len; i += 2) { ++ u32 v1 = array[i]; ++ u32 v2 = array[i + 1]; ++ ++ /* This (offset, data) pair meets the condition. */ ++ if (v1 < 0xCDCDCDCD) { ++ if (biol) { ++ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ rtw_IOL_append_WB_cmd(pxmit_frame, (u16)v1, (u8)v2, 0xFF); ++ } else { ++ odm_ConfigMAC_8188E(dm_odm, v1, (u8)v2); ++ } ++ continue; ++ } else { /* This line is the start line of branch. */ ++ if (!Checkcondition(array[i], hex)) { ++ /* Discard the following (offset, data) pairs. */ ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < array_len - 2) { ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ i -= 2; /* prevent from for-loop += 2 */ ++ } else { /* Configure matched pairs and skip to end of if-else. */ ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < array_len - 2) { ++ if (biol) { ++ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ rtw_IOL_append_WB_cmd(pxmit_frame, (u16)v1, (u8)v2, 0xFF); ++ } else { ++ odm_ConfigMAC_8188E(dm_odm, v1, (u8)v2); ++ } ++ ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ while (v2 != 0xDEAD && i < array_len - 2) ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ } ++ } ++ if (biol) { ++ if (!rtw_IOL_exec_cmds_sync(dm_odm->Adapter, pxmit_frame, 1000, bndy_cnt)) { ++ pr_info("~~~ MAC IOL_exec_cmds Failed !!!\n"); ++ rst = HAL_STATUS_FAILURE; ++ } ++ } ++ return rst; ++} +diff --git a/drivers/staging/r8188eu/hal/HalHWImg8188E_RF.c b/drivers/staging/r8188eu/hal/HalHWImg8188E_RF.c +new file mode 100644 +index 000000000000..55e4b4a877a4 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/HalHWImg8188E_RF.c +@@ -0,0 +1,250 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++#include "../include/rtw_iol.h" ++ ++static bool CheckCondition(const u32 Condition, const u32 Hex) ++{ ++ u32 _board = (Hex & 0x000000FF); ++ u32 _interface = (Hex & 0x0000FF00) >> 8; ++ u32 _platform = (Hex & 0x00FF0000) >> 16; ++ u32 cond = Condition; ++ ++ if (Condition == 0xCDCDCDCD) ++ return true; ++ ++ cond = Condition & 0x000000FF; ++ if ((_board == cond) && cond != 0x00) ++ return false; ++ ++ cond = Condition & 0x0000FF00; ++ cond = cond >> 8; ++ if ((_interface & cond) == 0 && cond != 0x07) ++ return false; ++ ++ cond = Condition & 0x00FF0000; ++ cond = cond >> 16; ++ if ((_platform & cond) == 0 && cond != 0x0F) ++ return false; ++ return true; ++} ++ ++/****************************************************************************** ++* RadioA_1T.TXT ++******************************************************************************/ ++ ++static u32 Array_RadioA_1T_8188E[] = { ++ 0x000, 0x00030000, ++ 0x008, 0x00084000, ++ 0x018, 0x00000407, ++ 0x019, 0x00000012, ++ 0x01E, 0x00080009, ++ 0x01F, 0x00000880, ++ 0x02F, 0x0001A060, ++ 0x03F, 0x00000000, ++ 0x042, 0x000060C0, ++ 0x057, 0x000D0000, ++ 0x058, 0x000BE180, ++ 0x067, 0x00001552, ++ 0x083, 0x00000000, ++ 0x0B0, 0x000FF8FC, ++ 0x0B1, 0x00054400, ++ 0x0B2, 0x000CCC19, ++ 0x0B4, 0x00043003, ++ 0x0B6, 0x0004953E, ++ 0x0B7, 0x0001C718, ++ 0x0B8, 0x000060FF, ++ 0x0B9, 0x00080001, ++ 0x0BA, 0x00040000, ++ 0x0BB, 0x00000400, ++ 0x0BF, 0x000C0000, ++ 0x0C2, 0x00002400, ++ 0x0C3, 0x00000009, ++ 0x0C4, 0x00040C91, ++ 0x0C5, 0x00099999, ++ 0x0C6, 0x000000A3, ++ 0x0C7, 0x00088820, ++ 0x0C8, 0x00076C06, ++ 0x0C9, 0x00000000, ++ 0x0CA, 0x00080000, ++ 0x0DF, 0x00000180, ++ 0x0EF, 0x000001A0, ++ 0x051, 0x0006B27D, ++ 0xFF0F041F, 0xABCD, ++ 0x052, 0x0007E4DD, ++ 0xCDCDCDCD, 0xCDCD, ++ 0x052, 0x0007E49D, ++ 0xFF0F041F, 0xDEAD, ++ 0x053, 0x00000073, ++ 0x056, 0x00051FF3, ++ 0x035, 0x00000086, ++ 0x035, 0x00000186, ++ 0x035, 0x00000286, ++ 0x036, 0x00001C25, ++ 0x036, 0x00009C25, ++ 0x036, 0x00011C25, ++ 0x036, 0x00019C25, ++ 0x0B6, 0x00048538, ++ 0x018, 0x00000C07, ++ 0x05A, 0x0004BD00, ++ 0x019, 0x000739D0, ++ 0x034, 0x0000ADF3, ++ 0x034, 0x00009DF0, ++ 0x034, 0x00008DED, ++ 0x034, 0x00007DEA, ++ 0x034, 0x00006DE7, ++ 0x034, 0x000054EE, ++ 0x034, 0x000044EB, ++ 0x034, 0x000034E8, ++ 0x034, 0x0000246B, ++ 0x034, 0x00001468, ++ 0x034, 0x0000006D, ++ 0x000, 0x00030159, ++ 0x084, 0x00068200, ++ 0x086, 0x000000CE, ++ 0x087, 0x00048A00, ++ 0x08E, 0x00065540, ++ 0x08F, 0x00088000, ++ 0x0EF, 0x000020A0, ++ 0x03B, 0x000F02B0, ++ 0x03B, 0x000EF7B0, ++ 0x03B, 0x000D4FB0, ++ 0x03B, 0x000CF060, ++ 0x03B, 0x000B0090, ++ 0x03B, 0x000A0080, ++ 0x03B, 0x00090080, ++ 0x03B, 0x0008F780, ++ 0x03B, 0x000722B0, ++ 0x03B, 0x0006F7B0, ++ 0x03B, 0x00054FB0, ++ 0x03B, 0x0004F060, ++ 0x03B, 0x00030090, ++ 0x03B, 0x00020080, ++ 0x03B, 0x00010080, ++ 0x03B, 0x0000F780, ++ 0x0EF, 0x000000A0, ++ 0x000, 0x00010159, ++ 0x018, 0x0000F407, ++ 0xFFE, 0x00000000, ++ 0xFFE, 0x00000000, ++ 0x01F, 0x00080003, ++ 0xFFE, 0x00000000, ++ 0xFFE, 0x00000000, ++ 0x01E, 0x00000001, ++ 0x01F, 0x00080000, ++ 0x000, 0x00033E60, ++}; ++ ++enum HAL_STATUS ODM_ReadAndConfig_RadioA_1T_8188E(struct odm_dm_struct *pDM_Odm) ++{ ++ #define READ_NEXT_PAIR(v1, v2, i) do \ ++ { i += 2; v1 = Array[i]; \ ++ v2 = Array[i + 1]; } while (0) ++ ++ u32 hex = 0; ++ u32 i = 0; ++ u8 platform = pDM_Odm->SupportPlatform; ++ u8 interfaceValue = pDM_Odm->SupportInterface; ++ u8 board = pDM_Odm->BoardType; ++ u32 ArrayLen = sizeof(Array_RadioA_1T_8188E) / sizeof(u32); ++ u32 *Array = Array_RadioA_1T_8188E; ++ bool biol = false; ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ struct xmit_frame *pxmit_frame = NULL; ++ u8 bndy_cnt = 1; ++ enum HAL_STATUS rst = HAL_STATUS_SUCCESS; ++ ++ hex += board; ++ hex += interfaceValue << 8; ++ hex += platform << 16; ++ hex += 0xFF000000; ++ biol = rtw_IOL_applied(Adapter); ++ ++ if (biol) { ++ pxmit_frame = rtw_IOL_accquire_xmit_frame(Adapter); ++ if (!pxmit_frame) { ++ pr_info("rtw_IOL_accquire_xmit_frame failed\n"); ++ return HAL_STATUS_FAILURE; ++ } ++ } ++ ++ for (i = 0; i < ArrayLen; i += 2) { ++ u32 v1 = Array[i]; ++ u32 v2 = Array[i + 1]; ++ ++ /* This (offset, data) pair meets the condition. */ ++ if (v1 < 0xCDCDCDCD) { ++ if (biol) { ++ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ ++ if (v1 == 0xffe) ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50); ++ else if (v1 == 0xfd) ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5); ++ else if (v1 == 0xfc) ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1); ++ else if (v1 == 0xfb) ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50); ++ else if (v1 == 0xfa) ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); ++ else if (v1 == 0xf9) ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1); ++ else ++ rtw_IOL_append_WRF_cmd(pxmit_frame, RF_PATH_A, (u16)v1, v2, bRFRegOffsetMask); ++ } else { ++ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); ++ } ++ continue; ++ } else { /* This line is the start line of branch. */ ++ if (!CheckCondition(Array[i], hex)) { ++ /* Discard the following (offset, data) pairs. */ ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen - 2) ++ READ_NEXT_PAIR(v1, v2, i); ++ i -= 2; /* prevent from for-loop += 2 */ ++ } else { /* Configure matched pairs and skip to end of if-else. */ ++ READ_NEXT_PAIR(v1, v2, i); ++ while (v2 != 0xDEAD && ++ v2 != 0xCDEF && ++ v2 != 0xCDCD && i < ArrayLen - 2) { ++ if (biol) { ++ if (rtw_IOL_cmd_boundary_handle(pxmit_frame)) ++ bndy_cnt++; ++ ++ if (v1 == 0xffe) ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 50); ++ else if (v1 == 0xfd) ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 5); ++ else if (v1 == 0xfc) ++ rtw_IOL_append_DELAY_MS_cmd(pxmit_frame, 1); ++ else if (v1 == 0xfb) ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 50); ++ else if (v1 == 0xfa) ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); ++ else if (v1 == 0xf9) ++ rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 1); ++ else ++ rtw_IOL_append_WRF_cmd(pxmit_frame, RF_PATH_A, (u16)v1, v2, bRFRegOffsetMask); ++ } else { ++ odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); ++ } ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ ++ while (v2 != 0xDEAD && i < ArrayLen - 2) ++ READ_NEXT_PAIR(v1, v2, i); ++ } ++ } ++ } ++ if (biol) { ++ if (!rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) { ++ rst = HAL_STATUS_FAILURE; ++ pr_info("~~~ IOL Config %s Failed !!!\n", __func__); ++ } ++ } ++ return rst; ++} +diff --git a/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c b/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c +new file mode 100644 +index 000000000000..356885e27edd +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c +@@ -0,0 +1,1264 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++ ++/*---------------------------Define Local Constant---------------------------*/ ++/* 2010/04/25 MH Define the max tx power tracking tx agc power. */ ++#define ODM_TXPWRTRACK_MAX_IDX_88E 6 ++ ++/*---------------------------Define Local Constant---------------------------*/ ++ ++/* 3============================================================ */ ++/* 3 Tx Power Tracking */ ++/* 3============================================================ */ ++/*----------------------------------------------------------------------------- ++ * Function: ODM_TxPwrTrackAdjust88E() ++ * ++ * Overview: 88E we can not write 0xc80/c94/c4c/ 0xa2x. Instead of write TX agc. ++ * No matter OFDM & CCK use the same method. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 04/23/2012 MHC Create Version 0. ++ * 04/23/2012 MHC Adjust TX agc directly not throughput BB digital. ++ * ++ *---------------------------------------------------------------------------*/ ++void ODM_TxPwrTrackAdjust88E(struct odm_dm_struct *dm_odm, u8 Type,/* 0 = OFDM, 1 = CCK */ ++ u8 *pDirection, /* 1 = +(increase) 2 = -(decrease) */ ++ u32 *pOutWriteVal /* Tx tracking CCK/OFDM BB swing index adjust */ ++ ) ++{ ++ u8 pwr_value = 0; ++ /* Tx power tracking BB swing table. */ ++ /* The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */ ++ if (Type == 0) { /* For OFDM afjust */ ++ if (dm_odm->BbSwingIdxOfdm <= dm_odm->BbSwingIdxOfdmBase) { ++ *pDirection = 1; ++ pwr_value = (dm_odm->BbSwingIdxOfdmBase - dm_odm->BbSwingIdxOfdm); ++ } else { ++ *pDirection = 2; ++ pwr_value = (dm_odm->BbSwingIdxOfdm - dm_odm->BbSwingIdxOfdmBase); ++ } ++ } else if (Type == 1) { /* For CCK adjust. */ ++ if (dm_odm->BbSwingIdxCck <= dm_odm->BbSwingIdxCckBase) { ++ *pDirection = 1; ++ pwr_value = (dm_odm->BbSwingIdxCckBase - dm_odm->BbSwingIdxCck); ++ } else { ++ *pDirection = 2; ++ pwr_value = (dm_odm->BbSwingIdxCck - dm_odm->BbSwingIdxCckBase); ++ } ++ } ++ ++ /* */ ++ /* 2012/04/25 MH According to Ed/Luke.Lees estimate for EVM the max tx power tracking */ ++ /* need to be less than 6 power index for 88E. */ ++ /* */ ++ if (pwr_value >= ODM_TXPWRTRACK_MAX_IDX_88E && *pDirection == 1) ++ pwr_value = ODM_TXPWRTRACK_MAX_IDX_88E; ++ ++ *pOutWriteVal = pwr_value | (pwr_value << 8) | (pwr_value << 16) | (pwr_value << 24); ++} /* ODM_TxPwrTrackAdjust88E */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: odm_TxPwrTrackSetPwr88E() ++ * ++ * Overview: 88E change all channel tx power accordign to flag. ++ * OFDM & CCK are all different. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 04/23/2012 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++static void odm_TxPwrTrackSetPwr88E(struct odm_dm_struct *dm_odm) ++{ ++ if (dm_odm->BbSwingFlagOfdm || dm_odm->BbSwingFlagCck) { ++ PHY_SetTxPowerLevel8188E(dm_odm->Adapter, *dm_odm->pChannel); ++ dm_odm->BbSwingFlagOfdm = false; ++ dm_odm->BbSwingFlagCck = false; ++ } ++} /* odm_TxPwrTrackSetPwr88E */ ++ ++/* 091212 chiyokolin */ ++void ++odm_TXPowerTrackingCallback_ThermalMeter_8188E( ++ struct adapter *Adapter ++ ) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, offset; ++ u8 ThermalValue_AVG_count = 0; ++ u32 ThermalValue_AVG = 0; ++ s32 ele_A = 0, ele_D, TempCCk, X, value32; ++ s32 Y, ele_C = 0; ++ s8 OFDM_index[2], CCK_index = 0; ++ s8 OFDM_index_old[2] = {0, 0}, CCK_index_old = 0; ++ u32 i = 0, j = 0; ++ bool is2t = false; ++ ++ u8 OFDM_min_index = 6, rf; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */ ++ u8 Indexforchannel = 0/*GetRightChnlPlaceforIQK(pHalData->CurrentChannel)*/; ++ s8 OFDM_index_mapping[2][index_mapping_NUM_88E] = { ++ {0, 0, 2, 3, 4, 4, /* 2.4G, decrease power */ ++ 5, 6, 7, 7, 8, 9, ++ 10, 10, 11}, /* For lower temperature, 20120220 updated on 20120220. */ ++ {0, 0, -1, -2, -3, -4, /* 2.4G, increase power */ ++ -4, -4, -4, -5, -7, -8, ++ -9, -9, -10}, ++ }; ++ u8 Thermal_mapping[2][index_mapping_NUM_88E] = { ++ {0, 2, 4, 6, 8, 10, /* 2.4G, decrease power */ ++ 12, 14, 16, 18, 20, 22, ++ 24, 26, 27}, ++ {0, 2, 4, 6, 8, 10, /* 2.4G,, increase power */ ++ 12, 14, 16, 18, 20, 22, ++ 25, 25, 25}, ++ }; ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ /* 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */ ++ odm_TxPwrTrackSetPwr88E(dm_odm); ++ ++ dm_odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++; /* cosa add for debug */ ++ dm_odm->RFCalibrateInfo.bTXPowerTrackingInit = true; ++ ++ /* RFCalibrateInfo.RegA24 will be initialized when ODM HW configuring, but MP configures with para files. */ ++ dm_odm->RFCalibrateInfo.RegA24 = 0x090e1317; ++ ++ ThermalValue = (u8)ODM_GetRFReg(dm_odm, RF_PATH_A, RF_T_METER_88E, 0xfc00); /* 0x42: RF Reg[15:10] 88E */ ++ ++ if (is2t) ++ rf = 2; ++ else ++ rf = 1; ++ ++ if (ThermalValue) { ++ /* Query OFDM path A default setting */ ++ ele_D = ODM_GetBBReg(dm_odm, rOFDM0_XATxIQImbalance, bMaskDWord) & bMaskOFDM_D; ++ for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { /* find the index */ ++ if (ele_D == (OFDMSwingTable[i] & bMaskOFDM_D)) { ++ OFDM_index_old[0] = (u8)i; ++ dm_odm->BbSwingIdxOfdmBase = (u8)i; ++ break; ++ } ++ } ++ ++ /* Query OFDM path B default setting */ ++ if (is2t) { ++ ele_D = ODM_GetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord) & bMaskOFDM_D; ++ for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) { /* find the index */ ++ if (ele_D == (OFDMSwingTable[i] & bMaskOFDM_D)) { ++ OFDM_index_old[1] = (u8)i; ++ break; ++ } ++ } ++ } ++ ++ /* Query CCK default setting From 0xa24 */ ++ TempCCk = dm_odm->RFCalibrateInfo.RegA24; ++ ++ for (i = 0; i < CCK_TABLE_SIZE; i++) { ++ if (dm_odm->RFCalibrateInfo.bCCKinCH14) { ++ if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4) == 0) { ++ CCK_index_old = (u8)i; ++ dm_odm->BbSwingIdxCckBase = (u8)i; ++ break; ++ } ++ } else { ++ if (ODM_CompareMemory(dm_odm, (void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4) == 0) { ++ CCK_index_old = (u8)i; ++ dm_odm->BbSwingIdxCckBase = (u8)i; ++ break; ++ } ++ } ++ } ++ ++ if (!dm_odm->RFCalibrateInfo.ThermalValue) { ++ dm_odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter; ++ dm_odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue; ++ dm_odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue; ++ ++ for (i = 0; i < rf; i++) ++ dm_odm->RFCalibrateInfo.OFDM_index[i] = OFDM_index_old[i]; ++ dm_odm->RFCalibrateInfo.CCK_index = CCK_index_old; ++ } ++ ++ /* calculate average thermal meter */ ++ dm_odm->RFCalibrateInfo.ThermalValue_AVG[dm_odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue; ++ dm_odm->RFCalibrateInfo.ThermalValue_AVG_index++; ++ if (dm_odm->RFCalibrateInfo.ThermalValue_AVG_index == AVG_THERMAL_NUM_88E) ++ dm_odm->RFCalibrateInfo.ThermalValue_AVG_index = 0; ++ ++ for (i = 0; i < AVG_THERMAL_NUM_88E; i++) { ++ if (dm_odm->RFCalibrateInfo.ThermalValue_AVG[i]) { ++ ThermalValue_AVG += dm_odm->RFCalibrateInfo.ThermalValue_AVG[i]; ++ ThermalValue_AVG_count++; ++ } ++ } ++ ++ if (ThermalValue_AVG_count) ++ ThermalValue = (u8)(ThermalValue_AVG / ThermalValue_AVG_count); ++ ++ if (dm_odm->RFCalibrateInfo.bReloadtxpowerindex) { ++ delta = ThermalValue > pHalData->EEPROMThermalMeter ? ++ (ThermalValue - pHalData->EEPROMThermalMeter) : ++ (pHalData->EEPROMThermalMeter - ThermalValue); ++ dm_odm->RFCalibrateInfo.bReloadtxpowerindex = false; ++ dm_odm->RFCalibrateInfo.bDoneTxpower = false; ++ } else if (dm_odm->RFCalibrateInfo.bDoneTxpower) { ++ delta = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue) ? ++ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue) : ++ (dm_odm->RFCalibrateInfo.ThermalValue - ThermalValue); ++ } else { ++ delta = ThermalValue > pHalData->EEPROMThermalMeter ? ++ (ThermalValue - pHalData->EEPROMThermalMeter) : ++ (pHalData->EEPROMThermalMeter - ThermalValue); ++ } ++ delta_LCK = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue_LCK) ? ++ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue_LCK) : ++ (dm_odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue); ++ delta_IQK = (ThermalValue > dm_odm->RFCalibrateInfo.ThermalValue_IQK) ? ++ (ThermalValue - dm_odm->RFCalibrateInfo.ThermalValue_IQK) : ++ (dm_odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue); ++ ++ if ((delta_LCK >= 8)) { /* Delta temperature is equal to or larger than 20 centigrade. */ ++ dm_odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue; ++ PHY_LCCalibrate_8188E(Adapter); ++ } ++ ++ if (delta > 0 && dm_odm->RFCalibrateInfo.TxPowerTrackControl) { ++ delta = ThermalValue > pHalData->EEPROMThermalMeter ? ++ (ThermalValue - pHalData->EEPROMThermalMeter) : ++ (pHalData->EEPROMThermalMeter - ThermalValue); ++ /* calculate new OFDM / CCK offset */ ++ if (ThermalValue > pHalData->EEPROMThermalMeter) ++ j = 1; ++ else ++ j = 0; ++ for (offset = 0; offset < index_mapping_NUM_88E; offset++) { ++ if (delta < Thermal_mapping[j][offset]) { ++ if (offset != 0) ++ offset--; ++ break; ++ } ++ } ++ if (offset >= index_mapping_NUM_88E) ++ offset = index_mapping_NUM_88E - 1; ++ for (i = 0; i < rf; i++) ++ OFDM_index[i] = dm_odm->RFCalibrateInfo.OFDM_index[i] + OFDM_index_mapping[j][offset]; ++ CCK_index = dm_odm->RFCalibrateInfo.CCK_index + OFDM_index_mapping[j][offset]; ++ ++ for (i = 0; i < rf; i++) { ++ if (OFDM_index[i] > OFDM_TABLE_SIZE_92D - 1) ++ OFDM_index[i] = OFDM_TABLE_SIZE_92D - 1; ++ else if (OFDM_index[i] < OFDM_min_index) ++ OFDM_index[i] = OFDM_min_index; ++ } ++ ++ if (CCK_index > CCK_TABLE_SIZE - 1) ++ CCK_index = CCK_TABLE_SIZE - 1; ++ else if (CCK_index < 0) ++ CCK_index = 0; ++ ++ /* 2 temporarily remove bNOPG */ ++ /* Config by SwingTable */ ++ if (dm_odm->RFCalibrateInfo.TxPowerTrackControl) { ++ dm_odm->RFCalibrateInfo.bDoneTxpower = true; ++ ++ /* Adujst OFDM Ant_A according to IQK result */ ++ ele_D = (OFDMSwingTable[(u8)OFDM_index[0]] & 0xFFC00000) >> 22; ++ X = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][0]; ++ Y = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][1]; ++ ++ /* Revse TX power table. */ ++ dm_odm->BbSwingIdxOfdm = (u8)OFDM_index[0]; ++ dm_odm->BbSwingIdxCck = (u8)CCK_index; ++ ++ if (dm_odm->BbSwingIdxOfdmCurrent != dm_odm->BbSwingIdxOfdm) { ++ dm_odm->BbSwingIdxOfdmCurrent = dm_odm->BbSwingIdxOfdm; ++ dm_odm->BbSwingFlagOfdm = true; ++ } ++ ++ if (dm_odm->BbSwingIdxCckCurrent != dm_odm->BbSwingIdxCck) { ++ dm_odm->BbSwingIdxCckCurrent = dm_odm->BbSwingIdxCck; ++ dm_odm->BbSwingFlagCck = true; ++ } ++ ++ if (X != 0) { ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ ele_A = ((X * ele_D) >> 8) & 0x000003FF; ++ ++ /* new element C = element D x Y */ ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ele_C = ((Y * ele_D) >> 8) & 0x000003FF; ++ ++ /* 2012/04/23 MH According to Luke's suggestion, we can not write BB digital */ ++ /* to increase TX power. Otherwise, EVM will be bad. */ ++ } ++ ++ if (is2t) { ++ ele_D = (OFDMSwingTable[(u8)OFDM_index[1]] & 0xFFC00000) >> 22; ++ ++ /* new element A = element D x X */ ++ X = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][4]; ++ Y = dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][5]; ++ ++ if ((X != 0) && (*dm_odm->pBandType == ODM_BAND_2_4G)) { ++ if ((X & 0x00000200) != 0) /* consider minus */ ++ X = X | 0xFFFFFC00; ++ ele_A = ((X * ele_D) >> 8) & 0x000003FF; ++ ++ /* new element C = element D x Y */ ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ele_C = ((Y * ele_D) >> 8) & 0x00003FF; ++ ++ /* wtite new elements A, C, D to regC88 and regC9C, element B is always 0 */ ++ value32 = (ele_D << 22) | ((ele_C & 0x3F) << 16) | ele_A; ++ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord, value32); ++ ++ value32 = (ele_C & 0x000003C0) >> 6; ++ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, bMaskH4Bits, value32); ++ ++ value32 = ((X * ele_D) >> 7) & 0x01; ++ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(28), value32); ++ } else { ++ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable[(u8)OFDM_index[1]]); ++ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00); ++ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(28), 0x00); ++ } ++ } ++ } ++ } ++ ++ if (delta_IQK >= 8) { /* Delta temperature is equal to or larger than 20 centigrade. */ ++ dm_odm->RFCalibrateInfo.ThermalValue_IQK = ThermalValue; ++ PHY_IQCalibrate_8188E(Adapter, false); ++ } ++ /* update thermal meter value */ ++ if (dm_odm->RFCalibrateInfo.TxPowerTrackControl) ++ dm_odm->RFCalibrateInfo.ThermalValue = ThermalValue; ++ } ++ dm_odm->RFCalibrateInfo.TXPowercount = 0; ++} ++ ++/* 1 7. IQK */ ++#define MAX_TOLERANCE 5 ++#define IQK_DELAY_TIME 1 /* ms */ ++ ++static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ ++phy_PathA_IQK_8188E(struct adapter *adapt, bool configPathB) ++{ ++ u32 regeac, regE94, regE9C; ++ u8 result = 0x00; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ /* 1 Tx IQK */ ++ /* path-A IQK setting */ ++ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c); ++ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c); ++ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x8214032a); ++ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000); ++ ++ /* LO calibration setting */ ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x00462911); ++ ++ /* One shot, path A LOK & IQK */ ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ /* delay x ms */ ++ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */ ++ ODM_delay_ms(IQK_DELAY_TIME_88E); ++ ++ /* Check failed */ ++ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord); ++ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord); ++ ++ if (!(regeac & BIT(28)) && ++ (((regE94 & 0x03FF0000) >> 16) != 0x142) && ++ (((regE9C & 0x03FF0000) >> 16) != 0x42)) ++ result |= 0x01; ++ return result; ++} ++ ++static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ ++phy_PathA_RxIQK(struct adapter *adapt, bool configPathB) ++{ ++ u32 regeac, regE94, regE9C, regEA4, u4tmp; ++ u8 result = 0x00; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ /* 1 Get TXIMR setting */ ++ /* modify RXIQK mode table */ ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf117B); ++ ++ /* PA,PAD off */ ++ ODM_SetRFReg(dm_odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x980); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, 0x56, bRFRegOffsetMask, 0x51000); ++ ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ ++ /* IQK setting */ ++ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, 0x01007c00); ++ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x81004800); ++ ++ /* path-A IQK setting */ ++ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c); ++ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c); ++ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c1f); ++ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000); ++ ++ /* LO calibration setting */ ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); ++ ++ /* One shot, path A LOK & IQK */ ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ /* delay x ms */ ++ ODM_delay_ms(IQK_DELAY_TIME_88E); ++ ++ /* Check failed */ ++ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord); ++ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord); ++ ++ if (!(regeac & BIT(28)) && ++ (((regE94 & 0x03FF0000) >> 16) != 0x142) && ++ (((regE9C & 0x03FF0000) >> 16) != 0x42)) ++ result |= 0x01; ++ else /* if Tx not OK, ignore Rx */ ++ return result; ++ ++ u4tmp = 0x80007C00 | (regE94 & 0x3FF0000) | ((regE9C & 0x3FF0000) >> 16); ++ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, u4tmp); ++ ++ /* 1 RX IQK */ ++ /* modify RXIQK mode table */ ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7ffa); ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ ++ /* IQK setting */ ++ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x01004800); ++ ++ /* path-A IQK setting */ ++ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x38008c1c); ++ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x18008c1c); ++ ODM_SetBBReg(dm_odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c05); ++ ODM_SetBBReg(dm_odm, rRx_IQK_PI_A, bMaskDWord, 0x28160c1f); ++ ++ /* LO calibration setting */ ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); ++ ++ /* One shot, path A LOK & IQK */ ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ++ /* delay x ms */ ++ /* PlatformStallExecution(IQK_DELAY_TIME_88E*1000); */ ++ ODM_delay_ms(IQK_DELAY_TIME_88E); ++ ++ /* Check failed */ ++ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regE94 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord); ++ regE9C = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord); ++ regEA4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord); ++ ++ /* reload RF 0xdf */ ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x180); ++ ++ if (!(regeac & BIT(27)) && /* if Tx is OK, check whether Rx is OK */ ++ (((regEA4 & 0x03FF0000) >> 16) != 0x132) && ++ (((regeac & 0x03FF0000) >> 16) != 0x36)) ++ result |= 0x02; ++ ++ return result; ++} ++ ++static u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ ++phy_PathB_IQK_8188E(struct adapter *adapt) ++{ ++ u32 regeac, regeb4, regebc, regec4, regecc; ++ u8 result = 0x00; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ /* One shot, path B LOK & IQK */ ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Cont, bMaskDWord, 0x00000002); ++ ODM_SetBBReg(dm_odm, rIQK_AGC_Cont, bMaskDWord, 0x00000000); ++ ++ /* delay x ms */ ++ ODM_delay_ms(IQK_DELAY_TIME_88E); ++ ++ /* Check failed */ ++ regeac = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord); ++ regeb4 = ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord); ++ regebc = ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord); ++ regec4 = ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_B_2, bMaskDWord); ++ regecc = ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_B_2, bMaskDWord); ++ ++ if (!(regeac & BIT(31)) && ++ (((regeb4 & 0x03FF0000) >> 16) != 0x142) && ++ (((regebc & 0x03FF0000) >> 16) != 0x42)) ++ result |= 0x01; ++ else ++ return result; ++ ++ if (!(regeac & BIT(30)) && ++ (((regec4 & 0x03FF0000) >> 16) != 0x132) && ++ (((regecc & 0x03FF0000) >> 16) != 0x36)) ++ result |= 0x02; ++ ++ return result; ++} ++ ++static void patha_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8], u8 final_candidate, bool txonly) ++{ ++ u32 Oldval_0, X, TX0_A, reg; ++ s32 Y, TX0_C; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ if (final_candidate == 0xFF) { ++ return; ++ } else if (iqkok) { ++ Oldval_0 = (ODM_GetBBReg(dm_odm, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF; ++ ++ X = result[final_candidate][0]; ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ TX0_A = (X * Oldval_0) >> 8; ++ ODM_SetBBReg(dm_odm, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A); ++ ++ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(31), ((X * Oldval_0 >> 7) & 0x1)); ++ ++ Y = result[final_candidate][1]; ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ++ TX0_C = (Y * Oldval_0) >> 8; ++ ODM_SetBBReg(dm_odm, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C & 0x3C0) >> 6)); ++ ODM_SetBBReg(dm_odm, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C & 0x3F)); ++ ++ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(29), ((Y * Oldval_0 >> 7) & 0x1)); ++ ++ if (txonly) ++ return; ++ ++ reg = result[final_candidate][2]; ++ ODM_SetBBReg(dm_odm, rOFDM0_XARxIQImbalance, 0x3FF, reg); ++ ++ reg = result[final_candidate][3] & 0x3F; ++ ODM_SetBBReg(dm_odm, rOFDM0_XARxIQImbalance, 0xFC00, reg); ++ ++ reg = (result[final_candidate][3] >> 6) & 0xF; ++ ODM_SetBBReg(dm_odm, rOFDM0_RxIQExtAnta, 0xF0000000, reg); ++ } ++} ++ ++static void pathb_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8], u8 final_candidate, bool txonly) ++{ ++ u32 Oldval_1, X, TX1_A, reg; ++ s32 Y, TX1_C; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ if (final_candidate == 0xFF) { ++ return; ++ } else if (iqkok) { ++ Oldval_1 = (ODM_GetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF; ++ ++ X = result[final_candidate][4]; ++ if ((X & 0x00000200) != 0) ++ X = X | 0xFFFFFC00; ++ TX1_A = (X * Oldval_1) >> 8; ++ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A); ++ ++ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(27), ((X * Oldval_1 >> 7) & 0x1)); ++ ++ Y = result[final_candidate][5]; ++ if ((Y & 0x00000200) != 0) ++ Y = Y | 0xFFFFFC00; ++ ++ TX1_C = (Y * Oldval_1) >> 8; ++ ODM_SetBBReg(dm_odm, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C & 0x3C0) >> 6)); ++ ODM_SetBBReg(dm_odm, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C & 0x3F)); ++ ++ ODM_SetBBReg(dm_odm, rOFDM0_ECCAThreshold, BIT(25), ((Y * Oldval_1 >> 7) & 0x1)); ++ ++ if (txonly) ++ return; ++ ++ reg = result[final_candidate][6]; ++ ODM_SetBBReg(dm_odm, rOFDM0_XBRxIQImbalance, 0x3FF, reg); ++ ++ reg = result[final_candidate][7] & 0x3F; ++ ODM_SetBBReg(dm_odm, rOFDM0_XBRxIQImbalance, 0xFC00, reg); ++ ++ reg = (result[final_candidate][7] >> 6) & 0xF; ++ ODM_SetBBReg(dm_odm, rOFDM0_AGCRSSITable, 0x0000F000, reg); ++ } ++} ++ ++/* */ ++/* 2011/07/26 MH Add an API for testing IQK fail case. */ ++/* */ ++/* MP Already declare in odm.c */ ++static bool ODM_CheckPowerStatus(struct adapter *Adapter) ++{ ++ return true; ++} ++ ++void _PHY_SaveADDARegisters(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegisterNum) ++{ ++ u32 i; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ if (!ODM_CheckPowerStatus(adapt)) ++ return; ++ ++ for (i = 0; i < RegisterNum; i++) { ++ ADDABackup[i] = ODM_GetBBReg(dm_odm, ADDAReg[i], bMaskDWord); ++ } ++} ++ ++static void _PHY_SaveMACRegisters( ++ struct adapter *adapt, ++ u32 *MACReg, ++ u32 *MACBackup ++ ) ++{ ++ u32 i; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) { ++ MACBackup[i] = ODM_Read1Byte(dm_odm, MACReg[i]); ++ } ++ MACBackup[i] = ODM_Read4Byte(dm_odm, MACReg[i]); ++} ++ ++static void reload_adda_reg(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegiesterNum) ++{ ++ u32 i; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ for (i = 0; i < RegiesterNum; i++) ++ ODM_SetBBReg(dm_odm, ADDAReg[i], bMaskDWord, ADDABackup[i]); ++} ++ ++static void ++_PHY_ReloadMACRegisters( ++ struct adapter *adapt, ++ u32 *MACReg, ++ u32 *MACBackup ++ ) ++{ ++ u32 i; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) { ++ ODM_Write1Byte(dm_odm, MACReg[i], (u8)MACBackup[i]); ++ } ++ ODM_Write4Byte(dm_odm, MACReg[i], MACBackup[i]); ++} ++ ++void ++_PHY_PathADDAOn( ++ struct adapter *adapt, ++ u32 *ADDAReg, ++ bool isPathAOn, ++ bool is2t ++ ) ++{ ++ u32 pathOn; ++ u32 i; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4; ++ if (!is2t) { ++ pathOn = 0x0bdb25a0; ++ ODM_SetBBReg(dm_odm, ADDAReg[0], bMaskDWord, 0x0b1b25a0); ++ } else { ++ ODM_SetBBReg(dm_odm, ADDAReg[0], bMaskDWord, pathOn); ++ } ++ ++ for (i = 1; i < IQK_ADDA_REG_NUM; i++) ++ ODM_SetBBReg(dm_odm, ADDAReg[i], bMaskDWord, pathOn); ++} ++ ++void ++_PHY_MACSettingCalibration( ++ struct adapter *adapt, ++ u32 *MACReg, ++ u32 *MACBackup ++ ) ++{ ++ u32 i = 0; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ ODM_Write1Byte(dm_odm, MACReg[i], 0x3F); ++ ++ for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++) { ++ ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i] & (~BIT(3)))); ++ } ++ ODM_Write1Byte(dm_odm, MACReg[i], (u8)(MACBackup[i] & (~BIT(5)))); ++} ++ ++void ++_PHY_PathAStandBy( ++ struct adapter *adapt ++ ) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x0); ++ ODM_SetBBReg(dm_odm, 0x840, bMaskDWord, 0x00010000); ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++} ++ ++static void _PHY_PIModeSwitch( ++ struct adapter *adapt, ++ bool PIMode ++ ) ++{ ++ u32 mode; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ mode = PIMode ? 0x01000100 : 0x01000000; ++ ODM_SetBBReg(dm_odm, rFPGA0_XA_HSSIParameter1, bMaskDWord, mode); ++ ODM_SetBBReg(dm_odm, rFPGA0_XB_HSSIParameter1, bMaskDWord, mode); ++} ++ ++static bool phy_SimularityCompare_8188E( ++ struct adapter *adapt, ++ s32 resulta[][8], ++ u8 c1, ++ u8 c2 ++ ) ++{ ++ u32 i, j, diff, sim_bitmap, bound = 0; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */ ++ bool result = true; ++ bool is2t; ++ s32 tmp1 = 0, tmp2 = 0; ++ ++ if ((dm_odm->RFType == ODM_2T2R) || (dm_odm->RFType == ODM_2T3R) || (dm_odm->RFType == ODM_2T4R)) ++ is2t = true; ++ else ++ is2t = false; ++ ++ if (is2t) ++ bound = 8; ++ else ++ bound = 4; ++ ++ sim_bitmap = 0; ++ ++ for (i = 0; i < bound; i++) { ++ if ((i == 1) || (i == 3) || (i == 5) || (i == 7)) { ++ if ((resulta[c1][i] & 0x00000200) != 0) ++ tmp1 = resulta[c1][i] | 0xFFFFFC00; ++ else ++ tmp1 = resulta[c1][i]; ++ ++ if ((resulta[c2][i] & 0x00000200) != 0) ++ tmp2 = resulta[c2][i] | 0xFFFFFC00; ++ else ++ tmp2 = resulta[c2][i]; ++ } else { ++ tmp1 = resulta[c1][i]; ++ tmp2 = resulta[c2][i]; ++ } ++ ++ diff = (tmp1 > tmp2) ? (tmp1 - tmp2) : (tmp2 - tmp1); ++ ++ if (diff > MAX_TOLERANCE) { ++ if ((i == 2 || i == 6) && !sim_bitmap) { ++ if (resulta[c1][i] + resulta[c1][i + 1] == 0) ++ final_candidate[(i / 4)] = c2; ++ else if (resulta[c2][i] + resulta[c2][i + 1] == 0) ++ final_candidate[(i / 4)] = c1; ++ else ++ sim_bitmap = sim_bitmap | (1 << i); ++ } else { ++ sim_bitmap = sim_bitmap | (1 << i); ++ } ++ } ++ } ++ ++ if (sim_bitmap == 0) { ++ for (i = 0; i < (bound / 4); i++) { ++ if (final_candidate[i] != 0xFF) { ++ for (j = i * 4; j < (i + 1) * 4 - 2; j++) ++ resulta[3][j] = resulta[final_candidate[i]][j]; ++ result = false; ++ } ++ } ++ return result; ++ } else { ++ if (!(sim_bitmap & 0x03)) { /* path A TX OK */ ++ for (i = 0; i < 2; i++) ++ resulta[3][i] = resulta[c1][i]; ++ } ++ if (!(sim_bitmap & 0x0c)) { /* path A RX OK */ ++ for (i = 2; i < 4; i++) ++ resulta[3][i] = resulta[c1][i]; ++ } ++ ++ if (!(sim_bitmap & 0x30)) { /* path B TX OK */ ++ for (i = 4; i < 6; i++) ++ resulta[3][i] = resulta[c1][i]; ++ } ++ ++ if (!(sim_bitmap & 0xc0)) { /* path B RX OK */ ++ for (i = 6; i < 8; i++) ++ resulta[3][i] = resulta[c1][i]; ++ } ++ return false; ++ } ++} ++ ++static void phy_IQCalibrate_8188E(struct adapter *adapt, s32 result[][8], u8 t, bool is2t) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ u32 i; ++ u8 PathAOK, PathBOK; ++ u32 ADDA_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN }; ++ u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = { ++ REG_TXPAUSE, REG_BCN_CTRL, ++ REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; ++ ++ /* since 92C & 92D have the different define in IQK_BB_REG */ ++ u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { ++ rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar, ++ rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB, ++ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, ++ rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD ++ }; ++ ++ u32 retryCount = 9; ++ if (*dm_odm->mp_mode == 1) ++ retryCount = 9; ++ else ++ retryCount = 2; ++ /* Note: IQ calibration must be performed after loading */ ++ /* PHY_REG.txt , and radio_a, radio_b.txt */ ++ ++ if (t == 0) { ++ /* Save ADDA parameters, turn Path A ADDA on */ ++ _PHY_SaveADDARegisters(adapt, ADDA_REG, dm_odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); ++ _PHY_SaveMACRegisters(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup); ++ _PHY_SaveADDARegisters(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); ++ } ++ ++ _PHY_PathADDAOn(adapt, ADDA_REG, true, is2t); ++ if (t == 0) ++ dm_odm->RFCalibrateInfo.bRfPiEnable = (u8)ODM_GetBBReg(dm_odm, rFPGA0_XA_HSSIParameter1, BIT(8)); ++ ++ if (!dm_odm->RFCalibrateInfo.bRfPiEnable) { ++ /* Switch BB to PI mode to do IQ Calibration. */ ++ _PHY_PIModeSwitch(adapt, true); ++ } ++ ++ /* BB setting */ ++ ODM_SetBBReg(dm_odm, rFPGA0_RFMOD, BIT(24), 0x00); ++ ODM_SetBBReg(dm_odm, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600); ++ ODM_SetBBReg(dm_odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4); ++ ODM_SetBBReg(dm_odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000); ++ ++ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFInterfaceSW, BIT(10), 0x01); ++ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFInterfaceSW, BIT(26), 0x01); ++ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT(10), 0x00); ++ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT(10), 0x00); ++ ++ if (is2t) { ++ ODM_SetBBReg(dm_odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000); ++ ODM_SetBBReg(dm_odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000); ++ } ++ ++ /* MAC settings */ ++ _PHY_MACSettingCalibration(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup); ++ ++ /* Page B init */ ++ /* AP or IQK */ ++ ODM_SetBBReg(dm_odm, rConfig_AntA, bMaskDWord, 0x0f600000); ++ ++ if (is2t) ++ ODM_SetBBReg(dm_odm, rConfig_AntB, bMaskDWord, 0x0f600000); ++ ++ /* IQ calibration setting */ ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ ODM_SetBBReg(dm_odm, rTx_IQK, bMaskDWord, 0x01007c00); ++ ODM_SetBBReg(dm_odm, rRx_IQK, bMaskDWord, 0x81004800); ++ ++ for (i = 0; i < retryCount; i++) { ++ PathAOK = phy_PathA_IQK_8188E(adapt, is2t); ++ if (PathAOK == 0x01) { ++ result[t][0] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_A, bMaskDWord) & 0x3FF0000) >> 16; ++ result[t][1] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_A, bMaskDWord) & 0x3FF0000) >> 16; ++ break; ++ } ++ } ++ ++ for (i = 0; i < retryCount; i++) { ++ PathAOK = phy_PathA_RxIQK(adapt, is2t); ++ if (PathAOK == 0x03) { ++ result[t][2] = (ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_A_2, bMaskDWord) & 0x3FF0000) >> 16; ++ result[t][3] = (ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_A_2, bMaskDWord) & 0x3FF0000) >> 16; ++ break; ++ } ++ } ++ ++ if (is2t) { ++ _PHY_PathAStandBy(adapt); ++ ++ /* Turn Path B ADDA on */ ++ _PHY_PathADDAOn(adapt, ADDA_REG, false, is2t); ++ ++ for (i = 0; i < retryCount; i++) { ++ PathBOK = phy_PathB_IQK_8188E(adapt); ++ if (PathBOK == 0x03) { ++ result[t][4] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord) & 0x3FF0000) >> 16; ++ result[t][5] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord) & 0x3FF0000) >> 16; ++ result[t][6] = (ODM_GetBBReg(dm_odm, rRx_Power_Before_IQK_B_2, bMaskDWord) & 0x3FF0000) >> 16; ++ result[t][7] = (ODM_GetBBReg(dm_odm, rRx_Power_After_IQK_B_2, bMaskDWord) & 0x3FF0000) >> 16; ++ break; ++ } else if (i == (retryCount - 1) && PathBOK == 0x01) { /* Tx IQK OK */ ++ result[t][4] = (ODM_GetBBReg(dm_odm, rTx_Power_Before_IQK_B, bMaskDWord) & 0x3FF0000) >> 16; ++ result[t][5] = (ODM_GetBBReg(dm_odm, rTx_Power_After_IQK_B, bMaskDWord) & 0x3FF0000) >> 16; ++ } ++ } ++ } ++ ++ /* Back to BB mode, load original value */ ++ ODM_SetBBReg(dm_odm, rFPGA0_IQK, bMaskDWord, 0); ++ ++ if (t != 0) { ++ if (!dm_odm->RFCalibrateInfo.bRfPiEnable) { ++ /* Switch back BB to SI mode after finish IQ Calibration. */ ++ _PHY_PIModeSwitch(adapt, false); ++ } ++ ++ /* Reload ADDA power saving parameters */ ++ reload_adda_reg(adapt, ADDA_REG, dm_odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); ++ ++ /* Reload MAC parameters */ ++ _PHY_ReloadMACRegisters(adapt, IQK_MAC_REG, dm_odm->RFCalibrateInfo.IQK_MAC_backup); ++ ++ reload_adda_reg(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); ++ ++ /* Restore RX initial gain */ ++ ODM_SetBBReg(dm_odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3); ++ if (is2t) ++ ODM_SetBBReg(dm_odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3); ++ ++ /* load 0xe30 IQC default value */ ++ ODM_SetBBReg(dm_odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ ODM_SetBBReg(dm_odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); ++ } ++} ++ ++static void phy_LCCalibrate_8188E(struct adapter *adapt, bool is2t) ++{ ++ u8 tmpreg; ++ u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ /* Check continuous TX and Packet TX */ ++ tmpreg = ODM_Read1Byte(dm_odm, 0xd03); ++ ++ if ((tmpreg & 0x70) != 0) /* Deal with contisuous TX case */ ++ ODM_Write1Byte(dm_odm, 0xd03, tmpreg & 0x8F); /* disable all continuous TX */ ++ else /* Deal with Packet TX case */ ++ ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0xFF); /* block all queues */ ++ ++ if ((tmpreg & 0x70) != 0) { ++ /* 1. Read original RF mode */ ++ /* Path-A */ ++ RF_Amode = PHY_QueryRFReg(adapt, RF_PATH_A, RF_AC, bMask12Bits); ++ ++ /* Path-B */ ++ if (is2t) ++ RF_Bmode = PHY_QueryRFReg(adapt, RF_PATH_B, RF_AC, bMask12Bits); ++ ++ /* 2. Set RF mode = standby mode */ ++ /* Path-A */ ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode & 0x8FFFF) | 0x10000); ++ ++ /* Path-B */ ++ if (is2t) ++ ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode & 0x8FFFF) | 0x10000); ++ } ++ ++ /* 3. Read RF reg18 */ ++ LC_Cal = PHY_QueryRFReg(adapt, RF_PATH_A, RF_CHNLBW, bMask12Bits); ++ ++ /* 4. Set LC calibration begin bit15 */ ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal | 0x08000); ++ ++ ODM_sleep_ms(100); ++ ++ /* Restore original situation */ ++ if ((tmpreg & 0x70) != 0) { ++ /* Deal with continuous TX case */ ++ /* Path-A */ ++ ODM_Write1Byte(dm_odm, 0xd03, tmpreg); ++ ODM_SetRFReg(dm_odm, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode); ++ ++ /* Path-B */ ++ if (is2t) ++ ODM_SetRFReg(dm_odm, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode); ++ } else { ++ /* Deal with Packet TX case */ ++ ODM_Write1Byte(dm_odm, REG_TXPAUSE, 0x00); ++ } ++} ++ ++void PHY_IQCalibrate_8188E(struct adapter *adapt, bool recovery) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ struct mpt_context *pMptCtx = &adapt->mppriv.MptCtx; ++ s32 result[4][8]; /* last is final result */ ++ u8 i, final_candidate; ++ bool pathaok, pathbok; ++ s32 RegE94, RegE9C, RegEA4, RegEB4, RegEBC, RegEC4; ++ bool is12simular, is13simular, is23simular; ++ bool singletone = false, carrier_sup = false; ++ u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { ++ rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance, ++ rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable, ++ rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance, ++ rOFDM0_XCTxAFE, rOFDM0_XDTxAFE, ++ rOFDM0_RxIQExtAnta}; ++ bool is2t; ++ ++ is2t = (dm_odm->RFType == ODM_2T2R) ? true : false; ++ if (!ODM_CheckPowerStatus(adapt)) ++ return; ++ ++ if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION)) ++ return; ++ ++ if (*dm_odm->mp_mode == 1) { ++ singletone = pMptCtx->bSingleTone; ++ carrier_sup = pMptCtx->bCarrierSuppression; ++ } ++ ++ /* 20120213 Turn on when continuous Tx to pass lab testing. (required by Edlu) */ ++ if (singletone || carrier_sup) ++ return; ++ ++ if (recovery) { ++ reload_adda_reg(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); ++ return; ++ } ++ ++ for (i = 0; i < 8; i++) { ++ result[0][i] = 0; ++ result[1][i] = 0; ++ result[2][i] = 0; ++ if ((i == 0) || (i == 2) || (i == 4) || (i == 6)) ++ result[3][i] = 0x100; ++ else ++ result[3][i] = 0; ++ } ++ final_candidate = 0xff; ++ pathaok = false; ++ pathbok = false; ++ is12simular = false; ++ is23simular = false; ++ is13simular = false; ++ ++ for (i = 0; i < 3; i++) { ++ phy_IQCalibrate_8188E(adapt, result, i, is2t); ++ ++ if (i == 1) { ++ is12simular = phy_SimularityCompare_8188E(adapt, result, 0, 1); ++ if (is12simular) { ++ final_candidate = 0; ++ break; ++ } ++ } ++ ++ if (i == 2) { ++ is13simular = phy_SimularityCompare_8188E(adapt, result, 0, 2); ++ if (is13simular) { ++ final_candidate = 0; ++ ++ break; ++ } ++ is23simular = phy_SimularityCompare_8188E(adapt, result, 1, 2); ++ if (is23simular) { ++ final_candidate = 1; ++ } else { ++ final_candidate = 3; ++ } ++ } ++ } ++ ++ for (i = 0; i < 4; i++) { ++ RegE94 = result[i][0]; ++ RegE9C = result[i][1]; ++ RegEA4 = result[i][2]; ++ RegEB4 = result[i][4]; ++ RegEBC = result[i][5]; ++ RegEC4 = result[i][6]; ++ } ++ ++ if (final_candidate != 0xff) { ++ RegE94 = result[final_candidate][0]; ++ RegE9C = result[final_candidate][1]; ++ RegEA4 = result[final_candidate][2]; ++ RegEB4 = result[final_candidate][4]; ++ RegEBC = result[final_candidate][5]; ++ dm_odm->RFCalibrateInfo.RegE94 = RegE94; ++ dm_odm->RFCalibrateInfo.RegE9C = RegE9C; ++ dm_odm->RFCalibrateInfo.RegEB4 = RegEB4; ++ dm_odm->RFCalibrateInfo.RegEBC = RegEBC; ++ RegEC4 = result[final_candidate][6]; ++ pathaok = true; ++ pathbok = true; ++ } else { ++ dm_odm->RFCalibrateInfo.RegE94 = 0x100; ++ dm_odm->RFCalibrateInfo.RegEB4 = 0x100; /* X default value */ ++ dm_odm->RFCalibrateInfo.RegE9C = 0x0; ++ dm_odm->RFCalibrateInfo.RegEBC = 0x0; /* Y default value */ ++ } ++ if (RegE94 != 0) ++ patha_fill_iqk(adapt, pathaok, result, final_candidate, (RegEA4 == 0)); ++ if (is2t) { ++ if (RegEB4 != 0) ++ pathb_fill_iqk(adapt, pathbok, result, final_candidate, (RegEC4 == 0)); ++ } ++ ++/* To Fix BSOD when final_candidate is 0xff */ ++/* by sherry 20120321 */ ++ if (final_candidate < 4) { ++ for (i = 0; i < IQK_Matrix_REG_NUM; i++) ++ dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[0].Value[0][i] = result[final_candidate][i]; ++ dm_odm->RFCalibrateInfo.IQKMatrixRegSetting[0].bIQKDone = true; ++ } ++ ++ _PHY_SaveADDARegisters(adapt, IQK_BB_REG_92C, dm_odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); ++} ++ ++void PHY_LCCalibrate_8188E(struct adapter *adapt) ++{ ++ bool singletone = false, carrier_sup = false; ++ u32 timeout = 2000, timecount = 0; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ struct mpt_context *pMptCtx = &adapt->mppriv.MptCtx; ++ ++ if (*dm_odm->mp_mode == 1) { ++ singletone = pMptCtx->bSingleTone; ++ carrier_sup = pMptCtx->bCarrierSuppression; ++ } ++ if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION)) ++ return; ++ /* 20120213 Turn on when continuous Tx to pass lab testing. (required by Edlu) */ ++ if (singletone || carrier_sup) ++ return; ++ ++ while (*dm_odm->pbScanInProcess && timecount < timeout) { ++ ODM_delay_ms(50); ++ timecount += 50; ++ } ++ ++ dm_odm->RFCalibrateInfo.bLCKInProgress = true; ++ ++ if (dm_odm->RFType == ODM_2T2R) { ++ phy_LCCalibrate_8188E(adapt, true); ++ } else { ++ /* For 88C 1T1R */ ++ phy_LCCalibrate_8188E(adapt, false); ++ } ++ ++ dm_odm->RFCalibrateInfo.bLCKInProgress = false; ++} ++ ++static void phy_setrfpathswitch_8188e(struct adapter *adapt, bool main, bool is2t) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ if (!adapt->hw_init_completed) { ++ u8 u1btmp; ++ u1btmp = ODM_Read1Byte(dm_odm, REG_LEDCFG2) | BIT(7); ++ ODM_Write1Byte(dm_odm, REG_LEDCFG2, u1btmp); ++ ODM_SetBBReg(dm_odm, rFPGA0_XAB_RFParameter, BIT(13), 0x01); ++ } ++ ++ if (is2t) { /* 92C */ ++ if (main) ++ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT(5) | BIT(6), 0x1); /* 92C_Path_A */ ++ else ++ ODM_SetBBReg(dm_odm, rFPGA0_XB_RFInterfaceOE, BIT(5) | BIT(6), 0x2); /* BT */ ++ } else { /* 88C */ ++ if (main) ++ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT(8) | BIT(9), 0x2); /* Main */ ++ else ++ ODM_SetBBReg(dm_odm, rFPGA0_XA_RFInterfaceOE, BIT(8) | BIT(9), 0x1); /* Aux */ ++ } ++} ++ ++void PHY_SetRFPathSwitch_8188E(struct adapter *adapt, bool main) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(adapt); ++ struct odm_dm_struct *dm_odm = &pHalData->odmpriv; ++ ++ if (dm_odm->RFType == ODM_2T2R) { ++ phy_setrfpathswitch_8188e(adapt, main, true); ++ } else { ++ /* For 88C 1T1R */ ++ phy_setrfpathswitch_8188e(adapt, main, false); ++ } ++} +diff --git a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c +new file mode 100644 +index 000000000000..0fd11aca7ac7 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c +@@ -0,0 +1,95 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++/*++ ++ ++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 "../include/HalPwrSeqCmd.h" ++ ++/* Description: */ ++/* This routine deals with the Power Configuration CMDs parsing ++ * for RTL8723/RTL8188E Series IC. ++ * Assumption: ++ * We should follow specific format which was released from HW SD. ++ */ ++u8 HalPwrSeqCmdParsing(struct adapter *padapter, u8 cut_vers, u8 fab_vers, ++ u8 ifacetype, struct wl_pwr_cfg pwrseqcmd[]) ++{ ++ struct wl_pwr_cfg pwrcfgcmd = {0}; ++ u8 poll_bit = false; ++ u32 aryidx = 0; ++ u8 value = 0; ++ u32 offset = 0; ++ u32 poll_count = 0; /* polling autoload done. */ ++ u32 max_poll_count = 5000; ++ ++ do { ++ pwrcfgcmd = pwrseqcmd[aryidx]; ++ ++ /* 2 Only Handle the command whose FAB, CUT, and Interface are matched */ ++ if ((GET_PWR_CFG_FAB_MASK(pwrcfgcmd) & fab_vers) && ++ (GET_PWR_CFG_CUT_MASK(pwrcfgcmd) & cut_vers) && ++ (GET_PWR_CFG_INTF_MASK(pwrcfgcmd) & ifacetype)) { ++ switch (GET_PWR_CFG_CMD(pwrcfgcmd)) { ++ case PWR_CMD_WRITE: ++ offset = GET_PWR_CFG_OFFSET(pwrcfgcmd); ++ ++ /* Read the value from system register */ ++ value = rtw_read8(padapter, offset); ++ ++ value &= ~(GET_PWR_CFG_MASK(pwrcfgcmd)); ++ value |= (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd)); ++ ++ /* Write the value back to system register */ ++ rtw_write8(padapter, offset, value); ++ break; ++ case PWR_CMD_POLLING: ++ poll_bit = false; ++ offset = GET_PWR_CFG_OFFSET(pwrcfgcmd); ++ do { ++ value = rtw_read8(padapter, offset); ++ ++ value &= GET_PWR_CFG_MASK(pwrcfgcmd); ++ if (value == (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd))) ++ poll_bit = true; ++ else ++ udelay(10); ++ ++ if (poll_count++ > max_poll_count) { ++ DBG_88E("Fail to polling Offset[%#x]\n", offset); ++ return false; ++ } ++ } while (!poll_bit); ++ break; ++ case PWR_CMD_DELAY: ++ if (GET_PWR_CFG_VALUE(pwrcfgcmd) == PWRSEQ_DELAY_US) ++ udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd)); ++ else ++ udelay(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 a/drivers/staging/r8188eu/hal/hal_com.c b/drivers/staging/r8188eu/hal/hal_com.c +new file mode 100644 +index 000000000000..f09d4d49b159 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/hal_com.c +@@ -0,0 +1,358 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++ ++#include "../include/hal_intf.h" ++#include "../include/hal_com.h" ++#include "../include/rtl8188e_hal.h" ++ ++#define _HAL_INIT_C_ ++ ++void dump_chip_info(struct HAL_VERSION chip_vers) ++{ ++ uint cnt = 0; ++ char buf[128]; ++ ++ if (IS_81XXC(chip_vers)) { ++ cnt += sprintf((buf + cnt), "Chip Version Info: %s_", ++ IS_92C_SERIAL(chip_vers) ? ++ "CHIP_8192C" : "CHIP_8188C"); ++ } else if (IS_92D(chip_vers)) { ++ cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8192D_"); ++ } else if (IS_8723_SERIES(chip_vers)) { ++ cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8723A_"); ++ } else if (IS_8188E(chip_vers)) { ++ cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8188E_"); ++ } ++ ++ cnt += sprintf((buf + cnt), "%s_", IS_NORMAL_CHIP(chip_vers) ? ++ "Normal_Chip" : "Test_Chip"); ++ cnt += sprintf((buf + cnt), "%s_", IS_CHIP_VENDOR_TSMC(chip_vers) ? ++ "TSMC" : "UMC"); ++ if (IS_A_CUT(chip_vers)) ++ cnt += sprintf((buf + cnt), "A_CUT_"); ++ else if (IS_B_CUT(chip_vers)) ++ cnt += sprintf((buf + cnt), "B_CUT_"); ++ else if (IS_C_CUT(chip_vers)) ++ cnt += sprintf((buf + cnt), "C_CUT_"); ++ else if (IS_D_CUT(chip_vers)) ++ cnt += sprintf((buf + cnt), "D_CUT_"); ++ else if (IS_E_CUT(chip_vers)) ++ cnt += sprintf((buf + cnt), "E_CUT_"); ++ else ++ cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_", ++ chip_vers.CUTVersion); ++ ++ if (IS_1T1R(chip_vers)) ++ cnt += sprintf((buf + cnt), "1T1R_"); ++ else if (IS_1T2R(chip_vers)) ++ cnt += sprintf((buf + cnt), "1T2R_"); ++ else if (IS_2T2R(chip_vers)) ++ cnt += sprintf((buf + cnt), "2T2R_"); ++ else ++ cnt += sprintf((buf + cnt), "UNKNOWN_RFTYPE(%d)_", ++ chip_vers.RFType); ++ ++ cnt += sprintf((buf + cnt), "RomVer(%d)\n", chip_vers.ROMVer); ++ ++ pr_info("%s", buf); ++} ++ ++#define CHAN_PLAN_HW 0x80 ++ ++u8 /* return the final channel plan decision */ ++hal_com_get_channel_plan(struct adapter *padapter, u8 hw_channel_plan, ++ u8 sw_channel_plan, u8 def_channel_plan, ++ bool load_fail) ++{ ++ u8 sw_cfg; ++ u8 chnlplan; ++ ++ sw_cfg = true; ++ if (!load_fail) { ++ if (!rtw_is_channel_plan_valid(sw_channel_plan)) ++ sw_cfg = false; ++ if (hw_channel_plan & CHAN_PLAN_HW) ++ sw_cfg = false; ++ } ++ ++ if (sw_cfg) ++ chnlplan = sw_channel_plan; ++ else ++ chnlplan = hw_channel_plan & (~CHAN_PLAN_HW); ++ ++ if (!rtw_is_channel_plan_valid(chnlplan)) ++ chnlplan = def_channel_plan; ++ ++ return chnlplan; ++} ++ ++u8 MRateToHwRate(u8 rate) ++{ ++ u8 ret = DESC_RATE1M; ++ ++ switch (rate) { ++ /* CCK and OFDM non-HT rates */ ++ case IEEE80211_CCK_RATE_1MB: ++ ret = DESC_RATE1M; ++ break; ++ case IEEE80211_CCK_RATE_2MB: ++ ret = DESC_RATE2M; ++ break; ++ case IEEE80211_CCK_RATE_5MB: ++ ret = DESC_RATE5_5M; ++ break; ++ case IEEE80211_CCK_RATE_11MB: ++ ret = DESC_RATE11M; ++ break; ++ case IEEE80211_OFDM_RATE_6MB: ++ ret = DESC_RATE6M; ++ break; ++ case IEEE80211_OFDM_RATE_9MB: ++ ret = DESC_RATE9M; ++ break; ++ case IEEE80211_OFDM_RATE_12MB: ++ ret = DESC_RATE12M; ++ break; ++ case IEEE80211_OFDM_RATE_18MB: ++ ret = DESC_RATE18M; ++ break; ++ case IEEE80211_OFDM_RATE_24MB: ++ ret = DESC_RATE24M; ++ break; ++ case IEEE80211_OFDM_RATE_36MB: ++ ret = DESC_RATE36M; ++ break; ++ case IEEE80211_OFDM_RATE_48MB: ++ ret = DESC_RATE48M; ++ break; ++ case IEEE80211_OFDM_RATE_54MB: ++ ret = DESC_RATE54M; ++ break; ++ default: ++ break; ++ } ++ return ret; ++} ++ ++void HalSetBrateCfg(struct adapter *adapt, u8 *brates, u16 *rate_cfg) ++{ ++ u8 i, is_brate, brate; ++ ++ for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { ++ is_brate = brates[i] & IEEE80211_BASIC_RATE_MASK; ++ brate = brates[i] & 0x7f; ++ ++ if (is_brate) { ++ switch (brate) { ++ case IEEE80211_CCK_RATE_1MB: ++ *rate_cfg |= RATE_1M; ++ break; ++ case IEEE80211_CCK_RATE_2MB: ++ *rate_cfg |= RATE_2M; ++ break; ++ case IEEE80211_CCK_RATE_5MB: ++ *rate_cfg |= RATE_5_5M; ++ break; ++ case IEEE80211_CCK_RATE_11MB: ++ *rate_cfg |= RATE_11M; ++ break; ++ case IEEE80211_OFDM_RATE_6MB: ++ *rate_cfg |= RATE_6M; ++ break; ++ case IEEE80211_OFDM_RATE_9MB: ++ *rate_cfg |= RATE_9M; ++ break; ++ case IEEE80211_OFDM_RATE_12MB: ++ *rate_cfg |= RATE_12M; ++ break; ++ case IEEE80211_OFDM_RATE_18MB: ++ *rate_cfg |= RATE_18M; ++ break; ++ case IEEE80211_OFDM_RATE_24MB: ++ *rate_cfg |= RATE_24M; ++ break; ++ case IEEE80211_OFDM_RATE_36MB: ++ *rate_cfg |= RATE_36M; ++ break; ++ case IEEE80211_OFDM_RATE_48MB: ++ *rate_cfg |= RATE_48M; ++ break; ++ case IEEE80211_OFDM_RATE_54MB: ++ *rate_cfg |= RATE_54M; ++ break; ++ } ++ } ++ } ++} ++ ++static void one_out_pipe(struct adapter *adapter) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter); ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++} ++ ++static void two_out_pipe(struct adapter *adapter, bool wifi_cfg) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter); ++ ++ if (wifi_cfg) { /* WMM */ ++ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ ++ /* 0, 1, 0, 1, 0, 0, 0, 0, 0}; */ ++ /* 0:H, 1:L */ ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++ ++ } else {/* typical setting */ ++ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ ++ /* 1, 1, 0, 0, 0, 0, 0, 0, 0}; */ ++ /* 0:H, 1:L */ ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++ } ++} ++ ++static void three_out_pipe(struct adapter *adapter, bool wifi_cfg) ++{ ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapter); ++ ++ if (wifi_cfg) {/* for WMM */ ++ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ ++ /* 1, 2, 1, 0, 0, 0, 0, 0, 0}; */ ++ /* 0:H, 1:N, 2:L */ ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++ ++ } else {/* typical setting */ ++ /* BK, BE, VI, VO, BCN, CMD, MGT, HIGH, HCCA */ ++ /* 2, 2, 1, 0, 0, 0, 0, 0, 0}; */ ++ /* 0:H, 1:N, 2:L */ ++ ++ pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ ++ pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ ++ pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ ++ pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */ ++ ++ pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ ++ pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ ++ pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ ++ pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ ++ } ++} ++ ++bool Hal_MappingOutPipe(struct adapter *adapter, u8 numoutpipe) ++{ ++ struct registry_priv *pregistrypriv = &adapter->registrypriv; ++ bool wifi_cfg = (pregistrypriv->wifi_spec) ? true : false; ++ bool result = true; ++ ++ switch (numoutpipe) { ++ case 2: ++ two_out_pipe(adapter, wifi_cfg); ++ break; ++ case 3: ++ three_out_pipe(adapter, wifi_cfg); ++ break; ++ case 1: ++ one_out_pipe(adapter); ++ break; ++ default: ++ result = false; ++ break; ++ } ++ return result; ++} ++ ++void hal_init_macaddr(struct adapter *adapter) ++{ ++ rtw_hal_set_hwreg(adapter, HW_VAR_MAC_ADDR, ++ adapter->eeprompriv.mac_addr); ++} ++ ++/* ++* C2H event format: ++* Field TRIGGER CONTENT CMD_SEQ CMD_LEN CMD_ID ++* BITS [127:120] [119:16] [15:8] [7:4] [3:0] ++*/ ++ ++void c2h_evt_clear(struct adapter *adapter) ++{ ++ rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); ++} ++ ++s32 c2h_evt_read(struct adapter *adapter, u8 *buf) ++{ ++ s32 ret = _FAIL; ++ struct c2h_evt_hdr *c2h_evt; ++ int i; ++ u8 trigger; ++ ++ if (!buf) ++ goto exit; ++ ++ trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR); ++ ++ if (trigger == C2H_EVT_HOST_CLOSE) ++ goto exit; /* Not ready */ ++ else if (trigger != C2H_EVT_FW_CLOSE) ++ goto clear_evt; /* Not a valid value */ ++ ++ c2h_evt = (struct c2h_evt_hdr *)buf; ++ ++ memset(c2h_evt, 0, 16); ++ ++ *buf = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL); ++ *(buf + 1) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1); ++ ++ /* Read the content */ ++ for (i = 0; i < c2h_evt->plen; i++) ++ c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + ++ sizeof(*c2h_evt) + i); ++ ++ ret = _SUCCESS; ++ ++clear_evt: ++ /* ++ * Clear event to notify FW we have read the command. ++ * If this field isn't clear, the FW won't update the next ++ * command message. ++ */ ++ c2h_evt_clear(adapter); ++exit: ++ return ret; ++} +diff --git a/drivers/staging/r8188eu/hal/hal_intf.c b/drivers/staging/r8188eu/hal/hal_intf.c +new file mode 100644 +index 000000000000..a6d589e89aeb +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/hal_intf.c +@@ -0,0 +1,441 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _HAL_INTF_C_ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/hal_intf.h" ++ ++void rtw_hal_chip_configure(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.intf_chip_configure) ++ adapt->HalFunc.intf_chip_configure(adapt); ++} ++ ++void rtw_hal_read_chip_info(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.read_adapter_info) ++ adapt->HalFunc.read_adapter_info(adapt); ++} ++ ++void rtw_hal_read_chip_version(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.read_chip_version) ++ adapt->HalFunc.read_chip_version(adapt); ++} ++ ++void rtw_hal_def_value_init(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.init_default_value) ++ adapt->HalFunc.init_default_value(adapt); ++} ++ ++void rtw_hal_free_data(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.free_hal_data) ++ adapt->HalFunc.free_hal_data(adapt); ++} ++ ++void rtw_hal_dm_init(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.dm_init) ++ adapt->HalFunc.dm_init(adapt); ++} ++ ++void rtw_hal_dm_deinit(struct adapter *adapt) ++{ ++ /* cancel dm timer */ ++ if (adapt->HalFunc.dm_deinit) ++ adapt->HalFunc.dm_deinit(adapt); ++} ++ ++void rtw_hal_sw_led_init(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.InitSwLeds) ++ adapt->HalFunc.InitSwLeds(adapt); ++} ++ ++void rtw_hal_sw_led_deinit(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.DeInitSwLeds) ++ adapt->HalFunc.DeInitSwLeds(adapt); ++} ++ ++u32 rtw_hal_power_on(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.hal_power_on) ++ return adapt->HalFunc.hal_power_on(adapt); ++ return _FAIL; ++} ++ ++uint rtw_hal_init(struct adapter *adapt) ++{ ++ uint status = _SUCCESS; ++ ++ adapt->hw_init_completed = false; ++ ++ status = adapt->HalFunc.hal_init(adapt); ++ ++ if (status == _SUCCESS) { ++ adapt->hw_init_completed = true; ++ ++ if (adapt->registrypriv.notch_filter == 1) ++ rtw_hal_notch_filter(adapt, 1); ++ ++ rtw_hal_reset_security_engine(adapt); ++ } else { ++ adapt->hw_init_completed = false; ++ DBG_88E("rtw_hal_init: hal__init fail\n"); ++ } ++ ++ return status; ++} ++ ++uint rtw_hal_deinit(struct adapter *adapt) ++{ ++ uint status = _SUCCESS; ++ ++ status = adapt->HalFunc.hal_deinit(adapt); ++ ++ if (status == _SUCCESS) ++ adapt->hw_init_completed = false; ++ else ++ DBG_88E("\n rtw_hal_deinit: hal_init fail\n"); ++ ++ return status; ++} ++ ++void rtw_hal_set_hwreg(struct adapter *adapt, u8 variable, u8 *val) ++{ ++ if (adapt->HalFunc.SetHwRegHandler) ++ adapt->HalFunc.SetHwRegHandler(adapt, variable, val); ++} ++ ++void rtw_hal_get_hwreg(struct adapter *adapt, u8 variable, u8 *val) ++{ ++ if (adapt->HalFunc.GetHwRegHandler) ++ adapt->HalFunc.GetHwRegHandler(adapt, variable, val); ++} ++ ++u8 rtw_hal_set_def_var(struct adapter *adapt, enum hal_def_variable var, ++ void *val) ++{ ++ if (adapt->HalFunc.SetHalDefVarHandler) ++ return adapt->HalFunc.SetHalDefVarHandler(adapt, var, val); ++ return _FAIL; ++} ++ ++u8 rtw_hal_get_def_var(struct adapter *adapt, ++ enum hal_def_variable var, void *val) ++{ ++ if (adapt->HalFunc.GetHalDefVarHandler) ++ return adapt->HalFunc.GetHalDefVarHandler(adapt, var, val); ++ return _FAIL; ++} ++ ++void rtw_hal_set_odm_var(struct adapter *adapt, ++ enum hal_odm_variable var, void *val1, ++ bool set) ++{ ++ if (adapt->HalFunc.SetHalODMVarHandler) ++ adapt->HalFunc.SetHalODMVarHandler(adapt, var, ++ val1, set); ++} ++ ++void rtw_hal_get_odm_var(struct adapter *adapt, ++ enum hal_odm_variable var, void *val1, ++ bool set) ++{ ++ if (adapt->HalFunc.GetHalODMVarHandler) ++ adapt->HalFunc.GetHalODMVarHandler(adapt, var, ++ val1, set); ++} ++ ++void rtw_hal_enable_interrupt(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.enable_interrupt) ++ adapt->HalFunc.enable_interrupt(adapt); ++ else ++ DBG_88E("%s: HalFunc.enable_interrupt is NULL!\n", __func__); ++} ++ ++void rtw_hal_disable_interrupt(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.disable_interrupt) ++ adapt->HalFunc.disable_interrupt(adapt); ++ else ++ DBG_88E("%s: HalFunc.disable_interrupt is NULL!\n", __func__); ++} ++ ++u32 rtw_hal_inirp_init(struct adapter *adapt) ++{ ++ u32 rst = _FAIL; ++ ++ if (adapt->HalFunc.inirp_init) ++ rst = adapt->HalFunc.inirp_init(adapt); ++ else ++ DBG_88E(" %s HalFunc.inirp_init is NULL!!!\n", __func__); ++ return rst; ++} ++ ++u32 rtw_hal_inirp_deinit(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.inirp_deinit) ++ return adapt->HalFunc.inirp_deinit(adapt); ++ ++ return _FAIL; ++} ++ ++u8 rtw_hal_intf_ps_func(struct adapter *adapt, ++ enum hal_intf_ps_func efunc_id, u8 *val) ++{ ++ if (adapt->HalFunc.interface_ps_func) ++ return adapt->HalFunc.interface_ps_func(adapt, efunc_id, ++ val); ++ return _FAIL; ++} ++ ++s32 rtw_hal_xmitframe_enqueue(struct adapter *padapter, ++ struct xmit_frame *pxmitframe) ++{ ++ if (padapter->HalFunc.hal_xmitframe_enqueue) ++ return padapter->HalFunc.hal_xmitframe_enqueue(padapter, pxmitframe); ++ return false; ++} ++ ++s32 rtw_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe) ++{ ++ if (adapt->HalFunc.hal_xmit) ++ return adapt->HalFunc.hal_xmit(adapt, pxmitframe); ++ ++ return false; ++} ++ ++s32 rtw_hal_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe) ++{ ++ s32 ret = _FAIL; ++ if (adapt->HalFunc.mgnt_xmit) ++ ret = adapt->HalFunc.mgnt_xmit(adapt, pmgntframe); ++ return ret; ++} ++ ++s32 rtw_hal_init_xmit_priv(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.init_xmit_priv) ++ return adapt->HalFunc.init_xmit_priv(adapt); ++ return _FAIL; ++} ++ ++s32 rtw_hal_init_recv_priv(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.init_recv_priv) ++ return adapt->HalFunc.init_recv_priv(adapt); ++ ++ return _FAIL; ++} ++ ++void rtw_hal_free_recv_priv(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.free_recv_priv) ++ adapt->HalFunc.free_recv_priv(adapt); ++} ++ ++void rtw_hal_update_ra_mask(struct adapter *adapt, u32 mac_id, u8 rssi_level) ++{ ++ struct mlme_priv *pmlmepriv = &adapt->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++#ifdef CONFIG_88EU_AP_MODE ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &adapt->stapriv; ++ if ((mac_id - 1) > 0) ++ psta = pstapriv->sta_aid[(mac_id - 1) - 1]; ++ if (psta) ++ add_RATid(adapt, psta, 0);/* todo: based on rssi_level*/ ++#endif ++ } else { ++ if (adapt->HalFunc.UpdateRAMaskHandler) ++ adapt->HalFunc.UpdateRAMaskHandler(adapt, mac_id, ++ rssi_level); ++ } ++} ++ ++void rtw_hal_add_ra_tid(struct adapter *adapt, u32 bitmap, u8 arg, ++ u8 rssi_level) ++{ ++ if (adapt->HalFunc.Add_RateATid) ++ adapt->HalFunc.Add_RateATid(adapt, bitmap, arg, ++ rssi_level); ++} ++ ++/* Start specifical interface thread */ ++void rtw_hal_start_thread(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.run_thread) ++ adapt->HalFunc.run_thread(adapt); ++} ++ ++/* Start specifical interface thread */ ++void rtw_hal_stop_thread(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.cancel_thread) ++ adapt->HalFunc.cancel_thread(adapt); ++} ++ ++u32 rtw_hal_read_bbreg(struct adapter *adapt, u32 regaddr, u32 bitmask) ++{ ++ u32 data = 0; ++ ++ if (adapt->HalFunc.read_bbreg) ++ data = adapt->HalFunc.read_bbreg(adapt, regaddr, bitmask); ++ return data; ++} ++ ++void rtw_hal_write_bbreg(struct adapter *adapt, u32 regaddr, u32 bitmask, ++ u32 data) ++{ ++ if (adapt->HalFunc.write_bbreg) ++ adapt->HalFunc.write_bbreg(adapt, regaddr, bitmask, data); ++} ++ ++u32 rtw_hal_read_rfreg(struct adapter *adapt, enum rf_radio_path rfpath, ++ u32 regaddr, u32 bitmask) ++{ ++ u32 data = 0; ++ ++ if (adapt->HalFunc.read_rfreg) ++ data = adapt->HalFunc.read_rfreg(adapt, rfpath, regaddr, ++ bitmask); ++ return data; ++} ++ ++void rtw_hal_write_rfreg(struct adapter *adapt, enum rf_radio_path rfpath, ++ u32 regaddr, u32 bitmask, u32 data) ++{ ++ if (adapt->HalFunc.write_rfreg) ++ adapt->HalFunc.write_rfreg(adapt, rfpath, regaddr, ++ bitmask, data); ++} ++ ++s32 rtw_hal_interrupt_handler(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.interrupt_handler) ++ return adapt->HalFunc.interrupt_handler(adapt); ++ return _FAIL; ++} ++ ++void rtw_hal_set_bwmode(struct adapter *adapt, ++ enum ht_channel_width bandwidth, u8 offset) ++{ ++ if (adapt->HalFunc.set_bwmode_handler) ++ adapt->HalFunc.set_bwmode_handler(adapt, bandwidth, ++ offset); ++} ++ ++void rtw_hal_set_chan(struct adapter *adapt, u8 channel) ++{ ++ if (adapt->HalFunc.set_channel_handler) ++ adapt->HalFunc.set_channel_handler(adapt, channel); ++} ++ ++void rtw_hal_dm_watchdog(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.hal_dm_watchdog) ++ adapt->HalFunc.hal_dm_watchdog(adapt); ++} ++ ++void rtw_hal_bcn_related_reg_setting(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.SetBeaconRelatedRegistersHandler) ++ adapt->HalFunc.SetBeaconRelatedRegistersHandler(adapt); ++} ++ ++u8 rtw_hal_antdiv_before_linked(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.AntDivBeforeLinkHandler) ++ return adapt->HalFunc.AntDivBeforeLinkHandler(adapt); ++ return false; ++} ++ ++void rtw_hal_antdiv_rssi_compared(struct adapter *adapt, ++ struct wlan_bssid_ex *dst, ++ struct wlan_bssid_ex *src) ++{ ++ if (adapt->HalFunc.AntDivCompareHandler) ++ adapt->HalFunc.AntDivCompareHandler(adapt, dst, src); ++} ++ ++void rtw_hal_sreset_init(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.sreset_init_value) ++ adapt->HalFunc.sreset_init_value(adapt); ++} ++ ++void rtw_hal_sreset_reset(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.silentreset) ++ adapt->HalFunc.silentreset(adapt); ++} ++ ++void rtw_hal_sreset_reset_value(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.sreset_reset_value) ++ adapt->HalFunc.sreset_reset_value(adapt); ++} ++ ++void rtw_hal_sreset_xmit_status_check(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.sreset_xmit_status_check) ++ adapt->HalFunc.sreset_xmit_status_check(adapt); ++} ++ ++void rtw_hal_sreset_linked_status_check(struct adapter *adapt) ++{ ++ if (adapt->HalFunc.sreset_linked_status_check) ++ adapt->HalFunc.sreset_linked_status_check(adapt); ++} ++ ++u8 rtw_hal_sreset_get_wifi_status(struct adapter *adapt) ++{ ++ u8 status = 0; ++ ++ if (adapt->HalFunc.sreset_get_wifi_status) ++ status = adapt->HalFunc.sreset_get_wifi_status(adapt); ++ return status; ++} ++ ++int rtw_hal_iol_cmd(struct adapter *adapter, struct xmit_frame *xmit_frame, ++ u32 max_wating_ms, u32 bndy_cnt) ++{ ++ if (adapter->HalFunc.IOL_exec_cmds_sync) ++ return adapter->HalFunc.IOL_exec_cmds_sync(adapter, xmit_frame, ++ max_wating_ms, ++ bndy_cnt); ++ return _FAIL; ++} ++ ++void rtw_hal_notch_filter(struct adapter *adapter, bool enable) ++{ ++ if (adapter->HalFunc.hal_notch_filter) ++ adapter->HalFunc.hal_notch_filter(adapter, enable); ++} ++ ++void rtw_hal_reset_security_engine(struct adapter *adapter) ++{ ++ if (adapter->HalFunc.hal_reset_security_engine) ++ adapter->HalFunc.hal_reset_security_engine(adapter); ++} ++ ++s32 rtw_hal_c2h_handler(struct adapter *adapter, struct c2h_evt_hdr *c2h_evt) ++{ ++ s32 ret = _FAIL; ++ ++ if (adapter->HalFunc.c2h_handler) ++ ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt); ++ return ret; ++} ++ ++c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter) ++{ ++ return adapter->HalFunc.c2h_id_filter_ccx; ++} +diff --git a/drivers/staging/r8188eu/hal/odm.c b/drivers/staging/r8188eu/hal/odm.c +new file mode 100644 +index 000000000000..ed94f64d878d +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/odm.c +@@ -0,0 +1,1968 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++/* include files */ ++ ++#include "../include/odm_precomp.h" ++ ++static const u16 dB_Invert_Table[8][12] = { ++ {1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4}, ++ {4, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16}, ++ {18, 20, 22, 25, 28, 32, 35, 40, 45, 50, 56, 63}, ++ {71, 79, 89, 100, 112, 126, 141, 158, 178, 200, 224, 251}, ++ {282, 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 1000}, ++ {1122, 1259, 1413, 1585, 1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981}, ++ {4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000, 11220, 12589, 14125, 15849}, ++ {17783, 19953, 22387, 25119, 28184, 31623, 35481, 39811, 44668, 50119, 56234, 65535} ++}; ++ ++/* avoid to warn in FreeBSD ==> To DO modify */ ++static u32 EDCAParam[HT_IOT_PEER_MAX][3] = { ++ /* UL DL */ ++ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 0:unknown AP */ ++ {0xa44f, 0x5ea44f, 0x5e431c}, /* 1:realtek AP */ ++ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 2:unknown AP => realtek_92SE */ ++ {0x5ea32b, 0x5ea42b, 0x5e4322}, /* 3:broadcom AP */ ++ {0x5ea422, 0x00a44f, 0x00a44f}, /* 4:ralink AP */ ++ {0x5ea322, 0x00a630, 0x00a44f}, /* 5:atheros AP */ ++ {0x5e4322, 0x5e4322, 0x5e4322},/* 6:cisco AP */ ++ {0x5ea44f, 0x00a44f, 0x5ea42b}, /* 8:marvell AP */ ++ {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 10:unknown AP=> 92U AP */ ++ {0x5ea42b, 0xa630, 0x5e431c}, /* 11:airgocap AP */ ++}; ++ ++/* Global var */ ++u32 OFDMSwingTable[OFDM_TABLE_SIZE_92D] = { ++ 0x7f8001fe, /* 0, +6.0dB */ ++ 0x788001e2, /* 1, +5.5dB */ ++ 0x71c001c7, /* 2, +5.0dB */ ++ 0x6b8001ae, /* 3, +4.5dB */ ++ 0x65400195, /* 4, +4.0dB */ ++ 0x5fc0017f, /* 5, +3.5dB */ ++ 0x5a400169, /* 6, +3.0dB */ ++ 0x55400155, /* 7, +2.5dB */ ++ 0x50800142, /* 8, +2.0dB */ ++ 0x4c000130, /* 9, +1.5dB */ ++ 0x47c0011f, /* 10, +1.0dB */ ++ 0x43c0010f, /* 11, +0.5dB */ ++ 0x40000100, /* 12, +0dB */ ++ 0x3c8000f2, /* 13, -0.5dB */ ++ 0x390000e4, /* 14, -1.0dB */ ++ 0x35c000d7, /* 15, -1.5dB */ ++ 0x32c000cb, /* 16, -2.0dB */ ++ 0x300000c0, /* 17, -2.5dB */ ++ 0x2d4000b5, /* 18, -3.0dB */ ++ 0x2ac000ab, /* 19, -3.5dB */ ++ 0x288000a2, /* 20, -4.0dB */ ++ 0x26000098, /* 21, -4.5dB */ ++ 0x24000090, /* 22, -5.0dB */ ++ 0x22000088, /* 23, -5.5dB */ ++ 0x20000080, /* 24, -6.0dB */ ++ 0x1e400079, /* 25, -6.5dB */ ++ 0x1c800072, /* 26, -7.0dB */ ++ 0x1b00006c, /* 27. -7.5dB */ ++ 0x19800066, /* 28, -8.0dB */ ++ 0x18000060, /* 29, -8.5dB */ ++ 0x16c0005b, /* 30, -9.0dB */ ++ 0x15800056, /* 31, -9.5dB */ ++ 0x14400051, /* 32, -10.0dB */ ++ 0x1300004c, /* 33, -10.5dB */ ++ 0x12000048, /* 34, -11.0dB */ ++ 0x11000044, /* 35, -11.5dB */ ++ 0x10000040, /* 36, -12.0dB */ ++ 0x0f00003c,/* 37, -12.5dB */ ++ 0x0e400039,/* 38, -13.0dB */ ++ 0x0d800036,/* 39, -13.5dB */ ++ 0x0cc00033,/* 40, -14.0dB */ ++ 0x0c000030,/* 41, -14.5dB */ ++ 0x0b40002d,/* 42, -15.0dB */ ++}; ++ ++u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8] = { ++ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */ ++ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */ ++ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */ ++ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */ ++ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */ ++ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */ ++ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */ ++ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */ ++ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */ ++ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */ ++ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */ ++ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */ ++ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */ ++ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */ ++ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */ ++ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */ ++ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */ ++ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */ ++ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */ ++ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */ ++ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB */ ++ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB */ ++ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB */ ++ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB */ ++ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB */ ++ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB */ ++ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB */ ++ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB */ ++ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB */ ++ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB */ ++ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB */ ++ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB */ ++ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB */ ++}; ++ ++u8 CCKSwingTable_Ch14[CCK_TABLE_SIZE][8] = { ++ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */ ++ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */ ++ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */ ++ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */ ++ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */ ++ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */ ++ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */ ++ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */ ++ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */ ++ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */ ++ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */ ++ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */ ++ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */ ++ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */ ++ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */ ++ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */ ++ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */ ++ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */ ++ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */ ++ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */ ++ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB */ ++ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB */ ++ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB */ ++ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB */ ++ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB */ ++ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB */ ++ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB */ ++ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB */ ++ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB */ ++ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB */ ++ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB */ ++ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB */ ++ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */ ++}; ++ ++#define RxDefaultAnt1 0x65a9 ++#define RxDefaultAnt2 0x569a ++ ++/* 3 Export Interface */ ++ ++/* 2011/09/21 MH Add to describe different team necessary resource allocate?? */ ++void ODM_DMInit(struct odm_dm_struct *pDM_Odm) ++{ ++ /* 2012.05.03 Luke: For all IC series */ ++ odm_CommonInfoSelfInit(pDM_Odm); ++ odm_DIGInit(pDM_Odm); ++ odm_RateAdaptiveMaskInit(pDM_Odm); ++ ++ if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { ++ ; ++ } else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { ++ odm_PrimaryCCA_Init(pDM_Odm); /* Gary */ ++ odm_DynamicBBPowerSavingInit(pDM_Odm); ++ odm_DynamicTxPowerInit(pDM_Odm); ++ odm_TXPowerTrackingInit(pDM_Odm); ++ ODM_EdcaTurboInit(pDM_Odm); ++ ODM_RAInfo_Init_all(pDM_Odm); ++ if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) || ++ (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) || ++ (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV)) ++ odm_InitHybridAntDiv(pDM_Odm); ++ else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV) ++ odm_SwAntDivInit(pDM_Odm); ++ } ++} ++ ++/* 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */ ++/* You can not add any dummy function here, be care, you can only use DM structure */ ++/* to perform any new ODM_DM. */ ++void ODM_DMWatchdog(struct odm_dm_struct *pDM_Odm) ++{ ++ /* 2012.05.03 Luke: For all IC series */ ++ odm_GlobalAdapterCheck(); ++ odm_CommonInfoSelfUpdate(pDM_Odm); ++ odm_FalseAlarmCounterStatistics(pDM_Odm); ++ odm_RSSIMonitorCheck(pDM_Odm); ++ ++ /* For CE Platform(SPRD or Tablet) */ ++ /* 8723A or 8189ES platform */ ++ /* NeilChen--2012--08--24-- */ ++ /* Fix Leave LPS issue */ ++ if ((pDM_Odm->Adapter->pwrctrlpriv.pwr_mode != PS_MODE_ACTIVE) &&/* in LPS mode */ ++ ((pDM_Odm->SupportICType & (ODM_RTL8723A)) || ++ (pDM_Odm->SupportICType & (ODM_RTL8188E) && ++ ((pDM_Odm->SupportInterface == ODM_ITRF_SDIO))))) ++ odm_DIGbyRSSI_LPS(pDM_Odm); ++ else ++ odm_DIG(pDM_Odm); ++ odm_CCKPacketDetectionThresh(pDM_Odm); ++ ++ if (*pDM_Odm->pbPowerSaving) ++ return; ++ ++ odm_RefreshRateAdaptiveMask(pDM_Odm); ++ ++ odm_DynamicBBPowerSaving(pDM_Odm); ++ if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) || ++ (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) || ++ (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV)) ++ odm_HwAntDiv(pDM_Odm); ++ else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV) ++ odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK); ++ ++ if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { ++ ; ++ } else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { ++ ODM_TXPowerTrackingCheck(pDM_Odm); ++ odm_EdcaTurboCheck(pDM_Odm); ++ odm_DynamicTxPower(pDM_Odm); ++ } ++ odm_dtc(pDM_Odm); ++} ++ ++/* Init /.. Fixed HW value. Only init time. */ ++void ODM_CmnInfoInit(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, u32 Value) ++{ ++ /* This section is used for init value */ ++ switch (CmnInfo) { ++ /* Fixed ODM value. */ ++ case ODM_CMNINFO_ABILITY: ++ pDM_Odm->SupportAbility = (u32)Value; ++ break; ++ case ODM_CMNINFO_PLATFORM: ++ pDM_Odm->SupportPlatform = (u8)Value; ++ break; ++ case ODM_CMNINFO_INTERFACE: ++ pDM_Odm->SupportInterface = (u8)Value; ++ break; ++ case ODM_CMNINFO_MP_TEST_CHIP: ++ pDM_Odm->bIsMPChip = (u8)Value; ++ break; ++ case ODM_CMNINFO_IC_TYPE: ++ pDM_Odm->SupportICType = Value; ++ break; ++ case ODM_CMNINFO_CUT_VER: ++ pDM_Odm->CutVersion = (u8)Value; ++ break; ++ case ODM_CMNINFO_FAB_VER: ++ pDM_Odm->FabVersion = (u8)Value; ++ break; ++ case ODM_CMNINFO_RF_TYPE: ++ pDM_Odm->RFType = (u8)Value; ++ break; ++ case ODM_CMNINFO_RF_ANTENNA_TYPE: ++ pDM_Odm->AntDivType = (u8)Value; ++ break; ++ case ODM_CMNINFO_BOARD_TYPE: ++ pDM_Odm->BoardType = (u8)Value; ++ break; ++ case ODM_CMNINFO_EXT_LNA: ++ pDM_Odm->ExtLNA = (u8)Value; ++ break; ++ case ODM_CMNINFO_EXT_PA: ++ pDM_Odm->ExtPA = (u8)Value; ++ break; ++ case ODM_CMNINFO_EXT_TRSW: ++ pDM_Odm->ExtTRSW = (u8)Value; ++ break; ++ case ODM_CMNINFO_PATCH_ID: ++ pDM_Odm->PatchID = (u8)Value; ++ break; ++ case ODM_CMNINFO_BINHCT_TEST: ++ pDM_Odm->bInHctTest = (bool)Value; ++ break; ++ case ODM_CMNINFO_BWIFI_TEST: ++ pDM_Odm->bWIFITest = (bool)Value; ++ break; ++ case ODM_CMNINFO_SMART_CONCURRENT: ++ pDM_Odm->bDualMacSmartConcurrent = (bool)Value; ++ break; ++ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ ++ default: ++ /* do nothing */ ++ break; ++ } ++ ++ /* Tx power tracking BB swing table. */ ++ /* The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */ ++ pDM_Odm->BbSwingIdxOfdm = 12; /* Set defalut value as index 12. */ ++ pDM_Odm->BbSwingIdxOfdmCurrent = 12; ++ pDM_Odm->BbSwingFlagOfdm = false; ++} ++ ++void ODM_CmnInfoHook(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, void *pValue) ++{ ++ /* */ ++ /* Hook call by reference pointer. */ ++ /* */ ++ switch (CmnInfo) { ++ /* Dynamic call by reference pointer. */ ++ case ODM_CMNINFO_MAC_PHY_MODE: ++ pDM_Odm->pMacPhyMode = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_TX_UNI: ++ pDM_Odm->pNumTxBytesUnicast = (u64 *)pValue; ++ break; ++ case ODM_CMNINFO_RX_UNI: ++ pDM_Odm->pNumRxBytesUnicast = (u64 *)pValue; ++ break; ++ case ODM_CMNINFO_WM_MODE: ++ pDM_Odm->pWirelessMode = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_BAND: ++ pDM_Odm->pBandType = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_SEC_CHNL_OFFSET: ++ pDM_Odm->pSecChOffset = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_SEC_MODE: ++ pDM_Odm->pSecurity = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_BW: ++ pDM_Odm->pBandWidth = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_CHNL: ++ pDM_Odm->pChannel = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_DMSP_GET_VALUE: ++ pDM_Odm->pbGetValueFromOtherMac = (bool *)pValue; ++ break; ++ case ODM_CMNINFO_BUDDY_ADAPTOR: ++ pDM_Odm->pBuddyAdapter = (struct adapter **)pValue; ++ break; ++ case ODM_CMNINFO_DMSP_IS_MASTER: ++ pDM_Odm->pbMasterOfDMSP = (bool *)pValue; ++ break; ++ case ODM_CMNINFO_SCAN: ++ pDM_Odm->pbScanInProcess = (bool *)pValue; ++ break; ++ case ODM_CMNINFO_POWER_SAVING: ++ pDM_Odm->pbPowerSaving = (bool *)pValue; ++ break; ++ case ODM_CMNINFO_ONE_PATH_CCA: ++ pDM_Odm->pOnePathCCA = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_DRV_STOP: ++ pDM_Odm->pbDriverStopped = (bool *)pValue; ++ break; ++ case ODM_CMNINFO_PNP_IN: ++ pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = (bool *)pValue; ++ break; ++ case ODM_CMNINFO_INIT_ON: ++ pDM_Odm->pinit_adpt_in_progress = (bool *)pValue; ++ break; ++ case ODM_CMNINFO_ANT_TEST: ++ pDM_Odm->pAntennaTest = (u8 *)pValue; ++ break; ++ case ODM_CMNINFO_NET_CLOSED: ++ pDM_Odm->pbNet_closed = (bool *)pValue; ++ break; ++ case ODM_CMNINFO_MP_MODE: ++ pDM_Odm->mp_mode = (u8 *)pValue; ++ break; ++ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ ++ default: ++ /* do nothing */ ++ break; ++ } ++} ++ ++void ODM_CmnInfoPtrArrayHook(struct odm_dm_struct *pDM_Odm, enum odm_common_info_def CmnInfo, u16 Index, void *pValue) ++{ ++ /* Hook call by reference pointer. */ ++ switch (CmnInfo) { ++ /* Dynamic call by reference pointer. */ ++ case ODM_CMNINFO_STA_STATUS: ++ pDM_Odm->pODM_StaInfo[Index] = (struct sta_info *)pValue; ++ break; ++ /* To remove the compiler warning, must add an empty default statement to handle the other values. */ ++ default: ++ /* do nothing */ ++ break; ++ } ++} ++ ++/* Update Band/CHannel/.. The values are dynamic but non-per-packet. */ ++void ODM_CmnInfoUpdate(struct odm_dm_struct *pDM_Odm, u32 CmnInfo, u64 Value) ++{ ++ /* */ ++ /* This init variable may be changed in run time. */ ++ /* */ ++ switch (CmnInfo) { ++ case ODM_CMNINFO_ABILITY: ++ pDM_Odm->SupportAbility = (u32)Value; ++ break; ++ case ODM_CMNINFO_RF_TYPE: ++ pDM_Odm->RFType = (u8)Value; ++ break; ++ case ODM_CMNINFO_WIFI_DIRECT: ++ pDM_Odm->bWIFI_Direct = (bool)Value; ++ break; ++ case ODM_CMNINFO_WIFI_DISPLAY: ++ pDM_Odm->bWIFI_Display = (bool)Value; ++ break; ++ case ODM_CMNINFO_LINK: ++ pDM_Odm->bLinked = (bool)Value; ++ break; ++ case ODM_CMNINFO_RSSI_MIN: ++ pDM_Odm->RSSI_Min = (u8)Value; ++ break; ++ case ODM_CMNINFO_RA_THRESHOLD_HIGH: ++ pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value; ++ break; ++ case ODM_CMNINFO_RA_THRESHOLD_LOW: ++ pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value; ++ break; ++ } ++} ++ ++void odm_CommonInfoSelfInit(struct odm_dm_struct *pDM_Odm) ++{ ++ pDM_Odm->bCckHighPower = (bool)ODM_GetBBReg(pDM_Odm, 0x824, BIT(9)); ++ pDM_Odm->RFPathRxEnable = (u8)ODM_GetBBReg(pDM_Odm, 0xc04, 0x0F); ++ if (pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D)) ++ pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; ++ if (pDM_Odm->SupportICType & (ODM_RTL8723A)) ++ pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; ++} ++ ++void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm) ++{ ++ u8 EntryCnt = 0; ++ u8 i; ++ struct sta_info *pEntry; ++ ++ if (*pDM_Odm->pBandWidth == ODM_BW40M) { ++ if (*pDM_Odm->pSecChOffset == 1) ++ pDM_Odm->ControlChannel = *pDM_Odm->pChannel - 2; ++ else if (*pDM_Odm->pSecChOffset == 2) ++ pDM_Odm->ControlChannel = *pDM_Odm->pChannel + 2; ++ } else { ++ pDM_Odm->ControlChannel = *pDM_Odm->pChannel; ++ } ++ ++ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { ++ pEntry = pDM_Odm->pODM_StaInfo[i]; ++ if (IS_STA_VALID(pEntry)) ++ EntryCnt++; ++ } ++ if (EntryCnt == 1) ++ pDM_Odm->bOneEntryOnly = true; ++ else ++ pDM_Odm->bOneEntryOnly = false; ++} ++ ++static int getIGIForDiff(int value_IGI) ++{ ++ #define ONERCCA_LOW_TH 0x30 ++ #define ONERCCA_LOW_DIFF 8 ++ ++ if (value_IGI < ONERCCA_LOW_TH) { ++ if ((ONERCCA_LOW_TH - value_IGI) < ONERCCA_LOW_DIFF) ++ return ONERCCA_LOW_TH; ++ else ++ return value_IGI + ONERCCA_LOW_DIFF; ++ } else { ++ return value_IGI; ++ } ++} ++ ++void ODM_Write_DIG(struct odm_dm_struct *pDM_Odm, u8 CurrentIGI) ++{ ++ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ if (pDM_DigTable->CurIGValue != CurrentIGI) { ++ if (pDM_Odm->SupportPlatform & (ODM_CE | ODM_MP)) { ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); ++ if (pDM_Odm->SupportICType != ODM_RTL8188E) ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); ++ } else if (pDM_Odm->SupportPlatform & (ODM_AP | ODM_ADSL)) { ++ switch (*pDM_Odm->pOnePathCCA) { ++ case ODM_CCA_2R: ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); ++ if (pDM_Odm->SupportICType != ODM_RTL8188E) ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); ++ break; ++ case ODM_CCA_1R_A: ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); ++ if (pDM_Odm->SupportICType != ODM_RTL8188E) ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), getIGIForDiff(CurrentIGI)); ++ break; ++ case ODM_CCA_1R_B: ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), getIGIForDiff(CurrentIGI)); ++ if (pDM_Odm->SupportICType != ODM_RTL8188E) ++ ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI); ++ break; ++ } ++ } ++ /* pDM_DigTable->PreIGValue = pDM_DigTable->CurIGValue; */ ++ pDM_DigTable->CurIGValue = CurrentIGI; ++ } ++/* Add by Neil Chen to enable edcca to MP Platform */ ++} ++ ++/* Need LPS mode for CE platform --2012--08--24--- */ ++/* 8723AS/8189ES */ ++void odm_DIGbyRSSI_LPS(struct odm_dm_struct *pDM_Odm) ++{ ++ struct adapter *pAdapter = pDM_Odm->Adapter; ++ struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ ++ u8 RSSI_Lower = DM_DIG_MIN_NIC; /* 0x1E or 0x1C */ ++ u8 bFwCurrentInPSMode = false; ++ u8 CurrentIGI = pDM_Odm->RSSI_Min; ++ ++ if (!(pDM_Odm->SupportICType & (ODM_RTL8723A | ODM_RTL8188E))) ++ return; ++ ++ CurrentIGI = CurrentIGI + RSSI_OFFSET_DIG; ++ bFwCurrentInPSMode = pAdapter->pwrctrlpriv.bFwCurrentInPSMode; ++ ++ /* Using FW PS mode to make IGI */ ++ if (bFwCurrentInPSMode) { ++ /* Adjust by FA in LPS MODE */ ++ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_LPS) ++ CurrentIGI = CurrentIGI + 2; ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS) ++ CurrentIGI = CurrentIGI + 1; ++ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS) ++ CurrentIGI = CurrentIGI - 1; ++ } else { ++ CurrentIGI = RSSI_Lower; ++ } ++ ++ /* Lower bound checking */ ++ ++ /* RSSI Lower bound check */ ++ if ((pDM_Odm->RSSI_Min - 10) > DM_DIG_MIN_NIC) ++ RSSI_Lower = (pDM_Odm->RSSI_Min - 10); ++ else ++ RSSI_Lower = DM_DIG_MIN_NIC; ++ ++ /* Upper and Lower Bound checking */ ++ if (CurrentIGI > DM_DIG_MAX_NIC) ++ CurrentIGI = DM_DIG_MAX_NIC; ++ else if (CurrentIGI < RSSI_Lower) ++ CurrentIGI = RSSI_Lower; ++ ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */ ++} ++ ++void odm_DIGInit(struct odm_dm_struct *pDM_Odm) ++{ ++ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ pDM_DigTable->CurIGValue = (u8)ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm)); ++ pDM_DigTable->RssiLowThresh = DM_DIG_THRESH_LOW; ++ pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH; ++ pDM_DigTable->FALowThresh = DM_false_ALARM_THRESH_LOW; ++ pDM_DigTable->FAHighThresh = DM_false_ALARM_THRESH_HIGH; ++ if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) { ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; ++ } else { ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; ++ } ++ pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT; ++ pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX; ++ pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN; ++ pDM_DigTable->PreCCK_CCAThres = 0xFF; ++ pDM_DigTable->CurCCK_CCAThres = 0x83; ++ pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC; ++ pDM_DigTable->LargeFAHit = 0; ++ pDM_DigTable->Recover_cnt = 0; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC; ++ pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC; ++ pDM_DigTable->bMediaConnect_0 = false; ++ pDM_DigTable->bMediaConnect_1 = false; ++ ++ /* To Initialize pDM_Odm->bDMInitialGainEnable == false to avoid DIG error */ ++ pDM_Odm->bDMInitialGainEnable = true; ++} ++ ++void odm_DIG(struct odm_dm_struct *pDM_Odm) ++{ ++ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable; ++ struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ u8 DIG_Dynamic_MIN; ++ u8 DIG_MaxOfMin; ++ bool FirstConnect, FirstDisConnect; ++ u8 dm_dig_max, dm_dig_min; ++ u8 CurrentIGI = pDM_DigTable->CurIGValue; ++ ++ if ((!(pDM_Odm->SupportAbility & ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))) ++ return; ++ ++ if (*pDM_Odm->pbScanInProcess) ++ return; ++ ++ /* add by Neil Chen to avoid PSD is processing */ ++ if (!pDM_Odm->bDMInitialGainEnable) ++ return; ++ ++ if (pDM_Odm->SupportICType == ODM_RTL8192D) { ++ if (*pDM_Odm->pMacPhyMode == ODM_DMSP) { ++ if (*pDM_Odm->pbMasterOfDMSP) { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0); ++ } else { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; ++ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_1); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1); ++ } ++ } else { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; ++ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_1); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1); ++ } ++ } else { ++ DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; ++ FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0); ++ FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0); ++ } ++ ++ /* 1 Boundary Decision */ ++ if ((pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8723A)) && ++ ((pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) || pDM_Odm->ExtLNA)) { ++ if (pDM_Odm->SupportPlatform & (ODM_AP | ODM_ADSL)) { ++ dm_dig_max = DM_DIG_MAX_AP_HP; ++ dm_dig_min = DM_DIG_MIN_AP_HP; ++ } else { ++ dm_dig_max = DM_DIG_MAX_NIC_HP; ++ dm_dig_min = DM_DIG_MIN_NIC_HP; ++ } ++ DIG_MaxOfMin = DM_DIG_MAX_AP_HP; ++ } else { ++ if (pDM_Odm->SupportPlatform & (ODM_AP | ODM_ADSL)) { ++ dm_dig_max = DM_DIG_MAX_AP; ++ dm_dig_min = DM_DIG_MIN_AP; ++ DIG_MaxOfMin = dm_dig_max; ++ } else { ++ dm_dig_max = DM_DIG_MAX_NIC; ++ dm_dig_min = DM_DIG_MIN_NIC; ++ DIG_MaxOfMin = DM_DIG_MAX_AP; ++ } ++ } ++ if (pDM_Odm->bLinked) { ++ /* 2 8723A Series, offset need to be 10 */ ++ if (pDM_Odm->SupportICType == (ODM_RTL8723A)) { ++ /* 2 Upper Bound */ ++ if ((pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC) ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; ++ else if ((pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC) ++ pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10; ++ /* 2 If BT is Concurrent, need to set Lower Bound */ ++ DIG_Dynamic_MIN = DM_DIG_MIN_NIC; ++ } else { ++ /* 2 Modify DIG upper bound */ ++ if ((pDM_Odm->RSSI_Min + 20) > dm_dig_max) ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ else if ((pDM_Odm->RSSI_Min + 20) < dm_dig_min) ++ pDM_DigTable->rx_gain_range_max = dm_dig_min; ++ else ++ pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20; ++ /* 2 Modify DIG lower bound */ ++ if (pDM_Odm->bOneEntryOnly) { ++ if (pDM_Odm->RSSI_Min < dm_dig_min) ++ DIG_Dynamic_MIN = dm_dig_min; ++ else if (pDM_Odm->RSSI_Min > DIG_MaxOfMin) ++ DIG_Dynamic_MIN = DIG_MaxOfMin; ++ else ++ DIG_Dynamic_MIN = pDM_Odm->RSSI_Min; ++ } else if ((pDM_Odm->SupportICType == ODM_RTL8188E) && ++ (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) { ++ /* 1 Lower Bound for 88E AntDiv */ ++ if (pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) ++ DIG_Dynamic_MIN = (u8)pDM_DigTable->AntDiv_RSSI_max; ++ } else { ++ DIG_Dynamic_MIN = dm_dig_min; ++ } ++ } ++ } else { ++ pDM_DigTable->rx_gain_range_max = dm_dig_max; ++ DIG_Dynamic_MIN = dm_dig_min; ++ } ++ ++ /* 1 Modify DIG lower bound, deal with abnormally large false alarm */ ++ if (pFalseAlmCnt->Cnt_all > 10000) { ++ if (pDM_DigTable->LargeFAHit != 3) ++ pDM_DigTable->LargeFAHit++; ++ if (pDM_DigTable->ForbiddenIGI < CurrentIGI) { ++ pDM_DigTable->ForbiddenIGI = CurrentIGI; ++ pDM_DigTable->LargeFAHit = 1; ++ } ++ ++ if (pDM_DigTable->LargeFAHit >= 3) { ++ if ((pDM_DigTable->ForbiddenIGI + 1) > pDM_DigTable->rx_gain_range_max) ++ pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; ++ else ++ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); ++ pDM_DigTable->Recover_cnt = 3600; /* 3600=2hr */ ++ } ++ ++ } else { ++ /* Recovery mechanism for IGI lower bound */ ++ if (pDM_DigTable->Recover_cnt != 0) { ++ pDM_DigTable->Recover_cnt--; ++ } else { ++ if (pDM_DigTable->LargeFAHit < 3) { ++ if ((pDM_DigTable->ForbiddenIGI - 1) < DIG_Dynamic_MIN) { /* DM_DIG_MIN) */ ++ pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */ ++ pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */ ++ } else { ++ pDM_DigTable->ForbiddenIGI--; ++ pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); ++ } ++ } else { ++ pDM_DigTable->LargeFAHit = 0; ++ } ++ } ++ } ++ ++ /* 1 Adjust initial gain by false alarm */ ++ if (pDM_Odm->bLinked) { ++ if (FirstConnect) { ++ CurrentIGI = pDM_Odm->RSSI_Min; ++ } else { ++ if (pDM_Odm->SupportICType == ODM_RTL8192D) { ++ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_92D) ++ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */ ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_92D) ++ CurrentIGI = CurrentIGI + 1; /* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */ ++ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_92D) ++ CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */ ++ } else { ++ if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2) ++ CurrentIGI = CurrentIGI + 4;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */ ++ else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1) ++ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */ ++ else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) ++ CurrentIGI = CurrentIGI - 2;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */ ++ } ++ } ++ } else { ++ if (FirstDisConnect) { ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ } else { ++ /* 2012.03.30 LukeLee: enable DIG before link but with very high thresholds */ ++ if (pFalseAlmCnt->Cnt_all > 10000) ++ CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */ ++ else if (pFalseAlmCnt->Cnt_all > 8000) ++ CurrentIGI = CurrentIGI + 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */ ++ else if (pFalseAlmCnt->Cnt_all < 500) ++ CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; */ ++ } ++ } ++ /* 1 Check initial gain by upper/lower bound */ ++ if (CurrentIGI > pDM_DigTable->rx_gain_range_max) ++ CurrentIGI = pDM_DigTable->rx_gain_range_max; ++ if (CurrentIGI < pDM_DigTable->rx_gain_range_min) ++ CurrentIGI = pDM_DigTable->rx_gain_range_min; ++ ++ /* 2 High power RSSI threshold */ ++ ++ ODM_Write_DIG(pDM_Odm, CurrentIGI);/* ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); */ ++ pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; ++ pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; ++} ++ ++/* 3============================================================ */ ++/* 3 FASLE ALARM CHECK */ ++/* 3============================================================ */ ++ ++void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm) ++{ ++ u32 ret_value; ++ struct false_alarm_stats *FalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) ++ return; ++ ++ if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { ++ /* hold ofdm counter */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT(31), 1); /* hold page C counter */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT(31), 1); /* hold page D counter */ ++ ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Fast_Fsync = (ret_value & 0xffff); ++ FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value & 0xffff0000) >> 16); ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_OFDM_CCA = (ret_value & 0xffff); ++ FalseAlmCnt->Cnt_Parity_Fail = ((ret_value & 0xffff0000) >> 16); ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Rate_Illegal = (ret_value & 0xffff); ++ FalseAlmCnt->Cnt_Crc8_fail = ((ret_value & 0xffff0000) >> 16); ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_Mcs_fail = (ret_value & 0xffff); ++ ++ FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + FalseAlmCnt->Cnt_Rate_Illegal + ++ FalseAlmCnt->Cnt_Crc8_fail + FalseAlmCnt->Cnt_Mcs_fail + ++ FalseAlmCnt->Cnt_Fast_Fsync + FalseAlmCnt->Cnt_SB_Search_fail; ++ ++ if (pDM_Odm->SupportICType == ODM_RTL8188E) { ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_SC_CNT_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_BW_LSC = (ret_value & 0xffff); ++ FalseAlmCnt->Cnt_BW_USC = ((ret_value & 0xffff0000) >> 16); ++ } ++ ++ /* hold cck counter */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT(12), 1); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT(14), 1); ++ ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_LSB_11N, bMaskByte0); ++ FalseAlmCnt->Cnt_Cck_fail = ret_value; ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_MSB_11N, bMaskByte3); ++ FalseAlmCnt->Cnt_Cck_fail += (ret_value & 0xff) << 8; ++ ++ ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord); ++ FalseAlmCnt->Cnt_CCK_CCA = ((ret_value & 0xFF) << 8) | ((ret_value & 0xFF00) >> 8); ++ ++ FalseAlmCnt->Cnt_all = (FalseAlmCnt->Cnt_Fast_Fsync + ++ FalseAlmCnt->Cnt_SB_Search_fail + ++ FalseAlmCnt->Cnt_Parity_Fail + ++ FalseAlmCnt->Cnt_Rate_Illegal + ++ FalseAlmCnt->Cnt_Crc8_fail + ++ FalseAlmCnt->Cnt_Mcs_fail + ++ FalseAlmCnt->Cnt_Cck_fail); ++ ++ FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA; ++ ++ if (pDM_Odm->SupportICType >= ODM_RTL8723A) { ++ /* reset false alarm counter registers */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT(31), 1); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT(31), 0); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT(27), 1); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT(27), 0); ++ /* update ofdm counter */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT(31), 0); /* update page C counter */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT(31), 0); /* update page D counter */ ++ ++ /* reset CCK CCA counter */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 0); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT(13) | BIT(12), 2); ++ /* reset CCK FA counter */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 0); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT(15) | BIT(14), 2); ++ } ++ } else { /* FOR ODM_IC_11AC_SERIES */ ++ /* read OFDM FA counter */ ++ FalseAlmCnt->Cnt_Ofdm_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_11AC, bMaskLWord); ++ FalseAlmCnt->Cnt_Cck_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_11AC, bMaskLWord); ++ FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail + FalseAlmCnt->Cnt_Cck_fail; ++ ++ /* reset OFDM FA coutner */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 1); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 0); ++ /* reset CCK FA counter */ ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT(15), 0); ++ ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT(15), 1); ++ } ++} ++ ++/* 3============================================================ */ ++/* 3 CCK Packet Detect Threshold */ ++/* 3============================================================ */ ++ ++void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm) ++{ ++ u8 CurCCK_CCAThres; ++ struct false_alarm_stats *FalseAlmCnt = &pDM_Odm->FalseAlmCnt; ++ ++ if (!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD | ODM_BB_FA_CNT))) ++ return; ++ if (pDM_Odm->ExtLNA) ++ return; ++ if (pDM_Odm->bLinked) { ++ if (pDM_Odm->RSSI_Min > 25) { ++ CurCCK_CCAThres = 0xcd; ++ } else if ((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) { ++ CurCCK_CCAThres = 0x83; ++ } else { ++ if (FalseAlmCnt->Cnt_Cck_fail > 1000) ++ CurCCK_CCAThres = 0x83; ++ else ++ CurCCK_CCAThres = 0x40; ++ } ++ } else { ++ if (FalseAlmCnt->Cnt_Cck_fail > 1000) ++ CurCCK_CCAThres = 0x83; ++ else ++ CurCCK_CCAThres = 0x40; ++ } ++ ODM_Write_CCK_CCA_Thres(pDM_Odm, CurCCK_CCAThres); ++} ++ ++void ODM_Write_CCK_CCA_Thres(struct odm_dm_struct *pDM_Odm, u8 CurCCK_CCAThres) ++{ ++ struct rtw_dig *pDM_DigTable = &pDM_Odm->DM_DigTable; ++ ++ if (pDM_DigTable->CurCCK_CCAThres != CurCCK_CCAThres) /* modify by Guo.Mingzhi 2012-01-03 */ ++ ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres); ++ pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres; ++ pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres; ++} ++ ++/* 3============================================================ */ ++/* 3 BB Power Save */ ++/* 3============================================================ */ ++void odm_DynamicBBPowerSavingInit(struct odm_dm_struct *pDM_Odm) ++{ ++ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable; ++ ++ pDM_PSTable->pre_cca_state = CCA_MAX; ++ pDM_PSTable->cur_cca_state = CCA_MAX; ++ pDM_PSTable->pre_rf_state = RF_MAX; ++ pDM_PSTable->cur_rf_state = RF_MAX; ++ pDM_PSTable->rssi_val_min = 0; ++ pDM_PSTable->initialize = 0; ++} ++ ++void odm_DynamicBBPowerSaving(struct odm_dm_struct *pDM_Odm) ++{ ++ if ((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8723A)) ++ return; ++ if (!(pDM_Odm->SupportAbility & ODM_BB_PWR_SAVE)) ++ return; ++ if (!(pDM_Odm->SupportPlatform & (ODM_MP | ODM_CE))) ++ return; ++ ++ /* 1 2.Power Saving for 92C */ ++ if ((pDM_Odm->SupportICType == ODM_RTL8192C) && (pDM_Odm->RFType == ODM_2T2R)) { ++ odm_1R_CCA(pDM_Odm); ++ } else { ++ /* 20100628 Joseph: Turn off BB power save for 88CE because it makesthroughput unstable. */ ++ /* 20100831 Joseph: Turn ON BB power save again after modifying AGC delay from 900ns ot 600ns. */ ++ /* 1 3.Power Saving for 88C */ ++ ODM_RF_Saving(pDM_Odm, false); ++ } ++} ++ ++void odm_1R_CCA(struct odm_dm_struct *pDM_Odm) ++{ ++ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable; ++ ++ if (pDM_Odm->RSSI_Min != 0xFF) { ++ if (pDM_PSTable->pre_cca_state == CCA_2R) { ++ if (pDM_Odm->RSSI_Min >= 35) ++ pDM_PSTable->cur_cca_state = CCA_1R; ++ else ++ pDM_PSTable->cur_cca_state = CCA_2R; ++ } else { ++ if (pDM_Odm->RSSI_Min <= 30) ++ pDM_PSTable->cur_cca_state = CCA_2R; ++ else ++ pDM_PSTable->cur_cca_state = CCA_1R; ++ } ++ } else { ++ pDM_PSTable->cur_cca_state = CCA_MAX; ++ } ++ ++ if (pDM_PSTable->pre_cca_state != pDM_PSTable->cur_cca_state) { ++ if (pDM_PSTable->cur_cca_state == CCA_1R) { ++ if (pDM_Odm->RFType == ODM_2T2R) ++ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x13); ++ else ++ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x23); ++ } else { ++ ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x33); ++ } ++ pDM_PSTable->pre_cca_state = pDM_PSTable->cur_cca_state; ++ } ++} ++ ++void ODM_RF_Saving(struct odm_dm_struct *pDM_Odm, u8 bForceInNormal) ++{ ++ struct rtl_ps *pDM_PSTable = &pDM_Odm->DM_PSTable; ++ u8 Rssi_Up_bound = 30; ++ u8 Rssi_Low_bound = 25; ++ ++ if (pDM_Odm->PatchID == 40) { /* RT_CID_819x_FUNAI_TV */ ++ Rssi_Up_bound = 50; ++ Rssi_Low_bound = 45; ++ } ++ if (pDM_PSTable->initialize == 0) { ++ pDM_PSTable->reg_874 = (ODM_GetBBReg(pDM_Odm, 0x874, bMaskDWord) & 0x1CC000) >> 14; ++ pDM_PSTable->reg_c70 = (ODM_GetBBReg(pDM_Odm, 0xc70, bMaskDWord) & BIT(3)) >> 3; ++ pDM_PSTable->reg_85c = (ODM_GetBBReg(pDM_Odm, 0x85c, bMaskDWord) & 0xFF000000) >> 24; ++ pDM_PSTable->reg_a74 = (ODM_GetBBReg(pDM_Odm, 0xa74, bMaskDWord) & 0xF000) >> 12; ++ pDM_PSTable->initialize = 1; ++ } ++ ++ if (!bForceInNormal) { ++ if (pDM_Odm->RSSI_Min != 0xFF) { ++ if (pDM_PSTable->pre_rf_state == RF_Normal) { ++ if (pDM_Odm->RSSI_Min >= Rssi_Up_bound) ++ pDM_PSTable->cur_rf_state = RF_Save; ++ else ++ pDM_PSTable->cur_rf_state = RF_Normal; ++ } else { ++ if (pDM_Odm->RSSI_Min <= Rssi_Low_bound) ++ pDM_PSTable->cur_rf_state = RF_Normal; ++ else ++ pDM_PSTable->cur_rf_state = RF_Save; ++ } ++ } else { ++ pDM_PSTable->cur_rf_state = RF_MAX; ++ } ++ } else { ++ pDM_PSTable->cur_rf_state = RF_Normal; ++ } ++ ++ if (pDM_PSTable->pre_rf_state != pDM_PSTable->cur_rf_state) { ++ if (pDM_PSTable->cur_rf_state == RF_Save) { ++ /* 8723 RSSI report will be wrong. Set 0x874[5]=1 when enter BB power saving mode. */ ++ /* Suggested by SD3 Yu-Nan. 2011.01.20. */ ++ if (pDM_Odm->SupportICType == ODM_RTL8723A) ++ ODM_SetBBReg(pDM_Odm, 0x874, BIT(5), 0x1); /* Reg874[5]=1b'1 */ ++ ODM_SetBBReg(pDM_Odm, 0x874, 0x1C0000, 0x2); /* Reg874[20:18]=3'b010 */ ++ ODM_SetBBReg(pDM_Odm, 0xc70, BIT(3), 0); /* RegC70[3]=1'b0 */ ++ ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, 0x63); /* Reg85C[31:24]=0x63 */ ++ ODM_SetBBReg(pDM_Odm, 0x874, 0xC000, 0x2); /* Reg874[15:14]=2'b10 */ ++ ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, 0x3); /* RegA75[7:4]=0x3 */ ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT(28), 0x0); /* Reg818[28]=1'b0 */ ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT(28), 0x1); /* Reg818[28]=1'b1 */ ++ } else { ++ ODM_SetBBReg(pDM_Odm, 0x874, 0x1CC000, pDM_PSTable->reg_874); ++ ODM_SetBBReg(pDM_Odm, 0xc70, BIT(3), pDM_PSTable->reg_c70); ++ ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, pDM_PSTable->reg_85c); ++ ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, pDM_PSTable->reg_a74); ++ ODM_SetBBReg(pDM_Odm, 0x818, BIT(28), 0x0); ++ ++ if (pDM_Odm->SupportICType == ODM_RTL8723A) ++ ODM_SetBBReg(pDM_Odm, 0x874, BIT(5), 0x0); /* Reg874[5]=1b'0 */ ++ } ++ pDM_PSTable->pre_rf_state = pDM_PSTable->cur_rf_state; ++ } ++} ++ ++/* 3============================================================ */ ++/* 3 RATR MASK */ ++/* 3============================================================ */ ++/* 3============================================================ */ ++/* 3 Rate Adaptive */ ++/* 3============================================================ */ ++ ++void odm_RateAdaptiveMaskInit(struct odm_dm_struct *pDM_Odm) ++{ ++ struct odm_rate_adapt *pOdmRA = &pDM_Odm->RateAdaptive; ++ ++ pOdmRA->Type = DM_Type_ByDriver; ++ if (pOdmRA->Type == DM_Type_ByDriver) ++ pDM_Odm->bUseRAMask = true; ++ else ++ pDM_Odm->bUseRAMask = false; ++ ++ pOdmRA->RATRState = DM_RATR_STA_INIT; ++ pOdmRA->HighRSSIThresh = 50; ++ pOdmRA->LowRSSIThresh = 20; ++} ++ ++u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, u32 ra_mask, u8 rssi_level) ++{ ++ struct sta_info *pEntry; ++ u32 rate_bitmap = 0x0fffffff; ++ u8 WirelessMode; ++ ++ pEntry = pDM_Odm->pODM_StaInfo[macid]; ++ if (!IS_STA_VALID(pEntry)) ++ return ra_mask; ++ ++ WirelessMode = pEntry->wireless_mode; ++ ++ switch (WirelessMode) { ++ case ODM_WM_B: ++ if (ra_mask & 0x0000000c) /* 11M or 5.5M enable */ ++ rate_bitmap = 0x0000000d; ++ else ++ rate_bitmap = 0x0000000f; ++ break; ++ case (ODM_WM_B | ODM_WM_G): ++ if (rssi_level == DM_RATR_STA_HIGH) ++ rate_bitmap = 0x00000f00; ++ else if (rssi_level == DM_RATR_STA_MIDDLE) ++ rate_bitmap = 0x00000ff0; ++ else ++ rate_bitmap = 0x00000ff5; ++ break; ++ case (ODM_WM_B | ODM_WM_G | ODM_WM_N24G): ++ if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) { ++ if (rssi_level == DM_RATR_STA_HIGH) { ++ rate_bitmap = 0x000f0000; ++ } else if (rssi_level == DM_RATR_STA_MIDDLE) { ++ rate_bitmap = 0x000ff000; ++ } else { ++ if (*pDM_Odm->pBandWidth == ODM_BW40M) ++ rate_bitmap = 0x000ff015; ++ else ++ rate_bitmap = 0x000ff005; ++ } ++ } else { ++ if (rssi_level == DM_RATR_STA_HIGH) { ++ rate_bitmap = 0x0f8f0000; ++ } else if (rssi_level == DM_RATR_STA_MIDDLE) { ++ rate_bitmap = 0x0f8ff000; ++ } else { ++ if (*pDM_Odm->pBandWidth == ODM_BW40M) ++ rate_bitmap = 0x0f8ff015; ++ else ++ rate_bitmap = 0x0f8ff005; ++ } ++ } ++ break; ++ default: ++ /* case WIRELESS_11_24N: */ ++ if (pDM_Odm->RFType == RF_1T2R) ++ rate_bitmap = 0x000fffff; ++ else ++ rate_bitmap = 0x0fffffff; ++ break; ++ } ++ ++ return rate_bitmap; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: odm_RefreshRateAdaptiveMask() ++ * ++ * Overview: Update rate table mask according to rssi ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 05/27/2009 hpfan Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++void odm_RefreshRateAdaptiveMask(struct odm_dm_struct *pDM_Odm) ++{ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) ++ return; ++ /* */ ++ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ ++ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ ++ /* HW dynamic mechanism. */ ++ /* */ ++ switch (pDM_Odm->SupportPlatform) { ++ case ODM_MP: ++ odm_RefreshRateAdaptiveMaskMP(pDM_Odm); ++ break; ++ case ODM_CE: ++ odm_RefreshRateAdaptiveMaskCE(pDM_Odm); ++ break; ++ case ODM_AP: ++ case ODM_ADSL: ++ odm_RefreshRateAdaptiveMaskAPADSL(pDM_Odm); ++ break; ++ } ++} ++ ++void odm_RefreshRateAdaptiveMaskMP(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm) ++{ ++ u8 i; ++ struct adapter *pAdapter = pDM_Odm->Adapter; ++ ++ if (pAdapter->bDriverStopped) ++ return; ++ ++ if (!pDM_Odm->bUseRAMask) ++ return; ++ ++ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { ++ struct sta_info *pstat = pDM_Odm->pODM_StaInfo[i]; ++ if (IS_STA_VALID(pstat)) { ++ if (ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level)) ++ rtw_hal_update_ra_mask(pAdapter, i, pstat->rssi_level); ++ } ++ } ++} ++ ++void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++/* Return Value: bool */ ++/* - true: RATRState is changed. */ ++bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI, bool bForceUpdate, u8 *pRATRState) ++{ ++ struct odm_rate_adapt *pRA = &pDM_Odm->RateAdaptive; ++ const u8 GoUpGap = 5; ++ u8 HighRSSIThreshForRA = pRA->HighRSSIThresh; ++ u8 LowRSSIThreshForRA = pRA->LowRSSIThresh; ++ u8 RATRState; ++ ++ /* Threshold Adjustment: */ ++ /* when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */ ++ /* Here GoUpGap is added to solve the boundary's level alternation issue. */ ++ switch (*pRATRState) { ++ case DM_RATR_STA_INIT: ++ case DM_RATR_STA_HIGH: ++ break; ++ case DM_RATR_STA_MIDDLE: ++ HighRSSIThreshForRA += GoUpGap; ++ break; ++ case DM_RATR_STA_LOW: ++ HighRSSIThreshForRA += GoUpGap; ++ LowRSSIThreshForRA += GoUpGap; ++ break; ++ default: ++ break; ++ } ++ ++ /* Decide RATRState by RSSI. */ ++ if (RSSI > HighRSSIThreshForRA) ++ RATRState = DM_RATR_STA_HIGH; ++ else if (RSSI > LowRSSIThreshForRA) ++ RATRState = DM_RATR_STA_MIDDLE; ++ else ++ RATRState = DM_RATR_STA_LOW; ++ ++ if (*pRATRState != RATRState || bForceUpdate) { ++ *pRATRState = RATRState; ++ return true; ++ } ++ return false; ++} ++ ++/* 3============================================================ */ ++/* 3 Dynamic Tx Power */ ++/* 3============================================================ */ ++ ++void odm_DynamicTxPowerInit(struct odm_dm_struct *pDM_Odm) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ pdmpriv->bDynamicTxPowerEnable = false; ++ pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal; ++ pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; ++} ++ ++void odm_DynamicTxPower(struct odm_dm_struct *pDM_Odm) ++{ ++ /* For AP/ADSL use struct rtl8192cd_priv * */ ++ /* For CE/NIC use struct adapter * */ ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR)) ++ return; ++ ++ /* 2012/01/12 MH According to Luke's suggestion, only high power will support the feature. */ ++ if (!pDM_Odm->ExtPA) ++ return; ++ ++ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ ++ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ ++ /* HW dynamic mechanism. */ ++ switch (pDM_Odm->SupportPlatform) { ++ case ODM_MP: ++ case ODM_CE: ++ odm_DynamicTxPowerNIC(pDM_Odm); ++ break; ++ case ODM_AP: ++ odm_DynamicTxPowerAP(pDM_Odm); ++ break; ++ case ODM_ADSL: ++ break; ++ } ++} ++ ++void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm) ++{ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR)) ++ return; ++ ++ if (pDM_Odm->SupportICType == ODM_RTL8188E) { ++ /* ??? */ ++ /* This part need to be redefined. */ ++ } ++} ++ ++void odm_DynamicTxPowerAP(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++/* 3============================================================ */ ++/* 3 RSSI Monitor */ ++/* 3============================================================ */ ++ ++void odm_RSSIMonitorCheck(struct odm_dm_struct *pDM_Odm) ++{ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) ++ return; ++ ++ /* */ ++ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ ++ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ ++ /* HW dynamic mechanism. */ ++ /* */ ++ switch (pDM_Odm->SupportPlatform) { ++ case ODM_MP: ++ odm_RSSIMonitorCheckMP(pDM_Odm); ++ break; ++ case ODM_CE: ++ odm_RSSIMonitorCheckCE(pDM_Odm); ++ break; ++ case ODM_AP: ++ odm_RSSIMonitorCheckAP(pDM_Odm); ++ break; ++ case ODM_ADSL: ++ /* odm_DIGAP(pDM_Odm); */ ++ break; ++ } ++ ++} /* odm_RSSIMonitorCheck */ ++ ++void odm_RSSIMonitorCheckMP(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++static void FindMinimumRSSI(struct adapter *pAdapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv; ++ ++ /* 1 1.Determine the minimum RSSI */ ++ if (!check_fwstate(pmlmepriv, _FW_LINKED) && ++ pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0) ++ pdmpriv->MinUndecoratedPWDBForDM = 0; ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) /* Default port */ ++ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++ else /* associated entry pwdb */ ++ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; ++} ++ ++void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ int i; ++ int tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff; ++ u8 sta_cnt = 0; ++ u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */ ++ struct sta_info *psta; ++ u8 bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ if (!check_fwstate(&Adapter->mlmepriv, _FW_LINKED)) ++ return; ++ ++ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { ++ psta = pDM_Odm->pODM_StaInfo[i]; ++ if (IS_STA_VALID(psta) && ++ (psta->state & WIFI_ASOC_STATE) && ++ memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) && ++ memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) { ++ if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) ++ tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) ++ tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)) ++ PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB << 16)); ++ } ++ } ++ ++ for (i = 0; i < sta_cnt; i++) { ++ if (PWDB_rssi[i] != (0)) { ++ if (pHalData->fw_ractrl) { ++ /* Report every sta's RSSI to FW */ ++ } else { ++ ODM_RA_SetRSSI_8188E( ++ &pHalData->odmpriv, (PWDB_rssi[i] & 0xFF), (u8)((PWDB_rssi[i] >> 16) & 0xFF)); ++ } ++ } ++ } ++ ++ if (tmpEntryMaxPWDB != 0) /* If associated entry is found */ ++ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; ++ else ++ pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0; ++ ++ if (tmpEntryMinPWDB != 0xff) /* If associated entry is found */ ++ pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; ++ else ++ pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0; ++ ++ FindMinimumRSSI(Adapter); ++ ODM_CmnInfoUpdate(&pHalData->odmpriv, ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); ++} ++ ++void odm_RSSIMonitorCheckAP(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++void ODM_InitAllTimers(struct odm_dm_struct *pDM_Odm) ++{ ++ timer_setup(&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer, odm_SwAntDivChkAntSwitchCallback, 0); ++} ++ ++void ODM_CancelAllTimers(struct odm_dm_struct *pDM_Odm) ++{ ++ ODM_CancelTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); ++} ++ ++void ODM_ReleaseAllTimers(struct odm_dm_struct *pDM_Odm) ++{ ++ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); ++ ++ ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->FastAntTrainingTimer); ++} ++ ++/* 3============================================================ */ ++/* 3 Tx Power Tracking */ ++/* 3============================================================ */ ++ ++void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm) ++{ ++ odm_TXPowerTrackingThermalMeterInit(pDM_Odm); ++} ++ ++void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm) ++{ ++ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true; ++ pDM_Odm->RFCalibrateInfo.TXPowercount = 0; ++ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false; ++ if (*pDM_Odm->mp_mode != 1) ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true; ++ MSG_88E("pDM_Odm TxPowerTrackControl = %d\n", pDM_Odm->RFCalibrateInfo.TxPowerTrackControl); ++ ++ pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true; ++} ++ ++void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm) ++{ ++ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ ++ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ ++ /* HW dynamic mechanism. */ ++ switch (pDM_Odm->SupportPlatform) { ++ case ODM_MP: ++ odm_TXPowerTrackingCheckMP(pDM_Odm); ++ break; ++ case ODM_CE: ++ odm_TXPowerTrackingCheckCE(pDM_Odm); ++ break; ++ case ODM_AP: ++ odm_TXPowerTrackingCheckAP(pDM_Odm); ++ break; ++ case ODM_ADSL: ++ break; ++ } ++} ++ ++void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK)) ++ return; ++ ++ if (!pDM_Odm->RFCalibrateInfo.TM_Trigger) { /* at least delay 1 sec */ ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER_88E, BIT(17) | BIT(16), 0x03); ++ ++ pDM_Odm->RFCalibrateInfo.TM_Trigger = 1; ++ return; ++ } else { ++ odm_TXPowerTrackingCallback_ThermalMeter_8188E(Adapter); ++ pDM_Odm->RFCalibrateInfo.TM_Trigger = 0; ++ } ++} ++ ++void odm_TXPowerTrackingCheckMP(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++void odm_TXPowerTrackingCheckAP(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++/* antenna mapping info */ ++/* 1: right-side antenna */ ++/* 2/0: left-side antenna */ ++/* PDM_SWAT_Table->CCK_Ant1_Cnt /OFDM_Ant1_Cnt: for right-side antenna: Ant:1 RxDefaultAnt1 */ ++/* PDM_SWAT_Table->CCK_Ant2_Cnt /OFDM_Ant2_Cnt: for left-side antenna: Ant:0 RxDefaultAnt2 */ ++/* We select left antenna as default antenna in initial process, modify it as needed */ ++/* */ ++ ++/* 3============================================================ */ ++/* 3 SW Antenna Diversity */ ++/* 3============================================================ */ ++void odm_SwAntDivInit(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++void ODM_SwAntDivChkPerPktRssi(struct odm_dm_struct *pDM_Odm, u8 StationID, struct odm_phy_status_info *pPhyInfo) ++{ ++} ++ ++void odm_SwAntDivChkAntSwitch(struct odm_dm_struct *pDM_Odm, u8 Step) ++{ ++} ++ ++void ODM_SwAntDivRestAfterLink(struct odm_dm_struct *pDM_Odm) ++{ ++} ++ ++void odm_SwAntDivChkAntSwitchCallback(struct timer_list *t) ++{ ++} ++ ++/* 3============================================================ */ ++/* 3 SW Antenna Diversity */ ++/* 3============================================================ */ ++ ++void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm) ++{ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) ++ return; ++ ++ if (pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D)) ++ ; ++ else if (pDM_Odm->SupportICType == ODM_RTL8188E) ++ ODM_AntennaDiversityInit_88E(pDM_Odm); ++} ++ ++void ODM_AntselStatistics_88C(struct odm_dm_struct *pDM_Odm, u8 MacId, u32 PWDBAll, bool isCCKrate) ++{ ++ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ if (pDM_SWAT_Table->antsel == 1) { ++ if (isCCKrate) { ++ pDM_SWAT_Table->CCK_Ant1_Cnt[MacId]++; ++ } else { ++ pDM_SWAT_Table->OFDM_Ant1_Cnt[MacId]++; ++ pDM_SWAT_Table->RSSI_Ant1_Sum[MacId] += PWDBAll; ++ } ++ } else { ++ if (isCCKrate) { ++ pDM_SWAT_Table->CCK_Ant2_Cnt[MacId]++; ++ } else { ++ pDM_SWAT_Table->OFDM_Ant2_Cnt[MacId]++; ++ pDM_SWAT_Table->RSSI_Ant2_Sum[MacId] += PWDBAll; ++ } ++ } ++} ++ ++void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm) ++{ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) ++ return; ++ ++ if (pDM_Odm->SupportICType == ODM_RTL8188E) ++ ODM_AntennaDiversity_88E(pDM_Odm); ++} ++ ++/* EDCA Turbo */ ++void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; ++ pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false; ++ Adapter->recvpriv.bIsAnyNonBEPkts = false; ++ ++} /* ODM_InitEdcaTurbo */ ++ ++void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm) ++{ ++ /* 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */ ++ /* at the same time. In the stage2/3, we need to prive universal interface and merge all */ ++ /* HW dynamic mechanism. */ ++ if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO)) ++ return; ++ ++ switch (pDM_Odm->SupportPlatform) { ++ case ODM_MP: ++ break; ++ case ODM_CE: ++ odm_EdcaTurboCheckCE(pDM_Odm); ++ break; ++ case ODM_AP: ++ case ODM_ADSL: ++ break; ++ } ++} /* odm_CheckEdcaTurbo */ ++ ++void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ u32 trafficIndex; ++ u32 edca_param; ++ u64 cur_tx_bytes = 0; ++ u64 cur_rx_bytes = 0; ++ u8 bbtchange = false; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct xmit_priv *pxmitpriv = &Adapter->xmitpriv; ++ struct recv_priv *precvpriv = &Adapter->recvpriv; ++ struct registry_priv *pregpriv = &Adapter->registrypriv; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (pregpriv->wifi_spec == 1) ++ goto dm_CheckEdcaTurbo_EXIT; ++ ++ if (pmlmeinfo->assoc_AP_vendor >= HT_IOT_PEER_MAX) ++ goto dm_CheckEdcaTurbo_EXIT; ++ ++ /* Check if the status needs to be changed. */ ++ if ((bbtchange) || (!precvpriv->bIsAnyNonBEPkts)) { ++ cur_tx_bytes = pxmitpriv->tx_bytes - pxmitpriv->last_tx_bytes; ++ cur_rx_bytes = precvpriv->rx_bytes - precvpriv->last_rx_bytes; ++ ++ /* traffic, TX or RX */ ++ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) || ++ (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS)) { ++ if (cur_tx_bytes > (cur_rx_bytes << 2)) { ++ /* Uplink TP is present. */ ++ trafficIndex = UP_LINK; ++ } else { ++ /* Balance TP is present. */ ++ trafficIndex = DOWN_LINK; ++ } ++ } else { ++ if (cur_rx_bytes > (cur_tx_bytes << 2)) { ++ /* Downlink TP is present. */ ++ trafficIndex = DOWN_LINK; ++ } else { ++ /* Balance TP is present. */ ++ trafficIndex = UP_LINK; ++ } ++ } ++ ++ if ((pDM_Odm->DM_EDCA_Table.prv_traffic_idx != trafficIndex) || (!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) { ++ if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_CISCO) && (pmlmeext->cur_wireless_mode & WIRELESS_11_24N)) ++ edca_param = EDCAParam[pmlmeinfo->assoc_AP_vendor][trafficIndex]; ++ else ++ edca_param = EDCAParam[HT_IOT_PEER_UNKNOWN][trafficIndex]; ++ ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param); ++ ++ pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex; ++ } ++ ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = true; ++ } else { ++ /* Turn Off EDCA turbo here. */ ++ /* Restore original EDCA according to the declaration of AP. */ ++ if (pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) { ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, pHalData->AcParam_BE); ++ pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false; ++ } ++ } ++ ++dm_CheckEdcaTurbo_EXIT: ++ /* Set variables for next time. */ ++ precvpriv->bIsAnyNonBEPkts = false; ++ pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes; ++ precvpriv->last_rx_bytes = precvpriv->rx_bytes; ++} ++ ++/* need to ODM CE Platform */ ++/* move to here for ANT detection mechanism using */ ++ ++u32 GetPSDData(struct odm_dm_struct *pDM_Odm, unsigned int point, u8 initial_gain_psd) ++{ ++ u32 psd_report; ++ ++ /* Set DCO frequency index, offset=(40MHz/SamplePts)*point */ ++ ODM_SetBBReg(pDM_Odm, 0x808, 0x3FF, point); ++ ++ /* Start PSD calculation, Reg808[22]=0->1 */ ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT(22), 1); ++ /* Need to wait for HW PSD report */ ++ ODM_StallExecution(30); ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT(22), 0); ++ /* Read PSD report, Reg8B4[15:0] */ ++ psd_report = ODM_GetBBReg(pDM_Odm, 0x8B4, bMaskDWord) & 0x0000FFFF; ++ ++ psd_report = (u32)(ConvertTo_dB(psd_report)) + (u32)(initial_gain_psd - 0x1c); ++ ++ return psd_report; ++} ++ ++u32 ConvertTo_dB(u32 Value) ++{ ++ u8 i; ++ u8 j; ++ u32 dB; ++ ++ Value = Value & 0xFFFF; ++ for (i = 0; i < 8; i++) { ++ if (Value <= dB_Invert_Table[i][11]) ++ break; ++ } ++ ++ if (i >= 8) ++ return 96; /* maximum 96 dB */ ++ ++ for (j = 0; j < 12; j++) { ++ if (Value <= dB_Invert_Table[i][j]) ++ break; ++ } ++ ++ dB = i * 12 + j + 1; ++ ++ return dB; ++} ++ ++/* 2011/09/22 MH Add for 92D global spin lock utilization. */ ++void odm_GlobalAdapterCheck(void) ++{ ++} /* odm_GlobalAdapterCheck */ ++ ++/* Description: */ ++/* Set Single/Dual Antenna default setting for products that do not do detection in advance. */ ++/* Added by Joseph, 2012.03.22 */ ++void ODM_SingleDualAntennaDefaultSetting(struct odm_dm_struct *pDM_Odm) ++{ ++ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ ++ pDM_SWAT_Table->ANTA_ON = true; ++ pDM_SWAT_Table->ANTB_ON = true; ++} ++ ++/* 2 8723A ANT DETECT */ ++ ++static void odm_PHY_SaveAFERegisters(struct odm_dm_struct *pDM_Odm, u32 *AFEReg, u32 *AFEBackup, u32 RegisterNum) ++{ ++ u32 i; ++ ++ /* RTPRINT(FINIT, INIT_IQK, ("Save ADDA parameters.\n")); */ ++ for (i = 0; i < RegisterNum; i++) ++ AFEBackup[i] = ODM_GetBBReg(pDM_Odm, AFEReg[i], bMaskDWord); ++} ++ ++static void odm_PHY_ReloadAFERegisters(struct odm_dm_struct *pDM_Odm, u32 *AFEReg, u32 *AFEBackup, u32 RegiesterNum) ++{ ++ u32 i; ++ ++ for (i = 0; i < RegiesterNum; i++) ++ ODM_SetBBReg(pDM_Odm, AFEReg[i], bMaskDWord, AFEBackup[i]); ++} ++ ++/* 2 8723A ANT DETECT */ ++/* Description: */ ++/* Implement IQK single tone for RF DPK loopback and BB PSD scanning. */ ++/* This function is cooperated with BB team Neil. */ ++bool ODM_SingleDualAntennaDetection(struct odm_dm_struct *pDM_Odm, u8 mode) ++{ ++ struct sw_ant_switch *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; ++ u32 CurrentChannel, RfLoopReg; ++ u8 n; ++ u32 Reg88c, Regc08, Reg874, Regc50; ++ u8 initial_gain = 0x5a; ++ u32 PSD_report_tmp; ++ u32 AntA_report = 0x0, AntB_report = 0x0, AntO_report = 0x0; ++ bool bResult = true; ++ u32 AFE_Backup[16]; ++ u32 AFE_REG_8723A[16] = { ++ rRx_Wait_CCA, rTx_CCK_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_OFDM_BBON, rTx_To_Rx, ++ rTx_To_Tx, rRx_CCK, ++ rRx_OFDM, rRx_Wait_RIFS, ++ rRx_TO_Rx, rStandby, ++ rSleep, rPMPD_ANAEN, ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth}; ++ ++ if (!(pDM_Odm->SupportICType & (ODM_RTL8723A | ODM_RTL8192C))) ++ return bResult; ++ ++ if (!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) ++ return bResult; ++ ++ if (pDM_Odm->SupportICType == ODM_RTL8192C) { ++ /* Which path in ADC/DAC is turnned on for PSD: both I/Q */ ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT(10) | BIT(11), 0x3); ++ /* Ageraged number: 8 */ ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT(12) | BIT(13), 0x1); ++ /* pts = 128; */ ++ ODM_SetBBReg(pDM_Odm, 0x808, BIT(14) | BIT(15), 0x0); ++ } ++ ++ /* 1 Backup Current RF/BB Settings */ ++ ++ CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask); ++ RfLoopReg = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A); /* change to Antenna A */ ++ /* Step 1: USE IQK to transmitter single tone */ ++ ++ ODM_StallExecution(10); ++ ++ /* Store A Path Register 88c, c08, 874, c50 */ ++ Reg88c = ODM_GetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord); ++ Regc08 = ODM_GetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord); ++ Reg874 = ODM_GetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord); ++ Regc50 = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord); ++ ++ /* Store AFE Registers */ ++ odm_PHY_SaveAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16); ++ ++ /* Set PSD 128 pts */ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_PSDFunction, BIT(14) | BIT(15), 0x0); /* 128 pts */ ++ ++ /* To SET CH1 to do */ ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask, 0x01); /* Channel 1 */ ++ ++ /* AFE all on step */ ++ ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_CCK_RFON, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_CCK_BBON, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_OFDM_RFON, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_OFDM_BBON, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_To_Rx, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rTx_To_Tx, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rRx_CCK, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rRx_OFDM, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rRx_Wait_RIFS, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rRx_TO_Rx, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rStandby, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rSleep, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rPMPD_ANAEN, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_SwitchControl, bMaskDWord, 0x6FDB25A4); ++ ODM_SetBBReg(pDM_Odm, rBlue_Tooth, bMaskDWord, 0x6FDB25A4); ++ ++ /* 3 wire Disable */ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, 0xCCF000C0); ++ ++ /* BB IQK Setting */ ++ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800E4); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22208000); ++ ++ /* IQK setting tone@ 4.34Mhz */ ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008C1C); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); ++ ++ /* Page B init */ ++ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00080000); ++ ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f); ++ ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82150008); ++ ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28150008); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x001028d0); ++ ++ /* RF loop Setting */ ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0, 0xFFFFF, 0x50008); ++ ++ /* IQK Single tone start */ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); ++ ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); ++ ODM_StallExecution(1000); ++ PSD_report_tmp = 0x0; ++ ++ for (n = 0; n < 2; n++) { ++ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); ++ if (PSD_report_tmp > AntA_report) ++ AntA_report = PSD_report_tmp; ++ } ++ ++ PSD_report_tmp = 0x0; ++ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); /* change to Antenna B */ ++ ODM_StallExecution(10); ++ ++ for (n = 0; n < 2; n++) { ++ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); ++ if (PSD_report_tmp > AntB_report) ++ AntB_report = PSD_report_tmp; ++ } ++ ++ /* change to open case */ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, 0); /* change to Ant A and B all open case */ ++ ODM_StallExecution(10); ++ ++ for (n = 0; n < 2; n++) { ++ PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); ++ if (PSD_report_tmp > AntO_report) ++ AntO_report = PSD_report_tmp; ++ } ++ ++ /* Close IQK Single Tone function */ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); ++ PSD_report_tmp = 0x0; ++ ++ /* 1 Return to antanna A */ ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, Reg88c); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, Regc08); ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, Reg874); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, 0x7F, 0x40); ++ ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord, Regc50); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel); ++ ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask, RfLoopReg); ++ ++ /* Reload AFE Registers */ ++ odm_PHY_ReloadAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16); ++ ++ if (pDM_Odm->SupportICType == ODM_RTL8723A) { ++ /* 2 Test Ant B based on Ant A is ON */ ++ if (mode == ANTTESTB) { ++ if (AntA_report >= 100) { ++ if (AntB_report > (AntA_report + 1)) ++ pDM_SWAT_Table->ANTB_ON = false; ++ else ++ pDM_SWAT_Table->ANTB_ON = true; ++ } else { ++ pDM_SWAT_Table->ANTB_ON = false; /* Set Antenna B off as default */ ++ bResult = false; ++ } ++ } else if (mode == ANTTESTALL) { ++ /* 2 Test Ant A and B based on DPDT Open */ ++ if ((AntO_report >= 100) & (AntO_report < 118)) { ++ if (AntA_report > (AntO_report + 1)) ++ pDM_SWAT_Table->ANTA_ON = false; ++ else ++ pDM_SWAT_Table->ANTA_ON = true; ++ ++ if (AntB_report > (AntO_report + 2)) ++ pDM_SWAT_Table->ANTB_ON = false; ++ else ++ pDM_SWAT_Table->ANTB_ON = true; ++ } ++ } ++ } else if (pDM_Odm->SupportICType == ODM_RTL8192C) { ++ if (AntA_report >= 100) { ++ if (AntB_report > (AntA_report + 2)) { ++ pDM_SWAT_Table->ANTA_ON = false; ++ pDM_SWAT_Table->ANTB_ON = true; ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); ++ } else if (AntA_report > (AntB_report + 2)) { ++ pDM_SWAT_Table->ANTA_ON = true; ++ pDM_SWAT_Table->ANTB_ON = false; ++ ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A); ++ } else { ++ pDM_SWAT_Table->ANTA_ON = true; ++ pDM_SWAT_Table->ANTB_ON = true; ++ } ++ } else { ++ pDM_SWAT_Table->ANTA_ON = true; /* Set Antenna A on as default */ ++ pDM_SWAT_Table->ANTB_ON = false; /* Set Antenna B off as default */ ++ bResult = false; ++ } ++ } ++ return bResult; ++} ++ ++/* Justin: According to the current RRSI to adjust Response Frame TX power, 2012/11/05 */ ++void odm_dtc(struct odm_dm_struct *pDM_Odm) ++{ ++} +diff --git a/drivers/staging/r8188eu/hal/odm_HWConfig.c b/drivers/staging/r8188eu/hal/odm_HWConfig.c +new file mode 100644 +index 000000000000..ada22a526fee +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/odm_HWConfig.c +@@ -0,0 +1,567 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++ ++#define READ_AND_CONFIG READ_AND_CONFIG_MP ++ ++#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig##txt##ic(dm_odm)) ++#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC##txt##ic(dm_odm)) ++ ++static u8 odm_QueryRxPwrPercentage(s8 AntPower) ++{ ++ if ((AntPower <= -100) || (AntPower >= 20)) ++ return 0; ++ else if (AntPower >= 0) ++ return 100; ++ else ++ return 100 + AntPower; ++} ++ ++/* 2012/01/12 MH MOve some signal strength smooth method to MP HAL layer. */ ++/* IF other SW team do not support the feature, remove this section.?? */ ++static s32 odm_sig_patch_lenove(struct odm_dm_struct *dm_odm, s32 CurrSig) ++{ ++ return 0; ++} ++ ++static s32 odm_sig_patch_netcore(struct odm_dm_struct *dm_odm, s32 CurrSig) ++{ ++ return 0; ++} ++ ++static s32 odm_SignalScaleMapping_92CSeries(struct odm_dm_struct *dm_odm, s32 CurrSig) ++{ ++ s32 RetSig = 0; ++ ++ if ((dm_odm->SupportInterface == ODM_ITRF_USB) || ++ (dm_odm->SupportInterface == ODM_ITRF_SDIO)) { ++ if (CurrSig >= 51 && CurrSig <= 100) ++ RetSig = 100; ++ else if (CurrSig >= 41 && CurrSig <= 50) ++ RetSig = 80 + ((CurrSig - 40) * 2); ++ else if (CurrSig >= 31 && CurrSig <= 40) ++ RetSig = 66 + (CurrSig - 30); ++ else if (CurrSig >= 21 && CurrSig <= 30) ++ RetSig = 54 + (CurrSig - 20); ++ else if (CurrSig >= 10 && CurrSig <= 20) ++ RetSig = 42 + (((CurrSig - 10) * 2) / 3); ++ else if (CurrSig >= 5 && CurrSig <= 9) ++ RetSig = 22 + (((CurrSig - 5) * 3) / 2); ++ else if (CurrSig >= 1 && CurrSig <= 4) ++ RetSig = 6 + (((CurrSig - 1) * 3) / 2); ++ else ++ RetSig = CurrSig; ++ } ++ return RetSig; ++} ++ ++static s32 odm_SignalScaleMapping(struct odm_dm_struct *dm_odm, s32 CurrSig) ++{ ++ if ((dm_odm->SupportPlatform == ODM_MP) && ++ (dm_odm->SupportInterface != ODM_ITRF_PCIE) && /* USB & SDIO */ ++ (dm_odm->PatchID == 10)) ++ return odm_sig_patch_netcore(dm_odm, CurrSig); ++ else if ((dm_odm->SupportPlatform == ODM_MP) && ++ (dm_odm->SupportInterface == ODM_ITRF_PCIE) && ++ (dm_odm->PatchID == 19)) ++ return odm_sig_patch_lenove(dm_odm, CurrSig); ++ else ++ return odm_SignalScaleMapping_92CSeries(dm_odm, CurrSig); ++} ++ ++/* pMgntInfo->CustomerID == RT_CID_819x_Lenovo */ ++static u8 odm_SQ_process_patch_RT_CID_819x_Lenovo(struct odm_dm_struct *dm_odm, ++ u8 isCCKrate, u8 PWDB_ALL, u8 path, u8 RSSI) ++{ ++ return 0; ++} ++ ++static u8 odm_evm_db_to_percentage(s8 value) ++{ ++ /* -33dB~0dB to 0%~99% */ ++ s8 ret_val = clamp(-value, 0, 33) * 3; ++ ++ if (ret_val == 99) ++ ret_val = 100; ++ ++ return ret_val; ++} ++ ++static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm, ++ struct odm_phy_status_info *pPhyInfo, ++ u8 *pPhyStatus, ++ struct odm_per_pkt_info *pPktinfo, ++ struct adapter *adapt) ++{ ++ struct sw_ant_switch *pDM_SWAT_Table = &dm_odm->DM_SWAT_Table; ++ u8 i, Max_spatial_stream; ++ s8 rx_pwr[4], rx_pwr_all = 0; ++ u8 EVM, PWDB_ALL = 0, PWDB_ALL_BT; ++ u8 RSSI, total_rssi = 0; ++ u8 isCCKrate = 0; ++ u8 rf_rx_num = 0; ++ u8 cck_highpwr = 0; ++ u8 LNA_idx, VGA_idx; ++ ++ struct phy_status_rpt *pPhyStaRpt = (struct phy_status_rpt *)pPhyStatus; ++ ++ isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M) && (pPktinfo->Rate <= DESC92C_RATE11M)) ? true : false; ++ ++ pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = -1; ++ pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1; ++ ++ if (isCCKrate) { ++ u8 report; ++ u8 cck_agc_rpt; ++ ++ dm_odm->PhyDbgInfo.NumQryPhyStatusCCK++; ++ /* (1)Hardware does not provide RSSI for CCK */ ++ /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ ++ ++ cck_highpwr = dm_odm->bCckHighPower; ++ ++ cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a; ++ ++ /* 2011.11.28 LukeLee: 88E use different LNA & VGA gain table */ ++ /* The RSSI formula should be modified according to the gain table */ ++ /* In 88E, cck_highpwr is always set to 1 */ ++ if (dm_odm->SupportICType & (ODM_RTL8188E | ODM_RTL8812)) { ++ LNA_idx = ((cck_agc_rpt & 0xE0) >> 5); ++ VGA_idx = (cck_agc_rpt & 0x1F); ++ switch (LNA_idx) { ++ case 7: ++ if (VGA_idx <= 27) ++ rx_pwr_all = -100 + 2 * (27 - VGA_idx); /* VGA_idx = 27~2 */ ++ else ++ rx_pwr_all = -100; ++ break; ++ case 6: ++ rx_pwr_all = -48 + 2 * (2 - VGA_idx); /* VGA_idx = 2~0 */ ++ break; ++ case 5: ++ rx_pwr_all = -42 + 2 * (7 - VGA_idx); /* VGA_idx = 7~5 */ ++ break; ++ case 4: ++ rx_pwr_all = -36 + 2 * (7 - VGA_idx); /* VGA_idx = 7~4 */ ++ break; ++ case 3: ++ rx_pwr_all = -24 + 2 * (7 - VGA_idx); /* VGA_idx = 7~0 */ ++ break; ++ case 2: ++ if (cck_highpwr) ++ rx_pwr_all = -12 + 2 * (5 - VGA_idx); /* VGA_idx = 5~0 */ ++ else ++ rx_pwr_all = -6 + 2 * (5 - VGA_idx); ++ break; ++ case 1: ++ rx_pwr_all = 8 - 2 * VGA_idx; ++ break; ++ case 0: ++ rx_pwr_all = 14 - 2 * VGA_idx; ++ break; ++ default: ++ break; ++ } ++ rx_pwr_all += 6; ++ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); ++ if (!cck_highpwr) { ++ if (PWDB_ALL >= 80) ++ PWDB_ALL = ((PWDB_ALL - 80) << 1) + ((PWDB_ALL - 80) >> 1) + 80; ++ else if ((PWDB_ALL <= 78) && (PWDB_ALL >= 20)) ++ PWDB_ALL += 3; ++ if (PWDB_ALL > 100) ++ PWDB_ALL = 100; ++ } ++ } else { ++ if (!cck_highpwr) { ++ report = (cck_agc_rpt & 0xc0) >> 6; ++ switch (report) { ++ /* 03312009 modified by cosa */ ++ /* Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion */ ++ /* Note: different RF with the different RNA gain. */ ++ case 0x3: ++ rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x2: ++ rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x1: ++ rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); ++ break; ++ case 0x0: ++ rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); ++ break; ++ } ++ } else { ++ report = (cck_agc_rpt & 0x60) >> 5; ++ switch (report) { ++ case 0x3: ++ rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1); ++ break; ++ case 0x2: ++ rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1); ++ break; ++ case 0x1: ++ rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1); ++ break; ++ case 0x0: ++ rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1); ++ break; ++ } ++ } ++ ++ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); ++ ++ /* Modification for ext-LNA board */ ++ if (dm_odm->BoardType == ODM_BOARD_HIGHPWR) { ++ if ((cck_agc_rpt >> 7) == 0) { ++ PWDB_ALL = (PWDB_ALL > 94) ? 100 : (PWDB_ALL + 6); ++ } else { ++ if (PWDB_ALL > 38) ++ PWDB_ALL -= 16; ++ else ++ PWDB_ALL = (PWDB_ALL <= 16) ? (PWDB_ALL >> 2) : (PWDB_ALL - 12); ++ } ++ ++ /* CCK modification */ ++ if (PWDB_ALL > 25 && PWDB_ALL <= 60) ++ PWDB_ALL += 6; ++ } else {/* Modification for int-LNA board */ ++ if (PWDB_ALL > 99) ++ PWDB_ALL -= 8; ++ else if (PWDB_ALL > 50 && PWDB_ALL <= 68) ++ PWDB_ALL += 4; ++ } ++ } ++ ++ pPhyInfo->RxPWDBAll = PWDB_ALL; ++ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; ++ pPhyInfo->RecvSignalPower = rx_pwr_all; ++ /* (3) Get Signal Quality (EVM) */ ++ if (pPktinfo->bPacketMatchBSSID) { ++ u8 SQ, SQ_rpt; ++ ++ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) { ++ SQ = odm_SQ_process_patch_RT_CID_819x_Lenovo(dm_odm, isCCKrate, PWDB_ALL, 0, 0); ++ } else if (pPhyInfo->RxPWDBAll > 40 && !dm_odm->bInHctTest) { ++ SQ = 100; ++ } else { ++ SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all; ++ ++ if (SQ_rpt > 64) ++ SQ = 0; ++ else if (SQ_rpt < 20) ++ SQ = 100; ++ else ++ SQ = ((64 - SQ_rpt) * 100) / 44; ++ } ++ pPhyInfo->SignalQuality = SQ; ++ pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = SQ; ++ pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1; ++ } ++ } else { /* is OFDM rate */ ++ dm_odm->PhyDbgInfo.NumQryPhyStatusOFDM++; ++ ++ /* (1)Get RSSI for HT rate */ ++ ++ for (i = RF_PATH_A; i < RF_PATH_MAX; i++) { ++ /* 2008/01/30 MH we will judge RF RX path now. */ ++ if (dm_odm->RFPathRxEnable & BIT(i)) ++ rf_rx_num++; ++ ++ rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F) * 2) - 110; ++ if (i == RF_PATH_A) ++ adapt->signal_strength = rx_pwr[i]; ++ ++ pPhyInfo->RxPwr[i] = rx_pwr[i]; ++ ++ /* Translate DBM to percentage. */ ++ RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); ++ total_rssi += RSSI; ++ ++ /* Modification for ext-LNA board */ ++ if (dm_odm->BoardType == ODM_BOARD_HIGHPWR) { ++ if ((pPhyStaRpt->path_agc[i].trsw) == 1) ++ RSSI = (RSSI > 94) ? 100 : (RSSI + 6); ++ else ++ RSSI = (RSSI <= 16) ? (RSSI >> 3) : (RSSI - 16); ++ ++ if ((RSSI <= 34) && (RSSI >= 4)) ++ RSSI -= 4; ++ } ++ ++ pPhyInfo->RxMIMOSignalStrength[i] = (u8)RSSI; ++ ++ /* Get Rx snr value in DB */ ++ pPhyInfo->RxSNR[i] = (s32)(pPhyStaRpt->path_rxsnr[i] / 2); ++ dm_odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i] / 2); ++ ++ /* Record Signal Strength for next packet */ ++ if (pPktinfo->bPacketMatchBSSID) { ++ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) { ++ if (i == RF_PATH_A) ++ pPhyInfo->SignalQuality = odm_SQ_process_patch_RT_CID_819x_Lenovo(dm_odm, isCCKrate, PWDB_ALL, i, RSSI); ++ } ++ } ++ } ++ /* (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */ ++ rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f) - 110; ++ ++ PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); ++ PWDB_ALL_BT = PWDB_ALL; ++ ++ pPhyInfo->RxPWDBAll = PWDB_ALL; ++ pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; ++ pPhyInfo->RxPower = rx_pwr_all; ++ pPhyInfo->RecvSignalPower = rx_pwr_all; ++ ++ if ((dm_odm->SupportPlatform == ODM_MP) && (dm_odm->PatchID == 19)) { ++ /* do nothing */ ++ } else { ++ /* (3)EVM of HT rate */ ++ if (pPktinfo->Rate >= DESC92C_RATEMCS8 && pPktinfo->Rate <= DESC92C_RATEMCS15) ++ Max_spatial_stream = 2; /* both spatial stream make sense */ ++ else ++ Max_spatial_stream = 1; /* only spatial stream 1 makes sense */ ++ ++ for (i = 0; i < Max_spatial_stream; i++) { ++ /* Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment */ ++ /* fill most significant bit to "zero" when doing shifting operation which may change a negative */ ++ /* value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. */ ++ EVM = odm_evm_db_to_percentage((pPhyStaRpt->stream_rxevm[i])); /* dbm */ ++ ++ if (pPktinfo->bPacketMatchBSSID) { ++ if (i == RF_PATH_A) /* Fill value in RFD, Get the first spatial stream only */ ++ pPhyInfo->SignalQuality = (u8)(EVM & 0xff); ++ pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff); ++ } ++ } ++ } ++ } ++ /* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */ ++ /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */ ++ if (isCCKrate) { ++ pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, PWDB_ALL));/* PWDB_ALL; */ ++ } else { ++ if (rf_rx_num != 0) ++ pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(dm_odm, total_rssi /= rf_rx_num)); ++ } ++ ++ /* For 92C/92D HW (Hybrid) Antenna Diversity */ ++ pDM_SWAT_Table->antsel = pPhyStaRpt->ant_sel; ++ /* For 88E HW Antenna Diversity */ ++ dm_odm->DM_FatTable.antsel_rx_keep_0 = pPhyStaRpt->ant_sel; ++ dm_odm->DM_FatTable.antsel_rx_keep_1 = pPhyStaRpt->ant_sel_b; ++ dm_odm->DM_FatTable.antsel_rx_keep_2 = pPhyStaRpt->antsel_rx_keep_2; ++} ++ ++void odm_Init_RSSIForDM(struct odm_dm_struct *dm_odm) ++{ ++} ++ ++static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm, ++ struct odm_phy_status_info *pPhyInfo, ++ struct odm_per_pkt_info *pPktinfo) ++{ ++ s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK; ++ s32 UndecoratedSmoothedOFDM, RSSI_Ave; ++ u8 isCCKrate = 0; ++ u8 RSSI_max, RSSI_min, i; ++ u32 OFDM_pkt = 0; ++ u32 Weighting = 0; ++ struct sta_info *pEntry; ++ ++ if (pPktinfo->StationID == 0xFF) ++ return; ++ pEntry = dm_odm->pODM_StaInfo[pPktinfo->StationID]; ++ if (!IS_STA_VALID(pEntry)) ++ return; ++ if ((!pPktinfo->bPacketMatchBSSID)) ++ return; ++ ++ isCCKrate = ((pPktinfo->Rate >= DESC92C_RATE1M) && (pPktinfo->Rate <= DESC92C_RATE11M)) ? true : false; ++ ++ /* Smart Antenna Debug Message------------------ */ ++ if (dm_odm->SupportICType == ODM_RTL8188E) { ++ u8 antsel_tr_mux; ++ struct fast_ant_train *pDM_FatTable = &dm_odm->DM_FatTable; ++ ++ if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV) { ++ if (pDM_FatTable->FAT_State == FAT_TRAINING_STATE) { ++ if (pPktinfo->bPacketToSelf) { ++ antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2 << 2) | ++ (pDM_FatTable->antsel_rx_keep_1 << 1) | ++ pDM_FatTable->antsel_rx_keep_0; ++ pDM_FatTable->antSumRSSI[antsel_tr_mux] += pPhyInfo->RxPWDBAll; ++ pDM_FatTable->antRSSIcnt[antsel_tr_mux]++; ++ } ++ } ++ } else if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)) { ++ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) { ++ antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2 << 2) | ++ (pDM_FatTable->antsel_rx_keep_1 << 1) | pDM_FatTable->antsel_rx_keep_0; ++ ODM_AntselStatistics_88E(dm_odm, antsel_tr_mux, pPktinfo->StationID, pPhyInfo->RxPWDBAll); ++ } ++ } ++ } ++ /* Smart Antenna Debug Message------------------ */ ++ ++ UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK; ++ UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM; ++ UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; ++ ++ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) { ++ if (!isCCKrate) { /* ofdm rate */ ++ if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_B] == 0) { ++ RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; ++ } else { ++ if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]) { ++ RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; ++ RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]; ++ } else { ++ RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]; ++ RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A]; ++ } ++ if ((RSSI_max - RSSI_min) < 3) ++ RSSI_Ave = RSSI_max; ++ else if ((RSSI_max - RSSI_min) < 6) ++ RSSI_Ave = RSSI_max - 1; ++ else if ((RSSI_max - RSSI_min) < 10) ++ RSSI_Ave = RSSI_max - 2; ++ else ++ RSSI_Ave = RSSI_max - 3; ++ } ++ ++ /* 1 Process OFDM RSSI */ ++ if (UndecoratedSmoothedOFDM <= 0) { /* initialize */ ++ UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll; ++ } else { ++ if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) { ++ UndecoratedSmoothedOFDM = ++ (((UndecoratedSmoothedOFDM) * (Rx_Smooth_Factor - 1)) + ++ (RSSI_Ave)) / (Rx_Smooth_Factor); ++ UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1; ++ } else { ++ UndecoratedSmoothedOFDM = ++ (((UndecoratedSmoothedOFDM) * (Rx_Smooth_Factor - 1)) + ++ (RSSI_Ave)) / (Rx_Smooth_Factor); ++ } ++ } ++ ++ pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap << 1) | BIT(0); ++ ++ } else { ++ RSSI_Ave = pPhyInfo->RxPWDBAll; ++ ++ /* 1 Process CCK RSSI */ ++ if (UndecoratedSmoothedCCK <= 0) { /* initialize */ ++ UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll; ++ } else { ++ if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) { ++ UndecoratedSmoothedCCK = ++ ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor - 1)) + ++ pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor; ++ UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1; ++ } else { ++ UndecoratedSmoothedCCK = ++ ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor - 1)) + ++ pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor; ++ } ++ } ++ pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap << 1; ++ } ++ /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */ ++ if (pEntry->rssi_stat.ValidBit >= 64) ++ pEntry->rssi_stat.ValidBit = 64; ++ else ++ pEntry->rssi_stat.ValidBit++; ++ ++ for (i = 0; i < pEntry->rssi_stat.ValidBit; i++) ++ OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap >> i) & BIT(0); ++ ++ if (pEntry->rssi_stat.ValidBit == 64) { ++ Weighting = ((OFDM_pkt << 4) > 64) ? 64 : (OFDM_pkt << 4); ++ UndecoratedSmoothedPWDB = (Weighting * UndecoratedSmoothedOFDM + (64 - Weighting) * UndecoratedSmoothedCCK) >> 6; ++ } else { ++ if (pEntry->rssi_stat.ValidBit != 0) ++ UndecoratedSmoothedPWDB = (OFDM_pkt * UndecoratedSmoothedOFDM + ++ (pEntry->rssi_stat.ValidBit - OFDM_pkt) * ++ UndecoratedSmoothedCCK) / pEntry->rssi_stat.ValidBit; ++ else ++ UndecoratedSmoothedPWDB = 0; ++ } ++ pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK; ++ pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM; ++ pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB; ++ } ++} ++ ++/* Endianness before calling this API */ ++static void ODM_PhyStatusQuery_92CSeries(struct odm_dm_struct *dm_odm, ++ struct odm_phy_status_info *pPhyInfo, ++ u8 *pPhyStatus, ++ struct odm_per_pkt_info *pPktinfo, ++ struct adapter *adapt) ++{ ++ odm_RxPhyStatus92CSeries_Parsing(dm_odm, pPhyInfo, pPhyStatus, ++ pPktinfo, adapt); ++ if (dm_odm->RSSI_test) { ++ /* Select the packets to do RSSI checking for antenna switching. */ ++ if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) ++ ODM_SwAntDivChkPerPktRssi(dm_odm, pPktinfo->StationID, pPhyInfo); ++ } else { ++ odm_Process_RSSIForDM(dm_odm, pPhyInfo, pPktinfo); ++ } ++} ++ ++void ODM_PhyStatusQuery(struct odm_dm_struct *dm_odm, ++ struct odm_phy_status_info *pPhyInfo, ++ u8 *pPhyStatus, struct odm_per_pkt_info *pPktinfo, ++ struct adapter *adapt) ++{ ++ ODM_PhyStatusQuery_92CSeries(dm_odm, pPhyInfo, pPhyStatus, pPktinfo, adapt); ++} ++ ++/* For future use. */ ++void ODM_MacStatusQuery(struct odm_dm_struct *dm_odm, u8 *mac_stat, ++ u8 macid, bool pkt_match_bssid, ++ bool pkttoself, bool pkt_beacon) ++{ ++ /* 2011/10/19 Driver team will handle in the future. */ ++} ++ ++enum HAL_STATUS ODM_ConfigRFWithHeaderFile(struct odm_dm_struct *dm_odm, ++ enum rf_radio_path content, ++ enum rf_radio_path rfpath) ++{ ++ if (dm_odm->SupportICType == ODM_RTL8188E) { ++ if (rfpath == RF_PATH_A) ++ READ_AND_CONFIG(8188E, _RadioA_1T_); ++ } ++ ++ return HAL_STATUS_SUCCESS; ++} ++ ++enum HAL_STATUS ODM_ConfigBBWithHeaderFile(struct odm_dm_struct *dm_odm, ++ enum odm_bb_config_type config_tp) ++{ ++ if (dm_odm->SupportICType == ODM_RTL8188E) { ++ if (config_tp == CONFIG_BB_PHY_REG) { ++ READ_AND_CONFIG(8188E, _PHY_REG_1T_); ++ } else if (config_tp == CONFIG_BB_AGC_TAB) { ++ READ_AND_CONFIG(8188E, _AGC_TAB_1T_); ++ } else if (config_tp == CONFIG_BB_PHY_REG_PG) { ++ READ_AND_CONFIG(8188E, _PHY_REG_PG_); ++ } ++ } ++ return HAL_STATUS_SUCCESS; ++} ++ ++enum HAL_STATUS ODM_ConfigMACWithHeaderFile(struct odm_dm_struct *dm_odm) ++{ ++ u8 result = HAL_STATUS_SUCCESS; ++ if (dm_odm->SupportICType == ODM_RTL8188E) ++ result = READ_AND_CONFIG(8188E, _MAC_REG_); ++ return result; ++} +diff --git a/drivers/staging/r8188eu/hal/odm_RTL8188E.c b/drivers/staging/r8188eu/hal/odm_RTL8188E.c +new file mode 100644 +index 000000000000..c64a291f9966 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/odm_RTL8188E.c +@@ -0,0 +1,337 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++ ++void ODM_DIG_LowerBound_88E(struct odm_dm_struct *dm_odm) ++{ ++ struct rtw_dig *pDM_DigTable = &dm_odm->DM_DigTable; ++ ++ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ++ pDM_DigTable->rx_gain_range_min = (u8)pDM_DigTable->AntDiv_RSSI_max; ++ /* If only one Entry connected */ ++} ++ ++static void odm_RX_HWAntDivInit(struct odm_dm_struct *dm_odm) ++{ ++ u32 value32; ++ ++ if (*dm_odm->mp_mode == 1) { ++ dm_odm->AntDivType = CGCS_RX_SW_ANTDIV; ++ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT(7), 0); /* disable HW AntDiv */ ++ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT(31), 1); /* 1:CG, 0:CS */ ++ return; ++ } ++ ++ /* MAC Setting */ ++ value32 = ODM_GetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord); ++ ODM_SetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32 | (BIT(23) | BIT(25))); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */ ++ /* Pin Settings */ ++ ODM_SetBBReg(dm_odm, ODM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */ ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT(10), 0); /* Reg864[10]=1'b0 antsel2 by HW */ ++ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT(22), 1); /* Regb2c[22]=1'b0 disable CS/CG switch */ ++ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT(31), 1); /* Regb2c[31]=1'b1 output at CG only */ ++ /* OFDM Settings */ ++ ODM_SetBBReg(dm_odm, ODM_REG_ANTDIV_PARA1_11N, bMaskDWord, 0x000000a0); ++ /* CCK Settings */ ++ ODM_SetBBReg(dm_odm, ODM_REG_BB_PWR_SAV4_11N, BIT(7), 1); /* Fix CCK PHY status report issue */ ++ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA2_11N, BIT(4), 1); /* CCK complete HW AntDiv within 64 samples */ ++ ODM_UpdateRxIdleAnt_88E(dm_odm, MAIN_ANT); ++ ODM_SetBBReg(dm_odm, ODM_REG_ANT_MAPPING1_11N, 0xFFFF, 0x0201); /* antenna mapping table */ ++} ++ ++static void odm_TRX_HWAntDivInit(struct odm_dm_struct *dm_odm) ++{ ++ u32 value32; ++ ++ if (*dm_odm->mp_mode == 1) { ++ dm_odm->AntDivType = CGCS_RX_SW_ANTDIV; ++ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT(7), 0); /* disable HW AntDiv */ ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT(5) | BIT(4) | BIT(3), 0); /* Default RX (0/1) */ ++ return; ++ } ++ ++ /* MAC Setting */ ++ value32 = ODM_GetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord); ++ ODM_SetMACReg(dm_odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32 | (BIT(23) | BIT(25))); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */ ++ /* Pin Settings */ ++ ODM_SetBBReg(dm_odm, ODM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */ ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT(10), 0); /* Reg864[10]=1'b0 antsel2 by HW */ ++ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT(22), 0); /* Regb2c[22]=1'b0 disable CS/CG switch */ ++ ODM_SetBBReg(dm_odm, ODM_REG_LNA_SWITCH_11N, BIT(31), 1); /* Regb2c[31]=1'b1 output at CG only */ ++ /* OFDM Settings */ ++ ODM_SetBBReg(dm_odm, ODM_REG_ANTDIV_PARA1_11N, bMaskDWord, 0x000000a0); ++ /* CCK Settings */ ++ ODM_SetBBReg(dm_odm, ODM_REG_BB_PWR_SAV4_11N, BIT(7), 1); /* Fix CCK PHY status report issue */ ++ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA2_11N, BIT(4), 1); /* CCK complete HW AntDiv within 64 samples */ ++ /* Tx Settings */ ++ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT(21), 0); /* Reg80c[21]=1'b0 from TX Reg */ ++ ODM_UpdateRxIdleAnt_88E(dm_odm, MAIN_ANT); ++ ++ /* antenna mapping table */ ++ if (!dm_odm->bIsMPChip) { /* testchip */ ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_DEFUALT_A_11N, BIT(10) | BIT(9) | BIT(8), 1); /* Reg858[10:8]=3'b001 */ ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_DEFUALT_A_11N, BIT(13) | BIT(12) | BIT(11), 2); /* Reg858[13:11]=3'b010 */ ++ } else { /* MPchip */ ++ ODM_SetBBReg(dm_odm, ODM_REG_ANT_MAPPING1_11N, bMaskDWord, 0x0201); /* Reg914=3'b010, Reg915=3'b001 */ ++ } ++} ++ ++static void odm_FastAntTrainingInit(struct odm_dm_struct *dm_odm) ++{ ++ u32 value32, i; ++ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; ++ u32 AntCombination = 2; ++ ++ if (*dm_odm->mp_mode == 1) ++ return; ++ ++ for (i = 0; i < 6; i++) { ++ dm_fat_tbl->Bssid[i] = 0; ++ dm_fat_tbl->antSumRSSI[i] = 0; ++ dm_fat_tbl->antRSSIcnt[i] = 0; ++ dm_fat_tbl->antAveRSSI[i] = 0; ++ } ++ dm_fat_tbl->TrainIdx = 0; ++ dm_fat_tbl->FAT_State = FAT_NORMAL_STATE; ++ ++ /* MAC Setting */ ++ value32 = ODM_GetMACReg(dm_odm, 0x4c, bMaskDWord); ++ ODM_SetMACReg(dm_odm, 0x4c, bMaskDWord, value32 | (BIT(23) | BIT(25))); /* Reg4C[25]=1, Reg4C[23]=1 for pin output */ ++ value32 = ODM_GetMACReg(dm_odm, 0x7B4, bMaskDWord); ++ ODM_SetMACReg(dm_odm, 0x7b4, bMaskDWord, value32 | (BIT(16) | BIT(17))); /* Reg7B4[16]=1 enable antenna training, Reg7B4[17]=1 enable A2 match */ ++ ++ /* Match MAC ADDR */ ++ ODM_SetMACReg(dm_odm, 0x7b4, 0xFFFF, 0); ++ ODM_SetMACReg(dm_odm, 0x7b0, bMaskDWord, 0); ++ ++ ODM_SetBBReg(dm_odm, 0x870, BIT(9) | BIT(8), 0);/* Reg870[8]=1'b0, Reg870[9]=1'b0 antsel antselb by HW */ ++ ODM_SetBBReg(dm_odm, 0x864, BIT(10), 0); /* Reg864[10]=1'b0 antsel2 by HW */ ++ ODM_SetBBReg(dm_odm, 0xb2c, BIT(22), 0); /* Regb2c[22]=1'b0 disable CS/CG switch */ ++ ODM_SetBBReg(dm_odm, 0xb2c, BIT(31), 1); /* Regb2c[31]=1'b1 output at CG only */ ++ ODM_SetBBReg(dm_odm, 0xca4, bMaskDWord, 0x000000a0); ++ ++ /* antenna mapping table */ ++ if (AntCombination == 2) { ++ if (!dm_odm->bIsMPChip) { /* testchip */ ++ ODM_SetBBReg(dm_odm, 0x858, BIT(10) | BIT(9) | BIT(8), 1); /* Reg858[10:8]=3'b001 */ ++ ODM_SetBBReg(dm_odm, 0x858, BIT(13) | BIT(12) | BIT(11), 2); /* Reg858[13:11]=3'b010 */ ++ } else { /* MPchip */ ++ ODM_SetBBReg(dm_odm, 0x914, bMaskByte0, 1); ++ ODM_SetBBReg(dm_odm, 0x914, bMaskByte1, 2); ++ } ++ } else if (AntCombination == 7) { ++ if (!dm_odm->bIsMPChip) { /* testchip */ ++ ODM_SetBBReg(dm_odm, 0x858, BIT(10) | BIT(9) | BIT(8), 0); /* Reg858[10:8]=3'b000 */ ++ ODM_SetBBReg(dm_odm, 0x858, BIT(13) | BIT(12) | BIT(11), 1); /* Reg858[13:11]=3'b001 */ ++ ODM_SetBBReg(dm_odm, 0x878, BIT(16), 0); ++ ODM_SetBBReg(dm_odm, 0x858, BIT(15) | BIT(14), 2); /* Reg878[0],Reg858[14:15])=3'b010 */ ++ ODM_SetBBReg(dm_odm, 0x878, BIT(19) | BIT(18) | BIT(17), 3);/* Reg878[3:1]=3b'011 */ ++ ODM_SetBBReg(dm_odm, 0x878, BIT(22) | BIT(21) | BIT(20), 4);/* Reg878[6:4]=3b'100 */ ++ ODM_SetBBReg(dm_odm, 0x878, BIT(25) | BIT(24) | BIT(23), 5);/* Reg878[9:7]=3b'101 */ ++ ODM_SetBBReg(dm_odm, 0x878, BIT(28) | BIT(27) | BIT(26), 6);/* Reg878[12:10]=3b'110 */ ++ ODM_SetBBReg(dm_odm, 0x878, BIT(31) | BIT(30) | BIT(29), 7);/* Reg878[15:13]=3b'111 */ ++ } else { /* MPchip */ ++ ODM_SetBBReg(dm_odm, 0x914, bMaskByte0, 0); ++ ODM_SetBBReg(dm_odm, 0x914, bMaskByte1, 1); ++ ODM_SetBBReg(dm_odm, 0x914, bMaskByte2, 2); ++ ODM_SetBBReg(dm_odm, 0x914, bMaskByte3, 3); ++ ODM_SetBBReg(dm_odm, 0x918, bMaskByte0, 4); ++ ODM_SetBBReg(dm_odm, 0x918, bMaskByte1, 5); ++ ODM_SetBBReg(dm_odm, 0x918, bMaskByte2, 6); ++ ODM_SetBBReg(dm_odm, 0x918, bMaskByte3, 7); ++ } ++ } ++ ++ /* Default Ant Setting when no fast training */ ++ ODM_SetBBReg(dm_odm, 0x80c, BIT(21), 1); /* Reg80c[21]=1'b1 from TX Info */ ++ ODM_SetBBReg(dm_odm, 0x864, BIT(5) | BIT(4) | BIT(3), 0); /* Default RX */ ++ ODM_SetBBReg(dm_odm, 0x864, BIT(8) | BIT(7) | BIT(6), 1); /* Optional RX */ ++ ++ /* Enter Traing state */ ++ ODM_SetBBReg(dm_odm, 0x864, BIT(2) | BIT(1) | BIT(0), (AntCombination - 1)); /* Reg864[2:0]=3'd6 ant combination=reg864[2:0]+1 */ ++ ODM_SetBBReg(dm_odm, 0xc50, BIT(7), 1); /* RegC50[7]=1'b1 enable HW AntDiv */ ++} ++ ++void ODM_AntennaDiversityInit_88E(struct odm_dm_struct *dm_odm) ++{ ++ if (dm_odm->SupportICType != ODM_RTL8188E) ++ return; ++ ++ if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) ++ odm_RX_HWAntDivInit(dm_odm); ++ else if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ++ odm_TRX_HWAntDivInit(dm_odm); ++ else if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV) ++ odm_FastAntTrainingInit(dm_odm); ++} ++ ++void ODM_UpdateRxIdleAnt_88E(struct odm_dm_struct *dm_odm, u8 Ant) ++{ ++ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; ++ u32 DefaultAnt, OptionalAnt; ++ ++ if (dm_fat_tbl->RxIdleAnt != Ant) { ++ if (Ant == MAIN_ANT) { ++ DefaultAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX; ++ OptionalAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX; ++ } else { ++ DefaultAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX; ++ OptionalAnt = (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ? MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX; ++ } ++ ++ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) { ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT(5) | BIT(4) | BIT(3), DefaultAnt); /* Default RX */ ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT(8) | BIT(7) | BIT(6), OptionalAnt); /* Optional RX */ ++ ODM_SetBBReg(dm_odm, ODM_REG_ANTSEL_CTRL_11N, BIT(14) | BIT(13) | BIT(12), DefaultAnt); /* Default TX */ ++ ODM_SetMACReg(dm_odm, ODM_REG_RESP_TX_11N, BIT(6) | BIT(7), DefaultAnt); /* Resp Tx */ ++ } else if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) { ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT(5) | BIT(4) | BIT(3), DefaultAnt); /* Default RX */ ++ ODM_SetBBReg(dm_odm, ODM_REG_RX_ANT_CTRL_11N, BIT(8) | BIT(7) | BIT(6), OptionalAnt); /* Optional RX */ ++ } ++ } ++ dm_fat_tbl->RxIdleAnt = Ant; ++ if (Ant != MAIN_ANT) ++ pr_info("RxIdleAnt=AUX_ANT\n"); ++} ++ ++static void odm_UpdateTxAnt_88E(struct odm_dm_struct *dm_odm, u8 Ant, u32 MacId) ++{ ++ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; ++ u8 TargetAnt; ++ ++ if (Ant == MAIN_ANT) ++ TargetAnt = MAIN_ANT_CG_TRX; ++ else ++ TargetAnt = AUX_ANT_CG_TRX; ++ dm_fat_tbl->antsel_a[MacId] = TargetAnt & BIT(0); ++ dm_fat_tbl->antsel_b[MacId] = (TargetAnt & BIT(1)) >> 1; ++ dm_fat_tbl->antsel_c[MacId] = (TargetAnt & BIT(2)) >> 2; ++} ++ ++void ODM_SetTxAntByTxInfo_88E(struct odm_dm_struct *dm_odm, u8 *pDesc, u8 macId) ++{ ++ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; ++ ++ if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV)) { ++ SET_TX_DESC_ANTSEL_A_88E(pDesc, dm_fat_tbl->antsel_a[macId]); ++ SET_TX_DESC_ANTSEL_B_88E(pDesc, dm_fat_tbl->antsel_b[macId]); ++ SET_TX_DESC_ANTSEL_C_88E(pDesc, dm_fat_tbl->antsel_c[macId]); ++ } ++} ++ ++void ODM_AntselStatistics_88E(struct odm_dm_struct *dm_odm, u8 antsel_tr_mux, u32 MacId, u8 RxPWDBAll) ++{ ++ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; ++ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) { ++ if (antsel_tr_mux == MAIN_ANT_CG_TRX) { ++ dm_fat_tbl->MainAnt_Sum[MacId] += RxPWDBAll; ++ dm_fat_tbl->MainAnt_Cnt[MacId]++; ++ } else { ++ dm_fat_tbl->AuxAnt_Sum[MacId] += RxPWDBAll; ++ dm_fat_tbl->AuxAnt_Cnt[MacId]++; ++ } ++ } else if (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV) { ++ if (antsel_tr_mux == MAIN_ANT_CGCS_RX) { ++ dm_fat_tbl->MainAnt_Sum[MacId] += RxPWDBAll; ++ dm_fat_tbl->MainAnt_Cnt[MacId]++; ++ } else { ++ dm_fat_tbl->AuxAnt_Sum[MacId] += RxPWDBAll; ++ dm_fat_tbl->AuxAnt_Cnt[MacId]++; ++ } ++ } ++} ++ ++static void odm_HWAntDiv(struct odm_dm_struct *dm_odm) ++{ ++ u32 i, MinRSSI = 0xFF, AntDivMaxRSSI = 0, MaxRSSI = 0, LocalMinRSSI, LocalMaxRSSI; ++ u32 Main_RSSI, Aux_RSSI; ++ u8 RxIdleAnt = 0, TargetAnt = 7; ++ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; ++ struct rtw_dig *pDM_DigTable = &dm_odm->DM_DigTable; ++ struct sta_info *pEntry; ++ ++ for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) { ++ pEntry = dm_odm->pODM_StaInfo[i]; ++ if (IS_STA_VALID(pEntry)) { ++ /* 2 Caculate RSSI per Antenna */ ++ Main_RSSI = (dm_fat_tbl->MainAnt_Cnt[i] != 0) ? (dm_fat_tbl->MainAnt_Sum[i] / dm_fat_tbl->MainAnt_Cnt[i]) : 0; ++ Aux_RSSI = (dm_fat_tbl->AuxAnt_Cnt[i] != 0) ? (dm_fat_tbl->AuxAnt_Sum[i] / dm_fat_tbl->AuxAnt_Cnt[i]) : 0; ++ TargetAnt = (Main_RSSI >= Aux_RSSI) ? MAIN_ANT : AUX_ANT; ++ /* 2 Select MaxRSSI for DIG */ ++ LocalMaxRSSI = (Main_RSSI > Aux_RSSI) ? Main_RSSI : Aux_RSSI; ++ if ((LocalMaxRSSI > AntDivMaxRSSI) && (LocalMaxRSSI < 40)) ++ AntDivMaxRSSI = LocalMaxRSSI; ++ if (LocalMaxRSSI > MaxRSSI) ++ MaxRSSI = LocalMaxRSSI; ++ ++ /* 2 Select RX Idle Antenna */ ++ if ((dm_fat_tbl->RxIdleAnt == MAIN_ANT) && (Main_RSSI == 0)) ++ Main_RSSI = Aux_RSSI; ++ else if ((dm_fat_tbl->RxIdleAnt == AUX_ANT) && (Aux_RSSI == 0)) ++ Aux_RSSI = Main_RSSI; ++ ++ LocalMinRSSI = (Main_RSSI > Aux_RSSI) ? Aux_RSSI : Main_RSSI; ++ if (LocalMinRSSI < MinRSSI) { ++ MinRSSI = LocalMinRSSI; ++ RxIdleAnt = TargetAnt; ++ } ++ /* 2 Select TRX Antenna */ ++ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ++ odm_UpdateTxAnt_88E(dm_odm, TargetAnt, i); ++ } ++ dm_fat_tbl->MainAnt_Sum[i] = 0; ++ dm_fat_tbl->AuxAnt_Sum[i] = 0; ++ dm_fat_tbl->MainAnt_Cnt[i] = 0; ++ dm_fat_tbl->AuxAnt_Cnt[i] = 0; ++ } ++ ++ /* 2 Set RX Idle Antenna */ ++ ODM_UpdateRxIdleAnt_88E(dm_odm, RxIdleAnt); ++ ++ pDM_DigTable->AntDiv_RSSI_max = AntDivMaxRSSI; ++ pDM_DigTable->RSSI_max = MaxRSSI; ++} ++ ++void ODM_AntennaDiversity_88E(struct odm_dm_struct *dm_odm) ++{ ++ struct fast_ant_train *dm_fat_tbl = &dm_odm->DM_FatTable; ++ if ((dm_odm->SupportICType != ODM_RTL8188E) || (!(dm_odm->SupportAbility & ODM_BB_ANT_DIV))) ++ return; ++ if (!dm_odm->bLinked) { ++ if (dm_fat_tbl->bBecomeLinked) { ++ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT(7), 0); /* RegC50[7]=1'b1 enable HW AntDiv */ ++ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA1_11N, BIT(15), 0); /* Enable CCK AntDiv */ ++ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ++ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT(21), 0); /* Reg80c[21]=1'b0 from TX Reg */ ++ dm_fat_tbl->bBecomeLinked = dm_odm->bLinked; ++ } ++ return; ++ } else { ++ if (!dm_fat_tbl->bBecomeLinked) { ++ /* Because HW AntDiv is disabled before Link, we enable HW AntDiv after link */ ++ ODM_SetBBReg(dm_odm, ODM_REG_IGI_A_11N, BIT(7), 1); /* RegC50[7]=1'b1 enable HW AntDiv */ ++ ODM_SetBBReg(dm_odm, ODM_REG_CCK_ANTDIV_PARA1_11N, BIT(15), 1); /* Enable CCK AntDiv */ ++ if (dm_odm->AntDivType == CG_TRX_HW_ANTDIV) ++ ODM_SetBBReg(dm_odm, ODM_REG_TX_ANT_CTRL_11N, BIT(21), 1); /* Reg80c[21]=1'b1 from TX Info */ ++ dm_fat_tbl->bBecomeLinked = dm_odm->bLinked; ++ } ++ } ++ if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)) ++ odm_HWAntDiv(dm_odm); ++} ++ ++/* 3============================================================ */ ++/* 3 Dynamic Primary CCA */ ++/* 3============================================================ */ ++ ++void odm_PrimaryCCA_Init(struct odm_dm_struct *dm_odm) ++{ ++ struct dyn_primary_cca *PrimaryCCA = &dm_odm->DM_PriCCA; ++ ++ PrimaryCCA->dup_rts_flag = 0; ++ PrimaryCCA->intf_flag = 0; ++ PrimaryCCA->intf_type = 0; ++ PrimaryCCA->monitor_flag = 0; ++ PrimaryCCA->pri_cca_flag = 0; ++} +diff --git a/drivers/staging/r8188eu/hal/odm_RegConfig8188E.c b/drivers/staging/r8188eu/hal/odm_RegConfig8188E.c +new file mode 100644 +index 000000000000..1bc3b49cd67f +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/odm_RegConfig8188E.c +@@ -0,0 +1,98 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++ ++void odm_ConfigRFReg_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, ++ u32 Data, enum rf_radio_path RF_PATH, ++ u32 RegAddr) ++{ ++ if (Addr == 0xffe) { ++ ODM_sleep_ms(50); ++ } else if (Addr == 0xfd) { ++ ODM_delay_ms(5); ++ } else if (Addr == 0xfc) { ++ ODM_delay_ms(1); ++ } else if (Addr == 0xfb) { ++ ODM_delay_us(50); ++ } else if (Addr == 0xfa) { ++ ODM_delay_us(5); ++ } else if (Addr == 0xf9) { ++ ODM_delay_us(1); ++ } else { ++ ODM_SetRFReg(pDM_Odm, RF_PATH, RegAddr, bRFRegOffsetMask, Data); ++ /* Add 1us delay between BB/RF register setting. */ ++ ODM_delay_us(1); ++ } ++} ++ ++void odm_ConfigRF_RadioA_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data) ++{ ++ u32 content = 0x1000; /* RF_Content: radioa_txt */ ++ u32 maskforPhySet = (u32)(content & 0xE000); ++ ++ odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, RF_PATH_A, Addr | maskforPhySet); ++} ++ ++void odm_ConfigRF_RadioB_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data) ++{ ++ u32 content = 0x1001; /* RF_Content: radiob_txt */ ++ u32 maskforPhySet = (u32)(content & 0xE000); ++ ++ odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, RF_PATH_B, Addr | maskforPhySet); ++} ++ ++void odm_ConfigMAC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u8 Data) ++{ ++ ODM_Write1Byte(pDM_Odm, Addr, Data); ++} ++ ++void odm_ConfigBB_AGC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data) ++{ ++ ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); ++ /* Add 1us delay between BB/RF register setting. */ ++ ODM_delay_us(1); ++} ++ ++void odm_ConfigBB_PHY_REG_PG_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, ++ u32 Bitmask, u32 Data) ++{ ++ if (Addr == 0xfe) ++ ODM_sleep_ms(50); ++ else if (Addr == 0xfd) ++ ODM_delay_ms(5); ++ else if (Addr == 0xfc) ++ ODM_delay_ms(1); ++ else if (Addr == 0xfb) ++ ODM_delay_us(50); ++ else if (Addr == 0xfa) ++ ODM_delay_us(5); ++ else if (Addr == 0xf9) ++ ODM_delay_us(1); ++ else ++ storePwrIndexDiffRateOffset(pDM_Odm->Adapter, Addr, Bitmask, Data); ++} ++ ++void odm_ConfigBB_PHY_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data) ++{ ++ if (Addr == 0xfe) { ++ ODM_sleep_ms(50); ++ } else if (Addr == 0xfd) { ++ ODM_delay_ms(5); ++ } else if (Addr == 0xfc) { ++ ODM_delay_ms(1); ++ } else if (Addr == 0xfb) { ++ ODM_delay_us(50); ++ } else if (Addr == 0xfa) { ++ ODM_delay_us(5); ++ } else if (Addr == 0xf9) { ++ ODM_delay_us(1); ++ } else { ++ if (Addr == 0xa24) ++ pDM_Odm->RFCalibrateInfo.RegA24 = Data; ++ ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); ++ ++ /* Add 1us delay between BB/RF register setting. */ ++ ODM_delay_us(1); ++ } ++} +diff --git a/drivers/staging/r8188eu/hal/odm_debug.c b/drivers/staging/r8188eu/hal/odm_debug.c +new file mode 100644 +index 000000000000..7029ec4f771e +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/odm_debug.c +@@ -0,0 +1,6 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++ ++u32 GlobalDebugLevel; +diff --git a/drivers/staging/r8188eu/hal/odm_interface.c b/drivers/staging/r8188eu/hal/odm_interface.c +new file mode 100644 +index 000000000000..5a01495d74bc +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/odm_interface.c +@@ -0,0 +1,178 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/odm_precomp.h" ++/* ODM IO Relative API. */ ++ ++u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ return rtw_read8(Adapter, RegAddr); ++} ++ ++u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ return rtw_read16(Adapter, RegAddr); ++} ++ ++u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ return rtw_read32(Adapter, RegAddr); ++} ++ ++void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ rtw_write8(Adapter, RegAddr, Data); ++} ++ ++void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ rtw_write16(Adapter, RegAddr, Data); ++} ++ ++void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ rtw_write32(Adapter, RegAddr, Data); ++} ++ ++void ODM_SetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); ++} ++ ++u32 ODM_GetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ return PHY_QueryBBReg(Adapter, RegAddr, BitMask); ++} ++ ++void ODM_SetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); ++} ++ ++u32 ODM_GetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ return PHY_QueryBBReg(Adapter, RegAddr, BitMask); ++} ++ ++void ODM_SetRFReg(struct odm_dm_struct *pDM_Odm, enum rf_radio_path eRFPath, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, RegAddr, BitMask, Data); ++} ++ ++u32 ODM_GetRFReg(struct odm_dm_struct *pDM_Odm, enum rf_radio_path eRFPath, u32 RegAddr, u32 BitMask) ++{ ++ struct adapter *Adapter = pDM_Odm->Adapter; ++ return PHY_QueryRFReg(Adapter, (enum rf_radio_path)eRFPath, RegAddr, BitMask); ++} ++ ++/* ODM Memory relative API. */ ++void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length) ++{ ++ *pPtr = vzalloc(length); ++} ++ ++/* length could be ignored, used to detect memory leakage. */ ++void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length) ++{ ++ vfree(pPtr); ++} ++ ++s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2, u32 length) ++{ ++ return !memcmp(pBuf1, pBuf2, length); ++} ++ ++/* ODM MISC relative API. */ ++void ODM_AcquireSpinLock(struct odm_dm_struct *pDM_Odm, enum RT_SPINLOCK_TYPE type) ++{ ++} ++ ++void ODM_ReleaseSpinLock(struct odm_dm_struct *pDM_Odm, enum RT_SPINLOCK_TYPE type) ++{ ++} ++ ++/* Work item relative API. FOr MP driver only~! */ ++void ODM_InitializeWorkItem(struct odm_dm_struct *pDM_Odm, void *pRtWorkItem, ++ RT_WORKITEM_CALL_BACK RtWorkItemCallback, ++ void *pContext, const char *szID) ++{ ++} ++ ++void ODM_StartWorkItem(void *pRtWorkItem) ++{ ++} ++ ++void ODM_StopWorkItem(void *pRtWorkItem) ++{ ++} ++ ++void ODM_FreeWorkItem(void *pRtWorkItem) ++{ ++} ++ ++void ODM_ScheduleWorkItem(void *pRtWorkItem) ++{ ++} ++ ++void ODM_IsWorkItemScheduled(void *pRtWorkItem) ++{ ++} ++ ++/* ODM Timer relative API. */ ++void ODM_StallExecution(u32 usDelay) ++{ ++ udelay(usDelay); ++} ++ ++void ODM_delay_ms(u32 ms) ++{ ++ mdelay(ms); ++} ++ ++void ODM_delay_us(u32 us) ++{ ++ udelay(us); ++} ++ ++void ODM_sleep_ms(u32 ms) ++{ ++ msleep(ms); ++} ++ ++void ODM_sleep_us(u32 us) ++{ ++ rtw_usleep_os(us); ++} ++ ++void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer, u32 msDelay) ++{ ++ _set_timer(pTimer, msDelay); /* ms */ ++} ++ ++void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer) ++{ ++ _cancel_timer_ex(pTimer); ++} ++ ++void ODM_ReleaseTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer) ++{ ++} ++ ++/* ODM FW relative API. */ ++u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum, ++ u32 *pElementID, u32 *pCmdLen, ++ u8 **pCmbBuffer, u8 *CmdStartSeq) ++{ ++ return true; ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_cmd.c b/drivers/staging/r8188eu/hal/rtl8188e_cmd.c +new file mode 100644 +index 000000000000..7d50d64cf34d +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_cmd.c +@@ -0,0 +1,737 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTL8188E_CMD_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/mlme_osdep.h" ++#include "../include/rtw_ioctl_set.h" ++ ++#include "../include/rtl8188e_hal.h" ++ ++#define RTL88E_MAX_H2C_BOX_NUMS 4 ++#define RTL88E_MAX_CMD_LEN 7 ++#define RTL88E_MESSAGE_BOX_SIZE 4 ++#define RTL88E_EX_MESSAGE_BOX_SIZE 4 ++ ++static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num) ++{ ++ u8 read_down = false; ++ int retry_cnts = 100; ++ ++ u8 valid; ++ ++ do { ++ valid = rtw_read8(adapt, REG_HMETFR) & BIT(msgbox_num); ++ if (0 == valid) ++ read_down = true; ++ } while ((!read_down) && (retry_cnts--)); ++ ++ return read_down; ++} ++ ++/***************************************** ++* H2C Msg format : ++* 0x1DF - 0x1D0 ++*| 31 - 8 | 7-5 4 - 0 | ++*| h2c_msg |Class_ID CMD_ID | ++* ++* Extend 0x1FF - 0x1F0 ++*|31 - 0 | ++*|ext_msg| ++******************************************/ ++static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) ++{ ++ u8 bcmd_down = false; ++ s32 retry_cnts = 100; ++ u8 h2c_box_num; ++ u32 msgbox_addr; ++ u32 msgbox_ex_addr; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ u8 cmd_idx, ext_cmd_len; ++ u32 h2c_cmd = 0; ++ u32 h2c_cmd_ex = 0; ++ s32 ret = _FAIL; ++ ++ if (!adapt->bFWReady) { ++ DBG_88E("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n"); ++ return ret; ++ } ++ ++ if (!pCmdBuffer) ++ goto exit; ++ if (CmdLen > RTL88E_MAX_CMD_LEN) ++ goto exit; ++ if (adapt->bSurpriseRemoved) ++ goto exit; ++ ++ /* pay attention to if race condition happened in H2C cmd setting. */ ++ do { ++ h2c_box_num = haldata->LastHMEBoxNum; ++ ++ if (!_is_fw_read_cmd_down(adapt, h2c_box_num)) { ++ DBG_88E(" fw read cmd failed...\n"); ++ goto exit; ++ } ++ ++ *(u8 *)(&h2c_cmd) = ElementID; ++ ++ if (CmdLen <= 3) { ++ memcpy((u8 *)(&h2c_cmd) + 1, pCmdBuffer, CmdLen); ++ } else { ++ memcpy((u8 *)(&h2c_cmd) + 1, pCmdBuffer, 3); ++ ext_cmd_len = CmdLen - 3; ++ memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer + 3, ext_cmd_len); ++ ++ /* Write Ext command */ ++ msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * RTL88E_EX_MESSAGE_BOX_SIZE); ++ for (cmd_idx = 0; cmd_idx < ext_cmd_len; cmd_idx++) { ++ rtw_write8(adapt, msgbox_ex_addr + cmd_idx, *((u8 *)(&h2c_cmd_ex) + cmd_idx)); ++ } ++ } ++ /* Write command */ ++ msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * RTL88E_MESSAGE_BOX_SIZE); ++ for (cmd_idx = 0; cmd_idx < RTL88E_MESSAGE_BOX_SIZE; cmd_idx++) { ++ rtw_write8(adapt, msgbox_addr + cmd_idx, *((u8 *)(&h2c_cmd) + cmd_idx)); ++ } ++ bcmd_down = true; ++ ++ haldata->LastHMEBoxNum = (h2c_box_num + 1) % RTL88E_MAX_H2C_BOX_NUMS; ++ ++ } while ((!bcmd_down) && (retry_cnts--)); ++ ++ ret = _SUCCESS; ++ ++exit: ++ ++ return ret; ++} ++ ++u8 rtl8188e_set_rssi_cmd(struct adapter *adapt, u8 *param) ++{ ++ u8 res = _SUCCESS; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ ++ if (haldata->fw_ractrl) { ++ ; ++ } else { ++ DBG_88E("==>%s fw dont support RA\n", __func__); ++ res = _FAIL; ++ } ++ ++ return res; ++} ++ ++u8 rtl8188e_set_raid_cmd(struct adapter *adapt, u32 mask) ++{ ++ u8 buf[3]; ++ u8 res = _SUCCESS; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ ++ if (haldata->fw_ractrl) { ++ __le32 lmask; ++ ++ memset(buf, 0, 3); ++ lmask = cpu_to_le32(mask); ++ memcpy(buf, &lmask, 3); ++ ++ FillH2CCmd_88E(adapt, H2C_DM_MACID_CFG, 3, buf); ++ } else { ++ DBG_88E("==>%s fw dont support RA\n", __func__); ++ res = _FAIL; ++ } ++ ++ return res; ++} ++ ++/* bitmap[0:27] = tx_rate_bitmap */ ++/* bitmap[28:31]= Rate Adaptive id */ ++/* arg[0:4] = macid */ ++/* arg[5] = Short GI */ ++void rtl8188e_Add_RateATid(struct adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(pAdapter); ++ ++ u8 macid, raid, short_gi_rate = false; ++ ++ macid = arg & 0x1f; ++ ++ raid = (bitmap >> 28) & 0x0f; ++ bitmap &= 0x0fffffff; ++ ++ if (rssi_level != DM_RATR_STA_INIT) ++ bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, macid, bitmap, rssi_level); ++ ++ bitmap |= ((raid << 28) & 0xf0000000); ++ ++ short_gi_rate = (arg & BIT(5)) ? true : false; ++ ++ raid = (bitmap >> 28) & 0x0f; ++ ++ bitmap &= 0x0fffffff; ++ ++ ODM_RA_UpdateRateInfo_8188E(&haldata->odmpriv, macid, raid, bitmap, short_gi_rate); ++} ++ ++void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode) ++{ ++ struct setpwrmode_parm H2CSetPwrMode; ++ struct pwrctrl_priv *pwrpriv = &adapt->pwrctrlpriv; ++ u8 RLBM = 0; /* 0:Min, 1:Max, 2:User define */ ++ ++ DBG_88E("%s: Mode=%d SmartPS=%d UAPSD=%d\n", __func__, ++ Mode, pwrpriv->smart_ps, adapt->registrypriv.uapsd_enable); ++ ++ switch (Mode) { ++ case PS_MODE_ACTIVE: ++ H2CSetPwrMode.Mode = 0; ++ break; ++ case PS_MODE_MIN: ++ H2CSetPwrMode.Mode = 1; ++ break; ++ case PS_MODE_MAX: ++ RLBM = 1; ++ H2CSetPwrMode.Mode = 1; ++ break; ++ case PS_MODE_DTIM: ++ RLBM = 2; ++ H2CSetPwrMode.Mode = 1; ++ break; ++ case PS_MODE_UAPSD_WMM: ++ H2CSetPwrMode.Mode = 2; ++ break; ++ default: ++ H2CSetPwrMode.Mode = 0; ++ break; ++ } ++ ++ H2CSetPwrMode.SmartPS_RLBM = (((pwrpriv->smart_ps << 4) & 0xf0) | (RLBM & 0x0f)); ++ ++ H2CSetPwrMode.AwakeInterval = 1; ++ ++ H2CSetPwrMode.bAllQueueUAPSD = adapt->registrypriv.uapsd_enable; ++ ++ if (Mode > 0) ++ H2CSetPwrMode.PwrState = 0x00;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ ++ else ++ H2CSetPwrMode.PwrState = 0x0C;/* AllON(0x0C), RFON(0x04), RFOFF(0x00) */ ++ ++ FillH2CCmd_88E(adapt, H2C_PS_PWR_MODE, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode); ++ ++} ++ ++void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt) ++{ ++ u8 opmode, macid; ++ u16 mst_rpt = le16_to_cpu(mstatus_rpt); ++ opmode = (u8)mst_rpt; ++ macid = (u8)(mst_rpt >> 8); ++ ++ DBG_88E("### %s: MStatus=%x MACID=%d\n", __func__, opmode, macid); ++ FillH2CCmd_88E(adapt, H2C_COM_MEDIA_STATUS_RPT, sizeof(mst_rpt), (u8 *)&mst_rpt); ++} ++ ++static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ u32 rate_len, pktlen; ++ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ ++ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&adapt->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); ++ SetFrameSubType(pframe, WIFI_BEACON); ++ ++ pframe += sizeof(struct rtw_ieee80211_hdr_3addr); ++ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ ++ /* timestamp will be inserted by hardware */ ++ pframe += 8; ++ pktlen += 8; ++ ++ /* beacon interval: 2 bytes */ ++ memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pktlen += 2; ++ ++ /* capability info: 2 bytes */ ++ memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); ++ ++ pframe += 2; ++ pktlen += 2; ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { ++ pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fixed_ie); ++ memcpy(pframe, cur_network->IEs + sizeof(struct ndis_802_11_fixed_ie), pktlen); ++ ++ goto _ConstructBeacon; ++ } ++ ++ /* below for ad-hoc mode */ ++ ++ /* SSID */ ++ pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); ++ ++ /* supported rates... */ ++ rate_len = rtw_get_rateset_len(cur_network->SupportedRates); ++ pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); ++ ++ /* DS parameter set */ ++ pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&cur_network->Configuration.DSConfig, &pktlen); ++ ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { ++ u32 ATIMWindow; ++ /* IBSS Parameter Set... */ ++ ATIMWindow = 0; ++ pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); ++ } ++ ++ /* todo: ERP IE */ ++ ++ /* EXTERNDED SUPPORTED RATE */ ++ if (rate_len > 8) ++ pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); ++ ++ /* todo:HT for adhoc */ ++ ++_ConstructBeacon: ++ ++ if ((pktlen + TXDESC_SIZE) > 512) { ++ DBG_88E("beacon frame too large\n"); ++ return; ++ } ++ ++ *pLength = pktlen; ++} ++ ++static void ConstructPSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ __le16 *fctrl; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ /* Frame control. */ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ SetPwrMgt(fctrl); ++ SetFrameSubType(pframe, WIFI_PSPOLL); ++ ++ /* AID. */ ++ SetDuration(pframe, (pmlmeinfo->aid | 0xc000)); ++ ++ /* BSSID. */ ++ memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ ++ /* TA. */ ++ memcpy(pwlanhdr->addr2, myid(&adapt->eeprompriv), ETH_ALEN); ++ ++ *pLength = 16; ++} ++ ++static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe, ++ u32 *pLength, ++ u8 *StaAddr, ++ u8 bQoS, ++ u8 AC, ++ u8 bEosp, ++ u8 bForcePowerSave) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ u32 pktlen; ++ struct mlme_priv *pmlmepriv = &adapt->mlmepriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ if (bForcePowerSave) ++ SetPwrMgt(fctrl); ++ ++ switch (cur_network->network.InfrastructureMode) { ++ case Ndis802_11Infrastructure: ++ SetToDs(fctrl); ++ memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&adapt->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); ++ break; ++ case Ndis802_11APMode: ++ SetFrDs(fctrl); ++ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, myid(&adapt->eeprompriv), ETH_ALEN); ++ break; ++ case Ndis802_11IBSS: ++ default: ++ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, myid(&adapt->eeprompriv), ETH_ALEN); ++ memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); ++ break; ++ } ++ ++ SetSeqNum(pwlanhdr, 0); ++ ++ if (bQoS) { ++ struct rtw_ieee80211_hdr_3addr_qos *pwlanqoshdr; ++ ++ SetFrameSubType(pframe, WIFI_QOS_DATA_NULL); ++ ++ pwlanqoshdr = (struct rtw_ieee80211_hdr_3addr_qos *)pframe; ++ SetPriority(&pwlanqoshdr->qc, AC); ++ SetEOSP(&pwlanqoshdr->qc, bEosp); ++ ++ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); ++ } else { ++ SetFrameSubType(pframe, WIFI_DATA_NULL); ++ ++ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ } ++ ++ *pLength = pktlen; ++} ++ ++static void ConstructProbeRsp(struct adapter *adapt, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID) ++{ ++ struct rtw_ieee80211_hdr *pwlanhdr; ++ __le16 *fctrl; ++ u8 *mac, *bssid; ++ u32 pktlen; ++ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ ++ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; ++ ++ mac = myid(&adapt->eeprompriv); ++ bssid = cur_network->MacAddress; ++ ++ fctrl = &pwlanhdr->frame_ctl; ++ *(fctrl) = 0; ++ memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); ++ memcpy(pwlanhdr->addr2, mac, ETH_ALEN); ++ memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); ++ ++ SetSeqNum(pwlanhdr, 0); ++ SetFrameSubType(fctrl, WIFI_PROBERSP); ++ ++ pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); ++ pframe += pktlen; ++ ++ if (cur_network->IELength > MAX_IE_SZ) ++ return; ++ ++ memcpy(pframe, cur_network->IEs, cur_network->IELength); ++ pframe += cur_network->IELength; ++ pktlen += cur_network->IELength; ++ ++ *pLength = pktlen; ++} ++ ++/* To check if reserved page content is destroyed by beacon because beacon is too large. */ ++/* 2010.06.23. Added by tynli. */ ++void CheckFwRsvdPageContent(struct adapter *Adapter) ++{ ++} ++ ++/* */ ++/* Description: Fill the reserved packets that FW will use to RSVD page. */ ++/* Now we just send 4 types packet to rsvd page. */ ++/* (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */ ++/* Input: */ ++/* bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */ ++/* so we need to set the packet length to total length. */ ++/* true: At the second time, we should send the first packet (default:beacon) */ ++/* to Hw again and set the length in descriptor to the real beacon length. */ ++/* 2009.10.15 by tynli. */ ++static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished) ++{ ++ struct hal_data_8188e *haldata; ++ struct xmit_frame *pmgntframe; ++ struct pkt_attrib *pattrib; ++ struct xmit_priv *pxmitpriv; ++ struct mlme_ext_priv *pmlmeext; ++ struct mlme_ext_info *pmlmeinfo; ++ u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength; ++ u32 NullDataLength, QosNullLength; ++ u8 *ReservedPagePacket; ++ u8 PageNum, PageNeed, TxDescLen; ++ u16 BufIndex; ++ u32 TotalPacketLen; ++ struct rsvdpage_loc RsvdPageLoc; ++ ++ DBG_88E("%s\n", __func__); ++ ReservedPagePacket = kzalloc(1000, GFP_KERNEL); ++ if (!ReservedPagePacket) { ++ DBG_88E("%s: alloc ReservedPagePacket fail!\n", __func__); ++ return; ++ } ++ ++ haldata = GET_HAL_DATA(adapt); ++ pxmitpriv = &adapt->xmitpriv; ++ pmlmeext = &adapt->mlmeextpriv; ++ pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ TxDescLen = TXDESC_SIZE; ++ PageNum = 0; ++ ++ /* 3 (1) beacon * 2 pages */ ++ BufIndex = TXDESC_OFFSET; ++ ConstructBeacon(adapt, &ReservedPagePacket[BufIndex], &BeaconLength); ++ ++ /* When we count the first page size, we need to reserve description size for the RSVD */ ++ /* packet, it will be filled in front of the packet in TXPKTBUF. */ ++ PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength); ++ /* To reserved 2 pages for beacon buffer. 2010.06.24. */ ++ if (PageNeed == 1) ++ PageNeed += 1; ++ PageNum += PageNeed; ++ haldata->FwRsvdPageStartOffset = PageNum; ++ ++ BufIndex += PageNeed * 128; ++ ++ /* 3 (2) ps-poll *1 page */ ++ RsvdPageLoc.LocPsPoll = PageNum; ++ ConstructPSPoll(adapt, &ReservedPagePacket[BufIndex], &PSPollLength); ++ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex - TxDescLen], PSPollLength, true, false); ++ ++ PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength); ++ PageNum += PageNeed; ++ ++ BufIndex += PageNeed * 128; ++ ++ /* 3 (3) null data * 1 page */ ++ RsvdPageLoc.LocNullData = PageNum; ++ ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, get_my_bssid(&pmlmeinfo->network), false, 0, 0, false); ++ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex - TxDescLen], NullDataLength, false, false); ++ ++ PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength); ++ PageNum += PageNeed; ++ ++ BufIndex += PageNeed * 128; ++ ++ /* 3 (4) probe response * 1page */ ++ RsvdPageLoc.LocProbeRsp = PageNum; ++ ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, get_my_bssid(&pmlmeinfo->network), false); ++ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex - TxDescLen], ProbeRspLength, false, false); ++ ++ PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength); ++ PageNum += PageNeed; ++ ++ BufIndex += PageNeed * 128; ++ ++ /* 3 (5) Qos null data */ ++ RsvdPageLoc.LocQosNull = PageNum; ++ ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], ++ &QosNullLength, get_my_bssid(&pmlmeinfo->network), true, 0, 0, false); ++ rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex - TxDescLen], QosNullLength, false, false); ++ ++ PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength); ++ PageNum += PageNeed; ++ ++ TotalPacketLen = BufIndex + QosNullLength; ++ pmgntframe = alloc_mgtxmitframe(pxmitpriv); ++ if (!pmgntframe) ++ goto exit; ++ ++ /* update attribute */ ++ pattrib = &pmgntframe->attrib; ++ update_mgntframe_attrib(adapt, pattrib); ++ pattrib->qsel = 0x10; ++ pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET; ++ pattrib->pktlen = pattrib->last_txcmdsz; ++ memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen); ++ ++ rtw_hal_mgnt_xmit(adapt, pmgntframe); ++ ++ DBG_88E("%s: Set RSVD page location to Fw\n", __func__); ++ FillH2CCmd_88E(adapt, H2C_COM_RSVD_PAGE, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc); ++ ++exit: ++ kfree(ReservedPagePacket); ++} ++ ++void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ bool bSendBeacon = false; ++ bool bcn_valid = false; ++ u8 DLBcnCount = 0; ++ u32 poll = 0; ++ ++ DBG_88E("%s mstatus(%x)\n", __func__, mstatus); ++ ++ if (mstatus == 1) { ++ /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ ++ /* Suggested by filen. Added by tynli. */ ++ rtw_write16(adapt, REG_BCN_PSR_RPT, (0xC000 | pmlmeinfo->aid)); ++ /* Do not set TSF again here or vWiFi beacon DMA INT will not work. */ ++ ++ /* Set REG_CR bit 8. DMA beacon by SW. */ ++ haldata->RegCR_1 |= BIT(0); ++ rtw_write8(adapt, REG_CR + 1, haldata->RegCR_1); ++ ++ /* Disable Hw protection for a time which revserd for Hw sending beacon. */ ++ /* Fix download reserved page packet fail that access collision with the protection time. */ ++ /* 2010.05.11. Added by tynli. */ ++ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) & (~BIT(3))); ++ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) | BIT(4)); ++ ++ if (haldata->RegFwHwTxQCtrl & BIT(6)) { ++ DBG_88E("HalDownloadRSVDPage(): There is an Adapter is sending beacon.\n"); ++ bSendBeacon = true; ++ } ++ ++ /* Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame. */ ++ rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl & (~BIT(6)))); ++ haldata->RegFwHwTxQCtrl &= (~BIT(6)); ++ ++ /* Clear beacon valid check bit. */ ++ rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL); ++ DLBcnCount = 0; ++ poll = 0; ++ do { ++ /* download rsvd page. */ ++ SetFwRsvdPagePkt(adapt, false); ++ DLBcnCount++; ++ do { ++ yield(); ++ /* mdelay(10); */ ++ /* check rsvd page download OK. */ ++ rtw_hal_get_hwreg(adapt, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid)); ++ poll++; ++ } while (!bcn_valid && (poll % 10) != 0 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped); ++ } while (!bcn_valid && DLBcnCount <= 100 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped); ++ ++ if (adapt->bSurpriseRemoved || adapt->bDriverStopped) ++ ; ++ else if (!bcn_valid) ++ DBG_88E("%s: 1 Download RSVD page failed! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll); ++ else ++ DBG_88E("%s: 1 Download RSVD success! DLBcnCount:%u, poll:%u\n", __func__, DLBcnCount, poll); ++ /* */ ++ /* We just can send the reserved page twice during the time that Tx thread is stopped (e.g. pnpsetpower) */ ++ /* because we need to free the Tx BCN Desc which is used by the first reserved page packet. */ ++ /* At run time, we cannot get the Tx Desc until it is released in TxHandleInterrupt() so we will return */ ++ /* the beacon TCB in the following code. 2011.11.23. by tynli. */ ++ /* */ ++ ++ /* Enable Bcn */ ++ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) | BIT(3)); ++ rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) & (~BIT(4))); ++ ++ /* To make sure that if there exists an adapter which would like to send beacon. */ ++ /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ ++ /* prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */ ++ /* the beacon cannot be sent by HW. */ ++ /* 2010.06.23. Added by tynli. */ ++ if (bSendBeacon) { ++ rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl | BIT(6))); ++ haldata->RegFwHwTxQCtrl |= BIT(6); ++ } ++ ++ /* Update RSVD page location H2C to Fw. */ ++ if (bcn_valid) { ++ rtw_hal_set_hwreg(adapt, HW_VAR_BCN_VALID, NULL); ++ DBG_88E("Set RSVD page location to Fw.\n"); ++ } ++ ++ /* Do not enable HW DMA BCN or it will cause Pcie interface hang by timing issue. 2011.11.24. by tynli. */ ++ /* Clear CR[8] or beacon packet will not be send to TxBuf anymore. */ ++ haldata->RegCR_1 &= (~BIT(0)); ++ rtw_write8(adapt, REG_CR + 1, haldata->RegCR_1); ++ } ++ ++} ++ ++void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state) ++{ ++#ifdef CONFIG_88EU_P2P ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ struct wifidirect_info *pwdinfo = &adapt->wdinfo; ++ struct P2P_PS_Offload_t *p2p_ps_offload = &haldata->p2p_ps_offload; ++ u8 i; ++ ++ switch (p2p_ps_state) { ++ case P2P_PS_DISABLE: ++ DBG_88E("P2P_PS_DISABLE\n"); ++ memset(p2p_ps_offload, 0, 1); ++ break; ++ case P2P_PS_ENABLE: ++ DBG_88E("P2P_PS_ENABLE\n"); ++ /* update CTWindow value. */ ++ if (pwdinfo->ctwindow > 0) { ++ p2p_ps_offload->CTWindow_En = 1; ++ rtw_write8(adapt, REG_P2P_CTWIN, pwdinfo->ctwindow); ++ } ++ ++ /* hw only support 2 set of NoA */ ++ for (i = 0; i < pwdinfo->noa_num; i++) { ++ /* To control the register setting for which NOA */ ++ rtw_write8(adapt, REG_NOA_DESC_SEL, (i << 4)); ++ if (i == 0) ++ p2p_ps_offload->NoA0_En = 1; ++ else ++ p2p_ps_offload->NoA1_En = 1; ++ ++ /* config P2P NoA Descriptor Register */ ++ rtw_write32(adapt, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]); ++ rtw_write32(adapt, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]); ++ rtw_write32(adapt, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]); ++ rtw_write8(adapt, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]); ++ } ++ ++ if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) { ++ /* rst p2p circuit */ ++ rtw_write8(adapt, REG_DUAL_TSF_RST, BIT(4)); ++ ++ p2p_ps_offload->Offload_En = 1; ++ ++ if (pwdinfo->role == P2P_ROLE_GO) { ++ p2p_ps_offload->role = 1; ++ p2p_ps_offload->AllStaSleep = 0; ++ } else { ++ p2p_ps_offload->role = 0; ++ } ++ ++ p2p_ps_offload->discovery = 0; ++ } ++ break; ++ case P2P_PS_SCAN: ++ DBG_88E("P2P_PS_SCAN\n"); ++ p2p_ps_offload->discovery = 1; ++ break; ++ case P2P_PS_SCAN_DONE: ++ DBG_88E("P2P_PS_SCAN_DONE\n"); ++ p2p_ps_offload->discovery = 0; ++ pwdinfo->p2p_ps_state = P2P_PS_ENABLE; ++ break; ++ default: ++ break; ++ } ++ ++ FillH2CCmd_88E(adapt, H2C_PS_P2P_OFFLOAD, 1, (u8 *)p2p_ps_offload); ++#endif ++ ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_dm.c b/drivers/staging/r8188eu/hal/rtl8188e_dm.c +new file mode 100644 +index 000000000000..78552303c990 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_dm.c +@@ -0,0 +1,238 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++/* This file is for 92CE/92CU dynamic mechanism only */ ++#define _RTL8188E_DM_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtl8188e_hal.h" ++ ++static void dm_CheckStatistics(struct adapter *Adapter) ++{ ++} ++ ++/* Initialize GPIO setting registers */ ++static void dm_InitGPIOSetting(struct adapter *Adapter) ++{ ++ u8 tmp1byte; ++ ++ tmp1byte = rtw_read8(Adapter, REG_GPIO_MUXCFG); ++ tmp1byte &= (GPIOSEL_GPIO | ~GPIOSEL_ENBT); ++ ++ rtw_write8(Adapter, REG_GPIO_MUXCFG, tmp1byte); ++} ++ ++/* */ ++/* functions */ ++/* */ ++static void Init_ODM_ComInfo_88E(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &hal_data->dmpriv; ++ struct odm_dm_struct *dm_odm = &hal_data->odmpriv; ++ u8 cut_ver, fab_ver; ++ ++ /* Init Value */ ++ memset(dm_odm, 0, sizeof(*dm_odm)); ++ ++ dm_odm->Adapter = Adapter; ++ ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PLATFORM, ODM_CE); ++ ++ if (Adapter->interface_type == RTW_GSPI) ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_INTERFACE, ODM_ITRF_SDIO); ++ else ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_INTERFACE, Adapter->interface_type);/* RTL871X_HCI_TYPE */ ++ ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_IC_TYPE, ODM_RTL8188E); ++ ++ fab_ver = ODM_TSMC; ++ cut_ver = ODM_CUT_A; ++ ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_FAB_VER, fab_ver); ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_CUT_VER, cut_ver); ++ ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(hal_data->VersionID)); ++ ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_PATCH_ID, hal_data->CustomerID); ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_BWIFI_TEST, Adapter->registrypriv.wifi_spec); ++ ++ if (hal_data->rf_type == RF_1T1R) ++ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R); ++ else if (hal_data->rf_type == RF_2T2R) ++ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R); ++ else if (hal_data->rf_type == RF_1T2R) ++ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R); ++ ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_RF_ANTENNA_TYPE, hal_data->TRxAntDivType); ++ ++ pdmpriv->InitODMFlag = ODM_RF_CALIBRATION | ++ ODM_RF_TX_PWR_TRACK; ++ ++ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag); ++} ++ ++static void Update_ODM_ComInfo_88E(struct adapter *Adapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; ++ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); ++ struct odm_dm_struct *dm_odm = &hal_data->odmpriv; ++ struct dm_priv *pdmpriv = &hal_data->dmpriv; ++ int i; ++ ++ pdmpriv->InitODMFlag = 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_SAVE | ++ ODM_MAC_EDCA_TURBO | ++ ODM_RF_CALIBRATION | ++ ODM_RF_TX_PWR_TRACK; ++ if (hal_data->AntDivCfg) ++ pdmpriv->InitODMFlag |= ODM_BB_ANT_DIV; ++ ++ if (Adapter->registrypriv.mp_mode == 1) { ++ pdmpriv->InitODMFlag = ODM_RF_CALIBRATION | ++ ODM_RF_TX_PWR_TRACK; ++ } ++ ++ ODM_CmnInfoUpdate(dm_odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag); ++ ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_TX_UNI, &Adapter->xmitpriv.tx_bytes); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_RX_UNI, &Adapter->recvpriv.rx_bytes); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_WM_MODE, &pmlmeext->cur_wireless_mode); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SEC_CHNL_OFFSET, &hal_data->nCur40MhzPrimeSC); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SEC_MODE, &Adapter->securitypriv.dot11PrivacyAlgrthm); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_BW, &hal_data->CurrentChannelBW); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_CHNL, &hal_data->CurrentChannel); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_NET_CLOSED, &Adapter->net_closed); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_MP_MODE, &Adapter->registrypriv.mp_mode); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_SCAN, &pmlmepriv->bScanInProcess); ++ ODM_CmnInfoHook(dm_odm, ODM_CMNINFO_POWER_SAVING, &pwrctrlpriv->bpower_saving); ++ ODM_CmnInfoInit(dm_odm, ODM_CMNINFO_RF_ANTENNA_TYPE, hal_data->TRxAntDivType); ++ ++ for (i = 0; i < NUM_STA; i++) ++ ODM_CmnInfoPtrArrayHook(dm_odm, ODM_CMNINFO_STA_STATUS, i, NULL); ++} ++ ++void rtl8188e_InitHalDm(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &hal_data->dmpriv; ++ struct odm_dm_struct *dm_odm = &hal_data->odmpriv; ++ ++ dm_InitGPIOSetting(Adapter); ++ pdmpriv->DM_Type = DM_Type_ByDriver; ++ pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE; ++ Update_ODM_ComInfo_88E(Adapter); ++ ODM_DMInit(dm_odm); ++ Adapter->fix_rate = 0xFF; ++} ++ ++void rtl8188e_HalDmWatchDog(struct adapter *Adapter) ++{ ++ bool fw_cur_in_ps = false; ++ bool fw_ps_awake = true; ++ u8 hw_init_completed = false; ++ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); ++ ++ ++ hw_init_completed = Adapter->hw_init_completed; ++ ++ if (!hw_init_completed) ++ return; ++ ++ fw_cur_in_ps = Adapter->pwrctrlpriv.bFwCurrentInPSMode; ++ rtw_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&fw_ps_awake)); ++ ++ /* Fw is under p2p powersaving mode, driver should stop dynamic mechanism. */ ++ /* modifed by thomas. 2011.06.11. */ ++ if (Adapter->wdinfo.p2p_ps_mode) ++ fw_ps_awake = false; ++ ++ if (hw_init_completed && ((!fw_cur_in_ps) && fw_ps_awake)) { ++ /* Calculate Tx/Rx statistics. */ ++ dm_CheckStatistics(Adapter); ++ ++ ++ } ++ ++ /* ODM */ ++ if (hw_init_completed) { ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ u8 bLinked = false; ++ ++ if ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE))) { ++ if (Adapter->stapriv.asoc_sta_count > 2) ++ bLinked = true; ++ } else {/* Station mode */ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ bLinked = true; ++ } ++ ++ ODM_CmnInfoUpdate(&hal_data->odmpriv, ODM_CMNINFO_LINK, bLinked); ++ ODM_DMWatchdog(&hal_data->odmpriv); ++ } ++} ++ ++void rtl8188e_init_dm_priv(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &hal_data->dmpriv; ++ ++ memset(pdmpriv, 0, sizeof(struct dm_priv)); ++ Init_ODM_ComInfo_88E(Adapter); ++} ++ ++void rtl8188e_deinit_dm_priv(struct adapter *Adapter) ++{ ++} ++ ++/* Add new function to reset the state of antenna diversity before link. */ ++/* Compare RSSI for deciding antenna */ ++void AntDivCompare8188E(struct adapter *Adapter, struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src) ++{ ++ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); ++ ++ if (0 != hal_data->AntDivCfg) { ++ /* select optimum_antenna for before linked =>For antenna diversity */ ++ if (dst->Rssi >= src->Rssi) {/* keep org parameter */ ++ src->Rssi = dst->Rssi; ++ src->PhyInfo.Optimum_antenna = dst->PhyInfo.Optimum_antenna; ++ } ++ } ++} ++ ++/* Add new function to reset the state of antenna diversity before link. */ ++u8 AntDivBeforeLink8188E(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *hal_data = GET_HAL_DATA(Adapter); ++ struct odm_dm_struct *dm_odm = &hal_data->odmpriv; ++ struct sw_ant_switch *dm_swat_tbl = &dm_odm->DM_SWAT_Table; ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ ++ /* Condition that does not need to use antenna diversity. */ ++ if (hal_data->AntDivCfg == 0) ++ return false; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ return false; ++ ++ if (dm_swat_tbl->SWAS_NoLink_State == 0) { ++ /* switch channel */ ++ dm_swat_tbl->SWAS_NoLink_State = 1; ++ dm_swat_tbl->CurAntenna = (dm_swat_tbl->CurAntenna == Antenna_A) ? Antenna_B : Antenna_A; ++ ++ rtw_antenna_select_cmd(Adapter, dm_swat_tbl->CurAntenna, false); ++ return true; ++ } else { ++ dm_swat_tbl->SWAS_NoLink_State = 0; ++ return false; ++ } ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +new file mode 100644 +index 000000000000..14758361960c +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +@@ -0,0 +1,2304 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _HAL_INIT_C_ ++ ++#include "../include/linux/firmware.h" ++#include "../include/drv_types.h" ++#include "../include/rtw_efuse.h" ++#include "../include/rtl8188e_hal.h" ++#include "../include/rtw_iol.h" ++#include "../include/usb_ops.h" ++ ++static void iol_mode_enable(struct adapter *padapter, u8 enable) ++{ ++ u8 reg_0xf0 = 0; ++ ++ if (enable) { ++ /* Enable initial offload */ ++ reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG); ++ rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 | SW_OFFLOAD_EN); ++ ++ if (!padapter->bFWReady) { ++ DBG_88E("bFWReady == false call reset 8051...\n"); ++ _8051Reset88E(padapter); ++ } ++ ++ } else { ++ /* disable initial offload */ ++ reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG); ++ rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 & ~SW_OFFLOAD_EN); ++ } ++} ++ ++static s32 iol_execute(struct adapter *padapter, u8 control) ++{ ++ s32 status = _FAIL; ++ u8 reg_0x88 = 0; ++ u32 start = 0, passing_time = 0; ++ ++ control = control & 0x0f; ++ reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0); ++ rtw_write8(padapter, REG_HMEBOX_E0, reg_0x88 | control); ++ ++ start = jiffies; ++ while ((reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0)) & control && ++ (passing_time = rtw_get_passing_time_ms(start)) < 1000) { ++ ; ++ } ++ ++ reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0); ++ status = (reg_0x88 & control) ? _FAIL : _SUCCESS; ++ if (reg_0x88 & control << 4) ++ status = _FAIL; ++ return status; ++} ++ ++static s32 iol_InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy) ++{ ++ s32 rst = _SUCCESS; ++ iol_mode_enable(padapter, 1); ++ rtw_write8(padapter, REG_TDECTRL + 1, txpktbuf_bndy); ++ rst = iol_execute(padapter, CMD_INIT_LLT); ++ iol_mode_enable(padapter, 0); ++ return rst; ++} ++ ++static void ++efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf) ++{ ++ u8 *efuseTbl = NULL; ++ u8 rtemp8; ++ u16 eFuse_Addr = 0; ++ u8 offset, wren; ++ u16 i, j; ++ u16 **eFuseWord = NULL; ++ u16 efuse_utilized = 0; ++ u8 u1temp = 0; ++ ++ efuseTbl = kzalloc(EFUSE_MAP_LEN_88E, GFP_KERNEL); ++ if (!efuseTbl) { ++ DBG_88E("%s: alloc efuseTbl fail!\n", __func__); ++ goto exit; ++ } ++ ++ eFuseWord = rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); ++ if (!eFuseWord) { ++ DBG_88E("%s: alloc eFuseWord fail!\n", __func__); ++ goto exit; ++ } ++ ++ /* 0. Refresh efuse init map as all oxFF. */ ++ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) ++ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) ++ eFuseWord[i][j] = 0xFFFF; ++ ++ /* */ ++ /* 1. Read the first byte to check if efuse is empty!!! */ ++ /* */ ++ /* */ ++ rtemp8 = *(phymap + eFuse_Addr); ++ if (rtemp8 != 0xFF) { ++ efuse_utilized++; ++ eFuse_Addr++; ++ } else { ++ DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, rtemp8); ++ goto exit; ++ } ++ ++ /* */ ++ /* 2. Read real efuse content. Filter PG header and every section data. */ ++ /* */ ++ while ((rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { ++ /* Check PG header for section num. */ ++ if ((rtemp8 & 0x1F) == 0x0F) { /* extended header */ ++ u1temp = ((rtemp8 & 0xE0) >> 5); ++ rtemp8 = *(phymap + eFuse_Addr); ++ if ((rtemp8 & 0x0F) == 0x0F) { ++ eFuse_Addr++; ++ rtemp8 = *(phymap + eFuse_Addr); ++ ++ if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) ++ eFuse_Addr++; ++ continue; ++ } else { ++ offset = ((rtemp8 & 0xF0) >> 1) | u1temp; ++ wren = (rtemp8 & 0x0F); ++ eFuse_Addr++; ++ } ++ } else { ++ offset = ((rtemp8 >> 4) & 0x0f); ++ wren = (rtemp8 & 0x0f); ++ } ++ ++ if (offset < EFUSE_MAX_SECTION_88E) { ++ /* Get word enable value from PG header */ ++ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { ++ /* Check word enable condition in the section */ ++ if (!(wren & 0x01)) { ++ rtemp8 = *(phymap + eFuse_Addr); ++ eFuse_Addr++; ++ efuse_utilized++; ++ eFuseWord[offset][i] = (rtemp8 & 0xff); ++ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) ++ break; ++ rtemp8 = *(phymap + eFuse_Addr); ++ eFuse_Addr++; ++ efuse_utilized++; ++ eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00); ++ ++ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) ++ break; ++ } ++ wren >>= 1; ++ } ++ } ++ /* Read next PG header */ ++ rtemp8 = *(phymap + eFuse_Addr); ++ ++ if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { ++ efuse_utilized++; ++ eFuse_Addr++; ++ } ++ } ++ ++ /* */ ++ /* 3. Collect 16 sections and 4 word unit into Efuse map. */ ++ /* */ ++ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) { ++ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { ++ efuseTbl[(i * 8) + (j * 2)] = (eFuseWord[i][j] & 0xff); ++ efuseTbl[(i * 8) + ((j * 2) + 1)] = ((eFuseWord[i][j] >> 8) & 0xff); ++ } ++ } ++ ++ /* */ ++ /* 4. Copy from Efuse map to output pointer memory!!! */ ++ /* */ ++ for (i = 0; i < _size_byte; i++) ++ pbuf[i] = efuseTbl[_offset + i]; ++ ++ /* */ ++ /* 5. Calculate Efuse utilization. */ ++ /* */ ++ ++exit: ++ kfree(efuseTbl); ++ kfree(eFuseWord); ++} ++ ++static void efuse_read_phymap_from_txpktbuf( ++ struct adapter *adapter, ++ int bcnhead, /* beacon head, where FW store len(2-byte) and efuse physical map. */ ++ u8 *content, /* buffer to store efuse physical map */ ++ u16 *size /* for efuse content: the max byte to read. will update to byte read */ ++ ) ++{ ++ u16 dbg_addr = 0; ++ u32 start = 0, passing_time = 0; ++ u8 reg_0x143 = 0; ++ __le32 lo32 = 0, hi32 = 0; ++ u16 len = 0, count = 0; ++ int i = 0; ++ u16 limit = *size; ++ ++ u8 *pos = content; ++ ++ if (bcnhead < 0) /* if not valid */ ++ bcnhead = rtw_read8(adapter, REG_TDECTRL + 1); ++ ++ DBG_88E("%s bcnhead:%d\n", __func__, bcnhead); ++ ++ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); ++ ++ dbg_addr = bcnhead * 128 / 8; /* 8-bytes addressing */ ++ ++ while (1) { ++ rtw_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr + i); ++ ++ rtw_write8(adapter, REG_TXPKTBUF_DBG, 0); ++ start = jiffies; ++ while (!(reg_0x143 = rtw_read8(adapter, REG_TXPKTBUF_DBG)) && ++ (passing_time = rtw_get_passing_time_ms(start)) < 1000) { ++ DBG_88E("%s polling reg_0x143:0x%02x, reg_0x106:0x%02x\n", __func__, reg_0x143, rtw_read8(adapter, 0x106)); ++ rtw_usleep_os(100); ++ } ++ ++ /* data from EEPROM needs to be in LE */ ++ lo32 = cpu_to_le32(rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L)); ++ hi32 = cpu_to_le32(rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H)); ++ ++ if (i == 0) { ++ /* Although lenc is only used in a debug statement, ++ * do not remove it as the rtw_read16() call consumes ++ * 2 bytes from the EEPROM source. ++ */ ++ u16 lenc = rtw_read16(adapter, REG_PKTBUF_DBG_DATA_L); ++ ++ len = le32_to_cpu(lo32) & 0x0000ffff; ++ ++ limit = (len - 2 < limit) ? len - 2 : limit; ++ ++ DBG_88E("%s len:%u, lenc:%u\n", __func__, len, lenc); ++ ++ memcpy(pos, ((u8 *)&lo32) + 2, (limit >= count + 2) ? 2 : limit - count); ++ count += (limit >= count + 2) ? 2 : limit - count; ++ pos = content + count; ++ } else { ++ memcpy(pos, ((u8 *)&lo32), (limit >= count + 4) ? 4 : limit - count); ++ count += (limit >= count + 4) ? 4 : limit - count; ++ pos = content + count; ++ } ++ ++ if (limit > count && len - 2 > count) { ++ memcpy(pos, (u8 *)&hi32, (limit >= count + 4) ? 4 : limit - count); ++ count += (limit >= count + 4) ? 4 : limit - count; ++ pos = content + count; ++ } ++ ++ if (limit <= count || len - 2 <= count) ++ break; ++ i++; ++ } ++ rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS); ++ DBG_88E("%s read count:%u\n", __func__, count); ++ *size = count; ++} ++ ++static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map) ++{ ++ s32 status = _FAIL; ++ u8 physical_map[512]; ++ u16 size = 512; ++ ++ rtw_write8(padapter, REG_TDECTRL + 1, txpktbuf_bndy); ++ memset(physical_map, 0xFF, 512); ++ rtw_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); ++ status = iol_execute(padapter, CMD_READ_EFUSE_MAP); ++ if (status == _SUCCESS) ++ efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size); ++ efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map); ++ return status; ++} ++ ++s32 rtl8188e_iol_efuse_patch(struct adapter *padapter) ++{ ++ s32 result = _SUCCESS; ++ ++ DBG_88E("==> %s\n", __func__); ++ if (rtw_IOL_applied(padapter)) { ++ iol_mode_enable(padapter, 1); ++ result = iol_execute(padapter, CMD_READ_EFUSE_MAP); ++ if (result == _SUCCESS) ++ result = iol_execute(padapter, CMD_EFUSE_PATCH); ++ ++ iol_mode_enable(padapter, 0); ++ } ++ return result; ++} ++ ++static s32 iol_ioconfig(struct adapter *padapter, u8 iocfg_bndy) ++{ ++ s32 rst = _SUCCESS; ++ ++ rtw_write8(padapter, REG_TDECTRL + 1, iocfg_bndy); ++ rst = iol_execute(padapter, CMD_IOCONFIG); ++ return rst; ++} ++ ++static int rtl8188e_IOL_exec_cmds_sync(struct adapter *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt) ++{ ++ struct pkt_attrib *pattrib = &xmit_frame->attrib; ++ u8 i; ++ int ret = _FAIL; ++ ++ if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS) ++ goto exit; ++ if (rtw_usb_bulk_size_boundary(adapter, TXDESC_SIZE + pattrib->last_txcmdsz)) { ++ if (rtw_IOL_append_END_cmd(xmit_frame) != _SUCCESS) ++ goto exit; ++ } ++ ++ dump_mgntframe_and_wait(adapter, xmit_frame, max_wating_ms); ++ ++ iol_mode_enable(adapter, 1); ++ for (i = 0; i < bndy_cnt; i++) { ++ u8 page_no = 0; ++ page_no = i * 2; ++ ret = iol_ioconfig(adapter, page_no); ++ if (ret != _SUCCESS) ++ break; ++ } ++ iol_mode_enable(adapter, 0); ++exit: ++ /* restore BCN_HEAD */ ++ rtw_write8(adapter, REG_TDECTRL + 1, 0); ++ return ret; ++} ++ ++void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int data_len) ++{ ++ u32 fifo_data, reg_140; ++ u32 addr, rstatus, loop = 0; ++ u16 data_cnts = (data_len / 8) + 1; ++ u8 *pbuf = vzalloc(data_len + 10); ++ DBG_88E("###### %s ######\n", __func__); ++ ++ rtw_write8(Adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); ++ if (pbuf) { ++ for (addr = 0; addr < data_cnts; addr++) { ++ rtw_write32(Adapter, 0x140, addr); ++ rtw_usleep_os(2); ++ loop = 0; ++ do { ++ rstatus = (reg_140 = rtw_read32(Adapter, REG_PKTBUF_DBG_CTRL) & BIT(24)); ++ if (rstatus) { ++ fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_L); ++ memcpy(pbuf + (addr * 8), &fifo_data, 4); ++ ++ fifo_data = rtw_read32(Adapter, REG_PKTBUF_DBG_DATA_H); ++ memcpy(pbuf + (addr * 8 + 4), &fifo_data, 4); ++ } ++ rtw_usleep_os(2); ++ } while (!rstatus && (loop++ < 10)); ++ } ++ rtw_IOL_cmd_buf_dump(Adapter, data_len, pbuf); ++ vfree(pbuf); ++ } ++ DBG_88E("###### %s ######\n", __func__); ++} ++ ++static void _FWDownloadEnable(struct adapter *padapter, bool enable) ++{ ++ u8 tmp; ++ ++ if (enable) { ++ /* MCU firmware download enable. */ ++ tmp = rtw_read8(padapter, REG_MCUFWDL); ++ rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01); ++ ++ /* 8051 reset */ ++ tmp = rtw_read8(padapter, REG_MCUFWDL + 2); ++ rtw_write8(padapter, REG_MCUFWDL + 2, tmp & 0xf7); ++ } else { ++ /* MCU firmware download disable. */ ++ tmp = rtw_read8(padapter, REG_MCUFWDL); ++ rtw_write8(padapter, REG_MCUFWDL, tmp & 0xfe); ++ ++ /* Reserved for fw extension. */ ++ rtw_write8(padapter, REG_MCUFWDL + 1, 0x00); ++ } ++} ++ ++#define MAX_REG_BOLCK_SIZE 196 ++ ++static int _BlockWrite(struct adapter *padapter, void *buffer, u32 buffSize) ++{ ++ int ret = _SUCCESS; ++ u32 blockSize_p1 = 4; /* (Default) Phase #1 : PCI muse use 4-byte write to download FW */ ++ u32 blockSize_p2 = 8; /* Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */ ++ u32 blockSize_p3 = 1; /* Phase #3 : Use 1-byte, the remnant of FW image. */ ++ u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0; ++ u32 remainSize_p1 = 0, remainSize_p2 = 0; ++ u8 *bufferPtr = (u8 *)buffer; ++ u32 i = 0, offset = 0; ++ ++ blockSize_p1 = MAX_REG_BOLCK_SIZE; ++ ++ /* 3 Phase #1 */ ++ blockCount_p1 = buffSize / blockSize_p1; ++ remainSize_p1 = buffSize % blockSize_p1; ++ ++ for (i = 0; i < blockCount_p1; i++) { ++ ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + i * blockSize_p1), blockSize_p1, (bufferPtr + i * blockSize_p1)); ++ if (ret == _FAIL) ++ goto exit; ++ } ++ ++ /* 3 Phase #2 */ ++ if (remainSize_p1) { ++ offset = blockCount_p1 * blockSize_p1; ++ ++ blockCount_p2 = remainSize_p1 / blockSize_p2; ++ remainSize_p2 = remainSize_p1 % blockSize_p2; ++ ++ for (i = 0; i < blockCount_p2; i++) { ++ ret = rtw_writeN(padapter, (FW_8188E_START_ADDRESS + offset + i * blockSize_p2), blockSize_p2, (bufferPtr + offset + i * blockSize_p2)); ++ ++ if (ret == _FAIL) ++ goto exit; ++ } ++ } ++ ++ /* 3 Phase #3 */ ++ if (remainSize_p2) { ++ offset = (blockCount_p1 * blockSize_p1) + (blockCount_p2 * blockSize_p2); ++ ++ blockCount_p3 = remainSize_p2 / blockSize_p3; ++ ++ for (i = 0; i < blockCount_p3; i++) { ++ ret = rtw_write8(padapter, (FW_8188E_START_ADDRESS + offset + i), *(bufferPtr + offset + i)); ++ ++ if (ret == _FAIL) ++ goto exit; ++ } ++ } ++ ++exit: ++ return ret; ++} ++ ++static int _PageWrite(struct adapter *padapter, u32 page, void *buffer, u32 size) ++{ ++ u8 value8; ++ u8 u8Page = (u8)(page & 0x07); ++ ++ value8 = (rtw_read8(padapter, REG_MCUFWDL + 2) & 0xF8) | u8Page; ++ rtw_write8(padapter, REG_MCUFWDL + 2, value8); ++ ++ return _BlockWrite(padapter, buffer, size); ++} ++ ++static int _WriteFW(struct adapter *padapter, void *buffer, u32 size) ++{ ++ /* Since we need dynamic decide method of dwonload fw, so we call this function to get chip version. */ ++ /* We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */ ++ int ret = _SUCCESS; ++ u32 pageNums, remainSize; ++ u32 page, offset; ++ u8 *bufferPtr = (u8 *)buffer; ++ ++ pageNums = size / MAX_PAGE_SIZE; ++ remainSize = size % MAX_PAGE_SIZE; ++ ++ for (page = 0; page < pageNums; page++) { ++ offset = page * MAX_PAGE_SIZE; ++ ret = _PageWrite(padapter, page, bufferPtr + offset, MAX_PAGE_SIZE); ++ ++ if (ret == _FAIL) ++ goto exit; ++ } ++ if (remainSize) { ++ offset = pageNums * MAX_PAGE_SIZE; ++ page = pageNums; ++ ret = _PageWrite(padapter, page, bufferPtr + offset, remainSize); ++ ++ if (ret == _FAIL) ++ goto exit; ++ } ++exit: ++ return ret; ++} ++ ++void _8051Reset88E(struct adapter *padapter) ++{ ++ u8 u1bTmp; ++ ++ u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1); ++ rtw_write8(padapter, REG_SYS_FUNC_EN + 1, u1bTmp & (~BIT(2))); ++ rtw_write8(padapter, REG_SYS_FUNC_EN + 1, u1bTmp | (BIT(2))); ++ DBG_88E("=====> _8051Reset88E(): 8051 reset success .\n"); ++} ++ ++static s32 _FWFreeToGo(struct adapter *padapter) ++{ ++ u32 counter = 0; ++ u32 value32; ++ ++ /* polling CheckSum report */ ++ do { ++ value32 = rtw_read32(padapter, REG_MCUFWDL); ++ if (value32 & FWDL_ChkSum_rpt) ++ break; ++ } while (counter++ < POLLING_READY_TIMEOUT_COUNT); ++ ++ if (counter >= POLLING_READY_TIMEOUT_COUNT) { ++ DBG_88E("%s: chksum report fail! REG_MCUFWDL:0x%08x\n", __func__, value32); ++ return _FAIL; ++ } ++ DBG_88E("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __func__, value32); ++ ++ value32 = rtw_read32(padapter, REG_MCUFWDL); ++ value32 |= MCUFWDL_RDY; ++ value32 &= ~WINTINI_RDY; ++ rtw_write32(padapter, REG_MCUFWDL, value32); ++ ++ _8051Reset88E(padapter); ++ ++ /* polling for FW ready */ ++ counter = 0; ++ do { ++ value32 = rtw_read32(padapter, REG_MCUFWDL); ++ if (value32 & WINTINI_RDY) { ++ DBG_88E("%s: Polling FW ready success!! REG_MCUFWDL:0x%08x\n", __func__, value32); ++ return _SUCCESS; ++ } ++ udelay(5); ++ } while (counter++ < POLLING_READY_TIMEOUT_COUNT); ++ ++ DBG_88E("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n", __func__, value32); ++ return _FAIL; ++} ++ ++#define IS_FW_81xxC(padapter) (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0) ++ ++static int load_firmware(struct rt_firmware *pFirmware, struct device *device) ++{ ++ s32 rtStatus = _SUCCESS; ++ const struct firmware *fw; ++ const char *fw_name = "rtlwifi/rtl8188eufw.bin"; ++ int err = request_firmware(&fw, fw_name, device); ++ ++ if (err) { ++ pr_err("Request firmware failed with error 0x%x\n", err); ++ rtStatus = _FAIL; ++ goto Exit; ++ } ++ if (!fw) { ++ pr_err("Firmware %s not available\n", fw_name); ++ rtStatus = _FAIL; ++ goto Exit; ++ } ++ if (fw->size > FW_8188E_SIZE) { ++ rtStatus = _FAIL; ++ goto Exit; ++ } ++ ++ pFirmware->szFwBuffer = kzalloc(FW_8188E_SIZE, GFP_KERNEL); ++ if (!pFirmware->szFwBuffer) { ++ pr_err("Failed to allocate pFirmware->szFwBuffer\n"); ++ rtStatus = _FAIL; ++ goto Exit; ++ } ++ memcpy(pFirmware->szFwBuffer, fw->data, fw->size); ++ pFirmware->ulFwLength = fw->size; ++ release_firmware(fw); ++ DBG_88E_LEVEL(_drv_info_, "+%s: !bUsedWoWLANFw, FmrmwareLen:%d+\n", __func__, pFirmware->ulFwLength); ++ ++Exit: ++ return rtStatus; ++} ++ ++s32 rtl8188e_FirmwareDownload(struct adapter *padapter) ++{ ++ s32 rtStatus = _SUCCESS; ++ u8 writeFW_retry = 0; ++ u32 fwdl_start_time; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ struct device *device = dvobj_to_dev(dvobj); ++ struct rt_firmware_hdr *pFwHdr = NULL; ++ u8 *pFirmwareBuf; ++ u32 FirmwareLen; ++ static int log_version; ++ ++ if (!dvobj->firmware.szFwBuffer) ++ rtStatus = load_firmware(&dvobj->firmware, device); ++ if (rtStatus == _FAIL) { ++ dvobj->firmware.szFwBuffer = NULL; ++ goto Exit; ++ } ++ pFirmwareBuf = dvobj->firmware.szFwBuffer; ++ FirmwareLen = dvobj->firmware.ulFwLength; ++ ++ /* To Check Fw header. Added by tynli. 2009.12.04. */ ++ pFwHdr = (struct rt_firmware_hdr *)dvobj->firmware.szFwBuffer; ++ ++ pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version); ++ pHalData->FirmwareSubVersion = pFwHdr->Subversion; ++ pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature); ++ ++ if (!log_version++) ++ pr_info("%sFirmware Version %d, SubVersion %d, Signature 0x%x\n", ++ DRIVER_PREFIX, pHalData->FirmwareVersion, ++ pHalData->FirmwareSubVersion, pHalData->FirmwareSignature); ++ ++ if (IS_FW_HEADER_EXIST(pFwHdr)) { ++ /* Shift 32 bytes for FW header */ ++ pFirmwareBuf = pFirmwareBuf + 32; ++ FirmwareLen = FirmwareLen - 32; ++ } ++ ++ /* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */ ++ /* or it will cause download Fw fail. 2010.02.01. by tynli. */ ++ if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) { /* 8051 RAM code */ ++ rtw_write8(padapter, REG_MCUFWDL, 0x00); ++ _8051Reset88E(padapter); ++ } ++ ++ _FWDownloadEnable(padapter, true); ++ fwdl_start_time = jiffies; ++ while (1) { ++ /* reset the FWDL chksum */ ++ rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_ChkSum_rpt); ++ ++ rtStatus = _WriteFW(padapter, pFirmwareBuf, FirmwareLen); ++ ++ if (rtStatus == _SUCCESS || ++ (rtw_get_passing_time_ms(fwdl_start_time) > 500 && writeFW_retry++ >= 3)) ++ break; ++ ++ DBG_88E("%s writeFW_retry:%u, time after fwdl_start_time:%ums\n", ++ __func__, writeFW_retry, rtw_get_passing_time_ms(fwdl_start_time) ++ ); ++ } ++ _FWDownloadEnable(padapter, false); ++ if (_SUCCESS != rtStatus) { ++ DBG_88E("DL Firmware failed!\n"); ++ goto Exit; ++ } ++ ++ rtStatus = _FWFreeToGo(padapter); ++ if (_SUCCESS != rtStatus) { ++ DBG_88E("DL Firmware failed!\n"); ++ goto Exit; ++ } ++ ++Exit: ++ return rtStatus; ++} ++ ++void rtl8188e_InitializeFirmwareVars(struct adapter *padapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ ++ /* Init Fw LPS related. */ ++ padapter->pwrctrlpriv.bFwCurrentInPSMode = false; ++ ++ /* Init H2C counter. by tynli. 2009.12.09. */ ++ pHalData->LastHMEBoxNum = 0; ++} ++ ++static void rtl8188e_free_hal_data(struct adapter *padapter) ++{ ++ ++ kfree(padapter->HalData); ++ padapter->HalData = NULL; ++ ++} ++ ++/* */ ++/* Efuse related code */ ++/* */ ++enum{ ++ VOLTAGE_V25 = 0x03, ++ LDOE25_SHIFT = 28, ++ }; ++ ++static bool ++hal_EfusePgPacketWrite2ByteHeader( ++ struct adapter *pAdapter, ++ u8 efuseType, ++ u16 *pAddr, ++ struct pgpkt *pTargetPkt, ++ bool bPseudoTest); ++static bool ++hal_EfusePgPacketWrite1ByteHeader( ++ struct adapter *pAdapter, ++ u8 efuseType, ++ u16 *pAddr, ++ struct pgpkt *pTargetPkt, ++ bool bPseudoTest); ++static bool ++hal_EfusePgPacketWriteData( ++ struct adapter *pAdapter, ++ u8 efuseType, ++ u16 *pAddr, ++ struct pgpkt *pTargetPkt, ++ bool bPseudoTest); ++ ++static void ++hal_EfusePowerSwitch_RTL8188E( ++ struct adapter *pAdapter, ++ u8 bWrite, ++ u8 PwrState) ++{ ++ u8 tempval; ++ u16 tmpV16; ++ ++ if (PwrState) { ++ rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); ++ ++ /* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */ ++ tmpV16 = rtw_read16(pAdapter, REG_SYS_ISO_CTRL); ++ if (!(tmpV16 & PWC_EV12V)) { ++ tmpV16 |= PWC_EV12V; ++ rtw_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16); ++ } ++ /* Reset: 0x0000h[28], default valid */ ++ tmpV16 = rtw_read16(pAdapter, REG_SYS_FUNC_EN); ++ if (!(tmpV16 & FEN_ELDR)) { ++ tmpV16 |= FEN_ELDR; ++ rtw_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16); ++ } ++ ++ /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */ ++ tmpV16 = rtw_read16(pAdapter, REG_SYS_CLKR); ++ if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { ++ tmpV16 |= (LOADER_CLK_EN | ANA8M); ++ rtw_write16(pAdapter, REG_SYS_CLKR, tmpV16); ++ } ++ ++ if (bWrite) { ++ /* Enable LDO 2.5V before read/write action */ ++ tempval = rtw_read8(pAdapter, EFUSE_TEST + 3); ++ tempval &= 0x0F; ++ tempval |= (VOLTAGE_V25 << 4); ++ rtw_write8(pAdapter, EFUSE_TEST + 3, (tempval | 0x80)); ++ } ++ } else { ++ rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF); ++ ++ if (bWrite) { ++ /* Disable LDO 2.5V after read/write action */ ++ tempval = rtw_read8(pAdapter, EFUSE_TEST + 3); ++ rtw_write8(pAdapter, EFUSE_TEST + 3, (tempval & 0x7F)); ++ } ++ } ++} ++ ++static void ++rtl8188e_EfusePowerSwitch( ++ struct adapter *pAdapter, ++ u8 bWrite, ++ u8 PwrState) ++{ ++ hal_EfusePowerSwitch_RTL8188E(pAdapter, bWrite, PwrState); ++} ++ ++static void Hal_EfuseReadEFuse88E(struct adapter *Adapter, ++ u16 _offset, ++ u16 _size_byte, ++ u8 *pbuf, ++ bool bPseudoTest ++ ) ++{ ++ u8 *efuseTbl = NULL; ++ u8 rtemp8[1]; ++ u16 eFuse_Addr = 0; ++ u8 offset, wren; ++ u16 i, j; ++ u16 **eFuseWord = NULL; ++ u16 efuse_utilized = 0; ++ u8 u1temp = 0; ++ ++ /* */ ++ /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ ++ /* */ ++ if ((_offset + _size_byte) > EFUSE_MAP_LEN_88E) {/* total E-Fuse table is 512bytes */ ++ DBG_88E("Hal_EfuseReadEFuse88E(): Invalid offset(%#x) with read bytes(%#x)!!\n", _offset, _size_byte); ++ goto exit; ++ } ++ ++ efuseTbl = kzalloc(EFUSE_MAP_LEN_88E, GFP_KERNEL); ++ if (!efuseTbl) { ++ DBG_88E("%s: alloc efuseTbl fail!\n", __func__); ++ goto exit; ++ } ++ ++ eFuseWord = rtw_malloc2d(EFUSE_MAX_SECTION_88E, EFUSE_MAX_WORD_UNIT, sizeof(u16)); ++ if (!eFuseWord) { ++ DBG_88E("%s: alloc eFuseWord fail!\n", __func__); ++ goto exit; ++ } ++ ++ /* 0. Refresh efuse init map as all oxFF. */ ++ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) ++ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) ++ eFuseWord[i][j] = 0xFFFF; ++ ++ /* */ ++ /* 1. Read the first byte to check if efuse is empty!!! */ ++ /* */ ++ /* */ ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ if (*rtemp8 != 0xFF) { ++ efuse_utilized++; ++ eFuse_Addr++; ++ } else { ++ DBG_88E("EFUSE is empty efuse_Addr-%d efuse_data =%x\n", eFuse_Addr, *rtemp8); ++ goto exit; ++ } ++ ++ /* */ ++ /* 2. Read real efuse content. Filter PG header and every section data. */ ++ /* */ ++ while ((*rtemp8 != 0xFF) && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { ++ /* Check PG header for section num. */ ++ if ((*rtemp8 & 0x1F) == 0x0F) { /* extended header */ ++ u1temp = ((*rtemp8 & 0xE0) >> 5); ++ ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ ++ if ((*rtemp8 & 0x0F) == 0x0F) { ++ eFuse_Addr++; ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ ++ if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) ++ eFuse_Addr++; ++ continue; ++ } else { ++ offset = ((*rtemp8 & 0xF0) >> 1) | u1temp; ++ wren = (*rtemp8 & 0x0F); ++ eFuse_Addr++; ++ } ++ } else { ++ offset = ((*rtemp8 >> 4) & 0x0f); ++ wren = (*rtemp8 & 0x0f); ++ } ++ ++ if (offset < EFUSE_MAX_SECTION_88E) { ++ /* Get word enable value from PG header */ ++ ++ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { ++ /* Check word enable condition in the section */ ++ if (!(wren & 0x01)) { ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ eFuse_Addr++; ++ efuse_utilized++; ++ eFuseWord[offset][i] = (*rtemp8 & 0xff); ++ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) ++ break; ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ eFuse_Addr++; ++ efuse_utilized++; ++ eFuseWord[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00); ++ if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) ++ break; ++ } ++ wren >>= 1; ++ } ++ } ++ ++ /* Read next PG header */ ++ ReadEFuseByte(Adapter, eFuse_Addr, rtemp8, bPseudoTest); ++ ++ if (*rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { ++ efuse_utilized++; ++ eFuse_Addr++; ++ } ++ } ++ ++ /* 3. Collect 16 sections and 4 word unit into Efuse map. */ ++ for (i = 0; i < EFUSE_MAX_SECTION_88E; i++) { ++ for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { ++ efuseTbl[(i * 8) + (j * 2)] = (eFuseWord[i][j] & 0xff); ++ efuseTbl[(i * 8) + ((j * 2) + 1)] = ((eFuseWord[i][j] >> 8) & 0xff); ++ } ++ } ++ ++ /* 4. Copy from Efuse map to output pointer memory!!! */ ++ for (i = 0; i < _size_byte; i++) ++ pbuf[i] = efuseTbl[_offset + i]; ++ ++ /* 5. Calculate Efuse utilization. */ ++ rtw_hal_set_hwreg(Adapter, HW_VAR_EFUSE_BYTES, (u8 *)&eFuse_Addr); ++ ++exit: ++ kfree(efuseTbl); ++ kfree(eFuseWord); ++} ++ ++static void ReadEFuseByIC(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest) ++{ ++ if (!bPseudoTest) { ++ int ret = _FAIL; ++ if (rtw_IOL_applied(Adapter)) { ++ rtw_hal_power_on(Adapter); ++ ++ iol_mode_enable(Adapter, 1); ++ ret = iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf); ++ iol_mode_enable(Adapter, 0); ++ ++ if (_SUCCESS == ret) ++ goto exit; ++ } ++ } ++ Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest); ++ ++exit: ++ return; ++} ++ ++static void ReadEFuse_Pseudo(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf, bool bPseudoTest) ++{ ++ Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf, bPseudoTest); ++} ++ ++static void rtl8188e_ReadEFuse(struct adapter *Adapter, u8 efuseType, ++ u16 _offset, u16 _size_byte, u8 *pbuf, ++ bool bPseudoTest) ++{ ++ if (bPseudoTest) ++ ReadEFuse_Pseudo(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); ++ else ++ ReadEFuseByIC(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); ++} ++ ++/* Do not support BT */ ++static void Hal_EFUSEGetEfuseDefinition88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut) ++{ ++ switch (type) { ++ case TYPE_EFUSE_MAX_SECTION: ++ { ++ u8 *pMax_section; ++ pMax_section = (u8 *)pOut; ++ *pMax_section = EFUSE_MAX_SECTION_88E; ++ } ++ break; ++ case TYPE_EFUSE_REAL_CONTENT_LEN: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; ++ } ++ break; ++ case TYPE_EFUSE_CONTENT_LEN_BANK: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; ++ } ++ break; ++ case TYPE_AVAILABLE_EFUSE_BYTES_BANK: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E - EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E - EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ case TYPE_EFUSE_MAP_LEN: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = (u16)EFUSE_MAP_LEN_88E; ++ } ++ break; ++ case TYPE_EFUSE_PROTECT_BYTES_BANK: ++ { ++ u8 *pu1Tmp; ++ pu1Tmp = (u8 *)pOut; ++ *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ default: ++ { ++ u8 *pu1Tmp; ++ pu1Tmp = (u8 *)pOut; ++ *pu1Tmp = 0; ++ } ++ break; ++ } ++} ++ ++static void Hal_EFUSEGetEfuseDefinition_Pseudo88E(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut) ++{ ++ switch (type) { ++ case TYPE_EFUSE_MAX_SECTION: ++ { ++ u8 *pMax_section; ++ pMax_section = (u8 *)pOut; ++ *pMax_section = EFUSE_MAX_SECTION_88E; ++ } ++ break; ++ case TYPE_EFUSE_REAL_CONTENT_LEN: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; ++ } ++ break; ++ case TYPE_EFUSE_CONTENT_LEN_BANK: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = EFUSE_REAL_CONTENT_LEN_88E; ++ } ++ break; ++ case TYPE_AVAILABLE_EFUSE_BYTES_BANK: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E - EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = (u16)(EFUSE_REAL_CONTENT_LEN_88E - EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ case TYPE_EFUSE_MAP_LEN: ++ { ++ u16 *pu2Tmp; ++ pu2Tmp = (u16 *)pOut; ++ *pu2Tmp = (u16)EFUSE_MAP_LEN_88E; ++ } ++ break; ++ case TYPE_EFUSE_PROTECT_BYTES_BANK: ++ { ++ u8 *pu1Tmp; ++ pu1Tmp = (u8 *)pOut; ++ *pu1Tmp = (u8)(EFUSE_OOB_PROTECT_BYTES_88E); ++ } ++ break; ++ default: ++ { ++ u8 *pu1Tmp; ++ pu1Tmp = (u8 *)pOut; ++ *pu1Tmp = 0; ++ } ++ break; ++ } ++} ++ ++static void rtl8188e_EFUSE_GetEfuseDefinition(struct adapter *pAdapter, u8 efuseType, u8 type, void *pOut, bool bPseudoTest) ++{ ++ if (bPseudoTest) ++ Hal_EFUSEGetEfuseDefinition_Pseudo88E(pAdapter, efuseType, type, pOut); ++ else ++ Hal_EFUSEGetEfuseDefinition88E(pAdapter, efuseType, type, pOut); ++} ++ ++static u8 Hal_EfuseWordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest) ++{ ++ u16 tmpaddr = 0; ++ u16 start_addr = efuse_addr; ++ u8 badworden = 0x0F; ++ u8 tmpdata[8]; ++ ++ memset((void *)tmpdata, 0xff, PGPKT_DATA_SIZE); ++ ++ if (!(word_en & BIT(0))) { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(pAdapter, start_addr++, data[0], bPseudoTest); ++ efuse_OneByteWrite(pAdapter, start_addr++, data[1], bPseudoTest); ++ ++ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[0], bPseudoTest); ++ efuse_OneByteRead(pAdapter, tmpaddr + 1, &tmpdata[1], bPseudoTest); ++ if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) ++ badworden &= (~BIT(0)); ++ } ++ if (!(word_en & BIT(1))) { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(pAdapter, start_addr++, data[2], bPseudoTest); ++ efuse_OneByteWrite(pAdapter, start_addr++, data[3], bPseudoTest); ++ ++ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[2], bPseudoTest); ++ efuse_OneByteRead(pAdapter, tmpaddr + 1, &tmpdata[3], bPseudoTest); ++ if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) ++ badworden &= (~BIT(1)); ++ } ++ if (!(word_en & BIT(2))) { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(pAdapter, start_addr++, data[4], bPseudoTest); ++ efuse_OneByteWrite(pAdapter, start_addr++, data[5], bPseudoTest); ++ ++ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[4], bPseudoTest); ++ efuse_OneByteRead(pAdapter, tmpaddr + 1, &tmpdata[5], bPseudoTest); ++ if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) ++ badworden &= (~BIT(2)); ++ } ++ if (!(word_en & BIT(3))) { ++ tmpaddr = start_addr; ++ efuse_OneByteWrite(pAdapter, start_addr++, data[6], bPseudoTest); ++ efuse_OneByteWrite(pAdapter, start_addr++, data[7], bPseudoTest); ++ ++ efuse_OneByteRead(pAdapter, tmpaddr, &tmpdata[6], bPseudoTest); ++ efuse_OneByteRead(pAdapter, tmpaddr + 1, &tmpdata[7], bPseudoTest); ++ if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) ++ badworden &= (~BIT(3)); ++ } ++ return badworden; ++} ++ ++static u8 Hal_EfuseWordEnableDataWrite_Pseudo(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest) ++{ ++ u8 ret; ++ ++ ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); ++ return ret; ++} ++ ++static u8 rtl8188e_Efuse_WordEnableDataWrite(struct adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data, bool bPseudoTest) ++{ ++ u8 ret = 0; ++ ++ if (bPseudoTest) ++ ret = Hal_EfuseWordEnableDataWrite_Pseudo(pAdapter, efuse_addr, word_en, data, bPseudoTest); ++ else ++ ret = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); ++ return ret; ++} ++ ++static u16 hal_EfuseGetCurrentSize_8188e(struct adapter *pAdapter, bool bPseudoTest) ++{ ++ int bContinual = true; ++ u16 efuse_addr = 0; ++ u8 hoffset = 0, hworden = 0; ++ u8 efuse_data, word_cnts = 0; ++ ++ if (bPseudoTest) ++ efuse_addr = (u16)(fakeEfuseUsedBytes); ++ else ++ rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); ++ ++ while (bContinual && ++ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) && ++ AVAILABLE_EFUSE_ADDR(efuse_addr)) { ++ if (efuse_data != 0xFF) { ++ if ((efuse_data & 0x1F) == 0x0F) { /* extended header */ ++ hoffset = efuse_data; ++ efuse_addr++; ++ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest); ++ if ((efuse_data & 0x0F) == 0x0F) { ++ efuse_addr++; ++ continue; ++ } else { ++ hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); ++ hworden = efuse_data & 0x0F; ++ } ++ } else { ++ hoffset = (efuse_data >> 4) & 0x0F; ++ hworden = efuse_data & 0x0F; ++ } ++ word_cnts = Efuse_CalculateWordCnts(hworden); ++ /* read next header */ ++ efuse_addr = efuse_addr + (word_cnts * 2) + 1; ++ } else { ++ bContinual = false; ++ } ++ } ++ ++ if (bPseudoTest) ++ fakeEfuseUsedBytes = efuse_addr; ++ else ++ rtw_hal_set_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_addr); ++ ++ return efuse_addr; ++} ++ ++static u16 Hal_EfuseGetCurrentSize_Pseudo(struct adapter *pAdapter, bool bPseudoTest) ++{ ++ u16 ret = 0; ++ ++ ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest); ++ return ret; ++} ++ ++static u16 rtl8188e_EfuseGetCurrentSize(struct adapter *pAdapter, u8 efuseType, bool bPseudoTest) ++{ ++ u16 ret = 0; ++ ++ if (bPseudoTest) ++ ret = Hal_EfuseGetCurrentSize_Pseudo(pAdapter, bPseudoTest); ++ else ++ ret = hal_EfuseGetCurrentSize_8188e(pAdapter, bPseudoTest); ++ return ret; ++} ++ ++static int hal_EfusePgPacketRead_8188e(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest) ++{ ++ u8 ReadState = PG_STATE_HEADER; ++ int bContinual = true; ++ int bDataEmpty = true; ++ u8 efuse_data, word_cnts = 0; ++ u16 efuse_addr = 0; ++ u8 hoffset = 0, hworden = 0; ++ u8 tmpidx = 0; ++ u8 tmpdata[8]; ++ u8 max_section = 0; ++ u8 tmp_header = 0; ++ ++ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION, (void *)&max_section, bPseudoTest); ++ ++ if (!data) ++ return false; ++ if (offset > max_section) ++ return false; ++ ++ memset((void *)data, 0xff, sizeof(u8) * PGPKT_DATA_SIZE); ++ memset((void *)tmpdata, 0xff, sizeof(u8) * PGPKT_DATA_SIZE); ++ ++ /* Efuse has been pre-programmed dummy 5Bytes at the end of Efuse by CP. */ ++ /* Skip dummy parts to prevent unexpected data read from Efuse. */ ++ /* By pass right now. 2009.02.19. */ ++ while (bContinual && AVAILABLE_EFUSE_ADDR(efuse_addr)) { ++ /* Header Read ------------- */ ++ if (ReadState & PG_STATE_HEADER) { ++ if (efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) { ++ if (EXT_HEADER(efuse_data)) { ++ tmp_header = efuse_data; ++ efuse_addr++; ++ efuse_OneByteRead(pAdapter, efuse_addr, &efuse_data, bPseudoTest); ++ if (!ALL_WORDS_DISABLED(efuse_data)) { ++ hoffset = ((tmp_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); ++ hworden = efuse_data & 0x0F; ++ } else { ++ DBG_88E("Error, All words disabled\n"); ++ efuse_addr++; ++ continue; ++ } ++ } else { ++ hoffset = (efuse_data >> 4) & 0x0F; ++ hworden = efuse_data & 0x0F; ++ } ++ word_cnts = Efuse_CalculateWordCnts(hworden); ++ bDataEmpty = true; ++ ++ if (hoffset == offset) { ++ for (tmpidx = 0; tmpidx < word_cnts * 2; tmpidx++) { ++ if (efuse_OneByteRead(pAdapter, efuse_addr + 1 + tmpidx, &efuse_data, bPseudoTest)) { ++ tmpdata[tmpidx] = efuse_data; ++ if (efuse_data != 0xff) ++ bDataEmpty = false; ++ } ++ } ++ if (!bDataEmpty) { ++ ReadState = PG_STATE_DATA; ++ } else {/* read next header */ ++ efuse_addr = efuse_addr + (word_cnts * 2) + 1; ++ ReadState = PG_STATE_HEADER; ++ } ++ } else {/* read next header */ ++ efuse_addr = efuse_addr + (word_cnts * 2) + 1; ++ ReadState = PG_STATE_HEADER; ++ } ++ } else { ++ bContinual = false; ++ } ++ } else if (ReadState & PG_STATE_DATA) { ++ /* Data section Read ------------- */ ++ efuse_WordEnableDataRead(hworden, tmpdata, data); ++ efuse_addr = efuse_addr + (word_cnts * 2) + 1; ++ ReadState = PG_STATE_HEADER; ++ } ++ ++ } ++ ++ if ((data[0] == 0xff) && (data[1] == 0xff) && (data[2] == 0xff) && (data[3] == 0xff) && ++ (data[4] == 0xff) && (data[5] == 0xff) && (data[6] == 0xff) && (data[7] == 0xff)) ++ return false; ++ else ++ return true; ++} ++ ++static int Hal_EfusePgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest) ++{ ++ int ret; ++ ++ ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest); ++ return ret; ++} ++ ++static int Hal_EfusePgPacketRead_Pseudo(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest) ++{ ++ int ret; ++ ++ ret = hal_EfusePgPacketRead_8188e(pAdapter, offset, data, bPseudoTest); ++ return ret; ++} ++ ++static int rtl8188e_Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data, bool bPseudoTest) ++{ ++ int ret; ++ ++ if (bPseudoTest) ++ ret = Hal_EfusePgPacketRead_Pseudo(pAdapter, offset, data, bPseudoTest); ++ else ++ ret = Hal_EfusePgPacketRead(pAdapter, offset, data, bPseudoTest); ++ return ret; ++} ++ ++static bool hal_EfuseFixHeaderProcess(struct adapter *pAdapter, u8 efuseType, struct pgpkt *pFixPkt, u16 *pAddr, bool bPseudoTest) ++{ ++ u8 originaldata[8], badworden = 0; ++ u16 efuse_addr = *pAddr; ++ u32 PgWriteSuccess = 0; ++ ++ memset((void *)originaldata, 0xff, 8); ++ ++ if (Efuse_PgPacketRead(pAdapter, pFixPkt->offset, originaldata, bPseudoTest)) { ++ /* check if data exist */ ++ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr + 1, pFixPkt->word_en, originaldata, bPseudoTest); ++ ++ if (badworden != 0xf) { /* write fail */ ++ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pFixPkt->offset, badworden, originaldata, bPseudoTest); ++ ++ if (!PgWriteSuccess) ++ return false; ++ else ++ efuse_addr = Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest); ++ } else { ++ efuse_addr = efuse_addr + (pFixPkt->word_cnts * 2) + 1; ++ } ++ } else { ++ efuse_addr = efuse_addr + (pFixPkt->word_cnts * 2) + 1; ++ } ++ *pAddr = efuse_addr; ++ return true; ++} ++ ++static bool hal_EfusePgPacketWrite2ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) ++{ ++ bool bRet = false; ++ u16 efuse_addr = *pAddr, efuse_max_available_len = 0; ++ u8 pg_header = 0, tmp_header = 0, pg_header_temp = 0; ++ u8 repeatcnt = 0; ++ ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest); ++ ++ while (efuse_addr < efuse_max_available_len) { ++ pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ ++ while (tmp_header == 0xFF) { ++ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ return false; ++ ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ } ++ ++ /* to write ext_header */ ++ if (tmp_header == pg_header) { ++ efuse_addr++; ++ pg_header_temp = pg_header; ++ pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; ++ ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ ++ while (tmp_header == 0xFF) { ++ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ return false; ++ ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ } ++ ++ if ((tmp_header & 0x0F) == 0x0F) { /* word_en PG fail */ ++ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { ++ return false; ++ } else { ++ efuse_addr++; ++ continue; ++ } ++ } else if (pg_header != tmp_header) { /* offset PG fail */ ++ struct pgpkt fixPkt; ++ fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1); ++ fixPkt.word_en = tmp_header & 0x0F; ++ fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); ++ if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest)) ++ return false; ++ } else { ++ bRet = true; ++ break; ++ } ++ } else if ((tmp_header & 0x1F) == 0x0F) { /* wrong extended header */ ++ efuse_addr += 2; ++ continue; ++ } ++ } ++ ++ *pAddr = efuse_addr; ++ return bRet; ++} ++ ++static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) ++{ ++ bool bRet = false; ++ u8 pg_header = 0, tmp_header = 0; ++ u16 efuse_addr = *pAddr; ++ u8 repeatcnt = 0; ++ ++ pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; ++ ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ ++ while (tmp_header == 0xFF) { ++ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) ++ return false; ++ efuse_OneByteWrite(pAdapter, efuse_addr, pg_header, bPseudoTest); ++ efuse_OneByteRead(pAdapter, efuse_addr, &tmp_header, bPseudoTest); ++ } ++ ++ if (pg_header == tmp_header) { ++ bRet = true; ++ } else { ++ struct pgpkt fixPkt; ++ fixPkt.offset = (tmp_header >> 4) & 0x0F; ++ fixPkt.word_en = tmp_header & 0x0F; ++ fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en); ++ if (!hal_EfuseFixHeaderProcess(pAdapter, efuseType, &fixPkt, &efuse_addr, bPseudoTest)) ++ return false; ++ } ++ ++ *pAddr = efuse_addr; ++ return bRet; ++} ++ ++static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) ++{ ++ u16 efuse_addr = *pAddr; ++ u8 badworden = 0; ++ u32 PgWriteSuccess = 0; ++ ++ badworden = 0x0f; ++ badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr + 1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest); ++ if (badworden == 0x0F) { ++ /* write ok */ ++ return true; ++ } else { ++ /* reorganize other pg packet */ ++ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); ++ if (!PgWriteSuccess) ++ return false; ++ else ++ return true; ++ } ++} ++ ++static bool ++hal_EfusePgPacketWriteHeader( ++ struct adapter *pAdapter, ++ u8 efuseType, ++ u16 *pAddr, ++ struct pgpkt *pTargetPkt, ++ bool bPseudoTest) ++{ ++ bool bRet = false; ++ ++ if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) ++ bRet = hal_EfusePgPacketWrite2ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest); ++ else ++ bRet = hal_EfusePgPacketWrite1ByteHeader(pAdapter, efuseType, pAddr, pTargetPkt, bPseudoTest); ++ ++ return bRet; ++} ++ ++static bool wordEnMatched(struct pgpkt *pTargetPkt, struct pgpkt *pCurPkt, ++ u8 *pWden) ++{ ++ u8 match_word_en = 0x0F; /* default all words are disabled */ ++ ++ /* check if the same words are enabled both target and current PG packet */ ++ if (((pTargetPkt->word_en & BIT(0)) == 0) && ++ ((pCurPkt->word_en & BIT(0)) == 0)) ++ match_word_en &= ~BIT(0); /* enable word 0 */ ++ if (((pTargetPkt->word_en & BIT(1)) == 0) && ++ ((pCurPkt->word_en & BIT(1)) == 0)) ++ match_word_en &= ~BIT(1); /* enable word 1 */ ++ if (((pTargetPkt->word_en & BIT(2)) == 0) && ++ ((pCurPkt->word_en & BIT(2)) == 0)) ++ match_word_en &= ~BIT(2); /* enable word 2 */ ++ if (((pTargetPkt->word_en & BIT(3)) == 0) && ++ ((pCurPkt->word_en & BIT(3)) == 0)) ++ match_word_en &= ~BIT(3); /* enable word 3 */ ++ ++ *pWden = match_word_en; ++ ++ if (match_word_en != 0xf) ++ return true; ++ else ++ return false; ++} ++ ++static bool hal_EfuseCheckIfDatafollowed(struct adapter *pAdapter, u8 word_cnts, u16 startAddr, bool bPseudoTest) ++{ ++ bool bRet = false; ++ u8 i, efuse_data; ++ ++ for (i = 0; i < (word_cnts * 2); i++) { ++ if (efuse_OneByteRead(pAdapter, (startAddr + i), &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) ++ bRet = true; ++ } ++ return bRet; ++} ++ ++static bool hal_EfusePartialWriteCheck(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt, bool bPseudoTest) ++{ ++ bool bRet = false; ++ u8 i, efuse_data = 0, cur_header = 0; ++ u8 matched_wden = 0, badworden = 0; ++ u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0; ++ struct pgpkt curPkt; ++ ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_AVAILABLE_EFUSE_BYTES_BANK, (void *)&efuse_max_available_len, bPseudoTest); ++ EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&efuse_max, bPseudoTest); ++ ++ if (efuseType == EFUSE_WIFI) { ++ if (bPseudoTest) { ++ startAddr = (u16)(fakeEfuseUsedBytes % EFUSE_REAL_CONTENT_LEN); ++ } else { ++ rtw_hal_get_hwreg(pAdapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); ++ startAddr %= EFUSE_REAL_CONTENT_LEN; ++ } ++ } else { ++ if (bPseudoTest) ++ startAddr = (u16)(fakeBTEfuseUsedBytes % EFUSE_REAL_CONTENT_LEN); ++ else ++ startAddr = (u16)(BTEfuseUsedBytes % EFUSE_REAL_CONTENT_LEN); ++ } ++ ++ while (1) { ++ if (startAddr >= efuse_max_available_len) { ++ bRet = false; ++ break; ++ } ++ ++ if (efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest) && (efuse_data != 0xFF)) { ++ if (EXT_HEADER(efuse_data)) { ++ cur_header = efuse_data; ++ startAddr++; ++ efuse_OneByteRead(pAdapter, startAddr, &efuse_data, bPseudoTest); ++ if (ALL_WORDS_DISABLED(efuse_data)) { ++ bRet = false; ++ break; ++ } else { ++ curPkt.offset = ((cur_header & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); ++ curPkt.word_en = efuse_data & 0x0F; ++ } ++ } else { ++ cur_header = efuse_data; ++ curPkt.offset = (cur_header >> 4) & 0x0F; ++ curPkt.word_en = cur_header & 0x0F; ++ } ++ ++ curPkt.word_cnts = Efuse_CalculateWordCnts(curPkt.word_en); ++ /* if same header is found but no data followed */ ++ /* write some part of data followed by the header. */ ++ if ((curPkt.offset == pTargetPkt->offset) && ++ (!hal_EfuseCheckIfDatafollowed(pAdapter, curPkt.word_cnts, startAddr + 1, bPseudoTest)) && ++ wordEnMatched(pTargetPkt, &curPkt, &matched_wden)) { ++ /* Here to write partial data */ ++ badworden = Efuse_WordEnableDataWrite(pAdapter, startAddr + 1, matched_wden, pTargetPkt->data, bPseudoTest); ++ if (badworden != 0x0F) { ++ u32 PgWriteSuccess = 0; ++ /* if write fail on some words, write these bad words again */ ++ ++ PgWriteSuccess = Efuse_PgPacketWrite(pAdapter, pTargetPkt->offset, badworden, pTargetPkt->data, bPseudoTest); ++ ++ if (!PgWriteSuccess) { ++ bRet = false; /* write fail, return */ ++ break; ++ } ++ } ++ /* partial write ok, update the target packet for later use */ ++ for (i = 0; i < 4; i++) { ++ if ((matched_wden & (0x1 << i)) == 0) /* this word has been written */ ++ pTargetPkt->word_en |= (0x1 << i); /* disable the word */ ++ } ++ pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); ++ } ++ /* read from next header */ ++ startAddr = startAddr + (curPkt.word_cnts * 2) + 1; ++ } else { ++ /* not used header, 0xff */ ++ *pAddr = startAddr; ++ bRet = true; ++ break; ++ } ++ } ++ return bRet; ++} ++ ++static bool ++hal_EfusePgCheckAvailableAddr( ++ struct adapter *pAdapter, ++ u8 efuseType, ++ bool bPseudoTest ++ ) ++{ ++ u16 efuse_max_available_len = 0; ++ ++ /* Change to check TYPE_EFUSE_MAP_LEN , because 8188E raw 256, logic map over 256. */ ++ EFUSE_GetEfuseDefinition(pAdapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&efuse_max_available_len, false); ++ ++ if (Efuse_GetCurrentSize(pAdapter, efuseType, bPseudoTest) >= efuse_max_available_len) ++ return false; ++ return true; ++} ++ ++static void hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData, struct pgpkt *pTargetPkt) ++{ ++ memset((void *)pTargetPkt->data, 0xFF, sizeof(u8) * 8); ++ pTargetPkt->offset = offset; ++ pTargetPkt->word_en = word_en; ++ efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); ++ pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); ++} ++ ++static bool hal_EfusePgPacketWrite_8188e(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *pData, bool bPseudoTest) ++{ ++ struct pgpkt targetPkt; ++ u16 startAddr = 0; ++ u8 efuseType = EFUSE_WIFI; ++ ++ if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType, bPseudoTest)) ++ return false; ++ ++ hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); ++ ++ if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) ++ return false; ++ ++ return true; ++} ++ ++static int Hal_EfusePgPacketWrite_Pseudo(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest) ++{ ++ int ret; ++ ++ ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest); ++ return ret; ++} ++ ++static int Hal_EfusePgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest) ++{ ++ int ret = 0; ++ ret = hal_EfusePgPacketWrite_8188e(pAdapter, offset, word_en, data, bPseudoTest); ++ ++ return ret; ++} ++ ++static int rtl8188e_Efuse_PgPacketWrite(struct adapter *pAdapter, u8 offset, u8 word_en, u8 *data, bool bPseudoTest) ++{ ++ int ret; ++ ++ if (bPseudoTest) ++ ret = Hal_EfusePgPacketWrite_Pseudo(pAdapter, offset, word_en, data, bPseudoTest); ++ else ++ ret = Hal_EfusePgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest); ++ return ret; ++} ++ ++static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) ++{ ++ u32 value32; ++ struct HAL_VERSION ChipVersion; ++ struct hal_data_8188e *pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ value32 = rtw_read32(padapter, REG_SYS_CFG); ++ ChipVersion.ICType = CHIP_8188E; ++ ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); ++ ++ ChipVersion.RFType = RF_TYPE_1T1R; ++ ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); ++ ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK) >> CHIP_VER_RTL_SHIFT; /* IC version (CUT) */ ++ ++ /* For regulator mode. by tynli. 2011.01.14 */ ++ pHalData->RegulatorMode = ((value32 & TRP_BT_EN) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR); ++ ++ ChipVersion.ROMVer = 0; /* ROM code version. */ ++ pHalData->MultiFunc = RT_MULTI_FUNC_NONE; ++ ++ dump_chip_info(ChipVersion); ++ ++ pHalData->VersionID = ChipVersion; ++ ++ if (IS_1T2R(ChipVersion)) { ++ pHalData->rf_type = RF_1T2R; ++ pHalData->NumTotalRFPath = 2; ++ } else if (IS_2T2R(ChipVersion)) { ++ pHalData->rf_type = RF_2T2R; ++ pHalData->NumTotalRFPath = 2; ++ } else { ++ pHalData->rf_type = RF_1T1R; ++ pHalData->NumTotalRFPath = 1; ++ } ++ ++ MSG_88E("RF_Type is %x!!\n", pHalData->rf_type); ++ ++ return ChipVersion; ++} ++ ++static void rtl8188e_read_chip_version(struct adapter *padapter) ++{ ++ ReadChipVersion8188E(padapter); ++} ++ ++static void rtl8188e_GetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) ++{ ++} ++ ++static void rtl8188e_SetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct odm_dm_struct *podmpriv = &pHalData->odmpriv; ++ switch (eVariable) { ++ case HAL_ODM_STA_INFO: ++ { ++ struct sta_info *psta = (struct sta_info *)pValue1; ++ if (bSet) { ++ DBG_88E("### Set STA_(%d) info\n", psta->mac_id); ++ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta); ++ ODM_RAInfo_Init(podmpriv, psta->mac_id); ++ } else { ++ DBG_88E("### Clean STA_(%d) info\n", psta->mac_id); ++ ODM_CmnInfoPtrArrayHook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL); ++ } ++ } ++ break; ++ case HAL_ODM_P2P_STATE: ++ ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet); ++ break; ++ case HAL_ODM_WIFI_DISPLAY_STATE: ++ ODM_CmnInfoUpdate(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet); ++ break; ++ default: ++ break; ++ } ++} ++ ++void rtl8188e_clone_haldata(struct adapter *dst_adapter, struct adapter *src_adapter) ++{ ++ memcpy(dst_adapter->HalData, src_adapter->HalData, dst_adapter->hal_data_sz); ++} ++ ++void rtl8188e_start_thread(struct adapter *padapter) ++{ ++} ++ ++void rtl8188e_stop_thread(struct adapter *padapter) ++{ ++} ++ ++static void hal_notch_filter_8188e(struct adapter *adapter, bool enable) ++{ ++ if (enable) { ++ DBG_88E("Enable notch filter\n"); ++ rtw_write8(adapter, rOFDM0_RxDSP + 1, rtw_read8(adapter, rOFDM0_RxDSP + 1) | BIT(1)); ++ } else { ++ DBG_88E("Disable notch filter\n"); ++ rtw_write8(adapter, rOFDM0_RxDSP + 1, rtw_read8(adapter, rOFDM0_RxDSP + 1) & ~BIT(1)); ++ } ++} ++void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc) ++{ ++ pHalFunc->free_hal_data = &rtl8188e_free_hal_data; ++ ++ pHalFunc->dm_init = &rtl8188e_init_dm_priv; ++ pHalFunc->dm_deinit = &rtl8188e_deinit_dm_priv; ++ ++ pHalFunc->read_chip_version = &rtl8188e_read_chip_version; ++ ++ pHalFunc->set_bwmode_handler = &PHY_SetBWMode8188E; ++ pHalFunc->set_channel_handler = &PHY_SwChnl8188E; ++ ++ pHalFunc->hal_dm_watchdog = &rtl8188e_HalDmWatchDog; ++ ++ pHalFunc->Add_RateATid = &rtl8188e_Add_RateATid; ++ pHalFunc->run_thread = &rtl8188e_start_thread; ++ pHalFunc->cancel_thread = &rtl8188e_stop_thread; ++ ++ pHalFunc->AntDivBeforeLinkHandler = &AntDivBeforeLink8188E; ++ pHalFunc->AntDivCompareHandler = &AntDivCompare8188E; ++ pHalFunc->read_bbreg = &rtl8188e_PHY_QueryBBReg; ++ pHalFunc->write_bbreg = &rtl8188e_PHY_SetBBReg; ++ pHalFunc->read_rfreg = &rtl8188e_PHY_QueryRFReg; ++ pHalFunc->write_rfreg = &rtl8188e_PHY_SetRFReg; ++ ++ /* Efuse related function */ ++ pHalFunc->EfusePowerSwitch = &rtl8188e_EfusePowerSwitch; ++ pHalFunc->ReadEFuse = &rtl8188e_ReadEFuse; ++ pHalFunc->EFUSEGetEfuseDefinition = &rtl8188e_EFUSE_GetEfuseDefinition; ++ pHalFunc->EfuseGetCurrentSize = &rtl8188e_EfuseGetCurrentSize; ++ pHalFunc->Efuse_PgPacketRead = &rtl8188e_Efuse_PgPacketRead; ++ pHalFunc->Efuse_PgPacketWrite = &rtl8188e_Efuse_PgPacketWrite; ++ pHalFunc->Efuse_WordEnableDataWrite = &rtl8188e_Efuse_WordEnableDataWrite; ++ ++ pHalFunc->sreset_init_value = &sreset_init_value; ++ pHalFunc->sreset_reset_value = &sreset_reset_value; ++ pHalFunc->silentreset = &rtl8188e_silentreset_for_specific_platform; ++ pHalFunc->sreset_xmit_status_check = &rtl8188e_sreset_xmit_status_check; ++ pHalFunc->sreset_linked_status_check = &rtl8188e_sreset_linked_status_check; ++ pHalFunc->sreset_get_wifi_status = &sreset_get_wifi_status; ++ ++ pHalFunc->GetHalODMVarHandler = &rtl8188e_GetHalODMVar; ++ pHalFunc->SetHalODMVarHandler = &rtl8188e_SetHalODMVar; ++ ++ pHalFunc->IOL_exec_cmds_sync = &rtl8188e_IOL_exec_cmds_sync; ++ ++ pHalFunc->hal_notch_filter = &hal_notch_filter_8188e; ++} ++ ++u8 GetEEPROMSize8188E(struct adapter *padapter) ++{ ++ u8 size = 0; ++ u32 cr; ++ ++ cr = rtw_read16(padapter, REG_9346CR); ++ /* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */ ++ size = (cr & BOOT_FROM_EEPROM) ? 6 : 4; ++ ++ MSG_88E("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46"); ++ ++ return size; ++} ++ ++/* */ ++/* */ ++/* LLT R/W/Init function */ ++/* */ ++/* */ ++static s32 _LLTWrite(struct adapter *padapter, u32 address, u32 data) ++{ ++ s32 status = _SUCCESS; ++ s32 count = 0; ++ u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); ++ u16 LLTReg = REG_LLT_INIT; ++ ++ rtw_write32(padapter, LLTReg, value); ++ ++ /* polling */ ++ do { ++ value = rtw_read32(padapter, LLTReg); ++ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) ++ break; ++ ++ if (count > POLLING_LLT_THRESHOLD) { ++ status = _FAIL; ++ break; ++ } ++ } while (count++); ++ ++ return status; ++} ++ ++s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy) ++{ ++ s32 status = _FAIL; ++ u32 i; ++ u32 Last_Entry_Of_TxPktBuf = LAST_ENTRY_OF_TX_PKT_BUFFER;/* 176, 22k */ ++ ++ if (rtw_IOL_applied(padapter)) { ++ status = iol_InitLLTTable(padapter, txpktbuf_bndy); ++ } else { ++ for (i = 0; i < (txpktbuf_bndy - 1); i++) { ++ status = _LLTWrite(padapter, i, i + 1); ++ if (_SUCCESS != status) ++ return status; ++ } ++ ++ /* end of list */ ++ status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF); ++ if (_SUCCESS != status) ++ return status; ++ ++ /* Make the other pages as ring buffer */ ++ /* This ring buffer is used as beacon buffer if we config this MAC as two MAC transfer. */ ++ /* Otherwise used as local loopback buffer. */ ++ for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) { ++ status = _LLTWrite(padapter, i, (i + 1)); ++ if (_SUCCESS != status) ++ return status; ++ } ++ ++ /* Let last entry point to the start entry of ring buffer */ ++ status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy); ++ if (_SUCCESS != status) { ++ return status; ++ } ++ } ++ ++ return status; ++} ++ ++void ++Hal_InitPGData88E(struct adapter *padapter) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ if (!pEEPROM->bautoload_fail_flag) { /* autoload OK. */ ++ if (!is_boot_from_eeprom(padapter)) { ++ /* Read EFUSE real map to shadow. */ ++ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); ++ } ++ } else {/* autoload fail */ ++ /* update to default value 0xFF */ ++ if (!is_boot_from_eeprom(padapter)) ++ EFUSE_ShadowMapUpdate(padapter, EFUSE_WIFI, false); ++ } ++} ++ ++void ++Hal_EfuseParseIDCode88E( ++ struct adapter *padapter, ++ u8 *hwinfo ++ ) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ u16 EEPROMId; ++ ++ /* Check 0x8129 again for making sure autoload status!! */ ++ EEPROMId = le16_to_cpu(*((__le16 *)hwinfo)); ++ if (EEPROMId != RTL_EEPROM_ID) { ++ pr_err("EEPROM ID(%#x) is invalid!!\n", EEPROMId); ++ pEEPROM->bautoload_fail_flag = true; ++ } else { ++ pEEPROM->bautoload_fail_flag = false; ++ } ++ ++ pr_info("EEPROM ID = 0x%04x\n", EEPROMId); ++} ++ ++static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G, u8 *PROMContent, bool AutoLoadFail) ++{ ++ u32 rfPath, eeAddr = EEPROM_TX_PWR_INX_88E, group, TxCount = 0; ++ ++ memset(pwrInfo24G, 0, sizeof(struct txpowerinfo24g)); ++ ++ if (AutoLoadFail) { ++ for (rfPath = 0; rfPath < RF_PATH_MAX; rfPath++) { ++ /* 2.4G default value */ ++ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ } ++ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { ++ if (TxCount == 0) { ++ pwrInfo24G->BW20_Diff[rfPath][0] = EEPROM_DEFAULT_24G_HT20_DIFF; ++ pwrInfo24G->OFDM_Diff[rfPath][0] = EEPROM_DEFAULT_24G_OFDM_DIFF; ++ } else { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ } ++ } ++ } ++ return; ++ } ++ ++ for (rfPath = 0; rfPath < RF_PATH_MAX; rfPath++) { ++ /* 2.4G default value */ ++ for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = PROMContent[eeAddr++]; ++ if (pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF) ++ pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ } ++ for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) { ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = PROMContent[eeAddr++]; ++ if (pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF) ++ pwrInfo24G->IndexBW40_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX; ++ } ++ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { ++ if (TxCount == 0) { ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = 0; ++ if (PROMContent[eeAddr] == 0xFF) { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF; ++ } else { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr] & 0xf0) >> 4; ++ if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT(3)) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if (PROMContent[eeAddr] == 0xFF) { ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_OFDM_DIFF; ++ } else { ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr] & 0x0f); ++ if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT(3)) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = 0; ++ eeAddr++; ++ } else { ++ if (PROMContent[eeAddr] == 0xFF) { ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ } else { ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] = (PROMContent[eeAddr] & 0xf0) >> 4; ++ if (pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT(3)) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if (PROMContent[eeAddr] == 0xFF) { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ } else { ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr] & 0x0f); ++ if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT(3)) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ eeAddr++; ++ ++ if (PROMContent[eeAddr] == 0xFF) { ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ } else { ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] = (PROMContent[eeAddr] & 0xf0) >> 4; ++ if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT(3)) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ ++ if (PROMContent[eeAddr] == 0xFF) { ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF; ++ } else { ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr] & 0x0f); ++ if (pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT(3)) /* 4bit sign number to 8 bit sign number */ ++ pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0; ++ } ++ eeAddr++; ++ } ++ } ++ } ++} ++ ++static void hal_get_chnl_group_88e(u8 chnl, u8 *group) ++{ ++ if (chnl < 3) /* Channel 1-2 */ ++ *group = 0; ++ else if (chnl < 6) /* Channel 3-5 */ ++ *group = 1; ++ else if (chnl < 9) /* Channel 6-8 */ ++ *group = 2; ++ else if (chnl < 12) /* Channel 9-11 */ ++ *group = 3; ++ else if (chnl < 14) /* Channel 12-13 */ ++ *group = 4; ++ else if (chnl == 14) /* Channel 14 */ ++ *group = 5; ++} ++ ++void Hal_ReadPowerSavingMode88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail) ++{ ++ if (AutoLoadFail) { ++ padapter->pwrctrlpriv.bHWPowerdown = false; ++ padapter->pwrctrlpriv.bSupportRemoteWakeup = false; ++ } else { ++ /* hw power down mode selection , 0:rf-off / 1:power down */ ++ ++ if (padapter->registrypriv.hwpdn_mode == 2) ++ padapter->pwrctrlpriv.bHWPowerdown = (hwinfo[EEPROM_RF_FEATURE_OPTION_88E] & BIT(4)); ++ else ++ padapter->pwrctrlpriv.bHWPowerdown = padapter->registrypriv.hwpdn_mode; ++ ++ /* decide hw if support remote wakeup function */ ++ /* if hw supported, 8051 (SIE) will generate WeakUP signal(D+/D- toggle) when autoresume */ ++ padapter->pwrctrlpriv.bSupportRemoteWakeup = (hwinfo[EEPROM_USB_OPTIONAL_FUNCTION0] & BIT(1)) ? true : false; ++ ++ DBG_88E("%s...bHWPwrPindetect(%x)-bHWPowerdown(%x) , bSupportRemoteWakeup(%x)\n", __func__, ++ padapter->pwrctrlpriv.bHWPwrPindetect, padapter->pwrctrlpriv.bHWPowerdown, padapter->pwrctrlpriv.bSupportRemoteWakeup); ++ ++ DBG_88E("### PS params => power_mgnt(%x), usbss_enable(%x) ###\n", padapter->registrypriv.power_mgnt, padapter->registrypriv.usbss_enable); ++ } ++} ++ ++void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool AutoLoadFail) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct txpowerinfo24g pwrInfo24G; ++ u8 rfPath, ch, group; ++ u8 TxCount; ++ ++ Hal_ReadPowerValueFromPROM_8188E(&pwrInfo24G, PROMContent, AutoLoadFail); ++ ++ if (!AutoLoadFail) ++ pHalData->bTXPowerDataReadFromEEPORM = true; ++ ++ for (rfPath = 0; rfPath < pHalData->NumTotalRFPath; rfPath++) { ++ for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) { ++ hal_get_chnl_group_88e(ch, &group); ++ ++ pHalData->Index24G_CCK_Base[rfPath][ch] = pwrInfo24G.IndexCCK_Base[rfPath][group]; ++ if (ch == 14) ++ pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][4]; ++ else ++ pHalData->Index24G_BW40_Base[rfPath][ch] = pwrInfo24G.IndexBW40_Base[rfPath][group]; ++ ++ DBG_88E("======= Path %d, Channel %d =======\n", rfPath, ch); ++ DBG_88E("Index24G_CCK_Base[%d][%d] = 0x%x\n", rfPath, ch, pHalData->Index24G_CCK_Base[rfPath][ch]); ++ DBG_88E("Index24G_BW40_Base[%d][%d] = 0x%x\n", rfPath, ch, pHalData->Index24G_BW40_Base[rfPath][ch]); ++ } ++ for (TxCount = 0; TxCount < MAX_TX_COUNT; TxCount++) { ++ pHalData->CCK_24G_Diff[rfPath][TxCount] = pwrInfo24G.CCK_Diff[rfPath][TxCount]; ++ pHalData->OFDM_24G_Diff[rfPath][TxCount] = pwrInfo24G.OFDM_Diff[rfPath][TxCount]; ++ pHalData->BW20_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW20_Diff[rfPath][TxCount]; ++ pHalData->BW40_24G_Diff[rfPath][TxCount] = pwrInfo24G.BW40_Diff[rfPath][TxCount]; ++ DBG_88E("======= TxCount %d =======\n", TxCount); ++ DBG_88E("CCK_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->CCK_24G_Diff[rfPath][TxCount]); ++ DBG_88E("OFDM_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->OFDM_24G_Diff[rfPath][TxCount]); ++ DBG_88E("BW20_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW20_24G_Diff[rfPath][TxCount]); ++ DBG_88E("BW40_24G_Diff[%d][%d] = %d\n", rfPath, TxCount, pHalData->BW40_24G_Diff[rfPath][TxCount]); ++ } ++ } ++ ++ /* 2010/10/19 MH Add Regulator recognize for CU. */ ++ if (!AutoLoadFail) { ++ pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_88E] & 0x7); /* bit0~2 */ ++ if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF) ++ pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION & 0x7); /* bit0~2 */ ++ } else { ++ pHalData->EEPROMRegulatory = 0; ++ } ++ DBG_88E("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory); ++} ++ ++void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if (!AutoLoadFail) { ++ pHalData->CrystalCap = hwinfo[EEPROM_XTAL_88E]; ++ if (pHalData->CrystalCap == 0xFF) ++ pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E; ++ } else { ++ pHalData->CrystalCap = EEPROM_Default_CrystalCap_88E; ++ } ++ DBG_88E("CrystalCap: 0x%2x\n", pHalData->CrystalCap); ++} ++ ++void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo, bool AutoLoadFail) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if (!AutoLoadFail) ++ pHalData->BoardType = ((hwinfo[EEPROM_RF_BOARD_OPTION_88E] & 0xE0) >> 5); ++ else ++ pHalData->BoardType = 0; ++ DBG_88E("Board Type: 0x%2x\n", pHalData->BoardType); ++} ++ ++void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ ++ if (!AutoLoadFail) { ++ pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_88E]; ++ if (pHalData->EEPROMVersion == 0xFF) ++ pHalData->EEPROMVersion = EEPROM_Default_Version; ++ } else { ++ pHalData->EEPROMVersion = 1; ++ } ++} ++ ++void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail) ++{ ++ padapter->mlmepriv.ChannelPlan = ++ hal_com_get_channel_plan(padapter, ++ hwinfo ? hwinfo[EEPROM_ChannelPlan_88E] : 0xFF, ++ padapter->registrypriv.channel_plan, ++ RT_CHANNEL_DOMAIN_WORLD_WIDE_13, AutoLoadFail); ++ ++ DBG_88E("mlmepriv.ChannelPlan = 0x%02x\n", padapter->mlmepriv.ChannelPlan); ++} ++ ++void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo, bool AutoLoadFail) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ ++ if (!AutoLoadFail) { ++ pHalData->EEPROMCustomerID = hwinfo[EEPROM_CUSTOMERID_88E]; ++ } else { ++ pHalData->EEPROMCustomerID = 0; ++ pHalData->EEPROMSubCustomerID = 0; ++ } ++ DBG_88E("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID); ++} ++ ++void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool AutoLoadFail) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ struct registry_priv *registry_par = &pAdapter->registrypriv; ++ ++ if (!AutoLoadFail) { ++ /* Antenna Diversity setting. */ ++ if (registry_par->antdiv_cfg == 2) { /* 2:By EFUSE */ ++ pHalData->AntDivCfg = (PROMContent[EEPROM_RF_BOARD_OPTION_88E] & 0x18) >> 3; ++ if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF) ++ pHalData->AntDivCfg = (EEPROM_DEFAULT_BOARD_OPTION & 0x18) >> 3; ++ } else { ++ pHalData->AntDivCfg = registry_par->antdiv_cfg; /* 0:OFF , 1:ON, 2:By EFUSE */ ++ } ++ ++ if (registry_par->antdiv_type == 0) { ++ /* If TRxAntDivType is AUTO in advanced setting, use EFUSE value instead. */ ++ pHalData->TRxAntDivType = PROMContent[EEPROM_RF_ANTENNA_OPT_88E]; ++ if (pHalData->TRxAntDivType == 0xFF) ++ pHalData->TRxAntDivType = CG_TRX_HW_ANTDIV; /* For 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */ ++ } else { ++ pHalData->TRxAntDivType = registry_par->antdiv_type; ++ } ++ ++ if (pHalData->TRxAntDivType == CG_TRX_HW_ANTDIV || pHalData->TRxAntDivType == CGCS_RX_HW_ANTDIV) ++ pHalData->AntDivCfg = 1; /* 0xC1[3] is ignored. */ ++ } else { ++ pHalData->AntDivCfg = 0; ++ pHalData->TRxAntDivType = pHalData->TRxAntDivType; /* The value in the driver setting of device manager. */ ++ } ++ DBG_88E("EEPROM : AntDivCfg = %x, TRxAntDivType = %x\n", pHalData->AntDivCfg, pHalData->TRxAntDivType); ++} ++ ++void Hal_ReadThermalMeter_88E(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ ++ /* ThermalMeter from EEPROM */ ++ if (!AutoloadFail) ++ pHalData->EEPROMThermalMeter = PROMContent[EEPROM_THERMAL_METER_88E]; ++ else ++ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E; ++ ++ if (pHalData->EEPROMThermalMeter == 0xff || AutoloadFail) { ++ pHalData->bAPKThermalMeterIgnore = true; ++ pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter_88E; ++ } ++ DBG_88E("ThermalMeter = 0x%x\n", pHalData->EEPROMThermalMeter); ++} ++ ++void Hal_InitChannelPlan(struct adapter *padapter) ++{ ++} ++ ++bool HalDetectPwrDownMode88E(struct adapter *Adapter) ++{ ++ u8 tmpvalue = 0; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; ++ ++ EFUSE_ShadowRead(Adapter, 1, EEPROM_RF_FEATURE_OPTION_88E, (u32 *)&tmpvalue); ++ ++ /* 2010/08/25 MH INF priority > PDN Efuse value. */ ++ if (tmpvalue & BIT(4) && pwrctrlpriv->reg_pdnmode) ++ pHalData->pwrdown = true; ++ else ++ pHalData->pwrdown = false; ++ ++ DBG_88E("HalDetectPwrDownMode(): PDN =%d\n", pHalData->pwrdown); ++ ++ return pHalData->pwrdown; ++} /* HalDetectPwrDownMode */ ++ ++/* This function is used only for 92C to set REG_BCN_CTRL(0x550) register. */ ++/* We just reserve the value of the register in variable pHalData->RegBcnCtrlVal and then operate */ ++/* the value of the register via atomic operation. */ ++/* This prevents from race condition when setting this register. */ ++/* The value of pHalData->RegBcnCtrlVal is initialized in HwConfigureRTL8192CE() function. */ ++ ++void SetBcnCtrlReg(struct adapter *padapter, u8 SetBits, u8 ClearBits) ++{ ++ struct hal_data_8188e *pHalData; ++ ++ pHalData = GET_HAL_DATA(padapter); ++ ++ pHalData->RegBcnCtrlVal |= SetBits; ++ pHalData->RegBcnCtrlVal &= ~ClearBits; ++ ++ rtw_write8(padapter, REG_BCN_CTRL, (u8)pHalData->RegBcnCtrlVal); ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_mp.c b/drivers/staging/r8188eu/hal/rtl8188e_mp.c +new file mode 100644 +index 000000000000..fc13db705511 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_mp.c +@@ -0,0 +1,798 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTL8188E_MP_C_ ++ ++#include "../include/drv_types.h" ++#include "../include/rtw_mp.h" ++#include "../include/rtl8188e_hal.h" ++#include "../include/rtl8188e_dm.h" ++ ++s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct odm_dm_struct *pDM_Odm = &pHalData->odmpriv; ++ ++ if (!netif_running(padapter->pnetdev)) ++ return _FAIL; ++ ++ if (!check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE)) ++ return _FAIL; ++ ++ if (enable) ++ pDM_Odm->RFCalibrateInfo.bTXPowerTracking = true; ++ else ++ pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = false; ++ ++ return _SUCCESS; ++} ++ ++void Hal_GetPowerTracking(struct adapter *padapter, u8 *enable) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct odm_dm_struct *pDM_Odm = &pHalData->odmpriv; ++ ++ *enable = pDM_Odm->RFCalibrateInfo.TxPowerTrackControl; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: mpt_SwitchRfSetting ++ * ++ * Overview: Change RF Setting when we siwthc channel/rate/BW for MP. ++ * ++ * Input: struct adapter * pAdapter ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 01/08/2009 MHC Suggestion from SD3 Willis for 92S series. ++ * 01/09/2009 MHC Add CCK modification for 40MHZ. Suggestion from SD3. ++ * ++ *---------------------------------------------------------------------------*/ ++void Hal_mpt_SwitchRfSetting(struct adapter *pAdapter) ++{ ++ struct mp_priv *pmp = &pAdapter->mppriv; ++ ++ /* <20120525, Kordan> Dynamic mechanism for APK, asked by Dennis. */ ++ pmp->MptCtx.backup0x52_RF_A = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); ++ pmp->MptCtx.backup0x52_RF_B = (u8)PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0); ++ PHY_SetRFReg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0, 0xD); ++ PHY_SetRFReg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0, 0xD); ++} ++/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/ ++ ++/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ ++void Hal_MPT_CCKTxPowerAdjust(struct adapter *Adapter, bool bInCH14) ++{ ++ u32 TempVal = 0, TempVal2 = 0, TempVal3 = 0; ++ u32 CurrCCKSwingVal = 0, CCKSwingIndex = 12; ++ u8 i; ++ ++ /* get current cck swing value and check 0xa22 & 0xa23 later to match the table. */ ++ CurrCCKSwingVal = read_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord); ++ ++ if (!bInCH14) { ++ /* Readback the current bb cck swing value and compare with the table to */ ++ /* get the current swing index */ ++ for (i = 0; i < CCK_TABLE_SIZE; i++) { ++ if (((CurrCCKSwingVal & 0xff) == (u32)CCKSwingTable_Ch1_Ch13[i][0]) && ++ (((CurrCCKSwingVal & 0xff00) >> 8) == (u32)CCKSwingTable_Ch1_Ch13[i][1])) { ++ CCKSwingIndex = i; ++ break; ++ } ++ } ++ ++ /* Write 0xa22 0xa23 */ ++ TempVal = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][0] + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][1] << 8); ++ ++ /* Write 0xa24 ~ 0xa27 */ ++ TempVal2 = 0; ++ TempVal2 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][2] + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][3] << 8) + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][4] << 16) + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][5] << 24); ++ ++ /* Write 0xa28 0xa29 */ ++ TempVal3 = 0; ++ TempVal3 = CCKSwingTable_Ch1_Ch13[CCKSwingIndex][6] + ++ (CCKSwingTable_Ch1_Ch13[CCKSwingIndex][7] << 8); ++ } else { ++ for (i = 0; i < CCK_TABLE_SIZE; i++) { ++ if (((CurrCCKSwingVal & 0xff) == (u32)CCKSwingTable_Ch14[i][0]) && ++ (((CurrCCKSwingVal & 0xff00) >> 8) == (u32)CCKSwingTable_Ch14[i][1])) { ++ CCKSwingIndex = i; ++ break; ++ } ++ } ++ ++ /* Write 0xa22 0xa23 */ ++ TempVal = CCKSwingTable_Ch14[CCKSwingIndex][0] + ++ (CCKSwingTable_Ch14[CCKSwingIndex][1] << 8); ++ ++ /* Write 0xa24 ~ 0xa27 */ ++ TempVal2 = 0; ++ TempVal2 = CCKSwingTable_Ch14[CCKSwingIndex][2] + ++ (CCKSwingTable_Ch14[CCKSwingIndex][3] << 8) + ++ (CCKSwingTable_Ch14[CCKSwingIndex][4] << 16) + ++ (CCKSwingTable_Ch14[CCKSwingIndex][5] << 24); ++ ++ /* Write 0xa28 0xa29 */ ++ TempVal3 = 0; ++ TempVal3 = CCKSwingTable_Ch14[CCKSwingIndex][6] + ++ (CCKSwingTable_Ch14[CCKSwingIndex][7] << 8); ++ } ++ ++ write_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord, TempVal); ++ write_bbreg(Adapter, rCCK0_TxFilter2, bMaskDWord, TempVal2); ++ write_bbreg(Adapter, rCCK0_DebugPort, bMaskLWord, TempVal3); ++} ++ ++void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ struct mpt_context *pMptCtx = &pAdapter->mppriv.MptCtx; ++ struct odm_dm_struct *pDM_Odm = &pHalData->odmpriv; ++ s32 TempCCk; ++ u8 CCK_index, CCK_index_old = 0; ++ u8 Action = 0; /* 0: no action, 1: even->odd, 2:odd->even */ ++ s32 i = 0; ++ ++ if (!IS_92C_SERIAL(pHalData->VersionID)) ++ return; ++ if (beven && !pMptCtx->bMptIndexEven) { ++ /* odd->even */ ++ Action = 2; ++ pMptCtx->bMptIndexEven = true; ++ } else if (!beven && pMptCtx->bMptIndexEven) { ++ /* even->odd */ ++ Action = 1; ++ pMptCtx->bMptIndexEven = false; ++ } ++ ++ if (Action != 0) { ++ /* Query CCK default setting From 0xa24 */ ++ TempCCk = read_bbreg(pAdapter, rCCK0_TxFilter2, bMaskDWord) & bMaskCCK; ++ for (i = 0; i < CCK_TABLE_SIZE; i++) { ++ if (pDM_Odm->RFCalibrateInfo.bCCKinCH14) { ++ if (!memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch14[i][2], 4)) { ++ CCK_index_old = (u8)i; ++ break; ++ } ++ } else { ++ if (!memcmp((void *)&TempCCk, (void *)&CCKSwingTable_Ch1_Ch13[i][2], 4)) { ++ CCK_index_old = (u8)i; ++ break; ++ } ++ } ++ } ++ ++ if (Action == 1) ++ CCK_index = CCK_index_old - 1; ++ else ++ CCK_index = CCK_index_old + 1; ++ ++ /* Adjust CCK according to gain index */ ++ if (!pDM_Odm->RFCalibrateInfo.bCCKinCH14) { ++ rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch1_Ch13[CCK_index][0]); ++ rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch1_Ch13[CCK_index][1]); ++ rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch1_Ch13[CCK_index][2]); ++ rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch1_Ch13[CCK_index][3]); ++ rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch1_Ch13[CCK_index][4]); ++ rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch1_Ch13[CCK_index][5]); ++ rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch1_Ch13[CCK_index][6]); ++ rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch1_Ch13[CCK_index][7]); ++ } else { ++ rtw_write8(pAdapter, 0xa22, CCKSwingTable_Ch14[CCK_index][0]); ++ rtw_write8(pAdapter, 0xa23, CCKSwingTable_Ch14[CCK_index][1]); ++ rtw_write8(pAdapter, 0xa24, CCKSwingTable_Ch14[CCK_index][2]); ++ rtw_write8(pAdapter, 0xa25, CCKSwingTable_Ch14[CCK_index][3]); ++ rtw_write8(pAdapter, 0xa26, CCKSwingTable_Ch14[CCK_index][4]); ++ rtw_write8(pAdapter, 0xa27, CCKSwingTable_Ch14[CCK_index][5]); ++ rtw_write8(pAdapter, 0xa28, CCKSwingTable_Ch14[CCK_index][6]); ++ rtw_write8(pAdapter, 0xa29, CCKSwingTable_Ch14[CCK_index][7]); ++ } ++ } ++} ++/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ ++ ++/* ++ * SetChannel ++ * Description ++ * Use H2C command to change channel, ++ * not only modify rf register, but also other setting need to be done. ++ */ ++void Hal_SetChannel(struct adapter *pAdapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ struct mp_priv *pmp = &pAdapter->mppriv; ++ struct odm_dm_struct *pDM_Odm = &pHalData->odmpriv; ++ u8 eRFPath; ++ u8 channel = pmp->channel; ++ ++ /* set RF channel register */ ++ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) ++ _write_rfreg(pAdapter, eRFPath, ODM_CHANNEL, 0x3FF, channel); ++ Hal_mpt_SwitchRfSetting(pAdapter); ++ ++ SelectChannel(pAdapter, channel); ++ ++ if (pHalData->CurrentChannel == 14 && !pDM_Odm->RFCalibrateInfo.bCCKinCH14) { ++ pDM_Odm->RFCalibrateInfo.bCCKinCH14 = true; ++ Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14); ++ } else if (pHalData->CurrentChannel != 14 && pDM_Odm->RFCalibrateInfo.bCCKinCH14) { ++ pDM_Odm->RFCalibrateInfo.bCCKinCH14 = false; ++ Hal_MPT_CCKTxPowerAdjust(pAdapter, pDM_Odm->RFCalibrateInfo.bCCKinCH14); ++ } ++} ++ ++/* ++ * Notice ++ * Switch bandwitdth may change center frequency(channel) ++ */ ++void Hal_SetBandwidth(struct adapter *pAdapter) ++{ ++ struct mp_priv *pmp = &pAdapter->mppriv; ++ ++ SetBWMode(pAdapter, pmp->bandwidth, pmp->prime_channel_offset); ++ Hal_mpt_SwitchRfSetting(pAdapter); ++} ++ ++void Hal_SetCCKTxPower(struct adapter *pAdapter, u8 *TxPower) ++{ ++ u32 tmpval = 0; ++ ++ /* rf-A cck tx power */ ++ write_bbreg(pAdapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, TxPower[RF_PATH_A]); ++ tmpval = (TxPower[RF_PATH_A] << 16) | (TxPower[RF_PATH_A] << 8) | TxPower[RF_PATH_A]; ++ write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); ++ ++ /* rf-B cck tx power */ ++ write_bbreg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, TxPower[RF_PATH_B]); ++ tmpval = (TxPower[RF_PATH_B] << 16) | (TxPower[RF_PATH_B] << 8) | TxPower[RF_PATH_B]; ++ write_bbreg(pAdapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); ++} ++ ++void Hal_SetOFDMTxPower(struct adapter *pAdapter, u8 *TxPower) ++{ ++ u32 TxAGC = 0; ++ u8 tmpval = 0; ++ ++ /* HT Tx-rf(A) */ ++ tmpval = TxPower[RF_PATH_A]; ++ TxAGC = (tmpval << 24) | (tmpval << 16) | (tmpval << 8) | tmpval; ++ ++ write_bbreg(pAdapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC); ++ ++ /* HT Tx-rf(B) */ ++ tmpval = TxPower[RF_PATH_B]; ++ TxAGC = (tmpval << 24) | (tmpval << 16) | (tmpval << 8) | tmpval; ++ ++ write_bbreg(pAdapter, rTxAGC_B_Rate18_06, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Rate54_24, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Mcs03_Mcs00, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Mcs07_Mcs04, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Mcs11_Mcs08, bMaskDWord, TxAGC); ++ write_bbreg(pAdapter, rTxAGC_B_Mcs15_Mcs12, bMaskDWord, TxAGC); ++} ++ ++void Hal_SetAntennaPathPower(struct adapter *pAdapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ u8 TxPowerLevel[RF_PATH_MAX]; ++ u8 rfPath; ++ ++ TxPowerLevel[RF_PATH_A] = pAdapter->mppriv.txpoweridx; ++ TxPowerLevel[RF_PATH_B] = pAdapter->mppriv.txpoweridx_b; ++ ++ switch (pAdapter->mppriv.antenna_tx) { ++ case ANTENNA_A: ++ default: ++ rfPath = RF_PATH_A; ++ break; ++ case ANTENNA_B: ++ rfPath = RF_PATH_B; ++ break; ++ case ANTENNA_C: ++ rfPath = RF_PATH_C; ++ break; ++ } ++ ++ switch (pHalData->rf_chip) { ++ case RF_8225: ++ case RF_8256: ++ case RF_6052: ++ Hal_SetCCKTxPower(pAdapter, TxPowerLevel); ++ if (pAdapter->mppriv.rateidx < MPT_RATE_6M) /* CCK rate */ ++ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath] % 2 == 0); ++ Hal_SetOFDMTxPower(pAdapter, TxPowerLevel); ++ break; ++ default: ++ break; ++ } ++} ++ ++void Hal_SetTxPower(struct adapter *pAdapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ u8 TxPower = pAdapter->mppriv.txpoweridx; ++ u8 TxPowerLevel[RF_PATH_MAX]; ++ u8 rf, rfPath; ++ ++ for (rf = 0; rf < RF_PATH_MAX; rf++) ++ TxPowerLevel[rf] = TxPower; ++ ++ switch (pAdapter->mppriv.antenna_tx) { ++ case ANTENNA_A: ++ default: ++ rfPath = RF_PATH_A; ++ break; ++ case ANTENNA_B: ++ rfPath = RF_PATH_B; ++ break; ++ case ANTENNA_C: ++ rfPath = RF_PATH_C; ++ break; ++ } ++ ++ switch (pHalData->rf_chip) { ++ /* 2008/09/12 MH Test only !! We enable the TX power tracking for MP!!!!! */ ++ /* We should call normal driver API later!! */ ++ case RF_8225: ++ case RF_8256: ++ case RF_6052: ++ Hal_SetCCKTxPower(pAdapter, TxPowerLevel); ++ if (pAdapter->mppriv.rateidx < MPT_RATE_6M) /* CCK rate */ ++ Hal_MPT_CCKTxPowerAdjustbyIndex(pAdapter, TxPowerLevel[rfPath] % 2 == 0); ++ Hal_SetOFDMTxPower(pAdapter, TxPowerLevel); ++ break; ++ default: ++ break; ++ } ++} ++ ++void Hal_SetDataRate(struct adapter *pAdapter) ++{ ++ Hal_mpt_SwitchRfSetting(pAdapter); ++} ++ ++void Hal_SetAntenna(struct adapter *pAdapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ ++ struct ant_sel_ofdm *p_ofdm_tx; /* OFDM Tx register */ ++ struct ant_sel_cck *p_cck_txrx; ++ u8 r_rx_antenna_ofdm = 0, r_ant_select_cck_val = 0; ++ u8 chgTx = 0, chgRx = 0; ++ u32 r_ant_select_ofdm_val = 0, r_ofdm_tx_en_val = 0; ++ ++ p_ofdm_tx = (struct ant_sel_ofdm *)&r_ant_select_ofdm_val; ++ p_cck_txrx = (struct ant_sel_cck *)&r_ant_select_cck_val; ++ ++ p_ofdm_tx->r_ant_ht1 = 0x1; ++ p_ofdm_tx->r_ant_ht2 = 0x2; /* Second TX RF path is A */ ++ p_ofdm_tx->r_ant_non_ht = 0x3; /* 0x1+0x2=0x3 */ ++ ++ switch (pAdapter->mppriv.antenna_tx) { ++ case ANTENNA_A: ++ p_ofdm_tx->r_tx_antenna = 0x1; ++ r_ofdm_tx_en_val = 0x1; ++ p_ofdm_tx->r_ant_l = 0x1; ++ p_ofdm_tx->r_ant_ht_s1 = 0x1; ++ p_ofdm_tx->r_ant_non_ht_s1 = 0x1; ++ p_cck_txrx->r_ccktx_enable = 0x8; ++ chgTx = 1; ++ ++ /* From SD3 Willis suggestion !!! Set RF A=TX and B as standby */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1); ++ r_ofdm_tx_en_val = 0x3; ++ ++ /* Power save */ ++ ++ /* We need to close RFB by SW control */ ++ if (pHalData->rf_type == RF_2T2R) { ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT(10), 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT(26), 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT(10), 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT(1), 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT(17), 0); ++ } ++ break; ++ case ANTENNA_B: ++ p_ofdm_tx->r_tx_antenna = 0x2; ++ r_ofdm_tx_en_val = 0x2; ++ p_ofdm_tx->r_ant_l = 0x2; ++ p_ofdm_tx->r_ant_ht_s1 = 0x2; ++ p_ofdm_tx->r_ant_non_ht_s1 = 0x2; ++ p_cck_txrx->r_ccktx_enable = 0x4; ++ chgTx = 1; ++ /* From SD3 Willis suggestion !!! Set RF A as standby */ ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); ++ ++ /* Power save */ ++ /* cosa r_ant_select_ofdm_val = 0x22222222; */ ++ ++ /* 2008/10/31 MH From SD3 Willi's suggestion. We must read RF 1T table. */ ++ /* 2009/01/08 MH From Sd3 Willis. We need to close RFA by SW control */ ++ if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_1T2R) { ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT(10), 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT(10), 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT(26), 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT(1), 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT(17), 1); ++ } ++ break; ++ case ANTENNA_AB: /* For 8192S */ ++ p_ofdm_tx->r_tx_antenna = 0x3; ++ r_ofdm_tx_en_val = 0x3; ++ p_ofdm_tx->r_ant_l = 0x3; ++ p_ofdm_tx->r_ant_ht_s1 = 0x3; ++ p_ofdm_tx->r_ant_non_ht_s1 = 0x3; ++ p_cck_txrx->r_ccktx_enable = 0xC; ++ chgTx = 1; ++ ++ /* From SD3 Willis suggestion !!! Set RF B as standby */ ++ PHY_SetBBReg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); ++ PHY_SetBBReg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); ++ ++ /* Disable Power save */ ++ /* cosa r_ant_select_ofdm_val = 0x3321333; */ ++ /* 2009/01/08 MH From Sd3 Willis. We need to enable RFA/B by SW control */ ++ if (pHalData->rf_type == RF_2T2R) { ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT(10), 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT(26), 0); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT(1), 1); ++ PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFParameter, BIT(17), 1); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ /* r_rx_antenna_ofdm, bit0=A, bit1=B, bit2=C, bit3=D */ ++ /* r_cckrx_enable : CCK default, 0=A, 1=B, 2=C, 3=D */ ++ /* r_cckrx_enable_2 : CCK option, 0=A, 1=B, 2=C, 3=D */ ++ switch (pAdapter->mppriv.antenna_rx) { ++ case ANTENNA_A: ++ r_rx_antenna_ofdm = 0x1; /* A */ ++ p_cck_txrx->r_cckrx_enable = 0x0; /* default: A */ ++ p_cck_txrx->r_cckrx_enable_2 = 0x0; /* option: A */ ++ chgRx = 1; ++ break; ++ case ANTENNA_B: ++ r_rx_antenna_ofdm = 0x2; /* B */ ++ p_cck_txrx->r_cckrx_enable = 0x1; /* default: B */ ++ p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option: B */ ++ chgRx = 1; ++ break; ++ case ANTENNA_AB: ++ r_rx_antenna_ofdm = 0x3; /* AB */ ++ p_cck_txrx->r_cckrx_enable = 0x0; /* default:A */ ++ p_cck_txrx->r_cckrx_enable_2 = 0x1; /* option:B */ ++ chgRx = 1; ++ break; ++ default: ++ break; ++ } ++ ++ if (chgTx && chgRx) { ++ switch (pHalData->rf_chip) { ++ case RF_8225: ++ case RF_8256: ++ case RF_6052: ++ /* r_ant_sel_cck_val = r_ant_select_cck_val; */ ++ PHY_SetBBReg(pAdapter, rFPGA1_TxInfo, 0x7fffffff, r_ant_select_ofdm_val); /* OFDM Tx */ ++ PHY_SetBBReg(pAdapter, rFPGA0_TxInfo, 0x0000000f, r_ofdm_tx_en_val); /* OFDM Tx */ ++ PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /* OFDM Rx */ ++ PHY_SetBBReg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /* OFDM Rx */ ++ PHY_SetBBReg(pAdapter, rCCK0_AFESetting, bMaskByte3, r_ant_select_cck_val); /* CCK TxRx */ ++ ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++s32 Hal_SetThermalMeter(struct adapter *pAdapter, u8 target_ther) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ ++ if (!netif_running(pAdapter->pnetdev)) ++ return _FAIL; ++ ++ if (!check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE)) ++ return _FAIL; ++ ++ target_ther &= 0xff; ++ if (target_ther < 0x07) ++ target_ther = 0x07; ++ else if (target_ther > 0x1d) ++ target_ther = 0x1d; ++ ++ pHalData->EEPROMThermalMeter = target_ther; ++ ++ return _SUCCESS; ++} ++ ++void Hal_TriggerRFThermalMeter(struct adapter *pAdapter) ++{ ++ _write_rfreg(pAdapter, RF_PATH_A, RF_T_METER_88E, BIT(17) | BIT(16), 0x03); ++} ++ ++u8 Hal_ReadRFThermalMeter(struct adapter *pAdapter) ++{ ++ u32 ThermalValue = 0; ++ ++ ThermalValue = _read_rfreg(pAdapter, RF_PATH_A, RF_T_METER_88E, 0xfc00); ++ return (u8)ThermalValue; ++} ++ ++void Hal_GetThermalMeter(struct adapter *pAdapter, u8 *value) ++{ ++ Hal_TriggerRFThermalMeter(pAdapter); ++ msleep(1000); ++ *value = Hal_ReadRFThermalMeter(pAdapter); ++} ++ ++void Hal_SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart) ++{ ++ pAdapter->mppriv.MptCtx.bSingleCarrier = bStart; ++ if (bStart) { ++ /* Start Single Carrier. */ ++ /* 1. if OFDM block on? */ ++ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */ ++ ++ /* 2. set CCK test mode off, set to CCK normal mode */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); ++ /* 3. turn on scramble setting */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); ++ /* 4. Turn On Single Carrier Tx and turn off the other test modes. */ ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bEnable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ /* for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ } else { ++ /* Stop Single Carrier. */ ++ /* Turn off all test modes. */ ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ msleep(10); ++ ++ /* BB Reset */ ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); ++ ++ /* Stop for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ } ++} ++ ++void Hal_SetSingleToneTx(struct adapter *pAdapter, u8 bStart) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter); ++ bool is92C = IS_92C_SERIAL(pHalData->VersionID); ++ ++ u8 rfPath; ++ u32 reg58 = 0x0; ++ switch (pAdapter->mppriv.antenna_tx) { ++ case ANTENNA_A: ++ default: ++ rfPath = RF_PATH_A; ++ break; ++ case ANTENNA_B: ++ rfPath = RF_PATH_B; ++ break; ++ case ANTENNA_C: ++ rfPath = RF_PATH_C; ++ break; ++ } ++ ++ pAdapter->mppriv.MptCtx.bSingleTone = bStart; ++ if (bStart) { ++ /* Start Single Tone. */ ++ /* <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */ ++ if (IS_HARDWARE_TYPE_8188E(pAdapter)) { ++ reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask); ++ reg58 &= 0xFFFFFFF0; ++ reg58 += 2; ++ PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58); ++ } ++ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x0); ++ PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x0); ++ ++ if (is92C) { ++ _write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT(19), 0x01); ++ rtw_usleep_os(100); ++ if (rfPath == RF_PATH_A) ++ write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x10000); /* PAD all on. */ ++ else if (rfPath == RF_PATH_B) ++ write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x10000); /* PAD all on. */ ++ write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /* PAD all on. */ ++ rtw_usleep_os(100); ++ } else { ++ write_rfreg(pAdapter, rfPath, 0x21, 0xd4000); ++ rtw_usleep_os(100); ++ write_rfreg(pAdapter, rfPath, 0x00, 0x2001f); /* PAD all on. */ ++ rtw_usleep_os(100); ++ } ++ ++ /* for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ ++ } else { ++ /* Stop Single Tone. */ ++ /* <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu) */ ++ /* <20120326, Kordan> Only in single tone mode. (asked by Edlu) */ ++ if (IS_HARDWARE_TYPE_8188E(pAdapter)) { ++ reg58 = PHY_QueryRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask); ++ reg58 &= 0xFFFFFFF0; ++ PHY_SetRFReg(pAdapter, RF_PATH_A, LNA_Low_Gain_3, bRFRegOffsetMask, reg58); ++ } ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x1); ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x1); ++ if (is92C) { ++ _write_rfreg(pAdapter, RF_PATH_A, 0x21, BIT(19), 0x00); ++ rtw_usleep_os(100); ++ write_rfreg(pAdapter, RF_PATH_A, 0x00, 0x32d75); /* PAD all on. */ ++ write_rfreg(pAdapter, RF_PATH_B, 0x00, 0x32d75); /* PAD all on. */ ++ rtw_usleep_os(100); ++ } else { ++ write_rfreg(pAdapter, rfPath, 0x21, 0x54000); ++ rtw_usleep_os(100); ++ write_rfreg(pAdapter, rfPath, 0x00, 0x30000); /* PAD all on. */ ++ rtw_usleep_os(100); ++ } ++ ++ /* Stop for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ } ++} ++ ++void Hal_SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart) ++{ ++ pAdapter->mppriv.MptCtx.bCarrierSuppression = bStart; ++ if (bStart) { ++ /* Start Carrier Suppression. */ ++ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) { ++ /* 1. if CCK block on? */ ++ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn)) ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */ ++ ++ /* Turn Off All Test Mode */ ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /* transmit mode */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x0); /* turn off scramble setting */ ++ ++ /* Set CCK Tx Test Rate */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, 0x0); /* Set FTxRate to 1Mbps */ ++ } ++ ++ /* for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ } else { ++ /* Stop Carrier Suppression. */ ++ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) { ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /* normal mode */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x1); /* turn on scramble setting */ ++ ++ /* BB Reset */ ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); ++ } ++ ++ /* Stop for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ } ++} ++ ++void Hal_SetCCKContinuousTx(struct adapter *pAdapter, u8 bStart) ++{ ++ u32 cckrate; ++ ++ if (bStart) { ++ /* 1. if CCK block on? */ ++ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn)) ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/* set CCK block on */ ++ ++ /* Turn Off All Test Mode */ ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ /* Set CCK Tx Test Rate */ ++ cckrate = pAdapter->mppriv.rateidx; ++ write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, cckrate); ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /* transmit mode */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); /* turn on scramble setting */ ++ ++ /* for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ } else { ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /* normal mode */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); /* turn on scramble setting */ ++ ++ /* BB Reset */ ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); ++ ++ /* Stop for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ } ++ ++ pAdapter->mppriv.MptCtx.bCckContTx = bStart; ++ pAdapter->mppriv.MptCtx.bOfdmContTx = false; ++} /* mpt_StartCckContTx */ ++ ++void Hal_SetOFDMContinuousTx(struct adapter *pAdapter, u8 bStart) ++{ ++ if (bStart) { ++ /* 1. if OFDM block on? */ ++ if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) ++ write_bbreg(pAdapter, rFPGA0_RFMOD, bOFDMEn, bEnable);/* set OFDM block on */ ++ ++ /* 2. set CCK test mode off, set to CCK normal mode */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, bDisable); ++ ++ /* 3. turn on scramble setting */ ++ write_bbreg(pAdapter, rCCK0_System, bCCKScramble, bEnable); ++ /* 4. Turn On Continue Tx and turn off the other test modes. */ ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bEnable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ ++ /* for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); ++ ++ } else { ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMContinueTx, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleCarrier, bDisable); ++ write_bbreg(pAdapter, rOFDM1_LSTF, bOFDMSingleTone, bDisable); ++ /* Delay 10 ms */ ++ msleep(10); ++ /* BB Reset */ ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); ++ write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); ++ ++ /* Stop for dynamic set Power index. */ ++ write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); ++ write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); ++ } ++ ++ pAdapter->mppriv.MptCtx.bCckContTx = false; ++ pAdapter->mppriv.MptCtx.bOfdmContTx = bStart; ++} /* mpt_StartOfdmContTx */ ++ ++void Hal_SetContinuousTx(struct adapter *pAdapter, u8 bStart) ++{ ++ pAdapter->mppriv.MptCtx.bStartContTx = bStart; ++ if (pAdapter->mppriv.rateidx <= MPT_RATE_11M) ++ Hal_SetCCKContinuousTx(pAdapter, bStart); ++ else if ((pAdapter->mppriv.rateidx >= MPT_RATE_6M) && ++ (pAdapter->mppriv.rateidx <= MPT_RATE_MCS15)) ++ Hal_SetOFDMContinuousTx(pAdapter, bStart); ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c +new file mode 100644 +index 000000000000..30a9dca8f453 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c +@@ -0,0 +1,1105 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTL8188E_PHYCFG_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtw_iol.h" ++#include "../include/rtl8188e_hal.h" ++ ++/*---------------------------Define Local Constant---------------------------*/ ++/* Channel switch:The size of command tables for switch channel*/ ++#define MAX_PRECMD_CNT 16 ++#define MAX_RFDEPENDCMD_CNT 16 ++#define MAX_POSTCMD_CNT 16 ++ ++#define MAX_DOZE_WAITING_TIMES_9x 64 ++ ++/*---------------------------Define Local Constant---------------------------*/ ++ ++/*------------------------Define global variable-----------------------------*/ ++ ++/*------------------------Define local variable------------------------------*/ ++ ++/*--------------------Define export function prototype-----------------------*/ ++/* Please refer to header file */ ++/*--------------------Define export function prototype-----------------------*/ ++ ++/*----------------------------Function Body----------------------------------*/ ++/* */ ++/* 1. BB register R/W API */ ++/* */ ++ ++/** ++* Function: phy_CalculateBitShift ++* ++* OverView: Get shifted position of the BitMask ++* ++* Input: ++* u32 BitMask, ++* ++* Output: none ++* Return: u32 Return the shift bit bit position of the mask ++*/ ++static u32 phy_CalculateBitShift(u32 BitMask) ++{ ++ u32 i; ++ ++ for (i = 0; i <= 31; i++) { ++ if (((BitMask >> i) & 0x1) == 1) ++ break; ++ } ++ return i; ++} ++ ++/** ++* Function: PHY_QueryBBReg ++* ++* OverView: Read "sepcific bits" from BB register ++* ++* Input: ++* struct adapter *Adapter, ++* u32 RegAddr, The target address to be readback ++* u32 BitMask The target bit position in the target address ++* to be readback ++* Output: None ++* Return: u32 Data The readback register value ++* Note: This function is equal to "GetRegSetting" in PHY programming guide ++*/ ++u32 ++rtl8188e_PHY_QueryBBReg( ++ struct adapter *Adapter, ++ u32 RegAddr, ++ u32 BitMask ++ ) ++{ ++ u32 ReturnValue = 0, OriginalValue, BitShift; ++ ++ OriginalValue = rtw_read32(Adapter, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ ReturnValue = (OriginalValue & BitMask) >> BitShift; ++ return ReturnValue; ++} ++ ++/** ++* Function: PHY_SetBBReg ++* ++* OverView: Write "Specific bits" to BB register (page 8~) ++* ++* Input: ++* struct adapter *Adapter, ++* u32 RegAddr, The target address to be modified ++* u32 BitMask The target bit position in the target address ++* to be modified ++* u32 Data The new register value in the target bit position ++* of the target address ++* ++* Output: None ++* Return: None ++* Note: This function is equal to "PutRegSetting" in PHY programming guide ++*/ ++ ++void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ u32 OriginalValue, BitShift; ++ ++ if (BitMask != bMaskDWord) { /* if not "double word" write */ ++ OriginalValue = rtw_read32(Adapter, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ Data = ((OriginalValue & (~BitMask)) | (Data << BitShift)); ++ } ++ ++ rtw_write32(Adapter, RegAddr, Data); ++} ++ ++/* */ ++/* 2. RF register R/W API */ ++/* */ ++/** ++* Function: phy_RFSerialRead ++* ++* OverView: Read regster from RF chips ++* ++* Input: ++* struct adapter *Adapter, ++* enum rf_radio_path eRFPath, Radio path of A/B/C/D ++* u32 Offset, The target address to be read ++* ++* Output: None ++* Return: u32 reback value ++* Note: Threre are three types of serial operations: ++* 1. Software serial write ++* 2. Hardware LSSI-Low Speed Serial Interface ++* 3. Hardware HSSI-High speed ++* serial write. Driver need to implement (1) and (2). ++* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() ++*/ ++static u32 ++phy_RFSerialRead( ++ struct adapter *Adapter, ++ enum rf_radio_path eRFPath, ++ u32 Offset ++ ) ++{ ++ u32 retValue = 0; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ u32 NewOffset; ++ u32 tmplong, tmplong2; ++ u8 RfPiEnable = 0; ++ /* */ ++ /* Make sure RF register offset is correct */ ++ /* */ ++ Offset &= 0xff; ++ ++ /* */ ++ /* Switch page for 8256 RF IC */ ++ /* */ ++ NewOffset = Offset; ++ ++ /* For 92S LSSI Read RFLSSIRead */ ++ /* For RF A/B write 0x824/82c(does not work in the future) */ ++ /* We must use 0x824 for RF A and B to execute read trigger */ ++ tmplong = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord); ++ if (eRFPath == RF_PATH_A) ++ tmplong2 = tmplong; ++ else ++ tmplong2 = PHY_QueryBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord); ++ ++ tmplong2 = (tmplong2 & (~bLSSIReadAddress)) | (NewOffset << 23) | bLSSIReadEdge; /* T65 RF */ ++ ++ PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord, tmplong & (~bLSSIReadEdge)); ++ udelay(10);/* PlatformStallExecution(10); */ ++ ++ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2); ++ udelay(100);/* PlatformStallExecution(100); */ ++ ++ udelay(10);/* PlatformStallExecution(10); */ ++ ++ if (eRFPath == RF_PATH_A) ++ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter1, BIT(8)); ++ else if (eRFPath == RF_PATH_B) ++ RfPiEnable = (u8)PHY_QueryBBReg(Adapter, rFPGA0_XB_HSSIParameter1, BIT(8)); ++ ++ if (RfPiEnable) { /* Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF */ ++ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi, bLSSIReadBackData); ++ } else { /* Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF */ ++ retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack, bLSSIReadBackData); ++ } ++ return retValue; ++} ++ ++/** ++* Function: phy_RFSerialWrite ++* ++* OverView: Write data to RF register (page 8~) ++* ++* Input: ++* struct adapter *Adapter, ++* enum rf_radio_path eRFPath, Radio path of A/B/C/D ++* u32 Offset, The target address to be read ++* u32 Data The new register Data in the target bit position ++* of the target to be read ++* ++* Output: None ++* Return: None ++* Note: Threre are three types of serial operations: ++* 1. Software serial write ++* 2. Hardware LSSI-Low Speed Serial Interface ++* 3. Hardware HSSI-High speed ++* serial write. Driver need to implement (1) and (2). ++* This function is equal to the combination of RF_ReadReg() and RFLSSIRead() ++ * ++ * Note: For RF8256 only ++ * The total count of RTL8256(Zebra4) register is around 36 bit it only employs ++ * 4-bit RF address. RTL8256 uses "register mode control bit" (Reg00[12], Reg00[10]) ++ * to access register address bigger than 0xf. See "Appendix-4 in PHY Configuration ++ * programming guide" for more details. ++ * Thus, we define a sub-finction for RTL8526 register address conversion ++ * =========================================================== ++ * Register Mode RegCTL[1] RegCTL[0] Note ++ * (Reg00[12]) (Reg00[10]) ++ * =========================================================== ++ * Reg_Mode0 0 x Reg 0 ~15(0x0 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * Reg_Mode1 1 0 Reg 16 ~30(0x1 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * Reg_Mode2 1 1 Reg 31 ~ 45(0x1 ~ 0xf) ++ * ------------------------------------------------------------------ ++ * ++ * 2008/09/02 MH Add 92S RF definition ++ * ++ * ++ * ++*/ ++static void ++phy_RFSerialWrite( ++ struct adapter *Adapter, ++ enum rf_radio_path eRFPath, ++ u32 Offset, ++ u32 Data ++ ) ++{ ++ u32 DataAndAddr = 0; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct bb_reg_def *pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ u32 NewOffset; ++ ++ /* 2009/06/17 MH We can not execute IO for power save or other accident mode. */ ++ ++ Offset &= 0xff; ++ ++ /* */ ++ /* Switch page for 8256 RF IC */ ++ /* */ ++ NewOffset = Offset; ++ ++ /* */ ++ /* Put write addr in [5:0] and write data in [31:16] */ ++ /* */ ++ DataAndAddr = ((NewOffset << 20) | (Data & 0x000fffff)) & 0x0fffffff; /* T65 RF */ ++ ++ /* */ ++ /* Write Operation */ ++ /* */ ++ PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); ++} ++ ++/** ++* Function: PHY_QueryRFReg ++* ++* OverView: Query "Specific bits" to RF register (page 8~) ++* ++* Input: ++* struct adapter *Adapter, ++* enum rf_radio_path eRFPath, Radio path of A/B/C/D ++* u32 RegAddr, The target address to be read ++* u32 BitMask The target bit position in the target address ++* to be read ++* ++* Output: None ++* Return: u32 Readback value ++* Note: This function is equal to "GetRFRegSetting" in PHY programming guide ++*/ ++u32 rtl8188e_PHY_QueryRFReg(struct adapter *Adapter, enum rf_radio_path eRFPath, ++ u32 RegAddr, u32 BitMask) ++{ ++ u32 Original_Value, Readback_Value, BitShift; ++ ++ Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr); ++ ++ BitShift = phy_CalculateBitShift(BitMask); ++ Readback_Value = (Original_Value & BitMask) >> BitShift; ++ return Readback_Value; ++} ++ ++/** ++* Function: PHY_SetRFReg ++* ++* OverView: Write "Specific bits" to RF register (page 8~) ++* ++* Input: ++* struct adapter *Adapter, ++* enum rf_radio_path eRFPath, Radio path of A/B/C/D ++* u32 RegAddr, The target address to be modified ++* u32 BitMask The target bit position in the target address ++* to be modified ++* u32 Data The new register Data in the target bit position ++* of the target address ++* ++* Output: None ++* Return: None ++* Note: This function is equal to "PutRFRegSetting" in PHY programming guide ++*/ ++void ++rtl8188e_PHY_SetRFReg( ++ struct adapter *Adapter, ++ enum rf_radio_path eRFPath, ++ u32 RegAddr, ++ u32 BitMask, ++ u32 Data ++ ) ++{ ++ u32 Original_Value, BitShift; ++ ++ /* RF data is 12 bits only */ ++ if (BitMask != bRFRegOffsetMask) { ++ Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr); ++ BitShift = phy_CalculateBitShift(BitMask); ++ Data = ((Original_Value & (~BitMask)) | (Data << BitShift)); ++ } ++ ++ phy_RFSerialWrite(Adapter, eRFPath, RegAddr, Data); ++} ++ ++/* */ ++/* 3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. */ ++/* */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_MACConfig8192C ++ * ++ * Overview: Condig MAC by header file or parameter file. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 08/12/2008 MHC Create Version 0. ++ * ++ *---------------------------------------------------------------------------*/ ++s32 PHY_MACConfig8188E(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ int rtStatus = _SUCCESS; ++ ++ /* */ ++ /* Config MAC */ ++ /* */ ++ if (HAL_STATUS_FAILURE == ODM_ConfigMACWithHeaderFile(&pHalData->odmpriv)) ++ rtStatus = _FAIL; ++ ++ /* 2010.07.13 AMPDU aggregation number B */ ++ rtw_write16(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM); ++ ++ return rtStatus; ++} ++ ++/** ++* Function: phy_InitBBRFRegisterDefinition ++* ++* OverView: Initialize Register definition offset for Radio Path A/B/C/D ++* ++* Input: ++* struct adapter *Adapter, ++* ++* Output: None ++* Return: None ++* Note: The initialization value is constant and it should never be changes ++*/ ++static void ++phy_InitBBRFRegisterDefinition( ++ struct adapter *Adapter ++) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ ++ /* RF Interface Sowrtware Control */ ++ pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 LSBs if read 32-bit from 0x870 */ ++ pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; /* 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */ ++ pHalData->PHYRegDef[RF_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;/* 16 LSBs if read 32-bit from 0x874 */ ++ pHalData->PHYRegDef[RF_PATH_D].rfintfs = rFPGA0_XCD_RFInterfaceSW;/* 16 MSBs if read 32-bit from 0x874 (16-bit for 0x876) */ ++ ++ /* RF Interface Readback Value */ ++ pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB; /* 16 LSBs if read 32-bit from 0x8E0 */ ++ pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;/* 16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */ ++ pHalData->PHYRegDef[RF_PATH_C].rfintfi = rFPGA0_XCD_RFInterfaceRB;/* 16 LSBs if read 32-bit from 0x8E4 */ ++ pHalData->PHYRegDef[RF_PATH_D].rfintfi = rFPGA0_XCD_RFInterfaceRB;/* 16 MSBs if read 32-bit from 0x8E4 (16-bit for 0x8E6) */ ++ ++ /* RF Interface Output (and Enable) */ ++ pHalData->PHYRegDef[RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x860 */ ++ pHalData->PHYRegDef[RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE; /* 16 LSBs if read 32-bit from 0x864 */ ++ ++ /* RF Interface (Output and) Enable */ ++ pHalData->PHYRegDef[RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */ ++ pHalData->PHYRegDef[RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE; /* 16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */ ++ ++ /* Addr of LSSI. Wirte RF register by driver */ ++ pHalData->PHYRegDef[RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; /* LSSI Parameter */ ++ pHalData->PHYRegDef[RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter; ++ ++ /* RF parameter */ ++ pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter; /* BB Band Select */ ++ pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter; ++ pHalData->PHYRegDef[RF_PATH_C].rfLSSI_Select = rFPGA0_XCD_RFParameter; ++ pHalData->PHYRegDef[RF_PATH_D].rfLSSI_Select = rFPGA0_XCD_RFParameter; ++ ++ /* Tx AGC Gain Stage (same for all path. Should we remove this?) */ ++ pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */ ++ pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */ ++ pHalData->PHYRegDef[RF_PATH_C].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */ ++ pHalData->PHYRegDef[RF_PATH_D].rfTxGainStage = rFPGA0_TxGainStage; /* Tx gain stage */ ++ ++ /* Tranceiver A~D HSSI Parameter-1 */ ++ pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1; /* wire control parameter1 */ ++ pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1; /* wire control parameter1 */ ++ ++ /* Tranceiver A~D HSSI Parameter-2 */ ++ pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2; /* wire control parameter2 */ ++ pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2; /* wire control parameter2 */ ++ ++ /* RF switch Control */ ++ pHalData->PHYRegDef[RF_PATH_A].rfSwitchControl = rFPGA0_XAB_SwitchControl; /* TR/Ant switch control */ ++ pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl = rFPGA0_XAB_SwitchControl; ++ pHalData->PHYRegDef[RF_PATH_C].rfSwitchControl = rFPGA0_XCD_SwitchControl; ++ pHalData->PHYRegDef[RF_PATH_D].rfSwitchControl = rFPGA0_XCD_SwitchControl; ++ ++ /* AGC control 1 */ ++ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1; ++ pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1; ++ pHalData->PHYRegDef[RF_PATH_C].rfAGCControl1 = rOFDM0_XCAGCCore1; ++ pHalData->PHYRegDef[RF_PATH_D].rfAGCControl1 = rOFDM0_XDAGCCore1; ++ ++ /* AGC control 2 */ ++ pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2; ++ pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2; ++ pHalData->PHYRegDef[RF_PATH_C].rfAGCControl2 = rOFDM0_XCAGCCore2; ++ pHalData->PHYRegDef[RF_PATH_D].rfAGCControl2 = rOFDM0_XDAGCCore2; ++ ++ /* RX AFE control 1 */ ++ pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_C].rfRxIQImbalance = rOFDM0_XCRxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_D].rfRxIQImbalance = rOFDM0_XDRxIQImbalance; ++ ++ /* RX AFE control 1 */ ++ pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE; ++ pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE; ++ pHalData->PHYRegDef[RF_PATH_C].rfRxAFE = rOFDM0_XCRxAFE; ++ pHalData->PHYRegDef[RF_PATH_D].rfRxAFE = rOFDM0_XDRxAFE; ++ ++ /* Tx AFE control 1 */ ++ pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_C].rfTxIQImbalance = rOFDM0_XCTxIQImbalance; ++ pHalData->PHYRegDef[RF_PATH_D].rfTxIQImbalance = rOFDM0_XDTxIQImbalance; ++ ++ /* Tx AFE control 2 */ ++ pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE; ++ pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE; ++ pHalData->PHYRegDef[RF_PATH_C].rfTxAFE = rOFDM0_XCTxAFE; ++ pHalData->PHYRegDef[RF_PATH_D].rfTxAFE = rOFDM0_XDTxAFE; ++ ++ /* Tranceiver LSSI Readback SI mode */ ++ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack; ++ pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack; ++ pHalData->PHYRegDef[RF_PATH_C].rfLSSIReadBack = rFPGA0_XC_LSSIReadBack; ++ pHalData->PHYRegDef[RF_PATH_D].rfLSSIReadBack = rFPGA0_XD_LSSIReadBack; ++ ++ /* Tranceiver LSSI Readback PI mode */ ++ pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi = TransceiverA_HSPI_Readback; ++ pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi = TransceiverB_HSPI_Readback; ++} ++ ++void storePwrIndexDiffRateOffset(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ ++ if (RegAddr == rTxAGC_A_Rate18_06) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0] = Data; ++ if (RegAddr == rTxAGC_A_Rate54_24) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1] = Data; ++ if (RegAddr == rTxAGC_A_CCK1_Mcs32) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6] = Data; ++ if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0xffffff00) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7] = Data; ++ if (RegAddr == rTxAGC_A_Mcs03_Mcs00) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2] = Data; ++ if (RegAddr == rTxAGC_A_Mcs07_Mcs04) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3] = Data; ++ if (RegAddr == rTxAGC_A_Mcs11_Mcs08) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4] = Data; ++ if (RegAddr == rTxAGC_A_Mcs15_Mcs12) { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5] = Data; ++ if (pHalData->rf_type == RF_1T1R) ++ pHalData->pwrGroupCnt++; ++ } ++ if (RegAddr == rTxAGC_B_Rate18_06) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8] = Data; ++ if (RegAddr == rTxAGC_B_Rate54_24) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9] = Data; ++ if (RegAddr == rTxAGC_B_CCK1_55_Mcs32) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14] = Data; ++ if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0x000000ff) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15] = Data; ++ if (RegAddr == rTxAGC_B_Mcs03_Mcs00) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10] = Data; ++ if (RegAddr == rTxAGC_B_Mcs07_Mcs04) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11] = Data; ++ if (RegAddr == rTxAGC_B_Mcs11_Mcs08) ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12] = Data; ++ if (RegAddr == rTxAGC_B_Mcs15_Mcs12) { ++ pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13] = Data; ++ if (pHalData->rf_type != RF_1T1R) ++ pHalData->pwrGroupCnt++; ++ } ++} ++ ++static int phy_BB8188E_Config_ParaFile(struct adapter *Adapter) ++{ ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter); ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ int rtStatus = _SUCCESS; ++ ++ /* */ ++ /* 1. Read PHY_REG.TXT BB INIT!! */ ++ /* We will separate as 88C / 92C according to chip version */ ++ /* */ ++ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG)) ++ rtStatus = _FAIL; ++ if (rtStatus != _SUCCESS) ++ goto phy_BB8190_Config_ParaFile_Fail; ++ ++ /* 2. If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt */ ++ if (!pEEPROM->bautoload_fail_flag) { ++ pHalData->pwrGroupCnt = 0; ++ ++ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG_PG)) ++ rtStatus = _FAIL; ++ } ++ ++ if (rtStatus != _SUCCESS) ++ goto phy_BB8190_Config_ParaFile_Fail; ++ ++ /* 3. BB AGC table Initialization */ ++ if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_AGC_TAB)) ++ rtStatus = _FAIL; ++ ++ if (rtStatus != _SUCCESS) ++ goto phy_BB8190_Config_ParaFile_Fail; ++ ++phy_BB8190_Config_ParaFile_Fail: ++ ++ return rtStatus; ++} ++ ++int ++PHY_BBConfig8188E( ++ struct adapter *Adapter ++ ) ++{ ++ int rtStatus = _SUCCESS; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u32 RegVal; ++ u8 CrystalCap; ++ ++ phy_InitBBRFRegisterDefinition(Adapter); ++ ++ /* Enable BB and RF */ ++ RegVal = rtw_read16(Adapter, REG_SYS_FUNC_EN); ++ rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal | BIT(13) | BIT(0) | BIT(1))); ++ ++ /* 20090923 Joseph: Advised by Steven and Jenyu. Power sequence before init RF. */ ++ ++ rtw_write8(Adapter, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); ++ ++ rtw_write8(Adapter, REG_SYS_FUNC_EN, FEN_USBA | FEN_USBD | FEN_BB_GLB_RSTn | FEN_BBRSTB); ++ ++ /* Config BB and AGC */ ++ rtStatus = phy_BB8188E_Config_ParaFile(Adapter); ++ ++ /* write 0x24[16:11] = 0x24[22:17] = CrystalCap */ ++ CrystalCap = pHalData->CrystalCap & 0x3F; ++ PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, 0x7ff800, (CrystalCap | (CrystalCap << 6))); ++ ++ return rtStatus; ++} ++ ++int PHY_RFConfig8188E(struct adapter *Adapter) ++{ ++ int rtStatus = _SUCCESS; ++ ++ /* RF config */ ++ rtStatus = PHY_RF6052_Config8188E(Adapter); ++ return rtStatus; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_ConfigRFWithParaFile() ++ * ++ * Overview: This function read RF parameters from general file format, and do RF 3-wire ++ * ++ * Input: struct adapter *Adapter ++ * ps8 pFileName ++ * enum rf_radio_path eRFPath ++ * ++ * Output: NONE ++ * ++ * Return: RT_STATUS_SUCCESS: configuration file exist ++ * ++ * Note: Delay may be required for RF configuration ++ *---------------------------------------------------------------------------*/ ++int rtl8188e_PHY_ConfigRFWithParaFile(struct adapter *Adapter, u8 *pFileName, enum rf_radio_path eRFPath) ++{ ++ return _SUCCESS; ++} ++ ++void ++rtl8192c_PHY_GetHWRegOriginalValue( ++ struct adapter *Adapter ++ ) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ ++ /* read rx initial gain */ ++ pHalData->DefaultInitialGain[0] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XAAGCCore1, bMaskByte0); ++ pHalData->DefaultInitialGain[1] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XBAGCCore1, bMaskByte0); ++ pHalData->DefaultInitialGain[2] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XCAGCCore1, bMaskByte0); ++ pHalData->DefaultInitialGain[3] = (u8)PHY_QueryBBReg(Adapter, rOFDM0_XDAGCCore1, bMaskByte0); ++ ++ /* read framesync */ ++ pHalData->framesync = (u8)PHY_QueryBBReg(Adapter, rOFDM0_RxDetector3, bMaskByte0); ++ pHalData->framesyncC34 = PHY_QueryBBReg(Adapter, rOFDM0_RxDetector2, bMaskDWord); ++} ++ ++/* */ ++/* Description: */ ++/* Map dBm into Tx power index according to */ ++/* current HW model, for example, RF and PA, and */ ++/* current wireless mode. */ ++/* By Bruce, 2008-01-29. */ ++/* */ ++static u8 phy_DbmToTxPwrIdx(struct adapter *Adapter, enum wireless_mode WirelessMode, int PowerInDbm) ++{ ++ u8 TxPwrIdx = 0; ++ int Offset = 0; ++ ++ /* */ ++ /* Tested by MP, we found that CCK Index 0 equals to 8dbm, OFDM legacy equals to */ ++ /* 3dbm, and OFDM HT equals to 0dbm respectively. */ ++ /* Note: */ ++ /* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */ ++ /* By Bruce, 2008-01-29. */ ++ /* */ ++ switch (WirelessMode) { ++ case WIRELESS_MODE_B: ++ Offset = -7; ++ break; ++ ++ case WIRELESS_MODE_G: ++ case WIRELESS_MODE_N_24G: ++ default: ++ Offset = -8; ++ break; ++ } ++ ++ if ((PowerInDbm - Offset) > 0) ++ TxPwrIdx = (u8)((PowerInDbm - Offset) * 2); ++ else ++ TxPwrIdx = 0; ++ ++ /* Tx Power Index is too large. */ ++ if (TxPwrIdx > MAX_TXPWR_IDX_NMODE_92S) ++ TxPwrIdx = MAX_TXPWR_IDX_NMODE_92S; ++ ++ return TxPwrIdx; ++} ++ ++/* */ ++/* Description: */ ++/* Map Tx power index into dBm according to */ ++/* current HW model, for example, RF and PA, and */ ++/* current wireless mode. */ ++/* By Bruce, 2008-01-29. */ ++/* */ ++static int phy_TxPwrIdxToDbm(struct adapter *Adapter, enum wireless_mode WirelessMode, u8 TxPwrIdx) ++{ ++ int Offset = 0; ++ int PwrOutDbm = 0; ++ ++ /* */ ++ /* Tested by MP, we found that CCK Index 0 equals to -7dbm, OFDM legacy equals to -8dbm. */ ++ /* Note: */ ++ /* The mapping may be different by different NICs. Do not use this formula for what needs accurate result. */ ++ /* By Bruce, 2008-01-29. */ ++ /* */ ++ switch (WirelessMode) { ++ case WIRELESS_MODE_B: ++ Offset = -7; ++ break; ++ case WIRELESS_MODE_G: ++ case WIRELESS_MODE_N_24G: ++ default: ++ Offset = -8; ++ break; ++ } ++ ++ PwrOutDbm = TxPwrIdx / 2 + Offset; /* Discard the decimal part. */ ++ ++ return PwrOutDbm; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: GetTxPowerLevel8190() ++ * ++ * Overview: This function is export to "common" moudule ++ * ++ * Input: struct adapter *Adapter ++ * psByte Power Level ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ *---------------------------------------------------------------------------*/ ++void PHY_GetTxPowerLevel8188E(struct adapter *Adapter, u32 *powerlevel) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u8 TxPwrLevel = 0; ++ int TxPwrDbm; ++ ++ /* */ ++ /* Because the Tx power indexes are different, we report the maximum of them to */ ++ /* meet the CCX TPC request. By Bruce, 2008-01-31. */ ++ /* */ ++ ++ /* CCK */ ++ TxPwrLevel = pHalData->CurrentCckTxPwrIdx; ++ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_B, TxPwrLevel); ++ ++ /* Legacy OFDM */ ++ TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx + pHalData->LegacyHTTxPowerDiff; ++ ++ /* Compare with Legacy OFDM Tx power. */ ++ if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel) > TxPwrDbm) ++ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_G, TxPwrLevel); ++ ++ /* HT OFDM */ ++ TxPwrLevel = pHalData->CurrentOfdm24GTxPwrIdx; ++ ++ /* Compare with HT OFDM Tx power. */ ++ if (phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel) > TxPwrDbm) ++ TxPwrDbm = phy_TxPwrIdxToDbm(Adapter, WIRELESS_MODE_N_24G, TxPwrLevel); ++ ++ *powerlevel = TxPwrDbm; ++} ++ ++static void getTxPowerIndex88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel, ++ u8 *ofdmPowerLevel, u8 *BW20PowerLevel, ++ u8 *BW40PowerLevel) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u8 index = (channel - 1); ++ u8 TxCount = 0, path_nums; ++ ++ if ((RF_1T2R == pHalData->rf_type) || (RF_1T1R == pHalData->rf_type)) ++ path_nums = 1; ++ else ++ path_nums = 2; ++ ++ for (TxCount = 0; TxCount < path_nums; TxCount++) { ++ if (TxCount == RF_PATH_A) { ++ /* 1. CCK */ ++ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; ++ /* 2. OFDM */ ++ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index] + ++ pHalData->OFDM_24G_Diff[TxCount][RF_PATH_A]; ++ /* 1. BW20 */ ++ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[TxCount][RF_PATH_A]; ++ /* 2. BW40 */ ++ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; ++ } else if (TxCount == RF_PATH_B) { ++ /* 1. CCK */ ++ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; ++ /* 2. OFDM */ ++ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ /* 1. BW20 */ ++ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[TxCount][RF_PATH_A] + ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ /* 2. BW40 */ ++ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; ++ } else if (TxCount == RF_PATH_C) { ++ /* 1. CCK */ ++ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; ++ /* 2. OFDM */ ++ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_B][index] + ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ /* 1. BW20 */ ++ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_B][index] + ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ /* 2. BW40 */ ++ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; ++ } else if (TxCount == RF_PATH_D) { ++ /* 1. CCK */ ++ cckPowerLevel[TxCount] = pHalData->Index24G_CCK_Base[TxCount][index]; ++ /* 2. OFDM */ ++ ofdmPowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_B][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_C][index] + ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ ++ /* 1. BW20 */ ++ BW20PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_A][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_B][index] + ++ pHalData->BW20_24G_Diff[RF_PATH_C][index] + ++ pHalData->BW20_24G_Diff[TxCount][index]; ++ ++ /* 2. BW40 */ ++ BW40PowerLevel[TxCount] = pHalData->Index24G_BW40_Base[TxCount][index]; ++ } ++ } ++} ++ ++static void phy_PowerIndexCheck88E(struct adapter *Adapter, u8 channel, u8 *cckPowerLevel, ++ u8 *ofdmPowerLevel, u8 *BW20PowerLevel, u8 *BW40PowerLevel) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ ++ pHalData->CurrentCckTxPwrIdx = cckPowerLevel[0]; ++ pHalData->CurrentOfdm24GTxPwrIdx = ofdmPowerLevel[0]; ++ pHalData->CurrentBW2024GTxPwrIdx = BW20PowerLevel[0]; ++ pHalData->CurrentBW4024GTxPwrIdx = BW40PowerLevel[0]; ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: SetTxPowerLevel8190() ++ * ++ * Overview: This function is export to "HalCommon" moudule ++ * We must consider RF path later!!!!!!! ++ * ++ * Input: struct adapter *Adapter ++ * u8 channel ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * 2008/11/04 MHC We remove EEPROM_93C56. ++ * We need to move CCX relative code to independet file. ++ * 2009/01/21 MHC Support new EEPROM format from SD3 requirement. ++ * ++ *---------------------------------------------------------------------------*/ ++void ++PHY_SetTxPowerLevel8188E( ++ struct adapter *Adapter, ++ u8 channel ++ ) ++{ ++ u8 cckPowerLevel[MAX_TX_COUNT] = {0}; ++ u8 ofdmPowerLevel[MAX_TX_COUNT] = {0};/* [0]:RF-A, [1]:RF-B */ ++ u8 BW20PowerLevel[MAX_TX_COUNT] = {0}; ++ u8 BW40PowerLevel[MAX_TX_COUNT] = {0}; ++ ++ getTxPowerIndex88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]); ++ ++ phy_PowerIndexCheck88E(Adapter, channel, &cckPowerLevel[0], &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0]); ++ ++ rtl8188e_PHY_RF6052SetCckTxPower(Adapter, &cckPowerLevel[0]); ++ rtl8188e_PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0], &BW20PowerLevel[0], &BW40PowerLevel[0], channel); ++} ++ ++/* */ ++/* Description: */ ++/* Update transmit power level of all channel supported. */ ++/* */ ++/* TODO: */ ++/* A mode. */ ++/* By Bruce, 2008-02-04. */ ++/* */ ++bool ++PHY_UpdateTxPowerDbm8188E( ++ struct adapter *Adapter, ++ int powerInDbm ++ ) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u8 idx; ++ u8 rf_path; ++ ++ /* TODO: A mode Tx power. */ ++ u8 CckTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_B, powerInDbm); ++ u8 OfdmTxPwrIdx = phy_DbmToTxPwrIdx(Adapter, WIRELESS_MODE_N_24G, powerInDbm); ++ ++ if (OfdmTxPwrIdx - pHalData->LegacyHTTxPowerDiff > 0) ++ OfdmTxPwrIdx -= pHalData->LegacyHTTxPowerDiff; ++ else ++ OfdmTxPwrIdx = 0; ++ ++ for (idx = 0; idx < 14; idx++) { ++ for (rf_path = 0; rf_path < 2; rf_path++) { ++ pHalData->TxPwrLevelCck[rf_path][idx] = CckTxPwrIdx; ++ pHalData->TxPwrLevelHT40_1S[rf_path][idx] = ++ pHalData->TxPwrLevelHT40_2S[rf_path][idx] = OfdmTxPwrIdx; ++ } ++ } ++ return true; ++} ++ ++void ++PHY_ScanOperationBackup8188E( ++ struct adapter *Adapter, ++ u8 Operation ++ ) ++{ ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_SetBWModeCallback8192C() ++ * ++ * Overview: Timer callback function for SetSetBWMode ++ * ++ * Input: PRT_TIMER pTimer ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Note: (1) We do not take j mode into consideration now ++ * (2) Will two workitem of "switch channel" and "switch channel bandwidth" run ++ * concurrently? ++ *---------------------------------------------------------------------------*/ ++static void ++_PHY_SetBWMode92C( ++ struct adapter *Adapter ++) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u8 regBwOpMode; ++ u8 regRRSR_RSC; ++ ++ if (pHalData->rf_chip == RF_PSEUDO_11N) ++ return; ++ ++ /* There is no 40MHz mode in RF_8225. */ ++ if (pHalData->rf_chip == RF_8225) ++ return; ++ ++ if (Adapter->bDriverStopped) ++ return; ++ ++ /* 3 */ ++ /* 3<1>Set MAC register */ ++ /* 3 */ ++ ++ regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE); ++ regRRSR_RSC = rtw_read8(Adapter, REG_RRSR + 2); ++ ++ switch (pHalData->CurrentChannelBW) { ++ case HT_CHANNEL_WIDTH_20: ++ regBwOpMode |= BW_OPMODE_20MHZ; ++ /* 2007/02/07 Mark by Emily because we have not verify whether this register works */ ++ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); ++ break; ++ case HT_CHANNEL_WIDTH_40: ++ regBwOpMode &= ~BW_OPMODE_20MHZ; ++ /* 2007/02/07 Mark by Emily because we have not verify whether this register works */ ++ rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode); ++ regRRSR_RSC = (regRRSR_RSC & 0x90) | (pHalData->nCur40MhzPrimeSC << 5); ++ rtw_write8(Adapter, REG_RRSR + 2, regRRSR_RSC); ++ break; ++ default: ++ break; ++ } ++ ++ /* 3 */ ++ /* 3 <2>Set PHY related register */ ++ /* 3 */ ++ switch (pHalData->CurrentChannelBW) { ++ /* 20 MHz channel*/ ++ case HT_CHANNEL_WIDTH_20: ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0); ++ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0); ++ break; ++ /* 40 MHz channel*/ ++ case HT_CHANNEL_WIDTH_40: ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1); ++ PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1); ++ /* Set Control channel to upper or lower. These settings are required only for 40MHz */ ++ PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand, (pHalData->nCur40MhzPrimeSC >> 1)); ++ PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00, pHalData->nCur40MhzPrimeSC); ++ PHY_SetBBReg(Adapter, 0x818, (BIT(26) | BIT(27)), ++ (pHalData->nCur40MhzPrimeSC == HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); ++ break; ++ default: ++ break; ++ } ++ /* Skip over setting of J-mode in BB register here. Default value is "None J mode". Emily 20070315 */ ++ ++ /* 3<3>Set RF related register */ ++ switch (pHalData->rf_chip) { ++ case RF_8225: ++ break; ++ case RF_8256: ++ /* Please implement this function in Hal8190PciPhy8256.c */ ++ break; ++ case RF_PSEUDO_11N: ++ break; ++ case RF_6052: ++ rtl8188e_PHY_RF6052SetBandwidth(Adapter, pHalData->CurrentChannelBW); ++ break; ++ default: ++ break; ++ } ++} ++ ++ /*----------------------------------------------------------------------------- ++ * Function: SetBWMode8190Pci() ++ * ++ * Overview: This function is export to "HalCommon" moudule ++ * ++ * Input: struct adapter *Adapter ++ * enum ht_channel_width Bandwidth 20M or 40M ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Note: We do not take j mode into consideration now ++ *---------------------------------------------------------------------------*/ ++void PHY_SetBWMode8188E(struct adapter *Adapter, enum ht_channel_width Bandwidth, /* 20M or 40M */ ++ unsigned char Offset) /* Upper, Lower, or Don't care */ ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ enum ht_channel_width tmpBW = pHalData->CurrentChannelBW; ++ ++ pHalData->CurrentChannelBW = Bandwidth; ++ ++ pHalData->nCur40MhzPrimeSC = Offset; ++ ++ if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) ++ _PHY_SetBWMode92C(Adapter); ++ else ++ pHalData->CurrentChannelBW = tmpBW; ++} ++ ++static void _PHY_SwChnl8192C(struct adapter *Adapter, u8 channel) ++{ ++ u8 eRFPath; ++ u32 param1, param2; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ ++ if (Adapter->bNotifyChannelChange) ++ DBG_88E("[%s] ch = %d\n", __func__, channel); ++ ++ /* s1. pre common command - CmdID_SetTxPowerLevel */ ++ PHY_SetTxPowerLevel8188E(Adapter, channel); ++ ++ /* s2. RF dependent command - CmdID_RF_WriteReg, param1=RF_CHNLBW, param2=channel */ ++ param1 = RF_CHNLBW; ++ param2 = channel; ++ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) { ++ pHalData->RfRegChnlVal[eRFPath] = ((pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2); ++ PHY_SetRFReg(Adapter, (enum rf_radio_path)eRFPath, param1, bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]); ++ } ++} ++ ++void PHY_SwChnl8188E(struct adapter *Adapter, u8 channel) ++{ ++ /* Call after initialization */ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ ++ if (pHalData->rf_chip == RF_PSEUDO_11N) ++ return; /* return immediately if it is peudo-phy */ ++ ++ if (channel == 0) ++ channel = 1; ++ ++ if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) { ++ pHalData->CurrentChannel = channel; ++ _PHY_SwChnl8192C(Adapter, channel); ++ } ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_rf6052.c b/drivers/staging/r8188eu/hal/rtl8188e_rf6052.c +new file mode 100644 +index 000000000000..ad0782259654 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_rf6052.c +@@ -0,0 +1,550 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++/****************************************************************************** ++ * ++ * ++ * Module: rtl8192c_rf6052.c ( Source C File) ++ * ++ * Note: Provide RF 6052 series relative API. ++ * ++ * Function: ++ * ++ * Export: ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * ++ * 09/25/2008 MHC Create initial version. ++ * 11/05/2008 MHC Add API for tw power setting. ++ * ++ * ++******************************************************************************/ ++ ++#define _RTL8188E_RF6052_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtl8188e_hal.h" ++ ++/*---------------------------Define Local Constant---------------------------*/ ++/* Define local structure for debug!!!!! */ ++struct rf_shadow { ++ /* Shadow register value */ ++ u32 Value; ++ /* Compare or not flag */ ++ u8 Compare; ++ /* Record If it had ever modified unpredicted */ ++ u8 ErrorOrNot; ++ /* Recorver Flag */ ++ u8 Recorver; ++ /* */ ++ u8 Driver_Write; ++}; ++ ++/*---------------------------Define Local Constant---------------------------*/ ++ ++/*------------------------Define global variable-----------------------------*/ ++ ++/*------------------------Define local variable------------------------------*/ ++ ++/*----------------------------------------------------------------------------- ++ * Function: RF_ChangeTxPath ++ * ++ * Overview: For RL6052, we must change some RF settign for 1T or 2T. ++ * ++ * Input: u16 DataRate 0x80-8f, 0x90-9f ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 09/25/2008 MHC Create Version 0. ++ * Firmwaer support the utility later. ++ * ++ *---------------------------------------------------------------------------*/ ++void rtl8188e_RF_ChangeTxPath(struct adapter *Adapter, u16 DataRate) ++{ ++/* We do not support gain table change inACUT now !!!! Delete later !!! */ ++} /* RF_ChangeTxPath */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RF6052SetBandwidth() ++ * ++ * Overview: This function is called by SetBWModeCallback8190Pci() only ++ * ++ * Input: struct adapter *Adapter ++ * WIRELESS_BANDWIDTH_E Bandwidth 20M or 40M ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Note: For RF type 0222D ++ *---------------------------------------------------------------------------*/ ++void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter, ++ enum ht_channel_width Bandwidth) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ ++ switch (Bandwidth) { ++ case HT_CHANNEL_WIDTH_20: ++ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10) | BIT(11)); ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); ++ break; ++ case HT_CHANNEL_WIDTH_40: ++ pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | BIT(10)); ++ PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]); ++ break; ++ default: ++ break; ++ } ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RF6052SetCckTxPower ++ * ++ * Overview: ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/05/2008 MHC Simulate 8192series.. ++ * ++ *---------------------------------------------------------------------------*/ ++ ++void ++rtl8188e_PHY_RF6052SetCckTxPower( ++ struct adapter *Adapter, ++ u8 *pPowerlevel) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ u32 TxAGC[2] = {0, 0}, tmpval = 0, pwrtrac_value; ++ bool TurboScanOff = false; ++ u8 idx1, idx2; ++ u8 *ptr; ++ u8 direction; ++ /* FOR CE ,must disable turbo scan */ ++ TurboScanOff = true; ++ ++ if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { ++ TxAGC[RF_PATH_A] = 0x3f3f3f3f; ++ TxAGC[RF_PATH_B] = 0x3f3f3f3f; ++ ++ TurboScanOff = true;/* disable turbo scan */ ++ ++ if (TurboScanOff) { ++ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { ++ TxAGC[idx1] = ++ pPowerlevel[idx1] | (pPowerlevel[idx1] << 8) | ++ (pPowerlevel[idx1] << 16) | (pPowerlevel[idx1] << 24); ++ /* 2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. */ ++ if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA) ++ TxAGC[idx1] = 0x20; ++ } ++ } ++ } else { ++ /* Driver dynamic Tx power shall not affect Tx power. ++ * It shall be determined by power training mechanism. ++i * Currently, we cannot fully disable driver dynamic ++ * tx power mechanism because it is referenced by BT ++ * coexist mechanism. ++ * In the future, two mechanism shall be separated from ++ * each other and maintained independently. */ ++ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) { ++ TxAGC[RF_PATH_A] = 0x10101010; ++ TxAGC[RF_PATH_B] = 0x10101010; ++ } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) { ++ TxAGC[RF_PATH_A] = 0x00000000; ++ TxAGC[RF_PATH_B] = 0x00000000; ++ } else { ++ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { ++ TxAGC[idx1] = ++ pPowerlevel[idx1] | (pPowerlevel[idx1] << 8) | ++ (pPowerlevel[idx1] << 16) | (pPowerlevel[idx1] << 24); ++ } ++ if (pHalData->EEPROMRegulatory == 0) { ++ tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) + ++ (pHalData->MCSTxPowerLevelOriginalOffset[0][7] << 8); ++ TxAGC[RF_PATH_A] += tmpval; ++ ++ tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) + ++ (pHalData->MCSTxPowerLevelOriginalOffset[0][15] << 24); ++ TxAGC[RF_PATH_B] += tmpval; ++ } ++ } ++ } ++ for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) { ++ ptr = (u8 *)(&TxAGC[idx1]); ++ for (idx2 = 0; idx2 < 4; idx2++) { ++ if (*ptr > RF6052_MAX_TX_PWR) ++ *ptr = RF6052_MAX_TX_PWR; ++ ptr++; ++ } ++ } ++ ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 1, &direction, &pwrtrac_value); ++ ++ if (direction == 1) { ++ /* Increase TX power */ ++ TxAGC[0] += pwrtrac_value; ++ TxAGC[1] += pwrtrac_value; ++ } else if (direction == 2) { ++ /* Decrease TX power */ ++ TxAGC[0] -= pwrtrac_value; ++ TxAGC[1] -= pwrtrac_value; ++ } ++ ++ /* rf-A cck tx power */ ++ tmpval = TxAGC[RF_PATH_A] & 0xff; ++ PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval); ++ tmpval = TxAGC[RF_PATH_A] >> 8; ++ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); ++ ++ /* rf-B cck tx power */ ++ tmpval = TxAGC[RF_PATH_B] >> 24; ++ PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval); ++ tmpval = TxAGC[RF_PATH_B] & 0x00ffffff; ++ PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval); ++} /* PHY_RF6052SetCckTxPower */ ++ ++/* */ ++/* powerbase0 for OFDM rates */ ++/* powerbase1 for HT MCS rates */ ++/* */ ++static void getpowerbase88e(struct adapter *Adapter, u8 *pPowerLevelOFDM, ++ u8 *pPowerLevelBW20, u8 *pPowerLevelBW40, u8 Channel, u32 *OfdmBase, u32 *MCSBase) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u32 powerBase0, powerBase1; ++ u8 i, powerlevel[2]; ++ ++ for (i = 0; i < 2; i++) { ++ powerBase0 = pPowerLevelOFDM[i]; ++ ++ powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) | (powerBase0 << 8) | powerBase0; ++ *(OfdmBase + i) = powerBase0; ++ } ++ for (i = 0; i < pHalData->NumTotalRFPath; i++) { ++ /* Check HT20 to HT40 diff */ ++ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ powerlevel[i] = pPowerLevelBW20[i]; ++ else ++ powerlevel[i] = pPowerLevelBW40[i]; ++ powerBase1 = powerlevel[i]; ++ powerBase1 = (powerBase1 << 24) | (powerBase1 << 16) | (powerBase1 << 8) | powerBase1; ++ *(MCSBase + i) = powerBase1; ++ } ++} ++static void get_rx_power_val_by_reg(struct adapter *Adapter, u8 Channel, ++ u8 index, u32 *powerBase0, u32 *powerBase1, ++ u32 *pOutWriteVal) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &pHalData->dmpriv; ++ u8 i, chnlGroup = 0, pwr_diff_limit[4], customer_pwr_limit; ++ s8 pwr_diff = 0; ++ u32 writeVal, customer_limit, rf; ++ u8 Regulatory = pHalData->EEPROMRegulatory; ++ ++ /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */ ++ ++ for (rf = 0; rf < 2; rf++) { ++ switch (Regulatory) { ++ case 0: /* Realtek better performance */ ++ /* increase power diff defined by Realtek for large power */ ++ chnlGroup = 0; ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] + ++ ((index < 2) ? powerBase0[rf] : powerBase1[rf]); ++ break; ++ case 1: /* Realtek regulatory */ ++ /* increase power diff defined by Realtek for regulatory */ ++ if (pHalData->pwrGroupCnt == 1) ++ chnlGroup = 0; ++ if (pHalData->pwrGroupCnt >= pHalData->PGMaxGroup) { ++ if (Channel < 3) /* Channel 1-2 */ ++ chnlGroup = 0; ++ else if (Channel < 6) /* Channel 3-5 */ ++ chnlGroup = 1; ++ else if (Channel < 9) /* Channel 6-8 */ ++ chnlGroup = 2; ++ else if (Channel < 12) /* Channel 9-11 */ ++ chnlGroup = 3; ++ else if (Channel < 14) /* Channel 12-13 */ ++ chnlGroup = 4; ++ else if (Channel == 14) /* Channel 14 */ ++ chnlGroup = 5; ++ } ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] + ++ ((index < 2) ? powerBase0[rf] : powerBase1[rf]); ++ break; ++ case 2: /* Better regulatory */ ++ /* don't increase any power diff */ ++ writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]); ++ break; ++ case 3: /* Customer defined power diff. */ ++ /* increase power diff defined by customer. */ ++ chnlGroup = 0; ++ ++ if (index < 2) ++ pwr_diff = pHalData->TxPwrLegacyHtDiff[rf][Channel - 1]; ++ else if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) ++ pwr_diff = pHalData->TxPwrHt20Diff[rf][Channel - 1]; ++ ++ if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) ++ customer_pwr_limit = pHalData->PwrGroupHT40[rf][Channel - 1]; ++ else ++ customer_pwr_limit = pHalData->PwrGroupHT20[rf][Channel - 1]; ++ ++ if (pwr_diff >= customer_pwr_limit) ++ pwr_diff = 0; ++ else ++ pwr_diff = customer_pwr_limit - pwr_diff; ++ ++ for (i = 0; i < 4; i++) { ++ pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] & (0x7f << (i * 8))) >> (i * 8)); ++ ++ if (pwr_diff_limit[i] > pwr_diff) ++ pwr_diff_limit[i] = pwr_diff; ++ } ++ customer_limit = (pwr_diff_limit[3] << 24) | (pwr_diff_limit[2] << 16) | ++ (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]); ++ writeVal = customer_limit + ((index < 2) ? powerBase0[rf] : powerBase1[rf]); ++ break; ++ default: ++ chnlGroup = 0; ++ writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] + ++ ((index < 2) ? powerBase0[rf] : powerBase1[rf]); ++ break; ++ } ++/* 20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */ ++/* Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */ ++/* In the future, two mechanism shall be separated from each other and maintained independently. Thanks for Lanhsin's reminder. */ ++ /* 92d do not need this */ ++ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) ++ writeVal = 0x14141414; ++ else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) ++ writeVal = 0x00000000; ++ ++ /* 20100628 Joseph: High power mode for BT-Coexist mechanism. */ ++ /* This mechanism is only applied when Driver-Highpower-Mechanism is OFF. */ ++ if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1) ++ writeVal = writeVal - 0x06060606; ++ *(pOutWriteVal + rf) = writeVal; ++ } ++} ++static void writeOFDMPowerReg88E(struct adapter *Adapter, u8 index, u32 *pValue) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u16 regoffset_a[6] = { ++ rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24, ++ rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04, ++ rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12}; ++ u16 regoffset_b[6] = { ++ rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24, ++ rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04, ++ rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12}; ++ u8 i, rf, pwr_val[4]; ++ u32 writeVal; ++ u16 regoffset; ++ ++ for (rf = 0; rf < 2; rf++) { ++ writeVal = pValue[rf]; ++ for (i = 0; i < 4; i++) { ++ pwr_val[i] = (u8)((writeVal & (0x7f << (i * 8))) >> (i * 8)); ++ if (pwr_val[i] > RF6052_MAX_TX_PWR) ++ pwr_val[i] = RF6052_MAX_TX_PWR; ++ } ++ writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) | (pwr_val[1] << 8) | pwr_val[0]; ++ ++ if (rf == 0) ++ regoffset = regoffset_a[index]; ++ else ++ regoffset = regoffset_b[index]; ++ ++ PHY_SetBBReg(Adapter, regoffset, bMaskDWord, writeVal); ++ ++ /* 201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */ ++ if (((pHalData->rf_type == RF_2T2R) && ++ (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs15_Mcs12)) || ++ ((pHalData->rf_type != RF_2T2R) && ++ (regoffset == rTxAGC_A_Mcs07_Mcs04 || regoffset == rTxAGC_B_Mcs07_Mcs04))) { ++ writeVal = pwr_val[3]; ++ if (regoffset == rTxAGC_A_Mcs15_Mcs12 || regoffset == rTxAGC_A_Mcs07_Mcs04) ++ regoffset = 0xc90; ++ if (regoffset == rTxAGC_B_Mcs15_Mcs12 || regoffset == rTxAGC_B_Mcs07_Mcs04) ++ regoffset = 0xc98; ++ for (i = 0; i < 3; i++) { ++ if (i != 2) ++ writeVal = (writeVal > 8) ? (writeVal - 8) : 0; ++ else ++ writeVal = (writeVal > 6) ? (writeVal - 6) : 0; ++ rtw_write8(Adapter, (u32)(regoffset + i), (u8)writeVal); ++ } ++ } ++ } ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: PHY_RF6052SetOFDMTxPower ++ * ++ * Overview: For legacy and HY OFDM, we must read EEPROM TX power index for ++ * different channel and read original value in TX power register area from ++ * 0xe00. We increase offset and original value to be correct tx pwr. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 11/05/2008 MHC Simulate 8192 series method. ++ * 01/06/2009 MHC 1. Prevent Path B tx power overflow or underflow dure to ++ * A/B pwr difference or legacy/HT pwr diff. ++ * 2. We concern with path B legacy/HT OFDM difference. ++ * 01/22/2009 MHC Support new EPRO format from SD3. ++ * ++ *---------------------------------------------------------------------------*/ ++ ++void ++rtl8188e_PHY_RF6052SetOFDMTxPower( ++ struct adapter *Adapter, ++ u8 *pPowerLevelOFDM, ++ u8 *pPowerLevelBW20, ++ u8 *pPowerLevelBW40, ++ u8 Channel) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u32 writeVal[2], powerBase0[2], powerBase1[2], pwrtrac_value; ++ u8 direction; ++ u8 index = 0; ++ ++ getpowerbase88e(Adapter, pPowerLevelOFDM, pPowerLevelBW20, pPowerLevelBW40, Channel, &powerBase0[0], &powerBase1[0]); ++ ++ /* 2012/04/23 MH According to power tracking value, we need to revise OFDM tx power. */ ++ /* This is ued to fix unstable power tracking mode. */ ++ ODM_TxPwrTrackAdjust88E(&pHalData->odmpriv, 0, &direction, &pwrtrac_value); ++ ++ for (index = 0; index < 6; index++) { ++ get_rx_power_val_by_reg(Adapter, Channel, index, ++ &powerBase0[0], &powerBase1[0], ++ &writeVal[0]); ++ ++ if (direction == 1) { ++ writeVal[0] += pwrtrac_value; ++ writeVal[1] += pwrtrac_value; ++ } else if (direction == 2) { ++ writeVal[0] -= pwrtrac_value; ++ writeVal[1] -= pwrtrac_value; ++ } ++ writeOFDMPowerReg88E(Adapter, index, &writeVal[0]); ++ } ++} ++ ++static int phy_RF6052_Config_ParaFile(struct adapter *Adapter) ++{ ++ struct bb_reg_def *pPhyReg; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ u32 u4RegValue = 0; ++ u8 eRFPath; ++ int rtStatus = _SUCCESS; ++ ++ /* 3----------------------------------------------------------------- */ ++ /* 3 <2> Initialize RF */ ++ /* 3----------------------------------------------------------------- */ ++ for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) { ++ pPhyReg = &pHalData->PHYRegDef[eRFPath]; ++ ++ /*----Store original RFENV control type----*/ ++ switch (eRFPath) { ++ case RF_PATH_A: ++ case RF_PATH_C: ++ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV); ++ break; ++ case RF_PATH_B: ++ case RF_PATH_D: ++ u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV << 16); ++ break; ++ } ++ /*----Set RF_ENV enable----*/ ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV << 16, 0x1); ++ udelay(1);/* PlatformStallExecution(1); */ ++ ++ /*----Set RF_ENV output high----*/ ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); ++ udelay(1);/* PlatformStallExecution(1); */ ++ ++ /* Set bit number of Address and Data for RF register */ ++ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0); /* Set 1 to 4 bits for 8255 */ ++ udelay(1);/* PlatformStallExecution(1); */ ++ ++ PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); /* Set 0 to 12 bits for 8255 */ ++ udelay(1);/* PlatformStallExecution(1); */ ++ ++ /*----Initialize RF fom connfiguration file----*/ ++ switch (eRFPath) { ++ case RF_PATH_A: ++ if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum rf_radio_path)eRFPath, (enum rf_radio_path)eRFPath)) ++ rtStatus = _FAIL; ++ break; ++ case RF_PATH_B: ++ if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, (enum rf_radio_path)eRFPath, (enum rf_radio_path)eRFPath)) ++ rtStatus = _FAIL; ++ break; ++ case RF_PATH_C: ++ break; ++ case RF_PATH_D: ++ break; ++ } ++ /*----Restore RFENV control type----*/; ++ switch (eRFPath) { ++ case RF_PATH_A: ++ case RF_PATH_C: ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue); ++ break; ++ case RF_PATH_B: ++ case RF_PATH_D: ++ PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV << 16, u4RegValue); ++ break; ++ } ++ if (rtStatus != _SUCCESS) ++ goto phy_RF6052_Config_ParaFile_Fail; ++ } ++ return rtStatus; ++ ++phy_RF6052_Config_ParaFile_Fail: ++ return rtStatus; ++} ++ ++int PHY_RF6052_Config8188E(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(Adapter); ++ int rtStatus = _SUCCESS; ++ ++ /* */ ++ /* Initialize general global value */ ++ /* */ ++ /* TODO: Extend RF_PATH_C and RF_PATH_D in the future */ ++ if (pHalData->rf_type == RF_1T1R) ++ pHalData->NumTotalRFPath = 1; ++ else ++ pHalData->NumTotalRFPath = 2; ++ ++ /* */ ++ /* Config BB and RF */ ++ /* */ ++ rtStatus = phy_RF6052_Config_ParaFile(Adapter); ++ return rtStatus; ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_rxdesc.c b/drivers/staging/r8188eu/hal/rtl8188e_rxdesc.c +new file mode 100644 +index 000000000000..244286789b6d +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_rxdesc.c +@@ -0,0 +1,186 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTL8188E_REDESC_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtl8188e_hal.h" ++ ++static void process_rssi(struct adapter *padapter, struct recv_frame *prframe) ++{ ++ struct rx_pkt_attrib *pattrib = &prframe->attrib; ++ struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data; ++ ++ if (signal_stat->update_req) { ++ signal_stat->total_num = 0; ++ signal_stat->total_val = 0; ++ signal_stat->update_req = 0; ++ } ++ ++ signal_stat->total_num++; ++ signal_stat->total_val += pattrib->phy_info.SignalStrength; ++ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; ++} /* Process_UI_RSSI_8192C */ ++ ++static void process_link_qual(struct adapter *padapter, struct recv_frame *prframe) ++{ ++ struct rx_pkt_attrib *pattrib; ++ struct signal_stat *signal_stat; ++ ++ if (!prframe || !padapter) ++ return; ++ ++ pattrib = &prframe->attrib; ++ signal_stat = &padapter->recvpriv.signal_qual_data; ++ ++ if (signal_stat->update_req) { ++ signal_stat->total_num = 0; ++ signal_stat->total_val = 0; ++ signal_stat->update_req = 0; ++ } ++ ++ signal_stat->total_num++; ++ signal_stat->total_val += pattrib->phy_info.SignalQuality; ++ signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; ++} ++ ++void rtl8188e_process_phy_info(struct adapter *padapter, void *prframe) ++{ ++ struct recv_frame *precvframe = (struct recv_frame *)prframe; ++ ++ /* Check RSSI */ ++ process_rssi(padapter, precvframe); ++ /* Check EVM */ ++ process_link_qual(padapter, precvframe); ++} ++ ++void update_recvframe_attrib_88e(struct recv_frame *precvframe, struct recv_stat *prxstat) ++{ ++ struct rx_pkt_attrib *pattrib; ++ struct recv_stat report; ++ ++ report.rxdw0 = prxstat->rxdw0; ++ report.rxdw1 = prxstat->rxdw1; ++ report.rxdw2 = prxstat->rxdw2; ++ report.rxdw3 = prxstat->rxdw3; ++ report.rxdw4 = prxstat->rxdw4; ++ report.rxdw5 = prxstat->rxdw5; ++ ++ pattrib = &precvframe->attrib; ++ memset(pattrib, 0, sizeof(struct rx_pkt_attrib)); ++ ++ pattrib->crc_err = (u8)((le32_to_cpu(report.rxdw0) >> 14) & 0x1);/* u8)prxreport->crc32; */ ++ ++ /* update rx report to recv_frame attribute */ ++ pattrib->pkt_rpt_type = (u8)((le32_to_cpu(report.rxdw3) >> 14) & 0x3);/* prxreport->rpt_sel; */ ++ ++ if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */ ++ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x00003fff);/* u16)prxreport->pktlen; */ ++ pattrib->drvinfo_sz = (u8)((le32_to_cpu(report.rxdw0) >> 16) & 0xf) * 8;/* u8)(prxreport->drvinfosize << 3); */ ++ ++ pattrib->physt = (u8)((le32_to_cpu(report.rxdw0) >> 26) & 0x1);/* u8)prxreport->physt; */ ++ ++ pattrib->bdecrypted = (le32_to_cpu(report.rxdw0) & BIT(27)) ? 0 : 1;/* u8)(prxreport->swdec ? 0 : 1); */ ++ pattrib->encrypt = (u8)((le32_to_cpu(report.rxdw0) >> 20) & 0x7);/* u8)prxreport->security; */ ++ ++ pattrib->qos = (u8)((le32_to_cpu(report.rxdw0) >> 23) & 0x1);/* u8)prxreport->qos; */ ++ pattrib->priority = (u8)((le32_to_cpu(report.rxdw1) >> 8) & 0xf);/* u8)prxreport->tid; */ ++ ++ pattrib->amsdu = (u8)((le32_to_cpu(report.rxdw1) >> 13) & 0x1);/* u8)prxreport->amsdu; */ ++ ++ pattrib->seq_num = (u16)(le32_to_cpu(report.rxdw2) & 0x00000fff);/* u16)prxreport->seq; */ ++ pattrib->frag_num = (u8)((le32_to_cpu(report.rxdw2) >> 12) & 0xf);/* u8)prxreport->frag; */ ++ pattrib->mfrag = (u8)((le32_to_cpu(report.rxdw1) >> 27) & 0x1);/* u8)prxreport->mf; */ ++ pattrib->mdata = (u8)((le32_to_cpu(report.rxdw1) >> 26) & 0x1);/* u8)prxreport->md; */ ++ ++ pattrib->mcs_rate = (u8)(le32_to_cpu(report.rxdw3) & 0x3f);/* u8)prxreport->rxmcs; */ ++ pattrib->rxht = (u8)((le32_to_cpu(report.rxdw3) >> 6) & 0x1);/* u8)prxreport->rxht; */ ++ ++ pattrib->icv_err = (u8)((le32_to_cpu(report.rxdw0) >> 15) & 0x1);/* u8)prxreport->icverr; */ ++ pattrib->shift_sz = (u8)((le32_to_cpu(report.rxdw0) >> 24) & 0x3); ++ } else if (pattrib->pkt_rpt_type == TX_REPORT1) { /* CCX */ ++ pattrib->pkt_len = TX_RPT1_PKT_LEN; ++ pattrib->drvinfo_sz = 0; ++ } else if (pattrib->pkt_rpt_type == TX_REPORT2) { /* TX RPT */ ++ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x3FF);/* Rx length[9:0] */ ++ pattrib->drvinfo_sz = 0; ++ ++ /* */ ++ /* Get TX report MAC ID valid. */ ++ /* */ ++ pattrib->MacIDValidEntry[0] = le32_to_cpu(report.rxdw4); ++ pattrib->MacIDValidEntry[1] = le32_to_cpu(report.rxdw5); ++ ++ } else if (pattrib->pkt_rpt_type == HIS_REPORT) { /* USB HISR RPT */ ++ pattrib->pkt_len = (u16)(le32_to_cpu(report.rxdw0) & 0x00003fff);/* u16)prxreport->pktlen; */ ++ } ++} ++ ++/* ++ * Notice: ++ * Before calling this function, ++ * precvframe->rx_data should be ready! ++ */ ++void update_recvframe_phyinfo_88e(struct recv_frame *precvframe, struct phy_stat *pphy_status) ++{ ++ struct adapter *padapter = precvframe->adapter; ++ struct rx_pkt_attrib *pattrib = &precvframe->attrib; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct odm_phy_status_info *pPHYInfo = (struct odm_phy_status_info *)(&pattrib->phy_info); ++ u8 *wlanhdr; ++ struct odm_per_pkt_info pkt_info; ++ u8 *sa = NULL; ++ struct sta_priv *pstapriv; ++ struct sta_info *psta; ++ ++ pkt_info.bPacketMatchBSSID = false; ++ pkt_info.bPacketToSelf = false; ++ pkt_info.bPacketBeacon = false; ++ ++ wlanhdr = get_recvframe_data(precvframe); ++ ++ pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) && ++ !pattrib->icv_err && !pattrib->crc_err && ++ !memcmp(get_hdr_bssid(wlanhdr), ++ get_bssid(&padapter->mlmepriv), ETH_ALEN)); ++ ++ pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && ++ (!memcmp(get_da(wlanhdr), ++ myid(&padapter->eeprompriv), ETH_ALEN)); ++ ++ pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && ++ (GetFrameSubType(wlanhdr) == WIFI_BEACON); ++ ++ if (pkt_info.bPacketBeacon) { ++ if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) ++ sa = padapter->mlmepriv.cur_network.network.MacAddress; ++ /* to do Ad-hoc */ ++ } else { ++ sa = get_sa(wlanhdr); ++ } ++ ++ pstapriv = &padapter->stapriv; ++ pkt_info.StationID = 0xFF; ++ psta = rtw_get_stainfo(pstapriv, sa); ++ if (psta) ++ pkt_info.StationID = psta->mac_id; ++ pkt_info.Rate = pattrib->mcs_rate; ++ ++ ODM_PhyStatusQuery(&pHalData->odmpriv, pPHYInfo, (u8 *)pphy_status, &(pkt_info), padapter); ++ ++ precvframe->psta = NULL; ++ if (pkt_info.bPacketMatchBSSID && ++ (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE))) { ++ if (psta) { ++ precvframe->psta = psta; ++ rtl8188e_process_phy_info(padapter, precvframe); ++ } ++ } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) { ++ if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { ++ if (psta) ++ precvframe->psta = psta; ++ } ++ rtl8188e_process_phy_info(padapter, precvframe); ++ } ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_sreset.c b/drivers/staging/r8188eu/hal/rtl8188e_sreset.c +new file mode 100644 +index 000000000000..16fa249e35d3 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_sreset.c +@@ -0,0 +1,64 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTL8188E_SRESET_C_ ++ ++#include "../include/rtl8188e_sreset.h" ++#include "../include/rtl8188e_hal.h" ++ ++void rtl8188e_silentreset_for_specific_platform(struct adapter *padapter) ++{ ++} ++ ++void rtl8188e_sreset_xmit_status_check(struct adapter *padapter) ++{ ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ struct sreset_priv *psrtpriv = &pHalData->srestpriv; ++ ++ unsigned long current_time; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ unsigned int diff_time; ++ u32 txdma_status; ++ ++ txdma_status = rtw_read32(padapter, REG_TXDMA_STATUS); ++ if (txdma_status != 0x00) { ++ DBG_88E("%s REG_TXDMA_STATUS:0x%08x\n", __func__, txdma_status); ++ rtw_write32(padapter, REG_TXDMA_STATUS, txdma_status); ++ rtl8188e_silentreset_for_specific_platform(padapter); ++ } ++ /* total xmit irp = 4 */ ++ current_time = jiffies; ++ if (0 == pxmitpriv->free_xmitbuf_cnt) { ++ diff_time = jiffies_to_msecs(current_time - psrtpriv->last_tx_time); ++ ++ if (diff_time > 2000) { ++ if (psrtpriv->last_tx_complete_time == 0) { ++ psrtpriv->last_tx_complete_time = current_time; ++ } else { ++ diff_time = jiffies_to_msecs(current_time - psrtpriv->last_tx_complete_time); ++ if (diff_time > 4000) { ++ DBG_88E("%s tx hang\n", __func__); ++ rtl8188e_silentreset_for_specific_platform(padapter); ++ } ++ } ++ } ++ } ++} ++ ++void rtl8188e_sreset_linked_status_check(struct adapter *padapter) ++{ ++ u32 rx_dma_status = 0; ++ u8 fw_status = 0; ++ rx_dma_status = rtw_read32(padapter, REG_RXDMA_STATUS); ++ if (rx_dma_status != 0x00) { ++ DBG_88E("%s REG_RXDMA_STATUS:0x%08x\n", __func__, rx_dma_status); ++ rtw_write32(padapter, REG_RXDMA_STATUS, rx_dma_status); ++ } ++ fw_status = rtw_read8(padapter, REG_FMETHR); ++ if (fw_status != 0x00) { ++ if (fw_status == 1) ++ DBG_88E("%s REG_FW_STATUS (0x%02x), Read_Efuse_Fail !!\n", __func__, fw_status); ++ else if (fw_status == 2) ++ DBG_88E("%s REG_FW_STATUS (0x%02x), Condition_No_Match !!\n", __func__, fw_status); ++ } ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188e_xmit.c b/drivers/staging/r8188eu/hal/rtl8188e_xmit.c +new file mode 100644 +index 000000000000..46b871f3f631 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188e_xmit.c +@@ -0,0 +1,22 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTL8188E_XMIT_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtl8188e_hal.h" ++ ++void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf) ++{ ++ struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf; ++ ++ if (txrpt_ccx->int_ccx) { ++ if (txrpt_ccx->pkt_ok) ++ rtw_ack_tx_done(&adapter->xmitpriv, ++ RTW_SCTX_DONE_SUCCESS); ++ else ++ rtw_ack_tx_done(&adapter->xmitpriv, ++ RTW_SCTX_DONE_CCX_PKT_FAIL); ++ } ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188eu_led.c b/drivers/staging/r8188eu/hal/rtl8188eu_led.c +new file mode 100644 +index 000000000000..452d4bb87aba +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188eu_led.c +@@ -0,0 +1,94 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtl8188e_hal.h" ++#include "../include/rtl8188e_led.h" ++ ++/* LED object. */ ++ ++/* LED_819xUsb routines. */ ++/* Description: */ ++/* Turn on LED according to LedPin specified. */ ++void SwLedOn(struct adapter *padapter, struct LED_871x *pLed) ++{ ++ u8 LedCfg; ++ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ return; ++ LedCfg = rtw_read8(padapter, REG_LEDCFG2); ++ switch (pLed->LedPin) { ++ case LED_PIN_LED0: ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg & 0xf0) | BIT(5) | BIT(6)); /* SW control led0 on. */ ++ break; ++ case LED_PIN_LED1: ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg & 0x0f) | BIT(5)); /* SW control led1 on. */ ++ break; ++ default: ++ break; ++ } ++ pLed->bLedOn = true; ++} ++ ++/* Description: */ ++/* Turn off LED according to LedPin specified. */ ++void SwLedOff(struct adapter *padapter, struct LED_871x *pLed) ++{ ++ u8 LedCfg; ++ struct hal_data_8188e *pHalData = GET_HAL_DATA(padapter); ++ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped) ++ goto exit; ++ ++ LedCfg = rtw_read8(padapter, REG_LEDCFG2);/* 0x4E */ ++ ++ switch (pLed->LedPin) { ++ case LED_PIN_LED0: ++ if (pHalData->bLedOpenDrain) { ++ /* Open-drain arrangement for controlling the LED) */ ++ LedCfg &= 0x90; /* Set to software control. */ ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg | BIT(3))); ++ LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG); ++ LedCfg &= 0xFE; ++ rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg); ++ } else { ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg | BIT(3) | BIT(5) | BIT(6))); ++ } ++ break; ++ case LED_PIN_LED1: ++ LedCfg &= 0x0f; /* Set to software control. */ ++ rtw_write8(padapter, REG_LEDCFG2, (LedCfg | BIT(3))); ++ break; ++ default: ++ break; ++ } ++exit: ++ pLed->bLedOn = false; ++} ++ ++/* Interface to manipulate LED objects. */ ++/* Default LED behavior. */ ++ ++/* Description: */ ++/* Initialize all LED_871x objects. */ ++void rtl8188eu_InitSwLeds(struct adapter *padapter) ++{ ++ struct led_priv *pledpriv = &padapter->ledpriv; ++ ++ pledpriv->LedControlHandler = LedControl8188eu; ++ ++ InitLed871x(padapter, &pledpriv->SwLed0, LED_PIN_LED0); ++ ++ InitLed871x(padapter, &pledpriv->SwLed1, LED_PIN_LED1); ++} ++ ++/* Description: */ ++/* DeInitialize all LED_819xUsb objects. */ ++void rtl8188eu_DeInitSwLeds(struct adapter *padapter) ++{ ++ struct led_priv *ledpriv = &padapter->ledpriv; ++ ++ DeInitLed871x(&ledpriv->SwLed0); ++ DeInitLed871x(&ledpriv->SwLed1); ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188eu_recv.c b/drivers/staging/r8188eu/hal/rtl8188eu_recv.c +new file mode 100644 +index 000000000000..2da7bde80cc0 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188eu_recv.c +@@ -0,0 +1,117 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTL8188EU_RECV_C_ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/mlme_osdep.h" ++ ++#include "../include/usb_ops.h" ++#include "../include/wifi.h" ++ ++#include "../include/rtl8188e_hal.h" ++ ++void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *precvbuf) ++{ ++ precvbuf->transfer_len = 0; ++ ++ precvbuf->len = 0; ++ ++ precvbuf->ref_cnt = 0; ++ ++ if (precvbuf->pbuf) { ++ precvbuf->pdata = precvbuf->pbuf; ++ precvbuf->phead = precvbuf->pbuf; ++ precvbuf->ptail = precvbuf->pbuf; ++ precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ; ++ } ++} ++ ++int rtl8188eu_init_recv_priv(struct adapter *padapter) ++{ ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ int i, res = _SUCCESS; ++ struct recv_buf *precvbuf; ++ ++ tasklet_init(&precvpriv->recv_tasklet, ++ rtl8188eu_recv_tasklet, ++ (unsigned long)padapter); ++ ++ /* init recv_buf */ ++ _rtw_init_queue(&precvpriv->free_recv_buf_queue); ++ ++ precvpriv->pallocated_recv_buf = kzalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4, ++ GFP_KERNEL); ++ if (!precvpriv->pallocated_recv_buf) { ++ res = _FAIL; ++ goto exit; ++ } ++ memset(precvpriv->pallocated_recv_buf, 0, NR_RECVBUFF * sizeof(struct recv_buf) + 4); ++ ++ precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_recv_buf), 4); ++ ++ precvbuf = (struct recv_buf *)precvpriv->precv_buf; ++ ++ for (i = 0; i < NR_RECVBUFF; i++) { ++ INIT_LIST_HEAD(&precvbuf->list); ++ spin_lock_init(&precvbuf->recvbuf_lock); ++ precvbuf->alloc_sz = MAX_RECVBUF_SZ; ++ res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf); ++ if (res == _FAIL) ++ break; ++ precvbuf->ref_cnt = 0; ++ precvbuf->adapter = padapter; ++ precvbuf++; ++ } ++ precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; ++ skb_queue_head_init(&precvpriv->rx_skb_queue); ++ { ++ int i; ++ size_t tmpaddr = 0; ++ size_t alignment = 0; ++ struct sk_buff *pskb = NULL; ++ ++ skb_queue_head_init(&precvpriv->free_recv_skb_queue); ++ ++ for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) { ++ pskb = __netdev_alloc_skb(padapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ, GFP_KERNEL); ++ if (pskb) { ++ pskb->dev = padapter->pnetdev; ++ tmpaddr = (size_t)pskb->data; ++ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1); ++ skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); ++ ++ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); ++ } ++ pskb = NULL; ++ } ++ } ++exit: ++ return res; ++} ++ ++void rtl8188eu_free_recv_priv(struct adapter *padapter) ++{ ++ int i; ++ struct recv_buf *precvbuf; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ precvbuf = (struct recv_buf *)precvpriv->precv_buf; ++ ++ for (i = 0; i < NR_RECVBUFF; i++) { ++ rtw_os_recvbuf_resource_free(padapter, precvbuf); ++ precvbuf++; ++ } ++ ++ kfree(precvpriv->pallocated_recv_buf); ++ ++ if (skb_queue_len(&precvpriv->rx_skb_queue)) ++ DBG_88E(KERN_WARNING "rx_skb_queue not empty\n"); ++ skb_queue_purge(&precvpriv->rx_skb_queue); ++ ++ if (skb_queue_len(&precvpriv->free_recv_skb_queue)) ++ DBG_88E(KERN_WARNING "free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue)); ++ ++ skb_queue_purge(&precvpriv->free_recv_skb_queue); ++} +diff --git a/drivers/staging/r8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/r8188eu/hal/rtl8188eu_xmit.c +new file mode 100644 +index 000000000000..17be67ac5fae +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/rtl8188eu_xmit.c +@@ -0,0 +1,672 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RTL8188E_XMIT_C_ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/wifi.h" ++#include "../include/osdep_intf.h" ++#include "../include/usb_ops.h" ++#include "../include/rtl8188e_hal.h" ++ ++s32 rtl8188eu_init_xmit_priv(struct adapter *adapt) ++{ ++ struct xmit_priv *pxmitpriv = &adapt->xmitpriv; ++ ++ tasklet_init(&pxmitpriv->xmit_tasklet, ++ rtl8188eu_xmit_tasklet, ++ (unsigned long)adapt); ++ return _SUCCESS; ++} ++ ++static u8 urb_zero_packet_chk(struct adapter *adapt, int sz) ++{ ++ u8 set_tx_desc_offset; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ set_tx_desc_offset = (((sz + TXDESC_SIZE) % haldata->UsbBulkOutSize) == 0) ? 1 : 0; ++ ++ return set_tx_desc_offset; ++} ++ ++static void rtl8188eu_cal_txdesc_chksum(struct tx_desc *ptxdesc) ++{ ++ u16 *usptr = (u16 *)ptxdesc; ++ u32 count = 16; /* (32 bytes / 2 bytes per XOR) => 16 times */ ++ u32 index; ++ u16 checksum = 0; ++ ++ /* Clear first */ ++ ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); ++ ++ for (index = 0; index < count; index++) ++ checksum = checksum ^ le16_to_cpu(*(__le16 *)(usptr + index)); ++ ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff & checksum); ++} ++ ++/* Description: In normal chip, we should send some packet to Hw which will be used by Fw */ ++/* in FW LPS mode. The function is to fill the Tx descriptor of this packets, then */ ++/* Fw can tell Hw to send these packet derectly. */ ++void rtl8188e_fill_fake_txdesc(struct adapter *adapt, u8 *desc, u32 BufferLen, u8 ispspoll, u8 is_btqosnull) ++{ ++ struct tx_desc *ptxdesc; ++ ++ /* Clear all status */ ++ ptxdesc = (struct tx_desc *)desc; ++ memset(desc, 0, TXDESC_SIZE); ++ ++ /* offset 0 */ ++ ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); /* own, bFirstSeg, bLastSeg; */ ++ ++ ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00ff0000); /* 32 bytes for TX Desc */ ++ ++ ptxdesc->txdw0 |= cpu_to_le32(BufferLen & 0x0000ffff); /* Buffer size + command header */ ++ ++ /* offset 4 */ ++ ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT << QSEL_SHT) & 0x00001f00); /* Fixed queue of Mgnt queue */ ++ ++ /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw. */ ++ if (ispspoll) { ++ ptxdesc->txdw1 |= cpu_to_le32(NAVUSEHDR); ++ } else { ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); /* Hw set sequence number */ ++ ptxdesc->txdw3 |= cpu_to_le32((8 << 28)); /* set bit3 to 1. Suugested by TimChen. 2009.12.29. */ ++ } ++ ++ if (is_btqosnull) ++ ptxdesc->txdw2 |= cpu_to_le32(BIT(23)); /* BT NULL */ ++ ++ /* offset 16 */ ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ ++ ++ /* USB interface drop packet if the checksum of descriptor isn't correct. */ ++ /* Using this checksum can let hardware recovery from packet bulk out error (e.g. Cancel URC, Bulk out error.). */ ++ rtl8188eu_cal_txdesc_chksum(ptxdesc); ++} ++ ++static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc) ++{ ++ if ((pattrib->encrypt > 0) && !pattrib->bswenc) { ++ switch (pattrib->encrypt) { ++ /* SEC_TYPE : 0:NO_ENC,1:WEP40/TKIP,2:WAPI,3:AES */ ++ case _WEP40_: ++ case _WEP104_: ++ ptxdesc->txdw1 |= cpu_to_le32((0x01 << SEC_TYPE_SHT) & 0x00c00000); ++ ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); ++ break; ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ ptxdesc->txdw1 |= cpu_to_le32((0x01 << SEC_TYPE_SHT) & 0x00c00000); ++ ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); ++ break; ++ case _AES_: ++ ptxdesc->txdw1 |= cpu_to_le32((0x03 << SEC_TYPE_SHT) & 0x00c00000); ++ ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT); ++ break; ++ case _NO_PRIVACY_: ++ default: ++ break; ++ } ++ } ++} ++ ++static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw) ++{ ++ switch (pattrib->vcs_mode) { ++ case RTS_CTS: ++ *pdw |= cpu_to_le32(RTS_EN); ++ break; ++ case CTS_TO_SELF: ++ *pdw |= cpu_to_le32(CTS_2_SELF); ++ break; ++ case NONE_VCS: ++ default: ++ break; ++ } ++ if (pattrib->vcs_mode) { ++ *pdw |= cpu_to_le32(HW_RTS_EN); ++ /* Set RTS BW */ ++ if (pattrib->ht_en) { ++ *pdw |= (pattrib->bwmode & HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0; ++ ++ if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ++ *pdw |= cpu_to_le32((0x01 << 28) & 0x30000000); ++ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) ++ *pdw |= cpu_to_le32((0x02 << 28) & 0x30000000); ++ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ++ *pdw |= 0; ++ else ++ *pdw |= cpu_to_le32((0x03 << 28) & 0x30000000); ++ } ++ } ++} ++ ++static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw) ++{ ++ if (pattrib->ht_en) { ++ *pdw |= (pattrib->bwmode & HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0; ++ ++ if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ++ *pdw |= cpu_to_le32((0x01 << DATA_SC_SHT) & 0x003f0000); ++ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) ++ *pdw |= cpu_to_le32((0x02 << DATA_SC_SHT) & 0x003f0000); ++ else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ++ *pdw |= 0; ++ else ++ *pdw |= cpu_to_le32((0x03 << DATA_SC_SHT) & 0x003f0000); ++ } ++} ++ ++static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt) ++{ ++ int pull = 0; ++ uint qsel; ++ u8 data_rate, pwr_status, offset; ++ struct adapter *adapt = pxmitframe->padapter; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ struct tx_desc *ptxdesc = (struct tx_desc *)pmem; ++ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if (adapt->registrypriv.mp_mode == 0) { ++ if ((!bagg_pkt) && (urb_zero_packet_chk(adapt, sz) == 0)) { ++ ptxdesc = (struct tx_desc *)(pmem + PACKET_OFFSET_SZ); ++ pull = 1; ++ } ++ } ++ ++ memset(ptxdesc, 0, sizeof(struct tx_desc)); ++ ++ /* 4 offset 0 */ ++ ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); ++ ptxdesc->txdw0 |= cpu_to_le32(sz & 0x0000ffff);/* update TXPKTSIZE */ ++ ++ offset = TXDESC_SIZE + OFFSET_SZ; ++ ++ ptxdesc->txdw0 |= cpu_to_le32(((offset) << OFFSET_SHT) & 0x00ff0000);/* 32 bytes for TX Desc */ ++ ++ if (is_multicast_ether_addr(pattrib->ra)) ++ ptxdesc->txdw0 |= cpu_to_le32(BMC); ++ ++ if (adapt->registrypriv.mp_mode == 0) { ++ if (!bagg_pkt) { ++ if ((pull) && (pxmitframe->pkt_offset > 0)) ++ pxmitframe->pkt_offset = pxmitframe->pkt_offset - 1; ++ } ++ } ++ ++ /* pkt_offset, unit:8 bytes padding */ ++ if (pxmitframe->pkt_offset > 0) ++ ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000); ++ ++ /* driver uses rate */ ++ ptxdesc->txdw4 |= cpu_to_le32(USERATE);/* rate control always by driver */ ++ ++ if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) { ++ /* offset 4 */ ++ ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3F); ++ ++ qsel = (uint)(pattrib->qsel & 0x0000001f); ++ ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); ++ ++ ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000); ++ ++ fill_txdesc_sectype(pattrib, ptxdesc); ++ ++ if (pattrib->ampdu_en) { ++ ptxdesc->txdw2 |= cpu_to_le32(AGG_EN);/* AGG EN */ ++ ptxdesc->txdw6 = cpu_to_le32(0x6666f800); ++ } else { ++ ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);/* AGG BK */ ++ } ++ ++ /* offset 8 */ ++ ++ /* offset 12 */ ++ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0x0FFF0000); ++ ++ /* offset 16 , offset 20 */ ++ if (pattrib->qos_en) ++ ptxdesc->txdw4 |= cpu_to_le32(QOS);/* QoS */ ++ ++ /* offset 20 */ ++ if (pxmitframe->agg_num > 1) ++ ptxdesc->txdw5 |= cpu_to_le32((pxmitframe->agg_num << USB_TXAGG_NUM_SHT) & 0xFF000000); ++ ++ if ((pattrib->ether_type != 0x888e) && ++ (pattrib->ether_type != 0x0806) && ++ (pattrib->ether_type != 0x88b4) && ++ (pattrib->dhcp_pkt != 1)) { ++ /* Non EAP & ARP & DHCP type data packet */ ++ ++ fill_txdesc_vcs(pattrib, &ptxdesc->txdw4); ++ fill_txdesc_phy(pattrib, &ptxdesc->txdw4); ++ ++ ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate=24M */ ++ ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/* DATA/RTS Rate FB LMT */ ++ ++ if (pattrib->ht_en) { ++ if (ODM_RA_GetShortGI_8188E(&haldata->odmpriv, pattrib->mac_id)) ++ ptxdesc->txdw5 |= cpu_to_le32(SGI);/* SGI */ ++ } ++ data_rate = ODM_RA_GetDecisionRate_8188E(&haldata->odmpriv, pattrib->mac_id); ++ ptxdesc->txdw5 |= cpu_to_le32(data_rate & 0x3F); ++ pwr_status = ODM_RA_GetHwPwrStatus_8188E(&haldata->odmpriv, pattrib->mac_id); ++ ptxdesc->txdw4 |= cpu_to_le32((pwr_status & 0x7) << PWR_STATUS_SHT); ++ } else { ++ /* EAP data packet and ARP packet and DHCP. */ ++ /* Use the 1M data rate to send the EAP/ARP packet. */ ++ /* This will maybe make the handshake smooth. */ ++ ptxdesc->txdw2 |= cpu_to_le32(AGG_BK);/* AGG BK */ ++ if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) ++ ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/* DATA_SHORT */ ++ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); ++ } ++ } else if ((pxmitframe->frame_tag & 0x0f) == MGNT_FRAMETAG) { ++ /* offset 4 */ ++ ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3f); ++ ++ qsel = (uint)(pattrib->qsel & 0x0000001f); ++ ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); ++ ++ ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000f0000); ++ ++ /* offset 8 */ ++ /* CCX-TXRPT ack for xmit mgmt frames. */ ++ if (pxmitframe->ack_report) ++ ptxdesc->txdw2 |= cpu_to_le32(BIT(19)); ++ ++ /* offset 12 */ ++ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0x0FFF0000); ++ ++ /* offset 20 */ ++ ptxdesc->txdw5 |= cpu_to_le32(RTY_LMT_EN);/* retry limit enable */ ++ if (pattrib->retry_ctrl) ++ ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */ ++ else ++ ptxdesc->txdw5 |= cpu_to_le32(0x00300000);/* retry limit = 12 */ ++ ++ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); ++ } else if ((pxmitframe->frame_tag & 0x0f) == TXAGG_FRAMETAG) { ++ DBG_88E("pxmitframe->frame_tag == TXAGG_FRAMETAG\n"); ++ } else if (((pxmitframe->frame_tag & 0x0f) == MP_FRAMETAG) && ++ (adapt->registrypriv.mp_mode == 1)) { ++ fill_txdesc_for_mp(adapt, ptxdesc); ++ } else { ++ DBG_88E("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag); ++ ++ /* offset 4 */ ++ ptxdesc->txdw1 |= cpu_to_le32((4) & 0x3f);/* CAM_ID(MAC_ID) */ ++ ++ ptxdesc->txdw1 |= cpu_to_le32((6 << RATE_ID_SHT) & 0x000f0000);/* raid */ ++ ++ /* offset 8 */ ++ ++ /* offset 12 */ ++ ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0x0fff0000); ++ ++ /* offset 20 */ ++ ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate)); ++ } ++ ++ /* 2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. */ ++ /* (1) The sequence number of each non-Qos frame / broadcast / multicast / */ ++ /* mgnt frame should be controlled by Hw because Fw will also send null data */ ++ /* which we cannot control when Fw LPS enable. */ ++ /* --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */ ++ /* (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */ ++ /* (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */ ++ /* 2010.06.23. Added by tynli. */ ++ if (!pattrib->qos_en) { ++ ptxdesc->txdw3 |= cpu_to_le32(EN_HWSEQ); /* Hw set sequence number */ ++ ptxdesc->txdw4 |= cpu_to_le32(HW_SSN); /* Hw set sequence number */ ++ } ++ ++ ODM_SetTxAntByTxInfo_88E(&haldata->odmpriv, pmem, pattrib->mac_id); ++ ++ rtl8188eu_cal_txdesc_chksum(ptxdesc); ++ return pull; ++} ++ ++/* for non-agg data frame or management frame */ ++static s32 rtw_dump_xframe(struct adapter *adapt, struct xmit_frame *pxmitframe) ++{ ++ s32 ret = _SUCCESS; ++ s32 inner_ret = _SUCCESS; ++ int t, sz, w_sz, pull = 0; ++ u8 *mem_addr; ++ u32 ff_hwaddr; ++ struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct xmit_priv *pxmitpriv = &adapt->xmitpriv; ++ struct security_priv *psecuritypriv = &adapt->securitypriv; ++ if ((pxmitframe->frame_tag == DATA_FRAMETAG) && ++ (pxmitframe->attrib.ether_type != 0x0806) && ++ (pxmitframe->attrib.ether_type != 0x888e) && ++ (pxmitframe->attrib.ether_type != 0x88b4) && ++ (pxmitframe->attrib.dhcp_pkt != 1)) ++ rtw_issue_addbareq_cmd(adapt, pxmitframe); ++ mem_addr = pxmitframe->buf_addr; ++ ++ for (t = 0; t < pattrib->nr_frags; t++) { ++ if (inner_ret != _SUCCESS && ret == _SUCCESS) ++ ret = _FAIL; ++ ++ if (t != (pattrib->nr_frags - 1)) { ++ sz = pxmitpriv->frag_len; ++ sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : pattrib->icv_len); ++ } else { ++ /* no frag */ ++ sz = pattrib->last_txcmdsz; ++ } ++ ++ pull = update_txdesc(pxmitframe, mem_addr, sz, false); ++ ++ if (pull) { ++ mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */ ++ pxmitframe->buf_addr = mem_addr; ++ w_sz = sz + TXDESC_SIZE; ++ } else { ++ w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ; ++ } ++ ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); ++ ++ inner_ret = rtw_write_port(adapt, ff_hwaddr, w_sz, (unsigned char *)pxmitbuf); ++ ++ rtw_count_tx_stats(adapt, pxmitframe, sz); ++ ++ mem_addr += w_sz; ++ ++ mem_addr = (u8 *)RND4(((size_t)(mem_addr))); ++ } ++ ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ if (ret != _SUCCESS) ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN); ++ ++ return ret; ++} ++ ++static u32 xmitframe_need_length(struct xmit_frame *pxmitframe) ++{ ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ ++ u32 len = 0; ++ ++ /* no consider fragement */ ++ len = pattrib->hdrlen + pattrib->iv_len + ++ SNAP_SIZE + sizeof(u16) + ++ pattrib->pktlen + ++ ((pattrib->bswenc) ? pattrib->icv_len : 0); ++ ++ if (pattrib->encrypt == _TKIP_) ++ len += 8; ++ ++ return len; ++} ++ ++s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ struct xmit_frame *pxmitframe = NULL; ++ struct xmit_frame *pfirstframe = NULL; ++ ++ /* aggregate variable */ ++ struct hw_xmit *phwxmit; ++ struct sta_info *psta = NULL; ++ struct tx_servq *ptxservq = NULL; ++ struct list_head *xmitframe_plist = NULL, *xmitframe_phead = NULL; ++ ++ u32 pbuf; /* next pkt address */ ++ u32 pbuf_tail; /* last pkt tail */ ++ u32 len; /* packet length, except TXDESC_SIZE and PKT_OFFSET */ ++ ++ u32 bulksize = haldata->UsbBulkOutSize; ++ u8 desc_cnt; ++ u32 bulkptr; ++ ++ /* dump frame variable */ ++ u32 ff_hwaddr; ++ ++ /* check xmitbuffer is ok */ ++ if (!pxmitbuf) { ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (!pxmitbuf) ++ return false; ++ } ++ ++ /* 3 1. pick up first frame */ ++ do { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); ++ if (!pxmitframe) { ++ /* no more xmit frame, release xmit buffer */ ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ return false; ++ } ++ ++ pxmitframe->pxmitbuf = pxmitbuf; ++ pxmitframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pxmitframe; ++ ++ pxmitframe->agg_num = 1; /* alloc xmitframe should assign to 1. */ ++ pxmitframe->pkt_offset = 1; /* first frame of aggregation, reserve offset */ ++ ++ rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); ++ ++ /* always return ndis_packet after rtw_xmitframe_coalesce */ ++ rtw_os_xmit_complete(adapt, pxmitframe); ++ ++ break; ++ } while (1); ++ ++ /* 3 2. aggregate same priority and same DA(AP or STA) frames */ ++ pfirstframe = pxmitframe; ++ len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE + (pfirstframe->pkt_offset * PACKET_OFFSET_SZ); ++ pbuf_tail = len; ++ pbuf = _RND8(pbuf_tail); ++ ++ /* check pkt amount in one bulk */ ++ desc_cnt = 0; ++ bulkptr = bulksize; ++ if (pbuf < bulkptr) { ++ desc_cnt++; ++ } else { ++ desc_cnt = 0; ++ bulkptr = ((pbuf / bulksize) + 1) * bulksize; /* round to next bulksize */ ++ } ++ ++ /* dequeue same priority packet from station tx queue */ ++ psta = pfirstframe->attrib.psta; ++ switch (pfirstframe->attrib.priority) { ++ case 1: ++ case 2: ++ ptxservq = &psta->sta_xmitpriv.bk_q; ++ phwxmit = pxmitpriv->hwxmits + 3; ++ break; ++ case 4: ++ case 5: ++ ptxservq = &psta->sta_xmitpriv.vi_q; ++ phwxmit = pxmitpriv->hwxmits + 1; ++ break; ++ case 6: ++ case 7: ++ ptxservq = &psta->sta_xmitpriv.vo_q; ++ phwxmit = pxmitpriv->hwxmits; ++ break; ++ case 0: ++ case 3: ++ default: ++ ptxservq = &psta->sta_xmitpriv.be_q; ++ phwxmit = pxmitpriv->hwxmits + 2; ++ break; ++ } ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ xmitframe_phead = get_list_head(&ptxservq->sta_pending); ++ xmitframe_plist = xmitframe_phead->next; ++ ++ while (xmitframe_phead != xmitframe_plist) { ++ pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); ++ xmitframe_plist = xmitframe_plist->next; ++ ++ pxmitframe->agg_num = 0; /* not first frame of aggregation */ ++ pxmitframe->pkt_offset = 0; /* not first frame of aggregation, no need to reserve offset */ ++ ++ len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); ++ ++ if (_RND8(pbuf + len) > MAX_XMITBUF_SZ) { ++ pxmitframe->agg_num = 1; ++ pxmitframe->pkt_offset = 1; ++ break; ++ } ++ list_del_init(&pxmitframe->list); ++ ptxservq->qcnt--; ++ phwxmit->accnt--; ++ ++ pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf; ++ ++ rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); ++ /* always return ndis_packet after rtw_xmitframe_coalesce */ ++ rtw_os_xmit_complete(adapt, pxmitframe); ++ ++ /* (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz */ ++ update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz, true); ++ ++ /* don't need xmitframe any more */ ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ /* handle pointer and stop condition */ ++ pbuf_tail = pbuf + len; ++ pbuf = _RND8(pbuf_tail); ++ ++ pfirstframe->agg_num++; ++ if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num) ++ break; ++ ++ if (pbuf < bulkptr) { ++ desc_cnt++; ++ if (desc_cnt == haldata->UsbTxAggDescNum) ++ break; ++ } else { ++ desc_cnt = 0; ++ bulkptr = ((pbuf / bulksize) + 1) * bulksize; ++ } ++ } /* end while (aggregate same priority and same DA(AP or STA) frames) */ ++ ++ if (list_empty(&ptxservq->sta_pending.queue)) ++ list_del_init(&ptxservq->tx_pending); ++ ++ spin_unlock_bh(&pxmitpriv->lock); ++ if ((pfirstframe->attrib.ether_type != 0x0806) && ++ (pfirstframe->attrib.ether_type != 0x888e) && ++ (pfirstframe->attrib.ether_type != 0x88b4) && ++ (pfirstframe->attrib.dhcp_pkt != 1)) ++ rtw_issue_addbareq_cmd(adapt, pfirstframe); ++ /* 3 3. update first frame txdesc */ ++ if ((pbuf_tail % bulksize) == 0) { ++ /* remove pkt_offset */ ++ pbuf_tail -= PACKET_OFFSET_SZ; ++ pfirstframe->buf_addr += PACKET_OFFSET_SZ; ++ pfirstframe->pkt_offset--; ++ } ++ ++ update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz, true); ++ ++ /* 3 4. write xmit buffer to USB FIFO */ ++ ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe); ++ rtw_write_port(adapt, ff_hwaddr, pbuf_tail, (u8 *)pxmitbuf); ++ ++ /* 3 5. update statisitc */ ++ pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE); ++ pbuf_tail -= (pfirstframe->pkt_offset * PACKET_OFFSET_SZ); ++ ++ rtw_count_tx_stats(adapt, pfirstframe, pbuf_tail); ++ ++ rtw_free_xmitframe(pxmitpriv, pfirstframe); ++ ++ return true; ++} ++ ++static s32 xmitframe_direct(struct adapter *adapt, struct xmit_frame *pxmitframe) ++{ ++ s32 res = _SUCCESS; ++ ++ res = rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); ++ if (res == _SUCCESS) ++ rtw_dump_xframe(adapt, pxmitframe); ++ else ++ DBG_88E("==> %s xmitframe_coalsece failed\n", __func__); ++ return res; ++} ++ ++/* ++ * Return ++ * true dump packet directly ++ * false enqueue packet ++ */ ++static s32 pre_xmitframe(struct adapter *adapt, struct xmit_frame *pxmitframe) ++{ ++ s32 res; ++ struct xmit_buf *pxmitbuf = NULL; ++ struct xmit_priv *pxmitpriv = &adapt->xmitpriv; ++ struct pkt_attrib *pattrib = &pxmitframe->attrib; ++ struct mlme_priv *pmlmepriv = &adapt->mlmepriv; ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ if (rtw_txframes_sta_ac_pending(adapt, pattrib) > 0) ++ goto enqueue; ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) ++ goto enqueue; ++ ++ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); ++ if (!pxmitbuf) ++ goto enqueue; ++ ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ pxmitframe->pxmitbuf = pxmitbuf; ++ pxmitframe->buf_addr = pxmitbuf->pbuf; ++ pxmitbuf->priv_data = pxmitframe; ++ ++ if (xmitframe_direct(adapt, pxmitframe) != _SUCCESS) { ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ } ++ ++ return true; ++ ++enqueue: ++ res = rtw_xmitframe_enqueue(adapt, pxmitframe); ++ spin_unlock_bh(&pxmitpriv->lock); ++ ++ if (res != _SUCCESS) { ++ rtw_free_xmitframe(pxmitpriv, pxmitframe); ++ ++ /* Trick, make the statistics correct */ ++ pxmitpriv->tx_pkts--; ++ pxmitpriv->tx_drop++; ++ return true; ++ } ++ ++ return false; ++} ++ ++s32 rtl8188eu_mgnt_xmit(struct adapter *adapt, struct xmit_frame *pmgntframe) ++{ ++ return rtw_dump_xframe(adapt, pmgntframe); ++} ++ ++/* ++ * Return ++ * true dump packet directly ok ++ * false temporary can't transmit packets to hardware ++ */ ++s32 rtl8188eu_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe) ++{ ++ return pre_xmitframe(adapt, pxmitframe); ++} +diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c +new file mode 100644 +index 000000000000..5cdabf43d4fd +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/usb_halinit.c +@@ -0,0 +1,2271 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _HCI_HAL_INIT_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/rtw_efuse.h" ++ ++#include "../include/rtl8188e_hal.h" ++#include "../include/rtl8188e_led.h" ++#include "../include/rtw_iol.h" ++#include "../include/usb_ops.h" ++#include "../include/usb_osintf.h" ++ ++#define HAL_MAC_ENABLE 1 ++#define HAL_BB_ENABLE 1 ++#define HAL_RF_ENABLE 1 ++ ++static void _ConfigNormalChipOutEP_8188E(struct adapter *adapt, u8 NumOutPipe) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ ++ switch (NumOutPipe) { ++ case 3: ++ haldata->OutEpQueueSel = TX_SELE_HQ | TX_SELE_LQ | TX_SELE_NQ; ++ haldata->OutEpNumber = 3; ++ break; ++ case 2: ++ haldata->OutEpQueueSel = TX_SELE_HQ | TX_SELE_NQ; ++ haldata->OutEpNumber = 2; ++ break; ++ case 1: ++ haldata->OutEpQueueSel = TX_SELE_HQ; ++ haldata->OutEpNumber = 1; ++ break; ++ default: ++ break; ++ } ++ DBG_88E("%s OutEpQueueSel(0x%02x), OutEpNumber(%d)\n", __func__, haldata->OutEpQueueSel, haldata->OutEpNumber); ++} ++ ++static bool HalUsbSetQueuePipeMapping8188EUsb(struct adapter *adapt, u8 NumInPipe, u8 NumOutPipe) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ bool result = false; ++ ++ _ConfigNormalChipOutEP_8188E(adapt, NumOutPipe); ++ ++ /* Normal chip with one IN and one OUT doesn't have interrupt IN EP. */ ++ if (1 == haldata->OutEpNumber) { ++ if (1 != NumInPipe) ++ return result; ++ } ++ ++ /* All config other than above support one Bulk IN and one Interrupt IN. */ ++ ++ result = Hal_MappingOutPipe(adapt, NumOutPipe); ++ ++ return result; ++} ++ ++static void rtl8188eu_interface_configure(struct adapter *adapt) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(adapt); ++ ++ if (pdvobjpriv->ishighspeed) ++ haldata->UsbBulkOutSize = USB_HIGH_SPEED_BULK_SIZE;/* 512 bytes */ ++ else ++ haldata->UsbBulkOutSize = USB_FULL_SPEED_BULK_SIZE;/* 64 bytes */ ++ ++ haldata->interfaceIndex = pdvobjpriv->InterfaceNumber; ++ ++ haldata->UsbTxAggMode = 1; ++ haldata->UsbTxAggDescNum = 0x6; /* only 4 bits */ ++ ++ haldata->UsbRxAggMode = USB_RX_AGG_DMA;/* USB_RX_AGG_DMA; */ ++ haldata->UsbRxAggBlockCount = 8; /* unit : 512b */ ++ haldata->UsbRxAggBlockTimeout = 0x6; ++ haldata->UsbRxAggPageCount = 48; /* uint :128 b 0x0A; 10 = MAX_RX_DMA_BUFFER_SIZE/2/haldata->UsbBulkOutSize */ ++ haldata->UsbRxAggPageTimeout = 0x4; /* 6, absolute time = 34ms/(2^6) */ ++ ++ HalUsbSetQueuePipeMapping8188EUsb(adapt, ++ pdvobjpriv->RtNumInPipes, pdvobjpriv->RtNumOutPipes); ++} ++ ++static u32 rtl8188eu_InitPowerOn(struct adapter *adapt) ++{ ++ u16 value16; ++ /* HW Power on sequence */ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ if (haldata->bMacPwrCtrlOn) ++ return _SUCCESS; ++ ++ if (!HalPwrSeqCmdParsing(adapt, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_PWR_ON_FLOW)) { ++ DBG_88E(KERN_ERR "%s: run power on flow fail\n", __func__); ++ return _FAIL; ++ } ++ ++ /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ ++ /* Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */ ++ rtw_write16(adapt, REG_CR, 0x00); /* suggseted by zhouzhou, by page, 20111230 */ ++ ++ /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ ++ value16 = rtw_read16(adapt, REG_CR); ++ value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN ++ | PROTOCOL_EN | SCHEDULE_EN | ENSEC | CALTMR_EN); ++ /* for SDIO - Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */ ++ ++ rtw_write16(adapt, REG_CR, value16); ++ haldata->bMacPwrCtrlOn = true; ++ ++ return _SUCCESS; ++} ++ ++/* Shall USB interface init this? */ ++static void _InitInterrupt(struct adapter *Adapter) ++{ ++ u32 imr, imr_ex; ++ u8 usb_opt; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ /* HISR write one to clear */ ++ rtw_write32(Adapter, REG_HISR_88E, 0xFFFFFFFF); ++ /* HIMR - */ ++ imr = IMR_PSTIMEOUT_88E | IMR_TBDER_88E | IMR_CPWM_88E | IMR_CPWM2_88E; ++ rtw_write32(Adapter, REG_HIMR_88E, imr); ++ haldata->IntrMask[0] = imr; ++ ++ imr_ex = IMR_TXERR_88E | IMR_RXERR_88E | IMR_TXFOVW_88E | IMR_RXFOVW_88E; ++ rtw_write32(Adapter, REG_HIMRE_88E, imr_ex); ++ haldata->IntrMask[1] = imr_ex; ++ ++ /* REG_USB_SPECIAL_OPTION - BIT(4) */ ++ /* 0; Use interrupt endpoint to upload interrupt pkt */ ++ /* 1; Use bulk endpoint to upload interrupt pkt, */ ++ usb_opt = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION); ++ ++ if (!adapter_to_dvobj(Adapter)->ishighspeed) ++ usb_opt = usb_opt & (~INT_BULK_SEL); ++ else ++ usb_opt = usb_opt | (INT_BULK_SEL); ++ ++ rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, usb_opt); ++} ++ ++static void _InitQueueReservedPage(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u32 numHQ = 0; ++ u32 numLQ = 0; ++ u32 numNQ = 0; ++ u32 numPubQ; ++ u32 value32; ++ u8 value8; ++ bool bWiFiConfig = pregistrypriv->wifi_spec; ++ ++ if (bWiFiConfig) { ++ if (haldata->OutEpQueueSel & TX_SELE_HQ) ++ numHQ = 0x29; ++ ++ if (haldata->OutEpQueueSel & TX_SELE_LQ) ++ numLQ = 0x1C; ++ ++ /* NOTE: This step shall be proceed before writting REG_RQPN. */ ++ if (haldata->OutEpQueueSel & TX_SELE_NQ) ++ numNQ = 0x1C; ++ value8 = (u8)_NPQ(numNQ); ++ rtw_write8(Adapter, REG_RQPN_NPQ, value8); ++ ++ numPubQ = 0xA8 - numHQ - numLQ - numNQ; ++ ++ /* TX DMA */ ++ value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN; ++ rtw_write32(Adapter, REG_RQPN, value32); ++ } else { ++ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0000);/* Just follow MP Team,??? Georgia 03/28 */ ++ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0d); ++ rtw_write32(Adapter, REG_RQPN, 0x808E000d);/* reserve 7 page for LPS */ ++ } ++} ++ ++static void _InitTxBufferBoundary(struct adapter *Adapter, u8 txpktbuf_bndy) ++{ ++ rtw_write8(Adapter, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy); ++ rtw_write8(Adapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy); ++ rtw_write8(Adapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy); ++ rtw_write8(Adapter, REG_TRXFF_BNDY, txpktbuf_bndy); ++ rtw_write8(Adapter, REG_TDECTRL + 1, txpktbuf_bndy); ++} ++ ++static void _InitPageBoundary(struct adapter *Adapter) ++{ ++ /* RX Page Boundary */ ++ /* */ ++ u16 rxff_bndy = MAX_RX_DMA_BUFFER_SIZE_88E - 1; ++ ++ rtw_write16(Adapter, (REG_TRXFF_BNDY + 2), rxff_bndy); ++} ++ ++static void _InitNormalChipRegPriority(struct adapter *Adapter, u16 beQ, ++ u16 bkQ, u16 viQ, u16 voQ, u16 mgtQ, ++ u16 hiQ) ++{ ++ u16 value16 = (rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7); ++ ++ value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) | ++ _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) | ++ _TXDMA_MGQ_MAP(mgtQ) | _TXDMA_HIQ_MAP(hiQ); ++ ++ rtw_write16(Adapter, REG_TRXDMA_CTRL, value16); ++} ++ ++static void _InitNormalChipOneOutEpPriority(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ u16 value = 0; ++ switch (haldata->OutEpQueueSel) { ++ case TX_SELE_HQ: ++ value = QUEUE_HIGH; ++ break; ++ case TX_SELE_LQ: ++ value = QUEUE_LOW; ++ break; ++ case TX_SELE_NQ: ++ value = QUEUE_NORMAL; ++ break; ++ default: ++ break; ++ } ++ _InitNormalChipRegPriority(Adapter, value, value, value, value, ++ value, value); ++} ++ ++static void _InitNormalChipTwoOutEpPriority(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; ++ u16 valueHi = 0; ++ u16 valueLow = 0; ++ ++ switch (haldata->OutEpQueueSel) { ++ case (TX_SELE_HQ | TX_SELE_LQ): ++ valueHi = QUEUE_HIGH; ++ valueLow = QUEUE_LOW; ++ break; ++ case (TX_SELE_NQ | TX_SELE_LQ): ++ valueHi = QUEUE_NORMAL; ++ valueLow = QUEUE_LOW; ++ break; ++ case (TX_SELE_HQ | TX_SELE_NQ): ++ valueHi = QUEUE_HIGH; ++ valueLow = QUEUE_NORMAL; ++ break; ++ default: ++ break; ++ } ++ ++ if (!pregistrypriv->wifi_spec) { ++ beQ = valueLow; ++ bkQ = valueLow; ++ viQ = valueHi; ++ voQ = valueHi; ++ mgtQ = valueHi; ++ hiQ = valueHi; ++ } else {/* for WMM ,CONFIG_OUT_EP_WIFI_MODE */ ++ beQ = valueLow; ++ bkQ = valueHi; ++ viQ = valueHi; ++ voQ = valueLow; ++ mgtQ = valueHi; ++ hiQ = valueHi; ++ } ++ _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ); ++} ++ ++static void _InitNormalChipThreeOutEpPriority(struct adapter *Adapter) ++{ ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ; ++ ++ if (!pregistrypriv->wifi_spec) {/* typical setting */ ++ beQ = QUEUE_LOW; ++ bkQ = QUEUE_LOW; ++ viQ = QUEUE_NORMAL; ++ voQ = QUEUE_HIGH; ++ mgtQ = QUEUE_HIGH; ++ hiQ = QUEUE_HIGH; ++ } else {/* for WMM */ ++ beQ = QUEUE_LOW; ++ bkQ = QUEUE_NORMAL; ++ viQ = QUEUE_NORMAL; ++ voQ = QUEUE_HIGH; ++ mgtQ = QUEUE_HIGH; ++ hiQ = QUEUE_HIGH; ++ } ++ _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ); ++} ++ ++static void _InitQueuePriority(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ switch (haldata->OutEpNumber) { ++ case 1: ++ _InitNormalChipOneOutEpPriority(Adapter); ++ break; ++ case 2: ++ _InitNormalChipTwoOutEpPriority(Adapter); ++ break; ++ case 3: ++ _InitNormalChipThreeOutEpPriority(Adapter); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void _InitNetworkType(struct adapter *Adapter) ++{ ++ u32 value32; ++ ++ value32 = rtw_read32(Adapter, REG_CR); ++ /* TODO: use the other function to set network type */ ++ value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP); ++ ++ rtw_write32(Adapter, REG_CR, value32); ++} ++ ++static void _InitTransferPageSize(struct adapter *Adapter) ++{ ++ /* Tx page size is always 128. */ ++ ++ u8 value8; ++ value8 = _PSRX(PBP_128) | _PSTX(PBP_128); ++ rtw_write8(Adapter, REG_PBP, value8); ++} ++ ++static void _InitDriverInfoSize(struct adapter *Adapter, u8 drvInfoSize) ++{ ++ rtw_write8(Adapter, REG_RX_DRVINFO_SZ, drvInfoSize); ++} ++ ++static void _InitWMACSetting(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ haldata->ReceiveConfig = RCR_AAP | RCR_APM | RCR_AM | RCR_AB | ++ RCR_CBSSID_DATA | RCR_CBSSID_BCN | ++ RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | ++ RCR_APP_MIC | RCR_APP_PHYSTS; ++ ++ /* some REG_RCR will be modified later by phy_ConfigMACWithHeaderFile() */ ++ rtw_write32(Adapter, REG_RCR, haldata->ReceiveConfig); ++ ++ /* Accept all multicast address */ ++ rtw_write32(Adapter, REG_MAR, 0xFFFFFFFF); ++ rtw_write32(Adapter, REG_MAR + 4, 0xFFFFFFFF); ++} ++ ++static void _InitAdaptiveCtrl(struct adapter *Adapter) ++{ ++ u16 value16; ++ u32 value32; ++ ++ /* Response Rate Set */ ++ value32 = rtw_read32(Adapter, REG_RRSR); ++ value32 &= ~RATE_BITMAP_ALL; ++ value32 |= RATE_RRSR_CCK_ONLY_1M; ++ rtw_write32(Adapter, REG_RRSR, value32); ++ ++ /* CF-END Threshold */ ++ ++ /* SIFS (used in NAV) */ ++ value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10); ++ rtw_write16(Adapter, REG_SPEC_SIFS, value16); ++ ++ /* Retry Limit */ ++ value16 = _LRL(0x30) | _SRL(0x30); ++ rtw_write16(Adapter, REG_RL, value16); ++} ++ ++static void _InitEDCA(struct adapter *Adapter) ++{ ++ /* Set Spec SIFS (used in NAV) */ ++ rtw_write16(Adapter, REG_SPEC_SIFS, 0x100a); ++ rtw_write16(Adapter, REG_MAC_SPEC_SIFS, 0x100a); ++ ++ /* Set SIFS for CCK */ ++ rtw_write16(Adapter, REG_SIFS_CTX, 0x100a); ++ ++ /* Set SIFS for OFDM */ ++ rtw_write16(Adapter, REG_SIFS_TRX, 0x100a); ++ ++ /* TXOP */ ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, 0x005EA42B); ++ rtw_write32(Adapter, REG_EDCA_BK_PARAM, 0x0000A44F); ++ rtw_write32(Adapter, REG_EDCA_VI_PARAM, 0x005EA324); ++ rtw_write32(Adapter, REG_EDCA_VO_PARAM, 0x002FA226); ++} ++ ++static void _InitBeaconMaxError(struct adapter *Adapter, bool InfraMode) ++{ ++} ++ ++static void _InitHWLed(struct adapter *Adapter) ++{ ++ struct led_priv *pledpriv = &Adapter->ledpriv; ++ ++ if (pledpriv->LedStrategy != HW_LED) ++ return; ++ ++/* HW led control */ ++/* to do .... */ ++/* must consider cases of antenna diversity/ commbo card/solo card/mini card */ ++} ++ ++static void _InitRDGSetting(struct adapter *Adapter) ++{ ++ rtw_write8(Adapter, REG_RD_CTRL, 0xFF); ++ rtw_write16(Adapter, REG_RD_NAV_NXT, 0x200); ++ rtw_write8(Adapter, REG_RD_RESP_PKT_TH, 0x05); ++} ++ ++static void _InitRxSetting(struct adapter *Adapter) ++{ ++ rtw_write32(Adapter, REG_MACID, 0x87654321); ++ rtw_write32(Adapter, 0x0700, 0x87654321); ++} ++ ++static void _InitRetryFunction(struct adapter *Adapter) ++{ ++ u8 value8; ++ ++ value8 = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL); ++ value8 |= EN_AMPDU_RTY_NEW; ++ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL, value8); ++ ++ /* Set ACK timeout */ ++ rtw_write8(Adapter, REG_ACKTO, 0x40); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: usb_AggSettingTxUpdate() ++ * ++ * Overview: Separate TX/RX parameters update independent for TP detection and ++ * dynamic TX/RX aggreagtion parameters update. ++ * ++ * Input: struct adapter * ++ * ++ * Output/Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 12/10/2010 MHC Separate to smaller function. ++ * ++ *---------------------------------------------------------------------------*/ ++static void usb_AggSettingTxUpdate(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ u32 value32; ++ ++ if (Adapter->registrypriv.wifi_spec) ++ haldata->UsbTxAggMode = false; ++ ++ if (haldata->UsbTxAggMode) { ++ value32 = rtw_read32(Adapter, REG_TDECTRL); ++ value32 = value32 & ~(BLK_DESC_NUM_MASK << BLK_DESC_NUM_SHIFT); ++ value32 |= ((haldata->UsbTxAggDescNum & BLK_DESC_NUM_MASK) << BLK_DESC_NUM_SHIFT); ++ ++ rtw_write32(Adapter, REG_TDECTRL, value32); ++ } ++} /* usb_AggSettingTxUpdate */ ++ ++/*----------------------------------------------------------------------------- ++ * Function: usb_AggSettingRxUpdate() ++ * ++ * Overview: Separate TX/RX parameters update independent for TP detection and ++ * dynamic TX/RX aggreagtion parameters update. ++ * ++ * Input: struct adapter * ++ * ++ * Output/Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 12/10/2010 MHC Separate to smaller function. ++ * ++ *---------------------------------------------------------------------------*/ ++static void ++usb_AggSettingRxUpdate( ++ struct adapter *Adapter ++ ) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ u8 valueDMA; ++ u8 valueUSB; ++ ++ valueDMA = rtw_read8(Adapter, REG_TRXDMA_CTRL); ++ valueUSB = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION); ++ ++ switch (haldata->UsbRxAggMode) { ++ case USB_RX_AGG_DMA: ++ valueDMA |= RXDMA_AGG_EN; ++ valueUSB &= ~USB_AGG_EN; ++ break; ++ case USB_RX_AGG_USB: ++ valueDMA &= ~RXDMA_AGG_EN; ++ valueUSB |= USB_AGG_EN; ++ break; ++ case USB_RX_AGG_MIX: ++ valueDMA |= RXDMA_AGG_EN; ++ valueUSB |= USB_AGG_EN; ++ break; ++ case USB_RX_AGG_DISABLE: ++ default: ++ valueDMA &= ~RXDMA_AGG_EN; ++ valueUSB &= ~USB_AGG_EN; ++ break; ++ } ++ ++ rtw_write8(Adapter, REG_TRXDMA_CTRL, valueDMA); ++ rtw_write8(Adapter, REG_USB_SPECIAL_OPTION, valueUSB); ++ ++ switch (haldata->UsbRxAggMode) { ++ case USB_RX_AGG_DMA: ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount); ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH + 1, haldata->UsbRxAggPageTimeout); ++ break; ++ case USB_RX_AGG_USB: ++ rtw_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount); ++ rtw_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout); ++ break; ++ case USB_RX_AGG_MIX: ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, haldata->UsbRxAggPageCount); ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH + 1, (haldata->UsbRxAggPageTimeout & 0x1F));/* 0x280[12:8] */ ++ rtw_write8(Adapter, REG_USB_AGG_TH, haldata->UsbRxAggBlockCount); ++ rtw_write8(Adapter, REG_USB_AGG_TO, haldata->UsbRxAggBlockTimeout); ++ break; ++ case USB_RX_AGG_DISABLE: ++ default: ++ /* TODO: */ ++ break; ++ } ++ ++ switch (PBP_128) { ++ case PBP_128: ++ haldata->HwRxPageSize = 128; ++ break; ++ case PBP_64: ++ haldata->HwRxPageSize = 64; ++ break; ++ case PBP_256: ++ haldata->HwRxPageSize = 256; ++ break; ++ case PBP_512: ++ haldata->HwRxPageSize = 512; ++ break; ++ case PBP_1024: ++ haldata->HwRxPageSize = 1024; ++ break; ++ default: ++ break; ++ } ++} /* usb_AggSettingRxUpdate */ ++ ++static void InitUsbAggregationSetting(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ /* Tx aggregation setting */ ++ usb_AggSettingTxUpdate(Adapter); ++ ++ /* Rx aggregation setting */ ++ usb_AggSettingRxUpdate(Adapter); ++ ++ /* 201/12/10 MH Add for USB agg mode dynamic switch. */ ++ haldata->UsbRxHighSpeedMode = false; ++} ++ ++static void _InitOperationMode(struct adapter *Adapter) ++{ ++} ++ ++static void _InitBeaconParameters(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ rtw_write16(Adapter, REG_BCN_CTRL, 0x1010); ++ ++ /* TODO: Remove these magic number */ ++ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0x6404);/* ms */ ++ rtw_write8(Adapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);/* 5ms */ ++ rtw_write8(Adapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME); /* 2ms */ ++ ++ /* Suggested by designer timchen. Change beacon AIFS to the largest number */ ++ /* beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 */ ++ rtw_write16(Adapter, REG_BCNTCFG, 0x660F); ++ ++ haldata->RegBcnCtrlVal = rtw_read8(Adapter, REG_BCN_CTRL); ++ haldata->RegTxPause = rtw_read8(Adapter, REG_TXPAUSE); ++ haldata->RegFwHwTxQCtrl = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL + 2); ++ haldata->RegReg542 = rtw_read8(Adapter, REG_TBTT_PROHIBIT + 2); ++ haldata->RegCR_1 = rtw_read8(Adapter, REG_CR + 1); ++} ++ ++static void _BeaconFunctionEnable(struct adapter *Adapter, ++ bool Enable, bool Linked) ++{ ++ rtw_write8(Adapter, REG_BCN_CTRL, (BIT(4) | BIT(3) | BIT(1))); ++ ++ rtw_write8(Adapter, REG_RD_CTRL + 1, 0x6F); ++} ++ ++/* Set CCK and OFDM Block "ON" */ ++static void _BBTurnOnBlock(struct adapter *Adapter) ++{ ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bCCKEn, 0x1); ++ PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bOFDMEn, 0x1); ++} ++ ++enum { ++ Antenna_Lfet = 1, ++ Antenna_Right = 2, ++}; ++ ++static void _InitAntenna_Selection(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ if (haldata->AntDivCfg == 0) ++ return; ++ DBG_88E("==> %s ....\n", __func__); ++ ++ rtw_write32(Adapter, REG_LEDCFG0, rtw_read32(Adapter, REG_LEDCFG0) | BIT(23)); ++ PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, BIT(13), 0x01); ++ ++ if (PHY_QueryBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300) == Antenna_A) ++ haldata->CurAntenna = Antenna_A; ++ else ++ haldata->CurAntenna = Antenna_B; ++ DBG_88E("%s,Cur_ant:(%x)%s\n", __func__, haldata->CurAntenna, (haldata->CurAntenna == Antenna_A) ? "Antenna_A" : "Antenna_B"); ++} ++ ++/*----------------------------------------------------------------------------- ++ * Function: HwSuspendModeEnable92Cu() ++ * ++ * Overview: HW suspend mode switch. ++ * ++ * Input: NONE ++ * ++ * Output: NONE ++ * ++ * Return: NONE ++ * ++ * Revised History: ++ * When Who Remark ++ * 08/23/2010 MHC HW suspend mode switch test.. ++ *---------------------------------------------------------------------------*/ ++enum rt_rf_power_state RfOnOffDetect(struct adapter *adapt) ++{ ++ u8 val8; ++ enum rt_rf_power_state rfpowerstate = rf_off; ++ ++ if (adapt->pwrctrlpriv.bHWPowerdown) { ++ val8 = rtw_read8(adapt, REG_HSISR); ++ DBG_88E("pwrdown, 0x5c(BIT(7))=%02x\n", val8); ++ rfpowerstate = (val8 & BIT(7)) ? rf_off : rf_on; ++ } else { /* rf on/off */ ++ rtw_write8(adapt, REG_MAC_PINMUX_CFG, rtw_read8(adapt, REG_MAC_PINMUX_CFG) & ~(BIT(3))); ++ val8 = rtw_read8(adapt, REG_GPIO_IO_SEL); ++ DBG_88E("GPIO_IN=%02x\n", val8); ++ rfpowerstate = (val8 & BIT(3)) ? rf_on : rf_off; ++ } ++ return rfpowerstate; ++} /* HalDetectPwrDownMode */ ++ ++static u32 rtl8188eu_hal_init(struct adapter *Adapter) ++{ ++ u8 value8 = 0; ++ u16 value16; ++ u8 txpktbuf_bndy; ++ u32 status = _SUCCESS; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; ++ struct registry_priv *pregistrypriv = &Adapter->registrypriv; ++ u32 init_start_time = jiffies; ++ ++ #define HAL_INIT_PROFILE_TAG(stage) do {} while (0) ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BEGIN); ++ ++ if (Adapter->pwrctrlpriv.bkeepfwalive) { ++ _ps_open_RF(Adapter); ++ ++ if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) { ++ PHY_IQCalibrate_8188E(Adapter, true); ++ } else { ++ PHY_IQCalibrate_8188E(Adapter, false); ++ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true; ++ } ++ ++ ODM_TXPowerTrackingCheck(&haldata->odmpriv); ++ PHY_LCCalibrate_8188E(Adapter); ++ ++ goto exit; ++ } ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON); ++ status = rtl8188eu_InitPowerOn(Adapter); ++ if (status == _FAIL) ++ goto exit; ++ ++ /* Save target channel */ ++ haldata->CurrentChannel = 6;/* default set to 6 */ ++ ++ if (pwrctrlpriv->reg_rfoff) { ++ pwrctrlpriv->rf_pwrstate = rf_off; ++ } ++ ++ /* 2010/08/09 MH We need to check if we need to turnon or off RF after detecting */ ++ /* HW GPIO pin. Before PHY_RFConfig8192C. */ ++ /* 2010/08/26 MH If Efuse does not support sective suspend then disable the function. */ ++ ++ if (!pregistrypriv->wifi_spec) { ++ txpktbuf_bndy = TX_PAGE_BOUNDARY_88E; ++ } else { ++ /* for WMM */ ++ txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY_88E; ++ } ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01); ++ _InitQueueReservedPage(Adapter); ++ _InitQueuePriority(Adapter); ++ _InitPageBoundary(Adapter); ++ _InitTransferPageSize(Adapter); ++ ++ _InitTxBufferBoundary(Adapter, 0); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW); ++ if (Adapter->registrypriv.mp_mode == 1) { ++ _InitRxSetting(Adapter); ++ Adapter->bFWReady = false; ++ haldata->fw_ractrl = false; ++ } else { ++ status = rtl8188e_FirmwareDownload(Adapter); ++ ++ if (status != _SUCCESS) { ++ DBG_88E("%s: Download Firmware failed!!\n", __func__); ++ Adapter->bFWReady = false; ++ haldata->fw_ractrl = false; ++ return status; ++ } else { ++ Adapter->bFWReady = true; ++ haldata->fw_ractrl = false; ++ } ++ } ++ rtl8188e_InitializeFirmwareVars(Adapter); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MAC); ++#if (HAL_MAC_ENABLE == 1) ++ status = PHY_MACConfig8188E(Adapter); ++ if (status == _FAIL) { ++ DBG_88E(" ### Failed to init MAC ......\n "); ++ goto exit; ++ } ++#endif ++ ++ /* */ ++ /* d. Initialize BB related configurations. */ ++ /* */ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BB); ++#if (HAL_BB_ENABLE == 1) ++ status = PHY_BBConfig8188E(Adapter); ++ if (status == _FAIL) { ++ DBG_88E(" ### Failed to init BB ......\n "); ++ goto exit; ++ } ++#endif ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_RF); ++#if (HAL_RF_ENABLE == 1) ++ status = PHY_RFConfig8188E(Adapter); ++ if (status == _FAIL) { ++ DBG_88E(" ### Failed to init RF ......\n "); ++ goto exit; ++ } ++#endif ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_EFUSE_PATCH); ++ status = rtl8188e_iol_efuse_patch(Adapter); ++ if (status == _FAIL) { ++ DBG_88E("%s rtl8188e_iol_efuse_patch failed\n", __func__); ++ goto exit; ++ } ++ ++ _InitTxBufferBoundary(Adapter, txpktbuf_bndy); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT); ++ status = InitLLTTable(Adapter, txpktbuf_bndy); ++ if (status == _FAIL) ++ goto exit; ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02); ++ /* Get Rx PHY status in order to report RSSI and others. */ ++ _InitDriverInfoSize(Adapter, DRVINFO_SZ); ++ ++ _InitInterrupt(Adapter); ++ hal_init_macaddr(Adapter);/* set mac_address */ ++ _InitNetworkType(Adapter);/* set msr */ ++ _InitWMACSetting(Adapter); ++ _InitAdaptiveCtrl(Adapter); ++ _InitEDCA(Adapter); ++ _InitRetryFunction(Adapter); ++ InitUsbAggregationSetting(Adapter); ++ _InitOperationMode(Adapter);/* todo */ ++ _InitBeaconParameters(Adapter); ++ _InitBeaconMaxError(Adapter, true); ++ ++ /* */ ++ /* Init CR MACTXEN, MACRXEN after setting RxFF boundary REG_TRXFF_BNDY to patch */ ++ /* Hw bug which Hw initials RxFF boundary size to a value which is larger than the real Rx buffer size in 88E. */ ++ /* */ ++ /* Enable MACTXEN/MACRXEN block */ ++ value16 = rtw_read16(Adapter, REG_CR); ++ value16 |= (MACTXEN | MACRXEN); ++ rtw_write8(Adapter, REG_CR, value16); ++ ++ if (haldata->bRDGEnable) ++ _InitRDGSetting(Adapter); ++ ++ /* Enable TX Report */ ++ /* Enable Tx Report Timer */ ++ value8 = rtw_read8(Adapter, REG_TX_RPT_CTRL); ++ rtw_write8(Adapter, REG_TX_RPT_CTRL, (value8 | BIT(1) | BIT(0))); ++ /* Set MAX RPT MACID */ ++ rtw_write8(Adapter, REG_TX_RPT_CTRL + 1, 2);/* FOR sta mode ,0: bc/mc ,1:AP */ ++ /* Tx RPT Timer. Unit: 32us */ ++ rtw_write16(Adapter, REG_TX_RPT_TIME, 0xCdf0); ++ ++ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL, 0); ++ ++ rtw_write16(Adapter, REG_PKT_VO_VI_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ ++ rtw_write16(Adapter, REG_PKT_BE_BK_LIFE_TIME, 0x0400); /* unit: 256us. 256ms */ ++ ++ _InitHWLed(Adapter); ++ ++ /* Keep RfRegChnlVal for later use. */ ++ haldata->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)0, RF_CHNLBW, bRFRegOffsetMask); ++ haldata->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum rf_radio_path)1, RF_CHNLBW, bRFRegOffsetMask); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK); ++ _BBTurnOnBlock(Adapter); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY); ++ invalidate_cam_all(Adapter); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11); ++ /* 2010/12/17 MH We need to set TX power according to EFUSE content at first. */ ++ PHY_SetTxPowerLevel8188E(Adapter, haldata->CurrentChannel); ++ ++/* Move by Neo for USB SS to below setp */ ++/* _RfPowerSave(Adapter); */ ++ ++ _InitAntenna_Selection(Adapter); ++ ++ /* */ ++ /* Disable BAR, suggested by Scott */ ++ /* 2010.04.09 add by hpfan */ ++ /* */ ++ rtw_write32(Adapter, REG_BAR_MODE_CTRL, 0x0201ffff); ++ ++ /* HW SEQ CTRL */ ++ /* set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. */ ++ rtw_write8(Adapter, REG_HWSEQ_CTRL, 0xFF); ++ ++ if (pregistrypriv->wifi_spec) ++ rtw_write16(Adapter, REG_FAST_EDCA_CTRL, 0); ++ ++ /* Nav limit , suggest by scott */ ++ rtw_write8(Adapter, 0x652, 0x0); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM); ++ rtl8188e_InitHalDm(Adapter); ++ ++ if (Adapter->registrypriv.mp_mode == 1) { ++ Adapter->mppriv.channel = haldata->CurrentChannel; ++ MPT_InitializeAdapter(Adapter, Adapter->mppriv.channel); ++ } else { ++ /* 2010/08/11 MH Merge from 8192SE for Minicard init. We need to confirm current radio status */ ++ /* and then decide to enable RF or not.!!!??? For Selective suspend mode. We may not */ ++ /* call initstruct adapter. May cause some problem?? */ ++ /* Fix the bug that Hw/Sw radio off before S3/S4, the RF off action will not be executed */ ++ /* in MgntActSet_RF_State() after wake up, because the value of haldata->eRFPowerState */ ++ /* is the same as eRfOff, we should change it to eRfOn after we config RF parameters. */ ++ /* Added by tynli. 2010.03.30. */ ++ pwrctrlpriv->rf_pwrstate = rf_on; ++ ++ /* enable Tx report. */ ++ rtw_write8(Adapter, REG_FWHW_TXQ_CTRL + 1, 0x0F); ++ ++ /* Suggested by SD1 pisa. Added by tynli. 2011.10.21. */ ++ rtw_write8(Adapter, REG_EARLY_MODE_CONTROL + 3, 0x01);/* Pretx_en, for WEP/TKIP SEC */ ++ ++ /* tynli_test_tx_report. */ ++ rtw_write16(Adapter, REG_TX_RPT_TIME, 0x3DF0); ++ ++ /* enable tx DMA to drop the redundate data of packet */ ++ rtw_write16(Adapter, REG_TXDMA_OFFSET_CHK, (rtw_read16(Adapter, REG_TXDMA_OFFSET_CHK) | DROP_DATA_EN)); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK); ++ /* 2010/08/26 MH Merge from 8192CE. */ ++ if (pwrctrlpriv->rf_pwrstate == rf_on) { ++ if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) { ++ PHY_IQCalibrate_8188E(Adapter, true); ++ } else { ++ PHY_IQCalibrate_8188E(Adapter, false); ++ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = true; ++ } ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK); ++ ++ ODM_TXPowerTrackingCheck(&haldata->odmpriv); ++ ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK); ++ PHY_LCCalibrate_8188E(Adapter); ++ } ++ } ++ ++/* HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); */ ++/* _InitPABias(Adapter); */ ++ rtw_write8(Adapter, REG_USB_HRPWM, 0); ++ ++ /* ack for xmit mgmt frames. */ ++ rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, rtw_read32(Adapter, REG_FWHW_TXQ_CTRL) | BIT(12)); ++ ++exit: ++ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END); ++ ++ DBG_88E("%s in %dms\n", __func__, rtw_get_passing_time_ms(init_start_time)); ++ ++ return status; ++} ++ ++void _ps_open_RF(struct adapter *adapt) ++{ ++ /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */ ++ /* phy_SsPwrSwitch92CU(adapt, rf_on, 1); */ ++} ++ ++static void _ps_close_RF(struct adapter *adapt) ++{ ++ /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */ ++ /* phy_SsPwrSwitch92CU(adapt, rf_off, 1); */ ++} ++ ++static void CardDisableRTL8188EU(struct adapter *Adapter) ++{ ++ u8 val8; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ /* Stop Tx Report Timer. 0x4EC[Bit1]=b'0 */ ++ val8 = rtw_read8(Adapter, REG_TX_RPT_CTRL); ++ rtw_write8(Adapter, REG_TX_RPT_CTRL, val8 & (~BIT(1))); ++ ++ /* stop rx */ ++ rtw_write8(Adapter, REG_CR, 0x0); ++ ++ /* Run LPS WL RFOFF flow */ ++ HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_LPS_ENTER_FLOW); ++ ++ /* 2. 0x1F[7:0] = 0 turn off RF */ ++ ++ val8 = rtw_read8(Adapter, REG_MCUFWDL); ++ if ((val8 & RAM_DL_SEL) && Adapter->bFWReady) { /* 8051 RAM code */ ++ /* Reset MCU 0x2[10]=0. */ ++ val8 = rtw_read8(Adapter, REG_SYS_FUNC_EN + 1); ++ val8 &= ~BIT(2); /* 0x2[10], FEN_CPUEN */ ++ rtw_write8(Adapter, REG_SYS_FUNC_EN + 1, val8); ++ } ++ ++ /* reset MCU ready status */ ++ rtw_write8(Adapter, REG_MCUFWDL, 0); ++ ++ /* YJ,add,111212 */ ++ /* Disable 32k */ ++ val8 = rtw_read8(Adapter, REG_32K_CTRL); ++ rtw_write8(Adapter, REG_32K_CTRL, val8 & (~BIT(0))); ++ ++ /* Card disable power action flow */ ++ HalPwrSeqCmdParsing(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, Rtl8188E_NIC_DISABLE_FLOW); ++ ++ /* Reset MCU IO Wrapper */ ++ val8 = rtw_read8(Adapter, REG_RSV_CTRL + 1); ++ rtw_write8(Adapter, REG_RSV_CTRL + 1, (val8 & (~BIT(3)))); ++ val8 = rtw_read8(Adapter, REG_RSV_CTRL + 1); ++ rtw_write8(Adapter, REG_RSV_CTRL + 1, val8 | BIT(3)); ++ ++ /* YJ,test add, 111207. For Power Consumption. */ ++ val8 = rtw_read8(Adapter, GPIO_IN); ++ rtw_write8(Adapter, GPIO_OUT, val8); ++ rtw_write8(Adapter, GPIO_IO_SEL, 0xFF);/* Reg0x46 */ ++ ++ val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL); ++ rtw_write8(Adapter, REG_GPIO_IO_SEL, (val8 << 4)); ++ val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL + 1); ++ rtw_write8(Adapter, REG_GPIO_IO_SEL + 1, val8 | 0x0F);/* Reg0x43 */ ++ rtw_write32(Adapter, REG_BB_PAD_CTRL, 0x00080808);/* set LNA ,TRSW,EX_PA Pin to output mode */ ++ haldata->bMacPwrCtrlOn = false; ++ Adapter->bFWReady = false; ++} ++static void rtl8192cu_hw_power_down(struct adapter *adapt) ++{ ++ /* 2010/-8/09 MH For power down module, we need to enable register block contrl reg at 0x1c. */ ++ /* Then enable power down control bit of register 0x04 BIT(4) and BIT(15) as 1. */ ++ ++ /* Enable register area 0x0-0xc. */ ++ rtw_write8(adapt, REG_RSV_CTRL, 0x0); ++ rtw_write16(adapt, REG_APS_FSMCO, 0x8812); ++} ++ ++static u32 rtl8188eu_hal_deinit(struct adapter *Adapter) ++{ ++ ++ DBG_88E("==> %s\n", __func__); ++ ++ rtw_write32(Adapter, REG_HIMR_88E, IMR_DISABLED_88E); ++ rtw_write32(Adapter, REG_HIMRE_88E, IMR_DISABLED_88E); ++ ++ DBG_88E("bkeepfwalive(%x)\n", Adapter->pwrctrlpriv.bkeepfwalive); ++ if (Adapter->pwrctrlpriv.bkeepfwalive) { ++ _ps_close_RF(Adapter); ++ if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown)) ++ rtl8192cu_hw_power_down(Adapter); ++ } else { ++ if (Adapter->hw_init_completed) { ++ CardDisableRTL8188EU(Adapter); ++ ++ if ((Adapter->pwrctrlpriv.bHWPwrPindetect) && (Adapter->pwrctrlpriv.bHWPowerdown)) ++ rtl8192cu_hw_power_down(Adapter); ++ } ++ } ++ return _SUCCESS; ++ } ++ ++static unsigned int rtl8188eu_inirp_init(struct adapter *Adapter) ++{ ++ u8 i; ++ struct recv_buf *precvbuf; ++ uint status; ++ struct intf_hdl *pintfhdl = &Adapter->iopriv.intf; ++ struct recv_priv *precvpriv = &Adapter->recvpriv; ++ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); ++ ++ _read_port = pintfhdl->io_ops._read_port; ++ ++ status = _SUCCESS; ++ ++ precvpriv->ff_hwaddr = RECV_BULK_IN_ADDR; ++ ++ /* issue Rx irp to receive data */ ++ precvbuf = (struct recv_buf *)precvpriv->precv_buf; ++ for (i = 0; i < NR_RECVBUFF; i++) { ++ if (!_read_port(pintfhdl, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf)) { ++ status = _FAIL; ++ goto exit; ++ } ++ ++ precvbuf++; ++ precvpriv->free_recv_buf_queue_cnt--; ++ } ++ ++exit: ++ return status; ++} ++ ++static unsigned int rtl8188eu_inirp_deinit(struct adapter *Adapter) ++{ ++ rtw_read_port_cancel(Adapter); ++ ++ return _SUCCESS; ++} ++ ++/* */ ++/* */ ++/* EEPROM/EFUSE Content Parsing */ ++/* */ ++/* */ ++static void _ReadLEDSetting(struct adapter *Adapter, u8 *PROMContent, bool AutoloadFail) ++{ ++ struct led_priv *pledpriv = &Adapter->ledpriv; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ pledpriv->bRegUseLed = true; ++ pledpriv->LedStrategy = SW_LED_MODE1; ++ haldata->bLedOpenDrain = true;/* Support Open-drain arrangement for controlling the LED. */ ++} ++ ++static void Hal_EfuseParsePIDVID_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ ++ if (!AutoLoadFail) { ++ /* VID, PID */ ++ haldata->EEPROMVID = EF2BYTE(*(__le16 *)&hwinfo[EEPROM_VID_88EU]); ++ haldata->EEPROMPID = EF2BYTE(*(__le16 *)&hwinfo[EEPROM_PID_88EU]); ++ ++ /* Customer ID, 0x00 and 0xff are reserved for Realtek. */ ++ haldata->EEPROMCustomerID = *(u8 *)&hwinfo[EEPROM_CUSTOMERID_88E]; ++ haldata->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID; ++ } else { ++ haldata->EEPROMVID = EEPROM_Default_VID; ++ haldata->EEPROMPID = EEPROM_Default_PID; ++ ++ /* Customer ID, 0x00 and 0xff are reserved for Realtek. */ ++ haldata->EEPROMCustomerID = EEPROM_Default_CustomerID; ++ haldata->EEPROMSubCustomerID = EEPROM_Default_SubCustomerID; ++ } ++ ++ DBG_88E("VID = 0x%04X, PID = 0x%04X\n", haldata->EEPROMVID, haldata->EEPROMPID); ++ DBG_88E("Customer ID: 0x%02X, SubCustomer ID: 0x%02X\n", haldata->EEPROMCustomerID, haldata->EEPROMSubCustomerID); ++} ++ ++static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail) ++{ ++ u16 i; ++ u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x88, 0x02}; ++ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt); ++ ++ if (AutoLoadFail) { ++ for (i = 0; i < 6; i++) ++ eeprom->mac_addr[i] = sMacAddr[i]; ++ } else { ++ /* Read Permanent MAC address */ ++ memcpy(eeprom->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88EU], ETH_ALEN); ++ } ++} ++ ++static void Hal_CustomizeByCustomerID_8188EU(struct adapter *adapt) ++{ ++} ++ ++static void ++readAdapterInfo_8188EU( ++ struct adapter *adapt ++ ) ++{ ++ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(adapt); ++ ++ /* parse the eeprom/efuse content */ ++ Hal_EfuseParseIDCode88E(adapt, eeprom->efuse_eeprom_data); ++ Hal_EfuseParsePIDVID_8188EU(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ Hal_EfuseParseMACAddr_8188EU(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ ++ Hal_ReadPowerSavingMode88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ Hal_ReadTxPowerInfo88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ Hal_EfuseParseEEPROMVer88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ rtl8188e_EfuseParseChnlPlan(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ Hal_EfuseParseXtal_8188E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ Hal_EfuseParseCustomerID88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ Hal_ReadAntennaDiversity88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ Hal_EfuseParseBoardType88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ Hal_ReadThermalMeter_88E(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++ ++ /* */ ++ /* The following part initialize some vars by PG info. */ ++ /* */ ++ Hal_InitChannelPlan(adapt); ++ Hal_CustomizeByCustomerID_8188EU(adapt); ++ ++ _ReadLEDSetting(adapt, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); ++} ++ ++static void _ReadPROMContent( ++ struct adapter *Adapter ++ ) ++{ ++ struct eeprom_priv *eeprom = GET_EEPROM_EFUSE_PRIV(Adapter); ++ u8 eeValue; ++ ++ /* check system boot selection */ ++ eeValue = rtw_read8(Adapter, REG_9346CR); ++ eeprom->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? true : false; ++ eeprom->bautoload_fail_flag = (eeValue & EEPROM_EN) ? false : true; ++ ++ DBG_88E("Boot from %s, Autoload %s !\n", (eeprom->EepromOrEfuse ? "EEPROM" : "EFUSE"), ++ (eeprom->bautoload_fail_flag ? "Fail" : "OK")); ++ ++ Hal_InitPGData88E(Adapter); ++ readAdapterInfo_8188EU(Adapter); ++} ++ ++static void _ReadRFType(struct adapter *Adapter) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ ++ haldata->rf_chip = RF_6052; ++} ++ ++static int _ReadAdapterInfo8188EU(struct adapter *Adapter) ++{ ++ u32 start = jiffies; ++ ++ MSG_88E("====> %s\n", __func__); ++ ++ _ReadRFType(Adapter);/* rf_chip -> _InitRFType() */ ++ _ReadPROMContent(Adapter); ++ ++ MSG_88E("<==== %s in %d ms\n", __func__, rtw_get_passing_time_ms(start)); ++ ++ return _SUCCESS; ++} ++ ++static void ReadAdapterInfo8188EU(struct adapter *Adapter) ++{ ++ /* Read EEPROM size before call any EEPROM function */ ++ Adapter->EepromAddressSize = GetEEPROMSize8188E(Adapter); ++ ++ _ReadAdapterInfo8188EU(Adapter); ++} ++ ++#define GPIO_DEBUG_PORT_NUM 0 ++static void rtl8192cu_trigger_gpio_0(struct adapter *adapt) ++{ ++} ++ ++static void ResumeTxBeacon(struct adapter *adapt) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ ++ /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ ++ /* which should be read from register to a global variable. */ ++ ++ rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl) | BIT(6)); ++ haldata->RegFwHwTxQCtrl |= BIT(6); ++ rtw_write8(adapt, REG_TBTT_PROHIBIT + 1, 0xff); ++ haldata->RegReg542 |= BIT(0); ++ rtw_write8(adapt, REG_TBTT_PROHIBIT + 2, haldata->RegReg542); ++} ++ ++static void StopTxBeacon(struct adapter *adapt) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ ++ /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ ++ /* which should be read from register to a global variable. */ ++ ++ rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl) & (~BIT(6))); ++ haldata->RegFwHwTxQCtrl &= (~BIT(6)); ++ rtw_write8(adapt, REG_TBTT_PROHIBIT + 1, 0x64); ++ haldata->RegReg542 &= ~(BIT(0)); ++ rtw_write8(adapt, REG_TBTT_PROHIBIT + 2, haldata->RegReg542); ++ ++ /* todo: CheckFwRsvdPageContent(Adapter); 2010.06.23. Added by tynli. */ ++} ++ ++static void hw_var_set_opmode(struct adapter *Adapter, u8 variable, u8 *val) ++{ ++ u8 val8; ++ u8 mode = *((u8 *)val); ++ ++ /* disable Port0 TSF update */ ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | BIT(4)); ++ ++ /* set net_type */ ++ val8 = rtw_read8(Adapter, MSR) & 0x0c; ++ val8 |= mode; ++ rtw_write8(Adapter, MSR, val8); ++ ++ DBG_88E("%s()-%d mode = %d\n", __func__, __LINE__, mode); ++ ++ if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { ++ StopTxBeacon(Adapter); ++ ++ rtw_write8(Adapter, REG_BCN_CTRL, 0x19);/* disable atim wnd */ ++ } else if (mode == _HW_STATE_ADHOC_) { ++ ResumeTxBeacon(Adapter); ++ rtw_write8(Adapter, REG_BCN_CTRL, 0x1a); ++ } else if (mode == _HW_STATE_AP_) { ++ ResumeTxBeacon(Adapter); ++ ++ rtw_write8(Adapter, REG_BCN_CTRL, 0x12); ++ ++ /* Set RCR */ ++ rtw_write32(Adapter, REG_RCR, 0x7000208e);/* CBSSID_DATA must set to 0,reject ICV_ERR packet */ ++ /* enable to rx data frame */ ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); ++ /* enable to rx ps-poll */ ++ rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400); ++ ++ /* Beacon Control related register for first time */ ++ rtw_write8(Adapter, REG_BCNDMATIM, 0x02); /* 2ms */ ++ ++ rtw_write8(Adapter, REG_ATIMWND, 0x0a); /* 10ms */ ++ rtw_write16(Adapter, REG_BCNTCFG, 0x00); ++ rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04); ++ rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/* +32767 (~32ms) */ ++ ++ /* reset TSF */ ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); ++ ++ /* BIT(3) - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 */ ++ rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM) | BIT(3) | BIT(4)); ++ ++ /* enable BCN0 Function for if1 */ ++ /* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */ ++ rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP | EN_BCN_FUNCTION | BIT(1))); ++ ++ /* dis BCN1 ATIM WND if if2 is station */ ++ rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1) | BIT(0)); ++ } ++} ++ ++static void hw_var_set_macaddr(struct adapter *Adapter, u8 variable, u8 *val) ++{ ++ u8 idx = 0; ++ u32 reg_macid; ++ ++ reg_macid = REG_MACID; ++ ++ for (idx = 0; idx < 6; idx++) ++ rtw_write8(Adapter, (reg_macid + idx), val[idx]); ++} ++ ++static void hw_var_set_bssid(struct adapter *Adapter, u8 variable, u8 *val) ++{ ++ u8 idx = 0; ++ u32 reg_bssid; ++ ++ reg_bssid = REG_BSSID; ++ ++ for (idx = 0; idx < 6; idx++) ++ rtw_write8(Adapter, (reg_bssid + idx), val[idx]); ++} ++ ++static void hw_var_set_bcn_func(struct adapter *Adapter, u8 variable, u8 *val) ++{ ++ u32 bcn_ctrl_reg; ++ ++ bcn_ctrl_reg = REG_BCN_CTRL; ++ ++ if (*((u8 *)val)) ++ rtw_write8(Adapter, bcn_ctrl_reg, (EN_BCN_FUNCTION | EN_TXBCN_RPT)); ++ else ++ rtw_write8(Adapter, bcn_ctrl_reg, rtw_read8(Adapter, bcn_ctrl_reg) & (~(EN_BCN_FUNCTION | EN_TXBCN_RPT))); ++} ++ ++static void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ struct dm_priv *pdmpriv = &haldata->dmpriv; ++ struct odm_dm_struct *podmpriv = &haldata->odmpriv; ++ ++ switch (variable) { ++ case HW_VAR_MEDIA_STATUS: ++ { ++ u8 val8; ++ ++ val8 = rtw_read8(Adapter, MSR) & 0x0c; ++ val8 |= *((u8 *)val); ++ rtw_write8(Adapter, MSR, val8); ++ } ++ break; ++ case HW_VAR_MEDIA_STATUS1: ++ { ++ u8 val8; ++ ++ val8 = rtw_read8(Adapter, MSR) & 0x03; ++ val8 |= *((u8 *)val) << 2; ++ rtw_write8(Adapter, MSR, val8); ++ } ++ break; ++ case HW_VAR_SET_OPMODE: ++ hw_var_set_opmode(Adapter, variable, val); ++ break; ++ case HW_VAR_MAC_ADDR: ++ hw_var_set_macaddr(Adapter, variable, val); ++ break; ++ case HW_VAR_BSSID: ++ hw_var_set_bssid(Adapter, variable, val); ++ break; ++ case HW_VAR_BASIC_RATE: ++ { ++ u16 BrateCfg = 0; ++ u8 RateIndex = 0; ++ ++ /* 2007.01.16, by Emily */ ++ /* Select RRSR (in Legacy-OFDM and CCK) */ ++ /* For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. */ ++ /* We do not use other rates. */ ++ HalSetBrateCfg(Adapter, val, &BrateCfg); ++ DBG_88E("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", BrateCfg); ++ ++ /* 2011.03.30 add by Luke Lee */ ++ /* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */ ++ /* because CCK 2M has poor TXEVM */ ++ /* CCK 5.5M & 11M ACK should be enabled for better performance */ ++ ++ BrateCfg = (BrateCfg | 0xd) & 0x15d; ++ haldata->BasicRateSet = BrateCfg; ++ ++ BrateCfg |= 0x01; /* default enable 1M ACK rate */ ++ /* Set RRSR rate table. */ ++ rtw_write8(Adapter, REG_RRSR, BrateCfg & 0xff); ++ rtw_write8(Adapter, REG_RRSR + 1, (BrateCfg >> 8) & 0xff); ++ rtw_write8(Adapter, REG_RRSR + 2, rtw_read8(Adapter, REG_RRSR + 2) & 0xf0); ++ ++ /* Set RTS initial rate */ ++ while (BrateCfg > 0x1) { ++ BrateCfg = (BrateCfg >> 1); ++ RateIndex++; ++ } ++ /* Ziv - Check */ ++ rtw_write8(Adapter, REG_INIRTS_RATE_SEL, RateIndex); ++ } ++ break; ++ case HW_VAR_TXPAUSE: ++ rtw_write8(Adapter, REG_TXPAUSE, *((u8 *)val)); ++ break; ++ case HW_VAR_BCN_FUNC: ++ hw_var_set_bcn_func(Adapter, variable, val); ++ break; ++ case HW_VAR_CORRECT_TSF: ++ { ++ u64 tsf; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ tsf = pmlmeext->TSFValue - do_div(pmlmeext->TSFValue, ++ pmlmeinfo->bcn_interval * 1024) - 1024; /* us */ ++ ++ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) ++ StopTxBeacon(Adapter); ++ ++ /* disable related TSF function */ ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) & (~BIT(3))); ++ ++ rtw_write32(Adapter, REG_TSFTR, tsf); ++ rtw_write32(Adapter, REG_TSFTR + 4, tsf >> 32); ++ ++ /* enable related TSF function */ ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | BIT(3)); ++ ++ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) ++ ResumeTxBeacon(Adapter); ++ } ++ break; ++ case HW_VAR_CHECK_BSSID: ++ if (*((u8 *)val)) { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR) | RCR_CBSSID_DATA | RCR_CBSSID_BCN); ++ } else { ++ u32 val32; ++ ++ val32 = rtw_read32(Adapter, REG_RCR); ++ ++ val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); ++ ++ rtw_write32(Adapter, REG_RCR, val32); ++ } ++ break; ++ case HW_VAR_MLME_DISCONNECT: ++ /* Set RCR to not to receive data frame when NO LINK state */ ++ /* reject all data frames */ ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); ++ ++ /* reset TSF */ ++ rtw_write8(Adapter, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); ++ ++ /* disable update TSF */ ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | BIT(4)); ++ break; ++ case HW_VAR_MLME_SITESURVEY: ++ if (*((u8 *)val)) { /* under sitesurvey */ ++ /* config RCR to receive different BSSID & not to receive data frame */ ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_BCN); ++ rtw_write32(Adapter, REG_RCR, v); ++ /* reject all data frame */ ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); ++ ++ /* disable update TSF */ ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | BIT(4)); ++ } else { /* sitesurvey done */ ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ if ((is_client_associated_to_ap(Adapter)) || ++ ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) { ++ /* enable to rx data frame */ ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); ++ ++ /* enable update TSF */ ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) & (~BIT(4))); ++ } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); ++ /* enable update TSF */ ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) & (~BIT(4))); ++ } ++ if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR) | RCR_CBSSID_BCN); ++ } else { ++ if (Adapter->in_cta_test) { ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */ ++ rtw_write32(Adapter, REG_RCR, v); ++ } else { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR) | RCR_CBSSID_BCN); ++ } ++ } ++ } ++ break; ++ case HW_VAR_MLME_JOIN: ++ { ++ u8 RetryLimit = 0x30; ++ u8 type = *((u8 *)val); ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ ++ if (type == 0) { /* prepare to join */ ++ /* enable to rx data frame.Accept all data frame */ ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); ++ ++ if (Adapter->in_cta_test) { ++ u32 v = rtw_read32(Adapter, REG_RCR); ++ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */ ++ rtw_write32(Adapter, REG_RCR, v); ++ } else { ++ rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR) | RCR_CBSSID_DATA | RCR_CBSSID_BCN); ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ RetryLimit = (haldata->CustomerID == RT_CID_CCX) ? 7 : 48; ++ else /* Ad-hoc Mode */ ++ RetryLimit = 0x7; ++ } else if (type == 1) { ++ /* joinbss_event call back when join res < 0 */ ++ rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); ++ } else if (type == 2) { ++ /* sta add event call back */ ++ /* enable update TSF */ ++ rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) & (~BIT(4))); ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) ++ RetryLimit = 0x7; ++ } ++ rtw_write16(Adapter, REG_RL, RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit << RETRY_LIMIT_LONG_SHIFT); ++ } ++ break; ++ case HW_VAR_BEACON_INTERVAL: ++ rtw_write16(Adapter, REG_BCN_INTERVAL, *((u16 *)val)); ++ break; ++ case HW_VAR_SLOT_TIME: ++ { ++ u8 u1bAIFS, aSifsTime; ++ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ ++ rtw_write8(Adapter, REG_SLOT, val[0]); ++ ++ if (pmlmeinfo->WMM_enable == 0) { ++ if (pmlmeext->cur_wireless_mode == WIRELESS_11B) ++ aSifsTime = 10; ++ else ++ aSifsTime = 16; ++ ++ u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime); ++ ++ /* Temporary removed, 2008.06.20. */ ++ rtw_write8(Adapter, REG_EDCA_VO_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_VI_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_BE_PARAM, u1bAIFS); ++ rtw_write8(Adapter, REG_EDCA_BK_PARAM, u1bAIFS); ++ } ++ } ++ break; ++ case HW_VAR_RESP_SIFS: ++ /* RESP_SIFS for CCK */ ++ rtw_write8(Adapter, REG_R2T_SIFS, val[0]); /* SIFS_T2T_CCK (0x08) */ ++ rtw_write8(Adapter, REG_R2T_SIFS + 1, val[1]); /* SIFS_R2T_CCK(0x08) */ ++ /* RESP_SIFS for OFDM */ ++ rtw_write8(Adapter, REG_T2T_SIFS, val[2]); /* SIFS_T2T_OFDM (0x0a) */ ++ rtw_write8(Adapter, REG_T2T_SIFS + 1, val[3]); /* SIFS_R2T_OFDM(0x0a) */ ++ break; ++ case HW_VAR_ACK_PREAMBLE: ++ { ++ u8 regTmp; ++ u8 bShortPreamble = *((bool *)val); ++ /* Joseph marked out for Netgear 3500 TKIP channel 7 issue.(Temporarily) */ ++ regTmp = (haldata->nCur40MhzPrimeSC) << 5; ++ if (bShortPreamble) ++ regTmp |= 0x80; ++ ++ rtw_write8(Adapter, REG_RRSR + 2, regTmp); ++ } ++ break; ++ case HW_VAR_SEC_CFG: ++ rtw_write8(Adapter, REG_SECCFG, *((u8 *)val)); ++ break; ++ case HW_VAR_DM_FLAG: ++ podmpriv->SupportAbility = *((u8 *)val); ++ break; ++ case HW_VAR_DM_FUNC_OP: ++ if (val[0]) ++ podmpriv->BK_SupportAbility = podmpriv->SupportAbility; ++ else ++ podmpriv->SupportAbility = podmpriv->BK_SupportAbility; ++ break; ++ case HW_VAR_DM_FUNC_SET: ++ if (*((u32 *)val) == DYNAMIC_ALL_FUNC_ENABLE) { ++ pdmpriv->DMFlag = pdmpriv->InitDMFlag; ++ podmpriv->SupportAbility = pdmpriv->InitODMFlag; ++ } else { ++ podmpriv->SupportAbility |= *((u32 *)val); ++ } ++ break; ++ case HW_VAR_DM_FUNC_CLR: ++ podmpriv->SupportAbility &= *((u32 *)val); ++ break; ++ case HW_VAR_CAM_EMPTY_ENTRY: ++ { ++ u8 ucIndex = *((u8 *)val); ++ u8 i; ++ u32 ulCommand = 0; ++ u32 ulContent = 0; ++ u32 ulEncAlgo = CAM_AES; ++ ++ for (i = 0; i < CAM_CONTENT_COUNT; i++) { ++ /* filled id in CAM config 2 byte */ ++ if (i == 0) ++ ulContent |= (ucIndex & 0x03) | ((u16)(ulEncAlgo) << 2); ++ else ++ ulContent = 0; ++ /* polling bit, and No Write enable, and address */ ++ ulCommand = CAM_CONTENT_COUNT * ucIndex + i; ++ ulCommand = ulCommand | CAM_POLLINIG | CAM_WRITE; ++ /* write content 0 is equall to mark invalid */ ++ rtw_write32(Adapter, WCAMI, ulContent); /* delay_ms(40); */ ++ rtw_write32(Adapter, RWCAM, ulCommand); /* delay_ms(40); */ ++ } ++ } ++ break; ++ case HW_VAR_CAM_INVALID_ALL: ++ rtw_write32(Adapter, RWCAM, BIT(31) | BIT(30)); ++ break; ++ case HW_VAR_CAM_WRITE: ++ { ++ u32 cmd; ++ u32 *cam_val = (u32 *)val; ++ rtw_write32(Adapter, WCAMI, cam_val[0]); ++ ++ cmd = CAM_POLLINIG | CAM_WRITE | cam_val[1]; ++ rtw_write32(Adapter, RWCAM, cmd); ++ } ++ break; ++ case HW_VAR_AC_PARAM_VO: ++ rtw_write32(Adapter, REG_EDCA_VO_PARAM, ((u32 *)(val))[0]); ++ break; ++ case HW_VAR_AC_PARAM_VI: ++ rtw_write32(Adapter, REG_EDCA_VI_PARAM, ((u32 *)(val))[0]); ++ break; ++ case HW_VAR_AC_PARAM_BE: ++ haldata->AcParam_BE = ((u32 *)(val))[0]; ++ rtw_write32(Adapter, REG_EDCA_BE_PARAM, ((u32 *)(val))[0]); ++ break; ++ case HW_VAR_AC_PARAM_BK: ++ rtw_write32(Adapter, REG_EDCA_BK_PARAM, ((u32 *)(val))[0]); ++ break; ++ case HW_VAR_ACM_CTRL: ++ { ++ u8 acm_ctrl = *((u8 *)val); ++ u8 AcmCtrl = rtw_read8(Adapter, REG_ACMHWCTRL); ++ ++ if (acm_ctrl > 1) ++ AcmCtrl = AcmCtrl | 0x1; ++ ++ if (acm_ctrl & BIT(3)) ++ AcmCtrl |= AcmHw_VoqEn; ++ else ++ AcmCtrl &= (~AcmHw_VoqEn); ++ ++ if (acm_ctrl & BIT(2)) ++ AcmCtrl |= AcmHw_ViqEn; ++ else ++ AcmCtrl &= (~AcmHw_ViqEn); ++ ++ if (acm_ctrl & BIT(1)) ++ AcmCtrl |= AcmHw_BeqEn; ++ else ++ AcmCtrl &= (~AcmHw_BeqEn); ++ ++ DBG_88E("[HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl); ++ rtw_write8(Adapter, REG_ACMHWCTRL, AcmCtrl); ++ } ++ break; ++ case HW_VAR_AMPDU_MIN_SPACE: ++ { ++ u8 MinSpacingToSet; ++ u8 SecMinSpace; ++ ++ MinSpacingToSet = *((u8 *)val); ++ if (MinSpacingToSet <= 7) { ++ switch (Adapter->securitypriv.dot11PrivacyAlgrthm) { ++ case _NO_PRIVACY_: ++ case _AES_: ++ SecMinSpace = 0; ++ break; ++ case _WEP40_: ++ case _WEP104_: ++ case _TKIP_: ++ case _TKIP_WTMIC_: ++ SecMinSpace = 6; ++ break; ++ default: ++ SecMinSpace = 7; ++ break; ++ } ++ if (MinSpacingToSet < SecMinSpace) ++ MinSpacingToSet = SecMinSpace; ++ rtw_write8(Adapter, REG_AMPDU_MIN_SPACE, (rtw_read8(Adapter, REG_AMPDU_MIN_SPACE) & 0xf8) | MinSpacingToSet); ++ } ++ } ++ break; ++ case HW_VAR_AMPDU_FACTOR: ++ { ++ u8 RegToSet_Normal[4] = {0x41, 0xa8, 0x72, 0xb9}; ++ u8 FactorToSet; ++ u8 *pRegToSet; ++ u8 index = 0; ++ ++ pRegToSet = RegToSet_Normal; /* 0xb972a841; */ ++ FactorToSet = *((u8 *)val); ++ if (FactorToSet <= 3) { ++ FactorToSet = (1 << (FactorToSet + 2)); ++ if (FactorToSet > 0xf) ++ FactorToSet = 0xf; ++ ++ for (index = 0; index < 4; index++) { ++ if ((pRegToSet[index] & 0xf0) > (FactorToSet << 4)) ++ pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet << 4); ++ ++ if ((pRegToSet[index] & 0x0f) > FactorToSet) ++ pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet); ++ ++ rtw_write8(Adapter, (REG_AGGLEN_LMT + index), pRegToSet[index]); ++ } ++ } ++ } ++ break; ++ case HW_VAR_RXDMA_AGG_PG_TH: ++ { ++ u8 threshold = *((u8 *)val); ++ if (threshold == 0) ++ threshold = haldata->UsbRxAggPageCount; ++ rtw_write8(Adapter, REG_RXDMA_AGG_PG_TH, threshold); ++ } ++ break; ++ case HW_VAR_SET_RPWM: ++ break; ++ case HW_VAR_H2C_FW_PWRMODE: ++ { ++ u8 psmode = (*(u8 *)val); ++ ++ /* Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power */ ++ /* saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. */ ++ if ((psmode != PS_MODE_ACTIVE) && (!IS_92C_SERIAL(haldata->VersionID))) ++ ODM_RF_Saving(podmpriv, true); ++ rtl8188e_set_FwPwrMode_cmd(Adapter, psmode); ++ } ++ break; ++ case HW_VAR_H2C_FW_JOINBSSRPT: ++ { ++ u8 mstatus = (*(u8 *)val); ++ rtl8188e_set_FwJoinBssReport_cmd(Adapter, mstatus); ++ } ++ break; ++#ifdef CONFIG_88EU_P2P ++ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD: ++ { ++ u8 p2p_ps_state = (*(u8 *)val); ++ rtl8188e_set_p2p_ps_offload_cmd(Adapter, p2p_ps_state); ++ } ++ break; ++#endif ++ case HW_VAR_INITIAL_GAIN: ++ { ++ struct rtw_dig *pDigTable = &podmpriv->DM_DigTable; ++ u32 rx_gain = ((u32 *)(val))[0]; ++ ++ if (rx_gain == 0xff) {/* restore rx gain */ ++ ODM_Write_DIG(podmpriv, pDigTable->BackupIGValue); ++ } else { ++ pDigTable->BackupIGValue = pDigTable->CurIGValue; ++ ODM_Write_DIG(podmpriv, rx_gain); ++ } ++ } ++ break; ++ case HW_VAR_TRIGGER_GPIO_0: ++ rtl8192cu_trigger_gpio_0(Adapter); ++ break; ++ case HW_VAR_RPT_TIMER_SETTING: ++ { ++ u16 min_rpt_time = (*(u16 *)val); ++ ODM_RA_Set_TxRPT_Time(podmpriv, min_rpt_time); ++ } ++ break; ++ case HW_VAR_ANTENNA_DIVERSITY_SELECT: ++ { ++ u8 Optimum_antenna = (*(u8 *)val); ++ u8 Ant; ++ /* switch antenna to Optimum_antenna */ ++ if (haldata->CurAntenna != Optimum_antenna) { ++ Ant = (Optimum_antenna == 2) ? MAIN_ANT : AUX_ANT; ++ ODM_UpdateRxIdleAnt_88E(&haldata->odmpriv, Ant); ++ ++ haldata->CurAntenna = Optimum_antenna; ++ } ++ } ++ break; ++ case HW_VAR_EFUSE_BYTES: /* To set EFUE total used bytes, added by Roger, 2008.12.22. */ ++ haldata->EfuseUsedBytes = *((u16 *)val); ++ break; ++ case HW_VAR_FIFO_CLEARN_UP: ++ { ++ struct pwrctrl_priv *pwrpriv = &Adapter->pwrctrlpriv; ++ u8 trycnt = 100; ++ ++ /* pause tx */ ++ rtw_write8(Adapter, REG_TXPAUSE, 0xff); ++ ++ /* keep sn */ ++ Adapter->xmitpriv.nqos_ssn = rtw_read16(Adapter, REG_NQOS_SEQ); ++ ++ if (!pwrpriv->bkeepfwalive) { ++ /* RX DMA stop */ ++ rtw_write32(Adapter, REG_RXPKT_NUM, (rtw_read32(Adapter, REG_RXPKT_NUM) | RW_RELEASE_EN)); ++ do { ++ if (!(rtw_read32(Adapter, REG_RXPKT_NUM) & RXDMA_IDLE)) ++ break; ++ } while (trycnt--); ++ if (trycnt == 0) ++ DBG_88E("Stop RX DMA failed......\n"); ++ ++ /* RQPN Load 0 */ ++ rtw_write16(Adapter, REG_RQPN_NPQ, 0x0); ++ rtw_write32(Adapter, REG_RQPN, 0x80000000); ++ mdelay(10); ++ } ++ } ++ break; ++ case HW_VAR_CHECK_TXBUF: ++ break; ++ case HW_VAR_APFM_ON_MAC: ++ haldata->bMacPwrCtrlOn = *val; ++ DBG_88E("%s: bMacPwrCtrlOn=%d\n", __func__, haldata->bMacPwrCtrlOn); ++ break; ++ case HW_VAR_TX_RPT_MAX_MACID: ++ { ++ u8 maxMacid = *val; ++ DBG_88E("### MacID(%d),Set Max Tx RPT MID(%d)\n", maxMacid, maxMacid + 1); ++ rtw_write8(Adapter, REG_TX_RPT_CTRL + 1, maxMacid + 1); ++ } ++ break; ++ case HW_VAR_H2C_MEDIA_STATUS_RPT: ++ rtl8188e_set_FwMediaStatus_cmd(Adapter, (*(__le16 *)val)); ++ break; ++ case HW_VAR_BCN_VALID: ++ /* BCN_VALID, BIT(16) of REG_TDECTRL = BIT(0) of REG_TDECTRL+2, write 1 to clear, Clear by sw */ ++ rtw_write8(Adapter, REG_TDECTRL + 2, rtw_read8(Adapter, REG_TDECTRL + 2) | BIT(0)); ++ break; ++ default: ++ break; ++ } ++ ++} ++ ++static void GetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ struct odm_dm_struct *podmpriv = &haldata->odmpriv; ++ ++ switch (variable) { ++ case HW_VAR_BASIC_RATE: ++ *((u16 *)(val)) = haldata->BasicRateSet; ++ fallthrough; ++ case HW_VAR_TXPAUSE: ++ val[0] = rtw_read8(Adapter, REG_TXPAUSE); ++ break; ++ case HW_VAR_BCN_VALID: ++ /* BCN_VALID, BIT(16) of REG_TDECTRL = BIT(0) of REG_TDECTRL+2 */ ++ val[0] = (BIT(0) & rtw_read8(Adapter, REG_TDECTRL + 2)) ? true : false; ++ break; ++ case HW_VAR_DM_FLAG: ++ val[0] = podmpriv->SupportAbility; ++ break; ++ case HW_VAR_RF_TYPE: ++ val[0] = haldata->rf_type; ++ break; ++ case HW_VAR_FWLPS_RF_ON: ++ { ++ /* When we halt NIC, we should check if FW LPS is leave. */ ++ if (Adapter->pwrctrlpriv.rf_pwrstate == rf_off) { ++ /* If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */ ++ /* because Fw is unload. */ ++ val[0] = true; ++ } else { ++ u32 valRCR; ++ valRCR = rtw_read32(Adapter, REG_RCR); ++ valRCR &= 0x00070000; ++ if (valRCR) ++ val[0] = false; ++ else ++ val[0] = true; ++ } ++ } ++ break; ++ case HW_VAR_CURRENT_ANTENNA: ++ val[0] = haldata->CurAntenna; ++ break; ++ case HW_VAR_EFUSE_BYTES: /* To get EFUE total used bytes, added by Roger, 2008.12.22. */ ++ *((u16 *)(val)) = haldata->EfuseUsedBytes; ++ break; ++ case HW_VAR_APFM_ON_MAC: ++ *val = haldata->bMacPwrCtrlOn; ++ break; ++ case HW_VAR_CHK_HI_QUEUE_EMPTY: ++ *val = ((rtw_read32(Adapter, REG_HGQ_INFORMATION) & 0x0000ff00) == 0) ? true : false; ++ break; ++ default: ++ break; ++ } ++ ++} ++ ++/* */ ++/* Description: */ ++/* Query setting of specified variable. */ ++/* */ ++static u8 ++GetHalDefVar8188EUsb( ++ struct adapter *Adapter, ++ enum hal_def_variable eVariable, ++ void *pValue ++ ) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ u8 bResult = _SUCCESS; ++ ++ switch (eVariable) { ++ case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB: ++ { ++ struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; ++ struct sta_priv *pstapriv = &Adapter->stapriv; ++ struct sta_info *psta; ++ psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress); ++ if (psta) ++ *((int *)pValue) = psta->rssi_stat.UndecoratedSmoothedPWDB; ++ } ++ break; ++ case HAL_DEF_IS_SUPPORT_ANT_DIV: ++ *((u8 *)pValue) = (haldata->AntDivCfg == 0) ? false : true; ++ break; ++ case HAL_DEF_CURRENT_ANTENNA: ++ *((u8 *)pValue) = haldata->CurAntenna; ++ break; ++ case HAL_DEF_DRVINFO_SZ: ++ *((u32 *)pValue) = DRVINFO_SZ; ++ break; ++ case HAL_DEF_MAX_RECVBUF_SZ: ++ *((u32 *)pValue) = MAX_RECVBUF_SZ; ++ break; ++ case HAL_DEF_RX_PACKET_OFFSET: ++ *((u32 *)pValue) = RXDESC_SIZE + DRVINFO_SZ; ++ break; ++ case HAL_DEF_DBG_DM_FUNC: ++ *((u32 *)pValue) = haldata->odmpriv.SupportAbility; ++ break; ++ case HAL_DEF_RA_DECISION_RATE: ++ { ++ u8 MacID = *((u8 *)pValue); ++ *((u8 *)pValue) = ODM_RA_GetDecisionRate_8188E(&haldata->odmpriv, MacID); ++ } ++ break; ++ case HAL_DEF_RA_SGI: ++ { ++ u8 MacID = *((u8 *)pValue); ++ *((u8 *)pValue) = ODM_RA_GetShortGI_8188E(&haldata->odmpriv, MacID); ++ } ++ break; ++ case HAL_DEF_PT_PWR_STATUS: ++ { ++ u8 MacID = *((u8 *)pValue); ++ *((u8 *)pValue) = ODM_RA_GetHwPwrStatus_8188E(&haldata->odmpriv, MacID); ++ } ++ break; ++ case HW_VAR_MAX_RX_AMPDU_FACTOR: ++ *((u32 *)pValue) = MAX_AMPDU_FACTOR_64K; ++ break; ++ case HW_DEF_RA_INFO_DUMP: ++ { ++ u8 entry_id = *((u8 *)pValue); ++ if (check_fwstate(&Adapter->mlmepriv, _FW_LINKED)) { ++ DBG_88E("============ RA status check ===================\n"); ++ DBG_88E("Mac_id:%d , RateID = %d, RAUseRate = 0x%08x, RateSGI = %d, DecisionRate = 0x%02x ,PTStage = %d\n", ++ entry_id, ++ haldata->odmpriv.RAInfo[entry_id].RateID, ++ haldata->odmpriv.RAInfo[entry_id].RAUseRate, ++ haldata->odmpriv.RAInfo[entry_id].RateSGI, ++ haldata->odmpriv.RAInfo[entry_id].DecisionRate, ++ haldata->odmpriv.RAInfo[entry_id].PTStage); ++ } ++ } ++ break; ++ case HAL_DEF_DBG_DUMP_RXPKT: ++ *((u8 *)pValue) = haldata->bDumpRxPkt; ++ break; ++ case HAL_DEF_DBG_DUMP_TXPKT: ++ *((u8 *)pValue) = haldata->bDumpTxPkt; ++ break; ++ default: ++ bResult = _FAIL; ++ break; ++ } ++ ++ return bResult; ++} ++ ++/* */ ++/* Description: */ ++/* Change default setting of specified variable. */ ++/* */ ++static u8 SetHalDefVar8188EUsb(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); ++ u8 bResult = _SUCCESS; ++ ++ switch (eVariable) { ++ case HAL_DEF_DBG_DM_FUNC: ++ { ++ u8 dm_func = *((u8 *)pValue); ++ struct odm_dm_struct *podmpriv = &haldata->odmpriv; ++ ++ if (dm_func == 0) { /* disable all dynamic func */ ++ podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE; ++ DBG_88E("==> Disable all dynamic function...\n"); ++ } else if (dm_func == 1) {/* disable DIG */ ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_DIG); ++ DBG_88E("==> Disable DIG...\n"); ++ } else if (dm_func == 2) {/* disable High power */ ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR); ++ } else if (dm_func == 3) {/* disable tx power tracking */ ++ podmpriv->SupportAbility &= (~DYNAMIC_RF_CALIBRATION); ++ DBG_88E("==> Disable tx power tracking...\n"); ++ } else if (dm_func == 5) {/* disable antenna diversity */ ++ podmpriv->SupportAbility &= (~DYNAMIC_BB_ANT_DIV); ++ } else if (dm_func == 6) {/* turn on all dynamic func */ ++ if (!(podmpriv->SupportAbility & DYNAMIC_BB_DIG)) { ++ struct rtw_dig *pDigTable = &podmpriv->DM_DigTable; ++ pDigTable->CurIGValue = rtw_read8(Adapter, 0xc50); ++ } ++ podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; ++ DBG_88E("==> Turn on all dynamic function...\n"); ++ } ++ } ++ break; ++ case HAL_DEF_DBG_DUMP_RXPKT: ++ haldata->bDumpRxPkt = *((u8 *)pValue); ++ break; ++ case HAL_DEF_DBG_DUMP_TXPKT: ++ haldata->bDumpTxPkt = *((u8 *)pValue); ++ break; ++ default: ++ bResult = _FAIL; ++ break; ++ } ++ ++ return bResult; ++} ++ ++static void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level) ++{ ++ u8 init_rate = 0; ++ u8 networkType, raid; ++ u32 mask, rate_bitmap; ++ u8 shortGIrate = false; ++ int supportRateNum = 0; ++ struct sta_info *psta; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct wlan_bssid_ex *cur_network = &pmlmeinfo->network; ++ ++ if (mac_id >= NUM_STA) /* CAM_SIZE */ ++ return; ++ psta = pmlmeinfo->FW_sta_info[mac_id].psta; ++ if (!psta) ++ return; ++ switch (mac_id) { ++ case 0:/* for infra mode */ ++ supportRateNum = rtw_get_rateset_len(cur_network->SupportedRates); ++ networkType = judge_network_type(adapt, cur_network->SupportedRates, supportRateNum) & 0xf; ++ raid = networktype_to_raid(networkType); ++ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum); ++ mask |= (pmlmeinfo->HT_enable) ? update_MSC_rate(&pmlmeinfo->HT_caps) : 0; ++ if (support_short_GI(adapt, &pmlmeinfo->HT_caps)) ++ shortGIrate = true; ++ break; ++ case 1:/* for broadcast/multicast */ ++ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); ++ if (pmlmeext->cur_wireless_mode & WIRELESS_11B) ++ networkType = WIRELESS_11B; ++ else ++ networkType = WIRELESS_11G; ++ raid = networktype_to_raid(networkType); ++ mask = update_basic_rate(cur_network->SupportedRates, supportRateNum); ++ break; ++ default: /* for each sta in IBSS */ ++ supportRateNum = rtw_get_rateset_len(pmlmeinfo->FW_sta_info[mac_id].SupportedRates); ++ networkType = judge_network_type(adapt, pmlmeinfo->FW_sta_info[mac_id].SupportedRates, supportRateNum) & 0xf; ++ raid = networktype_to_raid(networkType); ++ mask = update_supported_rate(cur_network->SupportedRates, supportRateNum); ++ ++ /* todo: support HT in IBSS */ ++ break; ++ } ++ ++ rate_bitmap = 0x0fffffff; ++ rate_bitmap = ODM_Get_Rate_Bitmap(&haldata->odmpriv, mac_id, mask, rssi_level); ++ DBG_88E("%s => mac_id:%d, networkType:0x%02x, mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n", ++ __func__, mac_id, networkType, mask, rssi_level, rate_bitmap); ++ ++ mask &= rate_bitmap; ++ ++ init_rate = get_highest_rate_idx(mask) & 0x3f; ++ ++ if (haldata->fw_ractrl) { ++ u8 arg; ++ ++ arg = mac_id & 0x1f;/* MACID */ ++ arg |= BIT(7); ++ if (shortGIrate) ++ arg |= BIT(5); ++ mask |= ((raid << 28) & 0xf0000000); ++ DBG_88E("update raid entry, mask=0x%x, arg=0x%x\n", mask, arg); ++ psta->ra_mask = mask; ++ mask |= ((raid << 28) & 0xf0000000); ++ ++ /* to do ,for 8188E-SMIC */ ++ rtl8188e_set_raid_cmd(adapt, mask); ++ } else { ++ ODM_RA_UpdateRateInfo_8188E(&haldata->odmpriv, ++ mac_id, ++ raid, ++ mask, ++ shortGIrate ++ ); ++ } ++ /* set ra_id */ ++ psta->raid = raid; ++ psta->init_rate = init_rate; ++} ++ ++static void SetBeaconRelatedRegisters8188EUsb(struct adapter *adapt) ++{ ++ u32 value32; ++ struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ u32 bcn_ctrl_reg = REG_BCN_CTRL; ++ /* reset TSF, enable update TSF, correcting TSF On Beacon */ ++ ++ /* BCN interval */ ++ rtw_write16(adapt, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval); ++ rtw_write8(adapt, REG_ATIMWND, 0x02);/* 2ms */ ++ ++ _InitBeaconParameters(adapt); ++ ++ rtw_write8(adapt, REG_SLOT, 0x09); ++ ++ value32 = rtw_read32(adapt, REG_TCR); ++ value32 &= ~TSFRST; ++ rtw_write32(adapt, REG_TCR, value32); ++ ++ value32 |= TSFRST; ++ rtw_write32(adapt, REG_TCR, value32); ++ ++ /* NOTE: Fix test chip's bug (about contention windows's randomness) */ ++ rtw_write8(adapt, REG_RXTSF_OFFSET_CCK, 0x50); ++ rtw_write8(adapt, REG_RXTSF_OFFSET_OFDM, 0x50); ++ ++ _BeaconFunctionEnable(adapt, true, true); ++ ++ ResumeTxBeacon(adapt); ++ ++ rtw_write8(adapt, bcn_ctrl_reg, rtw_read8(adapt, bcn_ctrl_reg) | BIT(1)); ++} ++ ++static void rtl8188eu_init_default_value(struct adapter *adapt) ++{ ++ struct hal_data_8188e *haldata; ++ struct pwrctrl_priv *pwrctrlpriv; ++ u8 i; ++ ++ haldata = GET_HAL_DATA(adapt); ++ pwrctrlpriv = &adapt->pwrctrlpriv; ++ ++ /* init default value */ ++ haldata->fw_ractrl = false; ++ if (!pwrctrlpriv->bkeepfwalive) ++ haldata->LastHMEBoxNum = 0; ++ ++ /* init dm default value */ ++ haldata->odmpriv.RFCalibrateInfo.bIQKInitialized = false; ++ haldata->odmpriv.RFCalibrateInfo.TM_Trigger = 0;/* for IQK */ ++ haldata->pwrGroupCnt = 0; ++ haldata->PGMaxGroup = 13; ++ haldata->odmpriv.RFCalibrateInfo.ThermalValue_HP_index = 0; ++ for (i = 0; i < HP_THERMAL_NUM; i++) ++ haldata->odmpriv.RFCalibrateInfo.ThermalValue_HP[i] = 0; ++} ++ ++static u8 rtl8188eu_ps_func(struct adapter *Adapter, enum hal_intf_ps_func efunc_id, u8 *val) ++{ ++ u8 bResult = true; ++ return bResult; ++} ++ ++void rtl8188eu_set_hal_ops(struct adapter *adapt) ++{ ++ struct hal_ops *halfunc = &adapt->HalFunc; ++ ++ adapt->HalData = kzalloc(sizeof(struct hal_data_8188e), GFP_KERNEL); ++ if (!adapt->HalData) ++ DBG_88E("cant not alloc memory for HAL DATA\n"); ++ adapt->hal_data_sz = sizeof(struct hal_data_8188e); ++ ++ halfunc->hal_power_on = rtl8188eu_InitPowerOn; ++ halfunc->hal_init = &rtl8188eu_hal_init; ++ halfunc->hal_deinit = &rtl8188eu_hal_deinit; ++ ++ halfunc->inirp_init = &rtl8188eu_inirp_init; ++ halfunc->inirp_deinit = &rtl8188eu_inirp_deinit; ++ ++ halfunc->init_xmit_priv = &rtl8188eu_init_xmit_priv; ++ ++ halfunc->init_recv_priv = &rtl8188eu_init_recv_priv; ++ halfunc->free_recv_priv = &rtl8188eu_free_recv_priv; ++ halfunc->InitSwLeds = &rtl8188eu_InitSwLeds; ++ halfunc->DeInitSwLeds = &rtl8188eu_DeInitSwLeds; ++ ++ halfunc->init_default_value = &rtl8188eu_init_default_value; ++ halfunc->intf_chip_configure = &rtl8188eu_interface_configure; ++ halfunc->read_adapter_info = &ReadAdapterInfo8188EU; ++ ++ halfunc->SetHwRegHandler = &SetHwReg8188EU; ++ halfunc->GetHwRegHandler = &GetHwReg8188EU; ++ halfunc->GetHalDefVarHandler = &GetHalDefVar8188EUsb; ++ halfunc->SetHalDefVarHandler = &SetHalDefVar8188EUsb; ++ ++ halfunc->UpdateRAMaskHandler = &UpdateHalRAMask8188EUsb; ++ halfunc->SetBeaconRelatedRegistersHandler = &SetBeaconRelatedRegisters8188EUsb; ++ ++ halfunc->hal_xmit = &rtl8188eu_hal_xmit; ++ halfunc->mgnt_xmit = &rtl8188eu_mgnt_xmit; ++ ++ halfunc->interface_ps_func = &rtl8188eu_ps_func; ++ ++ rtl8188e_set_hal_ops(halfunc); ++ ++} +diff --git a/drivers/staging/r8188eu/hal/usb_ops_linux.c b/drivers/staging/r8188eu/hal/usb_ops_linux.c +new file mode 100644 +index 000000000000..0cf69033c529 +--- /dev/null ++++ b/drivers/staging/r8188eu/hal/usb_ops_linux.c +@@ -0,0 +1,562 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/osdep_intf.h" ++#include "../include/usb_ops.h" ++#include "../include/recv_osdep.h" ++#include "../include/rtl8188e_hal.h" ++ ++static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u16 value, void *pdata, u16 len, u8 requesttype) ++{ ++ struct adapter *adapt = pintfhdl->padapter; ++ struct dvobj_priv *dvobjpriv = adapter_to_dvobj(adapt); ++ struct usb_device *udev = dvobjpriv->pusbdev; ++ unsigned int pipe; ++ int status = 0; ++ u8 *pIo_buf; ++ int vendorreq_times = 0; ++ ++ if ((adapt->bSurpriseRemoved) || (adapt->pwrctrlpriv.pnp_bstop_trx)) { ++ status = -EPERM; ++ goto exit; ++ } ++ ++ if (len > MAX_VENDOR_REQ_CMD_SIZE) { ++ DBG_88E("[%s] Buffer len error ,vendor request failed\n", __func__); ++ status = -EINVAL; ++ goto exit; ++ } ++ ++ _enter_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL); ++ ++ /* Acquire IO memory for vendorreq */ ++ pIo_buf = dvobjpriv->usb_vendor_req_buf; ++ ++ if (!pIo_buf) { ++ DBG_88E("[%s] pIo_buf == NULL\n", __func__); ++ status = -ENOMEM; ++ goto release_mutex; ++ } ++ ++ if (requesttype == REALTEK_USB_VENQT_READ) ++ pipe = usb_rcvctrlpipe(udev, 0);/* read_in */ ++ else ++ pipe = usb_sndctrlpipe(udev, 0);/* write_out */ ++ ++ while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) { ++ if (requesttype == REALTEK_USB_VENQT_READ) ++ memset(pIo_buf, 0, len); ++ else ++ memcpy(pIo_buf, pdata, len); ++ ++ status = usb_control_msg(udev, pipe, REALTEK_USB_VENQT_CMD_REQ, ++ requesttype, value, REALTEK_USB_VENQT_CMD_IDX, ++ pIo_buf, len, RTW_USB_CONTROL_MSG_TIMEOUT); ++ ++ if (status == len) { /* Success this control transfer. */ ++ rtw_reset_continual_urb_error(dvobjpriv); ++ if (requesttype == REALTEK_USB_VENQT_READ) ++ memcpy(pdata, pIo_buf, len); ++ } else { /* error cases */ ++ DBG_88E("reg 0x%x, usb %s %u fail, status:%d value=0x%x, vendorreq_times:%d\n", ++ value, (requesttype == REALTEK_USB_VENQT_READ) ? "read" : "write", ++ len, status, *(u32 *)pdata, vendorreq_times); ++ ++ if (status < 0) { ++ if (status == (-ESHUTDOWN) || status == -ENODEV) { ++ adapt->bSurpriseRemoved = true; ++ } else { ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ haldata->srestpriv.wifi_error_status = USB_VEN_REQ_CMD_FAIL; ++ } ++ } else { /* status != len && status >= 0 */ ++ if (status > 0) { ++ if (requesttype == REALTEK_USB_VENQT_READ) { ++ /* For Control read transfer, we have to copy the read data from pIo_buf to pdata. */ ++ memcpy(pdata, pIo_buf, len); ++ } ++ } ++ } ++ ++ if (rtw_inc_and_chk_continual_urb_error(dvobjpriv)) { ++ adapt->bSurpriseRemoved = true; ++ break; ++ } ++ ++ } ++ ++ /* firmware download is checksumed, don't retry */ ++ if ((value >= FW_8188E_START_ADDRESS && value <= FW_8188E_END_ADDRESS) || status == len) ++ break; ++ } ++release_mutex: ++ _exit_critical_mutex(&dvobjpriv->usb_vendor_req_mutex, NULL); ++exit: ++ return status; ++} ++ ++static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u16 wvalue = (u16)(addr & 0x0000ffff); ++ u8 data; ++ ++ usbctrl_vendorreq(pintfhdl, wvalue, &data, 1, REALTEK_USB_VENQT_READ); ++ ++ return data; ++} ++ ++static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u16 wvalue = (u16)(addr & 0x0000ffff); ++ __le32 data; ++ ++ usbctrl_vendorreq(pintfhdl, wvalue, &data, 2, REALTEK_USB_VENQT_READ); ++ ++ return (u16)(le32_to_cpu(data) & 0xffff); ++} ++ ++static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr) ++{ ++ u16 wvalue = (u16)(addr & 0x0000ffff); ++ __le32 data; ++ ++ usbctrl_vendorreq(pintfhdl, wvalue, &data, 4, REALTEK_USB_VENQT_READ); ++ ++ return le32_to_cpu(data); ++} ++ ++static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) ++{ ++ u16 wvalue = (u16)(addr & 0x0000ffff); ++ ++ return usbctrl_vendorreq(pintfhdl, wvalue, &val, 1, REALTEK_USB_VENQT_WRITE); ++} ++ ++static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) ++{ ++ u16 wvalue = (u16)(addr & 0x0000ffff); ++ __le32 data = cpu_to_le32(val & 0x0000ffff); ++ ++ return usbctrl_vendorreq(pintfhdl, wvalue, &data, 2, REALTEK_USB_VENQT_WRITE); ++} ++ ++static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) ++{ ++ u16 wvalue = (u16)(addr & 0x0000ffff); ++ __le32 data = cpu_to_le32(val); ++ ++ return usbctrl_vendorreq(pintfhdl, wvalue, &data, 4, REALTEK_USB_VENQT_WRITE); ++} ++ ++static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata) ++{ ++ u16 wvalue = (u16)(addr & 0x0000ffff); ++ u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0}; ++ ++ if (length > VENDOR_CMD_MAX_DATA_LEN) ++ return -EINVAL; ++ ++ memcpy(buf, pdata, length); ++ ++ return usbctrl_vendorreq(pintfhdl, wvalue, buf, (length & 0xffff), REALTEK_USB_VENQT_WRITE); ++} ++ ++static void interrupt_handler_8188eu(struct adapter *adapt, u16 pkt_len, u8 *pbuf) ++{ ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ ++ if (pkt_len != INTERRUPT_MSG_FORMAT_LEN) { ++ DBG_88E("%s Invalid interrupt content length (%d)!\n", __func__, pkt_len); ++ return; ++ } ++ ++ /* HISR */ ++ memcpy(&haldata->IntArray[0], &pbuf[USB_INTR_CONTENT_HISR_OFFSET], 4); ++ memcpy(&haldata->IntArray[1], &pbuf[USB_INTR_CONTENT_HISRE_OFFSET], 4); ++ ++ /* C2H Event */ ++ if (pbuf[0] != 0) ++ memcpy(&haldata->C2hArray[0], &pbuf[USB_INTR_CONTENT_C2H_OFFSET], 16); ++} ++ ++static int recvbuf2recvframe(struct adapter *adapt, struct sk_buff *pskb) ++{ ++ u8 *pbuf; ++ u8 shift_sz = 0; ++ u16 pkt_cnt; ++ u32 pkt_offset, skb_len, alloc_sz; ++ s32 transfer_len; ++ struct recv_stat *prxstat; ++ struct phy_stat *pphy_status = NULL; ++ struct sk_buff *pkt_copy = NULL; ++ struct recv_frame *precvframe = NULL; ++ struct rx_pkt_attrib *pattrib = NULL; ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ struct recv_priv *precvpriv = &adapt->recvpriv; ++ struct __queue *pfree_recv_queue = &precvpriv->free_recv_queue; ++ ++ transfer_len = (s32)pskb->len; ++ pbuf = pskb->data; ++ ++ prxstat = (struct recv_stat *)pbuf; ++ pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff; ++ ++ do { ++ prxstat = (struct recv_stat *)pbuf; ++ ++ precvframe = rtw_alloc_recvframe(pfree_recv_queue); ++ if (!precvframe) { ++ DBG_88E("%s()-%d: rtw_alloc_recvframe() failed! RX Drop!\n", __func__, __LINE__); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ INIT_LIST_HEAD(&precvframe->list); ++ precvframe->precvbuf = NULL; /* can't access the precvbuf for new arch. */ ++ precvframe->len = 0; ++ ++ update_recvframe_attrib_88e(precvframe, prxstat); ++ ++ pattrib = &precvframe->attrib; ++ ++ if ((pattrib->crc_err) || (pattrib->icv_err)) { ++ DBG_88E("%s: RX Warning! crc_err=%d icv_err=%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err); ++ ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ if ((pattrib->physt) && (pattrib->pkt_rpt_type == NORMAL_RX)) ++ pphy_status = (struct phy_stat *)(pbuf + RXDESC_OFFSET); ++ ++ pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz + pattrib->shift_sz + pattrib->pkt_len; ++ ++ if ((pattrib->pkt_len <= 0) || (pkt_offset > transfer_len)) { ++ DBG_88E("%s()-%d: RX Warning!,pkt_len<=0 or pkt_offset> transfoer_len\n", __func__, __LINE__); ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ ++ /* Modified by Albert 20101213 */ ++ /* For 8 bytes IP header alignment. */ ++ if (pattrib->qos) /* Qos data, wireless lan header length is 26 */ ++ shift_sz = 6; ++ else ++ shift_sz = 0; ++ ++ skb_len = pattrib->pkt_len; ++ ++ /* for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. */ ++ /* modify alloc_sz for recvive crc error packet by thomas 2011-06-02 */ ++ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) { ++ if (skb_len <= 1650) ++ alloc_sz = 1664; ++ else ++ alloc_sz = skb_len + 14; ++ } else { ++ alloc_sz = skb_len; ++ /* 6 is for IP header 8 bytes alignment in QoS packet case. */ ++ /* 8 is for skb->data 4 bytes alignment. */ ++ alloc_sz += 14; ++ } ++ ++ pkt_copy = netdev_alloc_skb(adapt->pnetdev, alloc_sz); ++ if (pkt_copy) { ++ pkt_copy->dev = adapt->pnetdev; ++ precvframe->pkt = pkt_copy; ++ precvframe->rx_head = pkt_copy->data; ++ precvframe->rx_end = pkt_copy->data + alloc_sz; ++ skb_reserve(pkt_copy, 8 - ((size_t)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */ ++ skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */ ++ memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len); ++ precvframe->rx_tail = pkt_copy->data; ++ precvframe->rx_data = pkt_copy->data; ++ } else { ++ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) { ++ DBG_88E("recvbuf2recvframe: alloc_skb fail , drop frag frame\n"); ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ precvframe->pkt = skb_clone(pskb, GFP_ATOMIC); ++ if (precvframe->pkt) { ++ precvframe->rx_tail = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE; ++ precvframe->rx_head = precvframe->rx_tail; ++ precvframe->rx_data = precvframe->rx_tail; ++ precvframe->rx_end = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE + alloc_sz; ++ } else { ++ DBG_88E("recvbuf2recvframe: skb_clone fail\n"); ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ goto _exit_recvbuf2recvframe; ++ } ++ } ++ ++ recvframe_put(precvframe, skb_len); ++ ++ switch (haldata->UsbRxAggMode) { ++ case USB_RX_AGG_DMA: ++ case USB_RX_AGG_MIX: ++ pkt_offset = (u16)_RND128(pkt_offset); ++ break; ++ case USB_RX_AGG_USB: ++ pkt_offset = (u16)_RND4(pkt_offset); ++ break; ++ case USB_RX_AGG_DISABLE: ++ default: ++ break; ++ } ++ if (pattrib->pkt_rpt_type == NORMAL_RX) { /* Normal rx packet */ ++ if (pattrib->physt) ++ update_recvframe_phyinfo_88e(precvframe, (struct phy_stat *)pphy_status); ++ rtw_recv_entry(precvframe); ++ } else { ++ /* enqueue recvframe to txrtp queue */ ++ if (pattrib->pkt_rpt_type == TX_REPORT1) { ++ /* CCX-TXRPT ack for xmit mgmt frames. */ ++ handle_txrpt_ccx_88e(adapt, precvframe->rx_data); ++ } else if (pattrib->pkt_rpt_type == TX_REPORT2) { ++ ODM_RA_TxRPT2Handle_8188E( ++ &haldata->odmpriv, ++ precvframe->rx_data, ++ pattrib->pkt_len, ++ pattrib->MacIDValidEntry[0], ++ pattrib->MacIDValidEntry[1] ++ ); ++ } else if (pattrib->pkt_rpt_type == HIS_REPORT) { ++ interrupt_handler_8188eu(adapt, pattrib->pkt_len, precvframe->rx_data); ++ } ++ rtw_free_recvframe(precvframe, pfree_recv_queue); ++ } ++ pkt_cnt--; ++ transfer_len -= pkt_offset; ++ pbuf += pkt_offset; ++ precvframe = NULL; ++ pkt_copy = NULL; ++ ++ if (transfer_len > 0 && pkt_cnt == 0) ++ pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff; ++ ++ } while ((transfer_len > 0) && (pkt_cnt > 0)); ++ ++_exit_recvbuf2recvframe: ++ ++ return _SUCCESS; ++} ++ ++void rtl8188eu_recv_tasklet(unsigned long priv) ++{ ++ struct sk_buff *pskb; ++ struct adapter *adapt = (struct adapter *)priv; ++ struct recv_priv *precvpriv = &adapt->recvpriv; ++ ++ while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) { ++ if ((adapt->bDriverStopped) || (adapt->bSurpriseRemoved)) { ++ DBG_88E("recv_tasklet => bDriverStopped or bSurpriseRemoved\n"); ++ dev_kfree_skb_any(pskb); ++ break; ++ } ++ recvbuf2recvframe(adapt, pskb); ++ skb_reset_tail_pointer(pskb); ++ pskb->len = 0; ++ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); ++ } ++} ++ ++static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs) ++{ ++ struct recv_buf *precvbuf = (struct recv_buf *)purb->context; ++ struct adapter *adapt = (struct adapter *)precvbuf->adapter; ++ struct recv_priv *precvpriv = &adapt->recvpriv; ++ ++ precvpriv->rx_pending_cnt--; ++ ++ if (adapt->bSurpriseRemoved || adapt->bDriverStopped || adapt->bReadPortCancel) { ++ precvbuf->reuse = true; ++ DBG_88E("%s() RX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bReadPortCancel(%d)\n", ++ __func__, adapt->bDriverStopped, ++ adapt->bSurpriseRemoved, adapt->bReadPortCancel); ++ return; ++ } ++ ++ if (purb->status == 0) { /* SUCCESS */ ++ if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) { ++ precvbuf->reuse = true; ++ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ DBG_88E("%s()-%d: RX Warning!\n", __func__, __LINE__); ++ } else { ++ rtw_reset_continual_urb_error(adapter_to_dvobj(adapt)); ++ ++ precvbuf->transfer_len = purb->actual_length; ++ skb_put(precvbuf->pskb, purb->actual_length); ++ skb_queue_tail(&precvpriv->rx_skb_queue, precvbuf->pskb); ++ ++ if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1) ++ tasklet_schedule(&precvpriv->recv_tasklet); ++ ++ precvbuf->pskb = NULL; ++ precvbuf->reuse = false; ++ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ } ++ } else { ++ DBG_88E("###=> usb_read_port_complete => urb status(%d)\n", purb->status); ++ skb_put(precvbuf->pskb, purb->actual_length); ++ precvbuf->pskb = NULL; ++ ++ if (rtw_inc_and_chk_continual_urb_error(adapter_to_dvobj(adapt))) ++ adapt->bSurpriseRemoved = true; ++ ++ switch (purb->status) { ++ case -EINVAL: ++ case -EPIPE: ++ case -ENODEV: ++ case -ESHUTDOWN: ++ case -ENOENT: ++ adapt->bDriverStopped = true; ++ break; ++ case -EPROTO: ++ case -EOVERFLOW: ++ { ++ struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); ++ haldata->srestpriv.wifi_error_status = USB_READ_PORT_FAIL; ++ } ++ precvbuf->reuse = true; ++ rtw_read_port(adapt, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); ++ break; ++ case -EINPROGRESS: ++ DBG_88E("ERROR: URB IS IN PROGRESS!/n"); ++ break; ++ default: ++ break; ++ } ++ } ++} ++ ++static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) ++{ ++ struct urb *purb = NULL; ++ struct recv_buf *precvbuf = (struct recv_buf *)rmem; ++ struct adapter *adapter = pintfhdl->padapter; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter); ++ struct recv_priv *precvpriv = &adapter->recvpriv; ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ int err; ++ unsigned int pipe; ++ size_t tmpaddr = 0; ++ size_t alignment = 0; ++ u32 ret = _SUCCESS; ++ ++ if (adapter->bDriverStopped || adapter->bSurpriseRemoved || ++ adapter->pwrctrlpriv.pnp_bstop_trx) ++ return _FAIL; ++ ++ if (!precvbuf) ++ return _FAIL; ++ ++ if (!precvbuf->reuse || !precvbuf->pskb) { ++ precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); ++ if (precvbuf->pskb) ++ precvbuf->reuse = true; ++ } ++ ++ rtl8188eu_init_recvbuf(adapter, precvbuf); ++ ++ /* re-assign for linux based on skb */ ++ if (!precvbuf->reuse || !precvbuf->pskb) { ++ precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); ++ if (!precvbuf->pskb) { ++ DBG_88E("#### usb_read_port() alloc_skb fail!#####\n"); ++ return _FAIL; ++ } ++ ++ tmpaddr = (size_t)precvbuf->pskb->data; ++ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1); ++ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); ++ ++ precvbuf->phead = precvbuf->pskb->head; ++ precvbuf->pdata = precvbuf->pskb->data; ++ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); ++ precvbuf->pend = skb_end_pointer(precvbuf->pskb); ++ precvbuf->pbuf = precvbuf->pskb->data; ++ } else { /* reuse skb */ ++ precvbuf->phead = precvbuf->pskb->head; ++ precvbuf->pdata = precvbuf->pskb->data; ++ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); ++ precvbuf->pend = skb_end_pointer(precvbuf->pskb); ++ precvbuf->pbuf = precvbuf->pskb->data; ++ ++ precvbuf->reuse = false; ++ } ++ ++ precvpriv->rx_pending_cnt++; ++ ++ purb = precvbuf->purb; ++ ++ /* translate DMA FIFO addr to pipehandle */ ++ pipe = ffaddr2pipehdl(pdvobj, addr); ++ ++ usb_fill_bulk_urb(purb, pusbd, pipe, ++ precvbuf->pbuf, ++ MAX_RECVBUF_SZ, ++ usb_read_port_complete, ++ precvbuf);/* context is precvbuf */ ++ ++ err = usb_submit_urb(purb, GFP_ATOMIC); ++ if ((err) && (err != (-EPERM))) { ++ DBG_88E("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n", ++ err, purb->status); ++ ret = _FAIL; ++ } ++ ++ return ret; ++} ++ ++void rtl8188eu_xmit_tasklet(unsigned long priv) ++{ ++ int ret = false; ++ struct adapter *adapt = (struct adapter *)priv; ++ struct xmit_priv *pxmitpriv = &adapt->xmitpriv; ++ ++ if (check_fwstate(&adapt->mlmepriv, _FW_UNDER_SURVEY)) ++ return; ++ ++ while (1) { ++ if ((adapt->bDriverStopped) || ++ (adapt->bSurpriseRemoved) || ++ (adapt->bWritePortCancel)) { ++ DBG_88E("xmit_tasklet => bDriverStopped or bSurpriseRemoved or bWritePortCancel\n"); ++ break; ++ } ++ ++ ret = rtl8188eu_xmitframe_complete(adapt, pxmitpriv, NULL); ++ ++ if (!ret) ++ break; ++ } ++} ++ ++void rtl8188eu_set_intf_ops(struct _io_ops *pops) ++{ ++ ++ memset((u8 *)pops, 0, sizeof(struct _io_ops)); ++ pops->_read8 = &usb_read8; ++ pops->_read16 = &usb_read16; ++ pops->_read32 = &usb_read32; ++ pops->_read_mem = &usb_read_mem; ++ pops->_read_port = &usb_read_port; ++ pops->_write8 = &usb_write8; ++ pops->_write16 = &usb_write16; ++ pops->_write32 = &usb_write32; ++ pops->_writeN = &usb_writeN; ++ pops->_write_mem = &usb_write_mem; ++ pops->_write_port = &usb_write_port; ++ pops->_read_port_cancel = &usb_read_port_cancel; ++ pops->_write_port_cancel = &usb_write_port_cancel; ++ ++} ++ ++void rtl8188eu_set_hw_type(struct adapter *adapt) ++{ ++ adapt->chip_type = RTL8188E; ++ adapt->HardwareType = HARDWARE_TYPE_RTL8188EU; ++ DBG_88E("CHIP TYPE: RTL8188E\n"); ++} +diff --git a/drivers/staging/r8188eu/include/Hal8188EPhyCfg.h b/drivers/staging/r8188eu/include/Hal8188EPhyCfg.h +new file mode 100644 +index 000000000000..4370ec2fa981 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/Hal8188EPhyCfg.h +@@ -0,0 +1,249 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __INC_HAL8188EPHYCFG_H__ ++#define __INC_HAL8188EPHYCFG_H__ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define LOOP_LIMIT 5 ++#define MAX_STALL_TIME 50 /* us */ ++#define AntennaDiversityValue 0x80 ++#define MAX_TXPWR_IDX_NMODE_92S 63 ++#define Reset_Cnt_Limit 3 ++ ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM 9 ++#define HP_THERMAL_NUM 8 ++ ++#define MAX_AGGR_NUM 0x07 ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++/*------------------------------Define structure----------------------------*/ ++enum sw_chnl_cmd_id { ++ CmdID_End, ++ CmdID_SetTxPowerLevel, ++ CmdID_BBRegWrite10, ++ CmdID_WritePortUlong, ++ CmdID_WritePortUshort, ++ CmdID_WritePortUchar, ++ CmdID_RF_WriteReg, ++}; ++ ++/* 1. Switch channel related */ ++struct sw_chnl_cmd { ++ enum sw_chnl_cmd_id CmdID; ++ u32 Para1; ++ u32 Para2; ++ u32 msDelay; ++}; ++ ++enum hw90_block { ++ HW90_BLOCK_MAC = 0, ++ HW90_BLOCK_PHY0 = 1, ++ HW90_BLOCK_PHY1 = 2, ++ HW90_BLOCK_RF = 3, ++ HW90_BLOCK_MAXIMUM = 4, /* Never use this */ ++}; ++ ++enum rf_radio_path { ++ RF_PATH_A = 0, /* Radio Path A */ ++ RF_PATH_B = 1, /* Radio Path B */ ++ RF_PATH_C = 2, /* Radio Path C */ ++ RF_PATH_D = 3, /* Radio Path D */ ++}; ++ ++#define MAX_PG_GROUP 13 ++ ++#define RF_PATH_MAX 3 ++#define MAX_TX_COUNT 4 /* path numbers */ ++ ++#define CHANNEL_MAX_NUMBER 14 /* 14 is the max chnl number */ ++#define MAX_CHNL_GROUP_24G 6 /* ch1~2, ch3~5, ch6~8, ++ *ch9~11, ch12~13, CH 14 ++ * total three groups */ ++#define CHANNEL_GROUP_MAX_88E 6 ++ ++enum wireless_mode { ++ WIRELESS_MODE_UNKNOWN = 0x00, ++ WIRELESS_MODE_B = BIT(0), ++ WIRELESS_MODE_G = BIT(1), ++ WIRELESS_MODE_AUTO = BIT(5), ++ WIRELESS_MODE_N_24G = BIT(3), ++}; ++ ++enum phy_rate_tx_offset_area { ++ RA_OFFSET_LEGACY_OFDM1, ++ RA_OFFSET_LEGACY_OFDM2, ++ RA_OFFSET_HT_OFDM1, ++ RA_OFFSET_HT_OFDM2, ++ RA_OFFSET_HT_OFDM3, ++ RA_OFFSET_HT_OFDM4, ++ RA_OFFSET_HT_CCK, ++}; ++ ++/* BB/RF related */ ++enum RF_TYPE_8190P { ++ RF_TYPE_MIN, /* 0 */ ++ RF_8225 = 1, /* 1 11b/g RF for verification only */ ++ RF_8256 = 2, /* 2 11b/g/n */ ++ RF_6052 = 4, /* 4 11b/g/n RF */ ++ /* TODO: We should remove this psudo PHY RF after we get new RF. */ ++ RF_PSEUDO_11N = 5, /* 5, It is a temporality RF. */ ++}; ++ ++struct bb_reg_def { ++ u32 rfintfs; /* set software control: */ ++ /* 0x870~0x877[8 bytes] */ ++ u32 rfintfi; /* readback data: */ ++ /* 0x8e0~0x8e7[8 bytes] */ ++ u32 rfintfo; /* output data: */ ++ /* 0x860~0x86f [16 bytes] */ ++ u32 rfintfe; /* output enable: */ ++ /* 0x860~0x86f [16 bytes] */ ++ u32 rf3wireOffset; /* LSSI data: */ ++ /* 0x840~0x84f [16 bytes] */ ++ u32 rfLSSI_Select; /* BB Band Select: */ ++ /* 0x878~0x87f [8 bytes] */ ++ u32 rfTxGainStage; /* Tx gain stage: */ ++ /* 0x80c~0x80f [4 bytes] */ ++ u32 rfHSSIPara1; /* wire parameter control1 : */ ++ /* 0x820~0x823,0x828~0x82b, ++ * 0x830~0x833, 0x838~0x83b [16 bytes] */ ++ u32 rfHSSIPara2; /* wire parameter control2 : */ ++ /* 0x824~0x827,0x82c~0x82f, 0x834~0x837, ++ * 0x83c~0x83f [16 bytes] */ ++ u32 rfSwitchControl; /* Tx Rx antenna control : */ ++ /* 0x858~0x85f [16 bytes] */ ++ u32 rfAGCControl1; /* AGC parameter control1 : */ ++ /* 0xc50~0xc53,0xc58~0xc5b, 0xc60~0xc63, ++ * 0xc68~0xc6b [16 bytes] */ ++ u32 rfAGCControl2; /* AGC parameter control2 : */ ++ /* 0xc54~0xc57,0xc5c~0xc5f, 0xc64~0xc67, ++ * 0xc6c~0xc6f [16 bytes] */ ++ u32 rfRxIQImbalance; /* OFDM Rx IQ imbalance matrix : */ ++ /* 0xc14~0xc17,0xc1c~0xc1f, 0xc24~0xc27, ++ * 0xc2c~0xc2f [16 bytes] */ ++ u32 rfRxAFE; /* Rx IQ DC ofset and Rx digital filter, ++ * Rx DC notch filter : */ ++ /* 0xc10~0xc13,0xc18~0xc1b, 0xc20~0xc23, ++ * 0xc28~0xc2b [16 bytes] */ ++ u32 rfTxIQImbalance; /* OFDM Tx IQ imbalance matrix */ ++ /* 0xc80~0xc83,0xc88~0xc8b, 0xc90~0xc93, ++ * 0xc98~0xc9b [16 bytes] */ ++ u32 rfTxAFE; /* Tx IQ DC Offset and Tx DFIR type */ ++ /* 0xc84~0xc87,0xc8c~0xc8f, 0xc94~0xc97, ++ * 0xc9c~0xc9f [16 bytes] */ ++ u32 rfLSSIReadBack; /* LSSI RF readback data SI mode */ ++ /* 0x8a0~0x8af [16 bytes] */ ++ u32 rfLSSIReadBackPi; /* LSSI RF readback data PI mode 0x8b8-8bc for ++ * Path A and B */ ++}; ++ ++struct ant_sel_ofdm { ++ u32 r_tx_antenna:4; ++ u32 r_ant_l:4; ++ u32 r_ant_non_ht:4; ++ u32 r_ant_ht1:4; ++ u32 r_ant_ht2:4; ++ u32 r_ant_ht_s1:4; ++ u32 r_ant_non_ht_s1:4; ++ u32 OFDM_TXSC:2; ++ u32 reserved:2; ++}; ++ ++struct ant_sel_cck { ++ u8 r_cckrx_enable_2:2; ++ u8 r_cckrx_enable:2; ++ u8 r_ccktx_enable:4; ++}; ++ ++/*------------------------------Define structure----------------------------*/ ++ ++/*------------------------Export global variable----------------------------*/ ++/*------------------------Export global variable----------------------------*/ ++ ++/*------------------------Export Marco Definition---------------------------*/ ++/*------------------------Export Marco Definition---------------------------*/ ++ ++/*--------------------------Exported Function prototype---------------------*/ ++/* */ ++/* BB and RF register read/write */ ++/* */ ++u32 rtl8188e_PHY_QueryBBReg(struct adapter *adapter, u32 regaddr, u32 mask); ++void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr, ++ u32 mask, u32 data); ++u32 rtl8188e_PHY_QueryRFReg(struct adapter *adapter, enum rf_radio_path rfpath, ++ u32 regaddr, u32 mask); ++void rtl8188e_PHY_SetRFReg(struct adapter *adapter, enum rf_radio_path rfpath, ++ u32 regaddr, u32 mask, u32 data); ++ ++/* Initialization related function */ ++/* MAC/BB/RF HAL config */ ++int PHY_MACConfig8188E(struct adapter *adapter); ++int PHY_BBConfig8188E(struct adapter *adapter); ++int PHY_RFConfig8188E(struct adapter *adapter); ++ ++/* RF config */ ++int rtl8188e_PHY_ConfigRFWithParaFile(struct adapter *adapter, u8 *filename, ++ enum rf_radio_path rfpath); ++int rtl8188e_PHY_ConfigRFWithHeaderFile(struct adapter *adapter, ++ enum rf_radio_path rfpath); ++ ++/* Read initi reg value for tx power setting. */ ++void rtl8192c_PHY_GetHWRegOriginalValue(struct adapter *adapter); ++ ++/* BB TX Power R/W */ ++void PHY_GetTxPowerLevel8188E(struct adapter *adapter, u32 *powerlevel); ++void PHY_SetTxPowerLevel8188E(struct adapter *adapter, u8 channel); ++bool PHY_UpdateTxPowerDbm8188E(struct adapter *adapter, int power); ++ ++void PHY_ScanOperationBackup8188E(struct adapter *Adapter, u8 Operation); ++ ++/* Switch bandwidth for 8192S */ ++void PHY_SetBWMode8188E(struct adapter *adapter, ++ enum ht_channel_width chnlwidth, unsigned char offset); ++ ++/* channel switch related funciton */ ++void PHY_SwChnl8188E(struct adapter *adapter, u8 channel); ++/* Call after initialization */ ++void ChkFwCmdIoDone(struct adapter *adapter); ++ ++/* BB/MAC/RF other monitor API */ ++void PHY_SetRFPathSwitch_8188E(struct adapter *adapter, bool main); ++ ++void PHY_SwitchEphyParameter(struct adapter *adapter); ++ ++void PHY_EnableHostClkReq(struct adapter *adapter); ++ ++bool SetAntennaConfig92C(struct adapter *adapter, u8 defaultant); ++ ++void storePwrIndexDiffRateOffset(struct adapter *adapter, u32 regaddr, ++ u32 mask, u32 data); ++/*--------------------------Exported Function prototype---------------------*/ ++ ++#define PHY_QueryBBReg(adapt, regaddr, mask) \ ++ rtl8188e_PHY_QueryBBReg((adapt), (regaddr), (mask)) ++#define PHY_SetBBReg(adapt, regaddr, bitmask, data) \ ++ rtl8188e_PHY_SetBBReg((adapt), (regaddr), (bitmask), (data)) ++#define PHY_QueryRFReg(adapt, rfpath, regaddr, bitmask) \ ++ rtl8188e_PHY_QueryRFReg((adapt), (rfpath), (regaddr), (bitmask)) ++#define PHY_SetRFReg(adapt, rfpath, regaddr, bitmask, data) \ ++ rtl8188e_PHY_SetRFReg((adapt), (rfpath), (regaddr), (bitmask), (data)) ++ ++#define PHY_SetMacReg PHY_SetBBReg ++ ++#define SIC_HW_SUPPORT 0 ++ ++#define SIC_MAX_POLL_CNT 5 ++ ++#define SIC_CMD_READY 0 ++#define SIC_CMD_WRITE 1 ++#define SIC_CMD_READ 2 ++ ++#define SIC_CMD_REG 0x1EB /* 1byte */ ++#define SIC_ADDR_REG 0x1E8 /* 1b9~1ba, 2 bytes */ ++#define SIC_DATA_REG 0x1EC /* 1bc~1bf */ ++ ++#endif /* __INC_HAL8192CPHYCFG_H */ +diff --git a/drivers/staging/r8188eu/include/Hal8188EPhyReg.h b/drivers/staging/r8188eu/include/Hal8188EPhyReg.h +new file mode 100644 +index 000000000000..8b8c75a1f149 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/Hal8188EPhyReg.h +@@ -0,0 +1,1072 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __INC_HAL8188EPHYREG_H__ ++#define __INC_HAL8188EPHYREG_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 definition for BB/RF R/W */ ++/* */ ++ ++/* */ ++/* 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 ++ ++/* 2. Page2(0x200) */ ++/* The following two definition are only used for USB interface. */ ++#define RF_BB_CMD_ADDR 0x02c0 /* RF/BB r/w cmd address. */ ++#define RF_BB_CMD_DATA 0x02c4 /* RF/BB r/w cmd data. */ ++ ++/* 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_RFTiming1 0x810 /* Useless now */ ++#define rFPGA0_RFTiming2 0x814 ++ ++#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_RFWakeUpParameter 0x850 /* Useless now */ ++#define rFPGA0_RFSleepUpParameter 0x854 ++ ++#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++ ++#define rFPGA0_XAB_RFInterfaceSW 0x870 /* RF Iface Software Control */ ++#define rFPGA0_XCD_RFInterfaceSW 0x874 ++ ++#define rFPGA0_XAB_RFParameter 0x878 /* RF Parameter */ ++#define rFPGA0_XCD_RFParameter 0x87c ++ ++/* Crystal cap setting RF-R/W protection for parameter4?? */ ++#define rFPGA0_AnalogParameter1 0x880 ++#define rFPGA0_AnalogParameter2 0x884 ++#define rFPGA0_AnalogParameter3 0x888 ++/* enable ad/da clock1 for dual-phy */ ++#define rFPGA0_AdDaClockEn 0x888 ++#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_PSDReport 0x8b4 /* Useless now */ ++/* Transceiver A HSPI Readback */ ++#define TransceiverA_HSPI_Readback 0x8b8 ++/* Transceiver B HSPI Readback */ ++#define TransceiverB_HSPI_Readback 0x8bc ++/* Useless now RF Interface Readback Value */ ++#define rFPGA0_XAB_RFInterfaceRB 0x8e0 ++#define rFPGA0_XCD_RFInterfaceRB 0x8e4 /* Useless now */ ++ ++/* 4. Page9(0x900) */ ++/* RF mode & OFDM TxSC RF BW Setting?? */ ++#define rFPGA1_RFMOD 0x900 ++ ++#define rFPGA1_TxBlock 0x904 /* Useless now */ ++#define rFPGA1_DebugSelect 0x908 /* Useless now */ ++#define rFPGA1_TxInfo 0x90c /* Useless now Status report */ ++ ++/* 5. PageA(0xA00) */ ++/* Set Control channel to upper or lower - required only for 40MHz */ ++#define rCCK0_System 0xa00 ++ ++/* Disable init gain now Select RX path by RSSI */ ++#define rCCK0_AFESetting 0xa04 ++/* Disable init gain now Init gain */ ++#define rCCK0_CCA 0xa08 ++ ++/* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold, ++ * RX LNA Threshold useless now. Not the same as 90 series */ ++#define rCCK0_RxAGC1 0xa0c ++#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */ ++ ++#define rCCK0_RxHP 0xa14 ++ ++/* Timing recovery & Channel estimation threshold */ ++#define rCCK0_DSPParameter1 0xa18 ++#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 */ ++#define rCCK0_TRSSIReport 0xa50 ++#define rCCK0_RxReport 0xa54 /* 0xa57 */ ++#define rCCK0_FACounterLower 0xa5c /* 0xa5b */ ++#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */ ++ ++/* */ ++/* 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 ++ ++/* RxIQ DC offset, Rx digital filter, DC notch filter */ ++#define rOFDM0_XARxAFE 0xc10 ++#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 ++ ++#define rOFDM1_CFO 0xd08 /* No setting now */ ++#define rOFDM1_CSI1 0xd10 ++#define rOFDM1_SBD 0xd14 ++#define rOFDM1_CSI2 0xd18 ++#define rOFDM1_CFOTracking 0xd2c ++#define rOFDM1_TRxMesaure1 0xd34 ++#define rOFDM1_IntfDet 0xd3c ++#define rOFDM1_PseudoNoiseStateAB 0xd50 ++#define rOFDM1_PseudoNoiseStateCD 0xd54 ++#define rOFDM1_RxPseudoNoiseWgt 0xd58 ++ ++#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */ ++#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */ ++#define rOFDM_PHYCounter3 0xda8 /* MCS not support */ ++ ++#define rOFDM_ShortCFOAB 0xdac /* No setting now */ ++#define rOFDM_ShortCFOCD 0xdb0 ++#define rOFDM_LongCFOAB 0xdb4 ++#define rOFDM_LongCFOCD 0xdb8 ++#define rOFDM_TailCFOAB 0xdbc ++#define rOFDM_TailCFOCD 0xdc0 ++#define rOFDM_PWMeasure1 0xdc4 ++#define rOFDM_PWMeasure2 0xdc8 ++#define rOFDM_BWReport 0xdcc ++#define rOFDM_AGCReport 0xdd0 ++#define rOFDM_RxSNR 0xdd4 ++#define rOFDM_RxEVMCSI 0xdd8 ++#define rOFDM_SIGReport 0xddc ++ ++/* */ ++/* 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 ++ ++/* */ ++/* 7. RF Register 0x00-0x2E (RF 8256) */ ++/* RF-0222D 0x00-3F */ ++/* */ ++/* Zebra1 */ ++#define rZebra1_HSSIEnable 0x0 /* Useless now */ ++#define rZebra1_TRxEnable1 0x1 ++#define rZebra1_TRxEnable2 0x2 ++#define rZebra1_AGC 0x4 ++#define rZebra1_ChargePump 0x5 ++#define rZebra1_Channel 0x7 /* RF channel switch */ ++ ++/* endif */ ++#define rZebra1_TxGain 0x8 /* Useless now */ ++#define rZebra1_TxLPF 0x9 ++#define rZebra1_RxLPF 0xb ++#define rZebra1_RxHPFCorner 0xc ++ ++/* Zebra4 */ ++#define rGlobalCtrl 0 /* Useless now */ ++#define rRTL8256_TxLPF 19 ++#define rRTL8256_RxLPF 11 ++ ++/* RTL8258 */ ++#define rRTL8258_TxLPF 0x11 /* Useless now */ ++#define rRTL8258_RxLPF 0x13 ++#define rRTL8258_RSSILPF 0xa ++ ++/* */ ++/* RL6052 Register definition */ ++/* */ ++#define RF_AC 0x00 /* */ ++ ++#define RF_IQADJ_G1 0x01 /* */ ++#define RF_IQADJ_G2 0x02 /* */ ++ ++#define RF_POW_TRSW 0x05 /* */ ++ ++#define RF_GAIN_RX 0x06 /* */ ++#define RF_GAIN_TX 0x07 /* */ ++ ++#define RF_TXM_IDAC 0x08 /* */ ++#define RF_IPA_G 0x09 /* */ ++#define RF_TXBIAS_G 0x0A ++#define RF_TXPA_AG 0x0B ++#define RF_IPA_A 0x0C /* */ ++#define RF_TXBIAS_A 0x0D ++#define RF_BS_PA_APSET_G9_G11 0x0E ++#define RF_BS_IQGEN 0x0F /* */ ++ ++#define RF_MODE1 0x10 /* */ ++#define RF_MODE2 0x11 /* */ ++ ++#define RF_RX_AGC_HP 0x12 /* */ ++#define RF_TX_AGC 0x13 /* */ ++#define RF_BIAS 0x14 /* */ ++#define RF_IPA 0x15 /* */ ++#define RF_TXBIAS 0x16 ++#define RF_POW_ABILITY 0x17 /* */ ++#define RF_CHNLBW 0x18 /* RF channel and BW switch */ ++#define RF_TOP 0x19 /* */ ++ ++#define RF_RX_G1 0x1A /* */ ++#define RF_RX_G2 0x1B /* */ ++ ++#define RF_RX_BB2 0x1C /* */ ++#define RF_RX_BB1 0x1D /* */ ++ ++#define RF_RCK1 0x1E /* */ ++#define RF_RCK2 0x1F /* */ ++ ++#define RF_TX_G1 0x20 /* */ ++#define RF_TX_G2 0x21 /* */ ++#define RF_TX_G3 0x22 /* */ ++ ++#define RF_TX_BB1 0x23 /* */ ++ ++#define RF_T_METER_92D 0x42 /* */ ++#define RF_T_METER_88E 0x42 /* */ ++#define RF_T_METER 0x24 /* */ ++ ++#define RF_SYN_G1 0x25 /* RF TX Power control */ ++#define RF_SYN_G2 0x26 /* RF TX Power control */ ++#define RF_SYN_G3 0x27 /* RF TX Power control */ ++#define RF_SYN_G4 0x28 /* RF TX Power control */ ++#define RF_SYN_G5 0x29 /* RF TX Power control */ ++#define RF_SYN_G6 0x2A /* RF TX Power control */ ++#define RF_SYN_G7 0x2B /* RF TX Power control */ ++#define RF_SYN_G8 0x2C /* RF TX Power control */ ++ ++#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_TX_BIAS_A 0x35 ++#define RF_TX_BIAS_D 0x36 ++#define RF_LOBF_9 0x38 ++#define RF_RXRF_A3 0x3C /* */ ++#define RF_TRSW 0x3F ++ ++#define RF_TXRF_A2 0x41 ++#define RF_TXPA_G4 0x46 ++#define RF_TXPA_A4 0x4B ++#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 ++ ++#define IS_BB_REG_OFFSET_92S(_Offset) \ ++ ((_Offset >= 0x800) && (_Offset <= 0xfff)) ++ ++/* 2. Page8(0x800) */ ++#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++ ++#define bOFDMRxADCPhase 0x10000 /* Useless now */ ++#define bOFDMTxDACPhase 0x40000 ++#define bXATxAGC 0x3f ++ ++#define bAntennaSelect 0x0300 ++ ++#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++#define bPAStart 0xf0000000 /* Useless now */ ++#define bTRStart 0x00f00000 ++#define bRFStart 0x0000f000 ++#define bBBStart 0x000000f0 ++#define bBBCCKStart 0x0000000f ++#define bPAEnd 0xf /* Reg0x814 */ ++#define bTREnd 0x0f000000 ++#define bRFEnd 0x000f0000 ++#define bCCAMask 0x000000f0 /* T2R */ ++#define bR2RCCAMask 0x00000f00 ++#define bHSSI_R2TDelay 0xf8000000 ++#define bHSSI_T2RDelay 0xf80000 ++#define bContTxHSSI 0x400 /* change gain at continue Tx */ ++#define bIGFromCCK 0x200 ++#define bAGCAddress 0x3f ++#define bRxHPTx 0x7000 ++#define bRxHPT2R 0x38000 ++#define bRxHPCCKIni 0xc0000 ++#define bAGCTxCode 0xc00000 ++#define bAGCRxCode 0x300000 ++ ++/* Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */ ++#define b3WireDataLength 0x800 ++#define b3WireAddressLength 0x400 ++ ++#define b3WireRFPowerDown 0x1 /* Useless now */ ++#define b5GPAPEPolarity 0x40000000 ++#define b2GPAPEPolarity 0x80000000 ++#define bRFSW_TxDefaultAnt 0x3 ++#define bRFSW_TxOptionAnt 0x30 ++#define bRFSW_RxDefaultAnt 0x300 ++#define bRFSW_RxOptionAnt 0x3000 ++#define bRFSI_3WireData 0x1 ++#define bRFSI_3WireClock 0x2 ++#define bRFSI_3WireLoad 0x4 ++#define bRFSI_3WireRW 0x8 ++#define bRFSI_3Wire 0xf ++ ++#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */ ++ ++#define bRFSI_TRSW 0x20 /* Useless now */ ++#define bRFSI_TRSWB 0x40 ++#define bRFSI_ANTSW 0x100 ++#define bRFSI_ANTSWB 0x200 ++#define bRFSI_PAPE 0x400 ++#define bRFSI_PAPE5G 0x800 ++#define bBandSelect 0x1 ++#define bHTSIG2_GI 0x80 ++#define bHTSIG2_Smoothing 0x01 ++#define bHTSIG2_Sounding 0x02 ++#define bHTSIG2_Aggreaton 0x08 ++#define bHTSIG2_STBC 0x30 ++#define bHTSIG2_AdvCoding 0x40 ++#define bHTSIG2_NumOfHTLTF 0x300 ++#define bHTSIG2_CRC8 0x3fc ++#define bHTSIG1_MCS 0x7f ++#define bHTSIG1_BandWidth 0x80 ++#define bHTSIG1_HTLength 0xffff ++#define bLSIG_Rate 0xf ++#define bLSIG_Reserved 0x10 ++#define bLSIG_Length 0x1fffe ++#define bLSIG_Parity 0x20 ++#define bCCKRxPhase 0x4 ++ ++#define bLSSIReadAddress 0x7f800000 /* T65 RF */ ++ ++#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */ ++ ++#define bLSSIReadBackData 0xfffff /* T65 RF */ ++ ++#define bLSSIReadOKFlag 0x1000 /* Useless now */ ++#define bCCKSampleRate 0x8 /* 0: 44MHz, 1:88MHz */ ++#define bRegulator0Standby 0x1 ++#define bRegulatorPLLStandby 0x2 ++#define bRegulator1Standby 0x4 ++#define bPLLPowerUp 0x8 ++#define bDPLLPowerUp 0x10 ++#define bDA10PowerUp 0x20 ++#define bAD7PowerUp 0x200 ++#define bDA6PowerUp 0x2000 ++#define bXtalPowerUp 0x4000 ++#define b40MDClkPowerUP 0x8000 ++#define bDA6DebugMode 0x20000 ++#define bDA6Swing 0x380000 ++ ++/* Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */ ++#define bADClkPhase 0x4000000 ++ ++#define b80MClkDelay 0x18000000 /* Useless */ ++#define bAFEWatchDogEnable 0x20000000 ++ ++/* Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */ ++#define bXtalCap01 0xc0000000 ++#define bXtalCap23 0x3 ++#define bXtalCap92x 0x0f000000 ++#define bXtalCap 0x0f000000 ++ ++#define bIntDifClkEnable 0x400 /* Useless */ ++#define bExtSigClkEnable 0x800 ++#define bBandgapMbiasPowerUp 0x10000 ++#define bAD11SHGain 0xc0000 ++#define bAD11InputRange 0x700000 ++#define bAD11OPCurrent 0x3800000 ++#define bIPathLoopback 0x4000000 ++#define bQPathLoopback 0x8000000 ++#define bAFELoopback 0x10000000 ++#define bDA10Swing 0x7e0 ++#define bDA10Reverse 0x800 ++#define bDAClkSource 0x1000 ++#define bAD7InputRange 0x6000 ++#define bAD7Gain 0x38000 ++#define bAD7OutputCMMode 0x40000 ++#define bAD7InputCMMode 0x380000 ++#define bAD7Current 0xc00000 ++#define bRegulatorAdjust 0x7000000 ++#define bAD11PowerUpAtTx 0x1 ++#define bDA10PSAtTx 0x10 ++#define bAD11PowerUpAtRx 0x100 ++#define bDA10PSAtRx 0x1000 ++#define bCCKRxAGCFormat 0x200 ++#define bPSDFFTSamplepPoint 0xc000 ++#define bPSDAverageNum 0x3000 ++#define bIQPathControl 0xc00 ++#define bPSDFreq 0x3ff ++#define bPSDAntennaPath 0x30 ++#define bPSDIQSwitch 0x40 ++#define bPSDRxTrigger 0x400000 ++#define bPSDTxTrigger 0x80000000 ++#define bPSDSineToneScale 0x7f000000 ++#define bPSDReport 0xffff ++ ++/* 3. Page9(0x900) */ ++#define bOFDMTxSC 0x30000000 /* Useless */ ++#define bCCKTxOn 0x1 ++#define bOFDMTxOn 0x2 ++#define bDebugPage 0xfff /* reset debug page and HWord, LWord */ ++#define bDebugItem 0xff /* reset debug page and LWord */ ++#define bAntL 0x10 ++#define bAntNonHT 0x100 ++#define bAntHT1 0x1000 ++#define bAntHT2 0x10000 ++#define bAntHT1S1 0x100000 ++#define bAntNonHTS1 0x1000000 ++ ++/* 4. PageA(0xA00) */ ++#define bCCKBBMode 0x3 /* Useless */ ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0_System 20/40 */ ++ ++#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 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 ++ ++/* 5. PageC(0xC00) */ ++#define bNumOfSTF 0x3 /* Useless */ ++#define bShift_L 0xc0 ++#define bGI_TH 0xc ++#define bRxPathA 0x1 ++#define bRxPathB 0x2 ++#define bRxPathC 0x4 ++#define bRxPathD 0x8 ++#define bTxPathA 0x1 ++#define bTxPathB 0x2 ++#define bTxPathC 0x4 ++#define bTxPathD 0x8 ++#define bTRSSIFreq 0x200 ++#define bADCBackoff 0x3000 ++#define bDFIRBackoff 0xc000 ++#define bTRSSILatchPhase 0x10000 ++#define bRxIDCOffset 0xff ++#define bRxQDCOffset 0xff00 ++#define bRxDFIRMode 0x1800000 ++#define bRxDCNFType 0xe000000 ++#define bRXIQImb_A 0x3ff ++#define bRXIQImb_B 0xfc00 ++#define bRXIQImb_C 0x3f0000 ++#define bRXIQImb_D 0xffc00000 ++#define bDC_dc_Notch 0x60000 ++#define bRxNBINotch 0x1f000000 ++#define bPD_TH 0xf ++#define bPD_TH_Opt2 0xc000 ++#define bPWED_TH 0x700 ++#define bIfMF_Win_L 0x800 ++#define bPD_Option 0x1000 ++#define bMF_Win_L 0xe000 ++#define bBW_Search_L 0x30000 ++#define bwin_enh_L 0xc0000 ++#define bBW_TH 0x700000 ++#define bED_TH2 0x3800000 ++#define bBW_option 0x4000000 ++#define bRatio_TH 0x18000000 ++#define bWindow_L 0xe0000000 ++#define bSBD_Option 0x1 ++#define bFrame_TH 0x1c ++#define bFS_Option 0x60 ++#define bDC_Slope_check 0x80 ++#define bFGuard_Counter_DC_L 0xe00 ++#define bFrame_Weight_Short 0x7000 ++#define bSub_Tune 0xe00000 ++#define bFrame_DC_Length 0xe000000 ++#define bSBD_start_offset 0x30000000 ++#define bFrame_TH_2 0x7 ++#define bFrame_GI2_TH 0x38 ++#define bGI2_Sync_en 0x40 ++#define bSarch_Short_Early 0x300 ++#define bSarch_Short_Late 0xc00 ++#define bSarch_GI2_Late 0x70000 ++#define bCFOAntSum 0x1 ++#define bCFOAcc 0x2 ++#define bCFOStartOffset 0xc ++#define bCFOLookBack 0x70 ++#define bCFOSumWeight 0x80 ++#define bDAGCEnable 0x10000 ++#define bTXIQImb_A 0x3ff ++#define bTXIQImb_B 0xfc00 ++#define bTXIQImb_C 0x3f0000 ++#define bTXIQImb_D 0xffc00000 ++#define bTxIDCOffset 0xff ++#define bTxQDCOffset 0xff00 ++#define bTxDFIRMode 0x10000 ++#define bTxPesudoNoiseOn 0x4000000 ++#define bTxPesudoNoise_A 0xff ++#define bTxPesudoNoise_B 0xff00 ++#define bTxPesudoNoise_C 0xff0000 ++#define bTxPesudoNoise_D 0xff000000 ++#define bCCADropOption 0x20000 ++#define bCCADropThres 0xfff00000 ++#define bEDCCA_H 0xf ++#define bEDCCA_L 0xf0 ++#define bLambda_ED 0x300 ++#define bRxInitialGain 0x7f ++#define bRxAntDivEn 0x80 ++#define bRxAGCAddressForLNA 0x7f00 ++#define bRxHighPowerFlow 0x8000 ++#define bRxAGCFreezeThres 0xc0000 ++#define bRxFreezeStep_AGC1 0x300000 ++#define bRxFreezeStep_AGC2 0xc00000 ++#define bRxFreezeStep_AGC3 0x3000000 ++#define bRxFreezeStep_AGC0 0xc000000 ++#define bRxRssi_Cmp_En 0x10000000 ++#define bRxQuickAGCEn 0x20000000 ++#define bRxAGCFreezeThresMode 0x40000000 ++#define bRxOverFlowCheckType 0x80000000 ++#define bRxAGCShift 0x7f ++#define bTRSW_Tri_Only 0x80 ++#define bPowerThres 0x300 ++#define bRxAGCEn 0x1 ++#define bRxAGCTogetherEn 0x2 ++#define bRxAGCMin 0x4 ++#define bRxHP_Ini 0x7 ++#define bRxHP_TRLNA 0x70 ++#define bRxHP_RSSI 0x700 ++#define bRxHP_BBP1 0x7000 ++#define bRxHP_BBP2 0x70000 ++#define bRxHP_BBP3 0x700000 ++#define bRSSI_H 0x7f0000 /* threshold for high power */ ++#define bRSSI_Gen 0x7f000000 /* threshold for ant diversity */ ++#define bRxSettle_TRSW 0x7 ++#define bRxSettle_LNA 0x38 ++#define bRxSettle_RSSI 0x1c0 ++#define bRxSettle_BBP 0xe00 ++#define bRxSettle_RxHP 0x7000 ++#define bRxSettle_AntSW_RSSI 0x38000 ++#define bRxSettle_AntSW 0xc0000 ++#define bRxProcessTime_DAGC 0x300000 ++#define bRxSettle_HSSI 0x400000 ++#define bRxProcessTime_BBPPW 0x800000 ++#define bRxAntennaPowerShift 0x3000000 ++#define bRSSITableSelect 0xc000000 ++#define bRxHP_Final 0x7000000 ++#define bRxHTSettle_BBP 0x7 ++#define bRxHTSettle_HSSI 0x8 ++#define bRxHTSettle_RxHP 0x70 ++#define bRxHTSettle_BBPPW 0x80 ++#define bRxHTSettle_Idle 0x300 ++#define bRxHTSettle_Reserved 0x1c00 ++#define bRxHTRxHPEn 0x8000 ++#define bRxHTAGCFreezeThres 0x30000 ++#define bRxHTAGCTogetherEn 0x40000 ++#define bRxHTAGCMin 0x80000 ++#define bRxHTAGCEn 0x100000 ++#define bRxHTDAGCEn 0x200000 ++#define bRxHTRxHP_BBP 0x1c00000 ++#define bRxHTRxHP_Final 0xe0000000 ++#define bRxPWRatioTH 0x3 ++#define bRxPWRatioEn 0x4 ++#define bRxMFHold 0x3800 ++#define bRxPD_Delay_TH1 0x38 ++#define bRxPD_Delay_TH2 0x1c0 ++#define bRxPD_DC_COUNT_MAX 0x600 ++#define bRxPD_Delay_TH 0x8000 ++#define bRxProcess_Delay 0xf0000 ++#define bRxSearchrange_GI2_Early 0x700000 ++#define bRxFrame_Guard_Counter_L 0x3800000 ++#define bRxSGI_Guard_L 0xc000000 ++#define bRxSGI_Search_L 0x30000000 ++#define bRxSGI_TH 0xc0000000 ++#define bDFSCnt0 0xff ++#define bDFSCnt1 0xff00 ++#define bDFSFlag 0xf0000 ++#define bMFWeightSum 0x300000 ++#define bMinIdxTH 0x7f000000 ++#define bDAFormat 0x40000 ++#define bTxChEmuEnable 0x01000000 ++#define bTRSWIsolation_A 0x7f ++#define bTRSWIsolation_B 0x7f00 ++#define bTRSWIsolation_C 0x7f0000 ++#define bTRSWIsolation_D 0x7f000000 ++#define bExtLNAGain 0x7c00 ++ ++/* 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 ++#define bHTDetect 0x100 ++#define bCFOEn 0x10000 ++#define bCFOValue 0xfff00000 ++#define bSigTone_Re 0x3f ++#define bSigTone_Im 0x7f00 ++#define bCounter_CCA 0xffff ++#define bCounter_ParityFail 0xffff0000 ++#define bCounter_RateIllegal 0xffff ++#define bCounter_CRC8Fail 0xffff0000 ++#define bCounter_MCSNoSupport 0xffff ++#define bCounter_FastSync 0xffff ++#define bShortCFO 0xfff ++#define bShortCFOTLength 12 /* total */ ++#define bShortCFOFLength 11 /* fraction */ ++#define bLongCFO 0x7ff ++#define bLongCFOTLength 11 ++#define bLongCFOFLength 11 ++#define bTailCFO 0x1fff ++#define bTailCFOTLength 13 ++#define bTailCFOFLength 12 ++#define bmax_en_pwdB 0xffff ++#define bCC_power_dB 0xffff0000 ++#define bnoise_pwdB 0xffff ++#define bPowerMeasTLength 10 ++#define bPowerMeasFLength 3 ++#define bRx_HT_BW 0x1 ++#define bRxSC 0x6 ++#define bRx_HT 0x8 ++#define bNB_intf_det_on 0x1 ++#define bIntf_win_len_cfg 0x30 ++#define bNB_Intf_TH_cfg 0x1c0 ++#define bRFGain 0x3f ++#define bTableSel 0x40 ++#define bTRSW 0x80 ++#define bRxSNR_A 0xff ++#define bRxSNR_B 0xff00 ++#define bRxSNR_C 0xff0000 ++#define bRxSNR_D 0xff000000 ++#define bSNREVMTLength 8 ++#define bSNREVMFLength 1 ++#define bCSI1st 0xff ++#define bCSI2nd 0xff00 ++#define bRxEVM1st 0xff0000 ++#define bRxEVM2nd 0xff000000 ++#define bSIGEVM 0xff ++#define bPWDB 0xff00 ++#define bSGIEN 0x10000 ++ ++#define bSFactorQAM1 0xf /* Useless */ ++#define bSFactorQAM2 0xf0 ++#define bSFactorQAM3 0xf00 ++#define bSFactorQAM4 0xf000 ++#define bSFactorQAM5 0xf0000 ++#define bSFactorQAM6 0xf0000 ++#define bSFactorQAM7 0xf00000 ++#define bSFactorQAM8 0xf000000 ++#define bSFactorQAM9 0xf0000000 ++#define bCSIScheme 0x100000 ++ ++#define bNoiseLvlTopSet 0x3 /* Useless */ ++#define bChSmooth 0x4 ++#define bChSmoothCfg1 0x38 ++#define bChSmoothCfg2 0x1c0 ++#define bChSmoothCfg3 0xe00 ++#define bChSmoothCfg4 0x7000 ++#define bMRCMode 0x800000 ++#define bTHEVMCfg 0x7000000 ++ ++#define bLoopFitType 0x1 /* Useless */ ++#define bUpdCFO 0x40 ++#define bUpdCFOOffData 0x80 ++#define bAdvUpdCFO 0x100 ++#define bAdvTimeCtrl 0x800 ++#define bUpdClko 0x1000 ++#define bFC 0x6000 ++#define bTrackingMode 0x8000 ++#define bPhCmpEnable 0x10000 ++#define bUpdClkoLTF 0x20000 ++#define bComChCFO 0x40000 ++#define bCSIEstiMode 0x80000 ++#define bAdvUpdEqz 0x100000 ++#define bUChCfg 0x7000000 ++#define bUpdEqz 0x8000000 ++ ++/* Rx Pseduo noise */ ++#define bRxPesudoNoiseOn 0x20000000 /* Useless */ ++#define bRxPesudoNoise_A 0xff ++#define bRxPesudoNoise_B 0xff00 ++#define bRxPesudoNoise_C 0xff0000 ++#define bRxPesudoNoise_D 0xff000000 ++#define bPesudoNoiseState_A 0xffff ++#define bPesudoNoiseState_B 0xffff0000 ++#define bPesudoNoiseState_C 0xffff ++#define bPesudoNoiseState_D 0xffff0000 ++ ++/* 7. RF Register */ ++/* Zebra1 */ ++#define bZebra1_HSSIEnable 0x8 /* Useless */ ++#define bZebra1_TRxControl 0xc00 ++#define bZebra1_TRxGainSetting 0x07f ++#define bZebra1_RxCorner 0xc00 ++#define bZebra1_TxChargePump 0x38 ++#define bZebra1_RxChargePump 0x7 ++#define bZebra1_ChannelNum 0xf80 ++#define bZebra1_TxLPFBW 0x400 ++#define bZebra1_RxLPFBW 0x600 ++ ++/* Zebra4 */ ++#define bRTL8256RegModeCtrl1 0x100 /* Useless */ ++#define bRTL8256RegModeCtrl0 0x40 ++#define bRTL8256_TxLPFBW 0x18 ++#define bRTL8256_RxLPFBW 0x600 ++ ++/* RTL8258 */ ++#define bRTL8258_TxLPFBW 0xc /* Useless */ ++#define bRTL8258_RxLPFBW 0xc00 ++#define bRTL8258_RSSILPFBW 0xc0 ++ ++/* */ ++/* Other Definition */ ++/* */ ++ ++/* byte endable for sb_write */ ++#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 bMask12Bits 0xfff ++#define bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++ ++/* for PutRFRegsetting & GetRFRegSetting BitMask */ ++#define bRFRegOffsetMask 0xfffff ++ ++#define bEnable 0x1 /* Useless */ ++#define bDisable 0x0 ++ ++#define LeftAntenna 0x0 /* Useless */ ++#define RightAntenna 0x1 ++ ++#define tCheckTxStatus 500 /* 500ms Useless */ ++#define tUpdateRxCounter 100 /* 100ms */ ++ ++#define rateCCK 0 /* Useless */ ++#define rateOFDM 1 ++#define rateHT 2 ++ ++/* define Register-End */ ++#define bPMAC_End 0x1ff /* Useless */ ++#define bFPGAPHY0_End 0x8ff ++#define bFPGAPHY1_End 0x9ff ++#define bCCKPHY0_End 0xaff ++#define bOFDMPHY0_End 0xcff ++#define bOFDMPHY1_End 0xdff ++ ++#define bPMACControl 0x0 /* Useless */ ++#define bWMACControl 0x1 ++#define bWNICControl 0x2 ++ ++#define PathA 0x0 /* Useless */ ++#define PathB 0x1 ++#define PathC 0x2 ++#define PathD 0x3 ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/Hal8188EPwrSeq.h b/drivers/staging/r8188eu/include/Hal8188EPwrSeq.h +new file mode 100644 +index 000000000000..a73bd1a5d57b +--- /dev/null ++++ b/drivers/staging/r8188eu/include/Hal8188EPwrSeq.h +@@ -0,0 +1,155 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __HAL8188EPWRSEQ_H__ ++#define __HAL8188EPWRSEQ_H__ ++ ++#include "HalPwrSeqCmd.h" ++ ++/* ++ Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.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 ++ ++ PWR SEQ Version: rtl8188E_PwrSeq_V09.h ++*/ ++#define RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS 10 ++#define RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS 10 ++#define RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS 10 ++#define RTL8188E_TRANS_SUS_TO_CARDEMU_STEPS 10 ++#define RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS 10 ++#define RTL8188E_TRANS_PDN_TO_CARDEMU_STEPS 10 ++#define RTL8188E_TRANS_ACT_TO_LPS_STEPS 15 ++#define RTL8188E_TRANS_LPS_TO_ACT_STEPS 15 ++#define RTL8188E_TRANS_END_STEPS 1 ++ ++#define RTL8188E_TRANS_CARDEMU_TO_ACT \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},/* wait till 0x04[17] = 1 power ready*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0)|BIT(1), 0}, /* 0x02[1:0] = 0 reset BB*/ \ ++ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}, /*0x24[23] = 2b'01 schmit trigger */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}, /* 0x04[15] = 0 disable HWPDN (control by DRV)*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3), 0}, /*0x04[12:11] = 2b'00 disable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*0x04[8] = 1 polling until return 0*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0}, /*wait till 0x04[8] = 0*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*LDO normal mode*/ \ ++ {0x0074, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*SDIO Driving*/ \ ++ ++#define RTL8188E_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*/ \ ++ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*LDO Sleep mode*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, /*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, BIT(1), 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \ ++ ++#define RTL8188E_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_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01enable WL suspend*/ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)}, /*0x04[12:11] = 2b'11enable WL suspend for PCIe*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, BIT(7)}, /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */ \ ++ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*Clear SIC_EN register 0x40[12] = 1'b0 */ \ ++ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*Set USB suspend enable local register 0xfe10[4]=1 */ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(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, BIT(1), 0}, /*wait power state to suspend*/ ++ ++#define RTL8188E_TRANS_SUS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 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, BIT(1), BIT(1)}, /*wait power state to suspend*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ ++ ++#define RTL8188E_TRANS_CARDEMU_TO_CARDDIS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}, /*0x24[23] = 2b'01 schmit trigger */ \ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \ ++ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */ \ ++ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*Clear SIC_EN register 0x40[12] = 1'b0 */ \ ++ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*Set USB suspend enable local register 0xfe10[4]=1 */ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(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, BIT(1), 0}, /*wait power state to suspend*/ ++ ++#define RTL8188E_TRANS_CARDDIS_TO_CARDEMU \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 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, BIT(1), BIT(1)}, /*wait power state to suspend*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/ ++ ++#define RTL8188E_TRANS_CARDEMU_TO_PDN \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here*/ \ ++ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},/* 0x04[16] = 0*/\ ++ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},/* 0x04[15] = 1*/ ++ ++#define RTL8188E_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, BIT(7), 0},/* 0x04[15] = 0*/ ++ ++/* This is used by driver for LPSRadioOff Procedure, not for FW LPS Step */ ++#define RTL8188E_TRANS_ACT_TO_LPS \ ++ /* format */ \ ++ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here */ \ ++ {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*/ \ ++ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 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*/ \ ++ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/ \ ++ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},/*check if removed later*/ \ ++ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)},/*Respond TxOK to scheduler*/ \ ++ ++#define RTL8188E_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, BIT(4), 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, BIT(7), 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, BIT(6)|BIT(7), 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, BIT(1), BIT(1)}, /*. 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, BIT(1)|BIT(0), BIT(1)|BIT(0)}, /*. 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 RTL8188E_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 struct wl_pwr_cfg rtl8188E_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern struct wl_pwr_cfg rtl8188E_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern struct wl_pwr_cfg rtl8188E_card_disable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern struct wl_pwr_cfg rtl8188E_card_enable_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern struct wl_pwr_cfg rtl8188E_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern struct wl_pwr_cfg rtl8188E_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern struct wl_pwr_cfg rtl8188E_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS+RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern struct wl_pwr_cfg rtl8188E_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS+RTL8188E_TRANS_END_STEPS]; ++extern struct wl_pwr_cfg rtl8188E_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS+RTL8188E_TRANS_END_STEPS]; ++ ++#endif /* __HAL8188EPWRSEQ_H__ */ +diff --git a/drivers/staging/r8188eu/include/Hal8188ERateAdaptive.h b/drivers/staging/r8188eu/include/Hal8188ERateAdaptive.h +new file mode 100644 +index 000000000000..d5ced507a648 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/Hal8188ERateAdaptive.h +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright (c) 2011 Realtek Semiconductor Corp. */ ++ ++#ifndef __INC_RA_H ++#define __INC_RA_H ++/* Module Name: RateAdaptive.h ++ * Abstract: Prototype of RA and related data structure. ++ */ ++ ++#include ++ ++/* Rate adaptive define */ ++#define PERENTRY 23 ++#define RETRYSIZE 5 ++#define RATESIZE 28 ++#define TX_RPT2_ITEM_SIZE 8 ++ ++/* TX report 2 format in Rx desc */ ++#define GET_TX_RPT2_DESC_PKT_LEN_88E(__rxstatusdesc) \ ++ le32_get_bits(*(__le32 *)__rxstatusdesc, GENMASK(8, 0)) ++#define GET_TX_RPT2_DESC_MACID_VALID_1_88E(__rxstatusdesc) \ ++ le32_to_cpu((*(__le32 *)(__rxstatusdesc + 16)) ++#define GET_TX_RPT2_DESC_MACID_VALID_2_88E(__rxstatusdesc) \ ++ le32_to_cpu((*(__le32 *)(__rxstatusdesc + 20)) ++ ++#define GET_TX_REPORT_TYPE1_RERTY_0(__paddr) \ ++ le16_get_bits(*(__le16 *)__paddr, GENMASK(15, 0)) ++#define GET_TX_REPORT_TYPE1_RERTY_1(__paddr) \ ++ LE_BITS_TO_1BYTE(__paddr + 2, 0, 8) ++#define GET_TX_REPORT_TYPE1_RERTY_2(__paddr) \ ++ LE_BITS_TO_1BYTE(__paddr + 3, 0, 8) ++#define GET_TX_REPORT_TYPE1_RERTY_3(__paddr) \ ++ LE_BITS_TO_1BYTE(__paddr + 4, 0, 8) ++#define GET_TX_REPORT_TYPE1_RERTY_4(__paddr) \ ++ LE_BITS_TO_1BYTE(__paddr + 5, 0, 8) ++#define GET_TX_REPORT_TYPE1_DROP_0(__paddr) \ ++ LE_BITS_TO_1BYTE(__paddr + 6, 0, 8) ++/* End rate adaptive define */ ++ ++void ODM_RASupport_Init(struct odm_dm_struct *dm_odm); ++ ++int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm); ++ ++int ODM_RAInfo_Init(struct odm_dm_struct *dm_odm, u8 MacID); ++ ++u8 ODM_RA_GetShortGI_8188E(struct odm_dm_struct *dm_odm, u8 MacID); ++ ++u8 ODM_RA_GetDecisionRate_8188E(struct odm_dm_struct *dm_odm, u8 MacID); ++ ++u8 ODM_RA_GetHwPwrStatus_8188E(struct odm_dm_struct *dm_odm, u8 MacID); ++void ODM_RA_UpdateRateInfo_8188E(struct odm_dm_struct *dm_odm, u8 MacID, ++ u8 RateID, u32 RateMask, ++ u8 SGIEnable); ++ ++void ODM_RA_SetRSSI_8188E(struct odm_dm_struct *dm_odm, u8 macid, ++ u8 rssi); ++ ++void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, ++ u8 *txrpt_buf, u16 txrpt_len, ++ u32 validentry0, u32 validentry1); ++ ++void ODM_RA_Set_TxRPT_Time(struct odm_dm_struct *dm_odm, u16 minRptTime); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/HalHWImg8188E_BB.h b/drivers/staging/r8188eu/include/HalHWImg8188E_BB.h +new file mode 100644 +index 000000000000..8270fdbc2844 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/HalHWImg8188E_BB.h +@@ -0,0 +1,27 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __INC_BB_8188E_HW_IMG_H ++#define __INC_BB_8188E_HW_IMG_H ++ ++/* static bool CheckCondition(const u32 Condition, const u32 Hex); */ ++ ++/****************************************************************************** ++* AGC_TAB_1T.TXT ++******************************************************************************/ ++ ++enum HAL_STATUS ODM_ReadAndConfig_AGC_TAB_1T_8188E(struct odm_dm_struct *odm); ++ ++/****************************************************************************** ++* PHY_REG_1T.TXT ++******************************************************************************/ ++ ++enum HAL_STATUS ODM_ReadAndConfig_PHY_REG_1T_8188E(struct odm_dm_struct *odm); ++ ++/****************************************************************************** ++* PHY_REG_PG.TXT ++******************************************************************************/ ++ ++void ODM_ReadAndConfig_PHY_REG_PG_8188E(struct odm_dm_struct *dm_odm); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/HalHWImg8188E_FW.h b/drivers/staging/r8188eu/include/HalHWImg8188E_FW.h +new file mode 100644 +index 000000000000..5ddcd283097b +--- /dev/null ++++ b/drivers/staging/r8188eu/include/HalHWImg8188E_FW.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __INC_FW_8188E_HW_IMG_H ++#define __INC_FW_8188E_HW_IMG_H ++ ++/****************************************************************************** ++* FW_AP.TXT ++******************************************************************************/ ++/****************************************************************************** ++* FW_WoWLAN.TXT ++******************************************************************************/ ++#define ArrayLength_8188E_FW_WoWLAN 15764 ++extern const u8 Array_8188E_FW_WoWLAN[ArrayLength_8188E_FW_WoWLAN]; ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/HalHWImg8188E_MAC.h b/drivers/staging/r8188eu/include/HalHWImg8188E_MAC.h +new file mode 100644 +index 000000000000..391c1754b0b6 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/HalHWImg8188E_MAC.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __INC_MAC_8188E_HW_IMG_H ++#define __INC_MAC_8188E_HW_IMG_H ++ ++/****************************************************************************** ++* MAC_REG.TXT ++******************************************************************************/ ++ ++enum HAL_STATUS ODM_ReadAndConfig_MAC_REG_8188E(struct odm_dm_struct *pDM_Odm); ++ ++#endif /* end of HWIMG_SUPPORT */ +diff --git a/drivers/staging/r8188eu/include/HalHWImg8188E_RF.h b/drivers/staging/r8188eu/include/HalHWImg8188E_RF.h +new file mode 100644 +index 000000000000..0c67c3df20b9 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/HalHWImg8188E_RF.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __INC_RF_8188E_HW_IMG_H ++#define __INC_RF_8188E_HW_IMG_H ++ ++/****************************************************************************** ++ * RadioA_1T.TXT ++ ******************************************************************************/ ++ ++enum HAL_STATUS ODM_ReadAndConfig_RadioA_1T_8188E(struct odm_dm_struct *odm); ++ ++#endif /* end of HWIMG_SUPPORT */ +diff --git a/drivers/staging/r8188eu/include/HalPhyRf_8188e.h b/drivers/staging/r8188eu/include/HalPhyRf_8188e.h +new file mode 100644 +index 000000000000..d4a27662309f +--- /dev/null ++++ b/drivers/staging/r8188eu/include/HalPhyRf_8188e.h +@@ -0,0 +1,41 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __HAL_PHY_RF_8188E_H__ ++#define __HAL_PHY_RF_8188E_H__ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++#define IQK_DELAY_TIME_88E 10 /* ms */ ++#define index_mapping_NUM_88E 15 ++#define AVG_THERMAL_NUM_88E 4 ++ ++void ODM_TxPwrTrackAdjust88E(struct odm_dm_struct *pDM_Odm, ++ u8 Type, /* 0 = OFDM, 1 = CCK */ ++ u8 *pDirection,/* 1 = +(incr) 2 = -(decr) */ ++ u32 *pOutWriteVal); /* Tx tracking CCK/OFDM BB ++ * swing index adjust */ ++ ++void odm_TXPowerTrackingCallback_ThermalMeter_8188E(struct adapter *Adapter); ++ ++/* 1 7. IQK */ ++ ++void PHY_IQCalibrate_8188E(struct adapter *Adapter, bool ReCovery); ++ ++/* LC calibrate */ ++void PHY_LCCalibrate_8188E(struct adapter *pAdapter); ++ ++/* AP calibrate */ ++void PHY_DigitalPredistortion_8188E(struct adapter *pAdapter); ++ ++void _PHY_SaveADDARegisters(struct adapter *pAdapter, u32 *ADDAReg, ++ u32 *ADDABackup, u32 RegisterNum); ++ ++void _PHY_PathADDAOn(struct adapter *pAdapter, u32 *ADDAReg, ++ bool isPathAOn, bool is2T); ++ ++void _PHY_MACSettingCalibration(struct adapter *pAdapter, u32 *MACReg, ++ u32 *MACBackup); ++ ++void _PHY_PathAStandBy(struct adapter *pAdapter); ++ ++#endif /* #ifndef __HAL_PHY_RF_8188E_H__ */ +diff --git a/drivers/staging/r8188eu/include/HalPwrSeqCmd.h b/drivers/staging/r8188eu/include/HalPwrSeqCmd.h +new file mode 100644 +index 000000000000..fe7ac910beb8 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/HalPwrSeqCmd.h +@@ -0,0 +1,110 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __HALPWRSEQCMD_H__ ++#define __HALPWRSEQCMD_H__ ++ ++#include "drv_types.h" ++ ++/*---------------------------------------------*/ ++/* 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 ++ ++enum pwrseq_cmd_delat_unit { ++ PWRSEQ_DELAY_US, ++ PWRSEQ_DELAY_MS, ++}; ++ ++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; ++}; ++ ++#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(struct adapter *padapter, u8 CutVersion, u8 FabVersion, ++ u8 InterfaceType, struct wl_pwr_cfg PwrCfgCmd[]); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/HalVerDef.h b/drivers/staging/r8188eu/include/HalVerDef.h +new file mode 100644 +index 000000000000..a0f5bf52e75a +--- /dev/null ++++ b/drivers/staging/r8188eu/include/HalVerDef.h +@@ -0,0 +1,149 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++#ifndef __HAL_VERSION_DEF_H__ ++#define __HAL_VERSION_DEF_H__ ++ ++enum HAL_IC_TYPE { ++ CHIP_8192S = 0, ++ CHIP_8188C = 1, ++ CHIP_8192C = 2, ++ CHIP_8192D = 3, ++ CHIP_8723A = 4, ++ CHIP_8188E = 5, ++ CHIP_8881A = 6, ++ CHIP_8812A = 7, ++ CHIP_8821A = 8, ++ CHIP_8723B = 9, ++ CHIP_8192E = 10, ++}; ++ ++enum HAL_CHIP_TYPE { ++ TEST_CHIP = 0, ++ NORMAL_CHIP = 1, ++ FPGA = 2, ++}; ++ ++enum HAL_CUT_VERSION { ++ 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, ++}; ++ ++enum HAL_VENDOR { ++ CHIP_VENDOR_TSMC = 0, ++ CHIP_VENDOR_UMC = 1, ++}; ++ ++enum HAL_RF_TYPE { ++ 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, ++}; ++ ++struct HAL_VERSION { ++ enum HAL_IC_TYPE ICType; ++ enum HAL_CHIP_TYPE ChipType; ++ enum HAL_CUT_VERSION CUTVersion; ++ enum HAL_VENDOR VendorType; ++ enum HAL_RF_TYPE RFType; ++ u8 ROMVer; ++}; ++ ++/* Get element */ ++#define GET_CVID_IC_TYPE(version) (((version).ICType)) ++#define GET_CVID_CHIP_TYPE(version) (((version).ChipType)) ++#define GET_CVID_RF_TYPE(version) (((version).RFType)) ++#define GET_CVID_MANUFACTUER(version) (((version).VendorType)) ++#define GET_CVID_CUT_VERSION(version) (((version).CUTVersion)) ++#define GET_CVID_ROM_VERSION(version) (((version).ROMVer) & ROM_VERSION_MASK) ++ ++/* Common Macro. -- */ ++/* HAL_VERSION VersionID */ ++ ++/* HAL_IC_TYPE_E */ ++#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) ++#define IS_8188E(version) \ ++ ((GET_CVID_IC_TYPE(version) == CHIP_8188E) ? 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) ++ ++/* 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) ++ ++/* 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) ++ ++/* Chip version Macro. -- */ ++#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 +diff --git a/drivers/staging/r8188eu/include/basic_types.h b/drivers/staging/r8188eu/include/basic_types.h +new file mode 100644 +index 000000000000..d82b2171d584 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/basic_types.h +@@ -0,0 +1,123 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __BASIC_TYPES_H__ ++#define __BASIC_TYPES_H__ ++ ++#define SUCCESS 0 ++#define FAIL (-1) ++ ++#include ++#define NDIS_OID uint ++ ++typedef void (*proc_t)(void *); ++ ++#define FIELD_OFFSET(s, field) ((ssize_t)&((s *)(0))->field) ++ ++#define MEM_ALIGNMENT_OFFSET (sizeof(size_t)) ++#define MEM_ALIGNMENT_PADDING (sizeof(size_t) - 1) ++ ++/* port from fw */ ++/* TODO: Macros Below are Sync from SD7-Driver. It is necessary ++ * to check correctness */ ++ ++/* ++ * Call endian free function when ++ * 1. Read/write packet content. ++ * 2. Before write integer to IO. ++ * 3. After read integer from IO. ++*/ ++ ++/* Convert little data endian to host ordering */ ++#define EF1BYTE(_val) \ ++ ((u8)(_val)) ++#define EF2BYTE(_val) \ ++ (le16_to_cpu(_val)) ++#define EF4BYTE(_val) \ ++ (le32_to_cpu(_val)) ++ ++/* Read data from memory */ ++#define READEF1BYTE(_ptr) \ ++ EF1BYTE(*((u8 *)(_ptr))) ++/* Read le16 data from memory and convert to host ordering */ ++#define READEF2BYTE(_ptr) \ ++ EF2BYTE(*(_ptr)) ++#define READEF4BYTE(_ptr) \ ++ EF4BYTE(*(_ptr)) ++ ++/* Write data to memory */ ++#define WRITEEF1BYTE(_ptr, _val) \ ++ do { \ ++ (*((u8 *)(_ptr))) = EF1BYTE(_val) \ ++ } while (0) ++/* Write le data to memory in host ordering */ ++#define WRITEEF2BYTE(_ptr, _val) \ ++ do { \ ++ (*((u16 *)(_ptr))) = EF2BYTE(_val) \ ++ } while (0) ++ ++#define WRITEEF4BYTE(_ptr, _val) \ ++ do { \ ++ (*((u32 *)(_ptr))) = EF2BYTE(_val) \ ++ } while (0) ++ ++/* Create a bit mask ++ * Examples: ++ * BIT_LEN_MASK_32(0) => 0x00000000 ++ * BIT_LEN_MASK_32(1) => 0x00000001 ++ * BIT_LEN_MASK_32(2) => 0x00000003 ++ * BIT_LEN_MASK_32(32) => 0xFFFFFFFF ++ */ ++#define BIT_LEN_MASK_32(__bitlen) \ ++ (0xFFFFFFFF >> (32 - (__bitlen))) ++#define BIT_LEN_MASK_16(__bitlen) \ ++ (0xFFFF >> (16 - (__bitlen))) ++#define BIT_LEN_MASK_8(__bitlen) \ ++ (0xFF >> (8 - (__bitlen))) ++ ++/* Create an offset bit mask ++ * Examples: ++ * BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003 ++ * BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000 ++ */ ++#define BIT_OFFSET_LEN_MASK_32(__bitoffset, __bitlen) \ ++ (BIT_LEN_MASK_32(__bitlen) << (__bitoffset)) ++#define BIT_OFFSET_LEN_MASK_16(__bitoffset, __bitlen) \ ++ (BIT_LEN_MASK_16(__bitlen) << (__bitoffset)) ++#define BIT_OFFSET_LEN_MASK_8(__bitoffset, __bitlen) \ ++ (BIT_LEN_MASK_8(__bitlen) << (__bitoffset)) ++ ++/*Description: ++ * Return 4-byte value in host byte ordering from ++ * 4-byte pointer in little-endian system. ++ */ ++#define LE_P4BYTE_TO_HOST_4BYTE(__pstart) \ ++ (EF4BYTE(*((__le32 *)(__pstart)))) ++#define LE_P2BYTE_TO_HOST_2BYTE(__pstart) \ ++ (EF2BYTE(*((__le16 *)(__pstart)))) ++#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ ++ (EF1BYTE(*((u8 *)(__pstart)))) ++ ++/*Description: ++Translate subfield (continuous bits in little-endian) of 4-byte ++value to host byte ordering.*/ ++#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ ++ ( \ ++ (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \ ++ BIT_LEN_MASK_32(__bitlen) \ ++ ) ++#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ ++ ( \ ++ (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \ ++ BIT_LEN_MASK_16(__bitlen) \ ++ ) ++#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ ++ ( \ ++ (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \ ++ BIT_LEN_MASK_8(__bitlen) \ ++ ) ++ ++#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ ++ (__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) ++ ++#endif /* __BASIC_TYPES_H__ */ +diff --git a/drivers/staging/r8188eu/include/drv_types.h b/drivers/staging/r8188eu/include/drv_types.h +new file mode 100644 +index 000000000000..04f4224c11de +--- /dev/null ++++ b/drivers/staging/r8188eu/include/drv_types.h +@@ -0,0 +1,323 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++/*----------------------------------------------------------------------------- ++ ++ For type defines and data structure defines ++ ++------------------------------------------------------------------------------*/ ++ ++#ifndef __DRV_TYPES_H__ ++#define __DRV_TYPES_H__ ++ ++#define DRV_NAME "r8188eu" ++#define CONFIG_88EU_AP_MODE 1 ++#define CONFIG_88EU_P2P 1 ++ ++#include "osdep_service.h" ++#include "wlan_bssdef.h" ++#include "rtw_ht.h" ++#include "rtw_cmd.h" ++#include "rtw_xmit.h" ++#include "rtw_recv.h" ++#include "hal_intf.h" ++#include "hal_com.h" ++#include "rtw_security.h" ++#include "rtw_pwrctrl.h" ++#include "rtw_io.h" ++#include "rtw_eeprom.h" ++#include "sta_info.h" ++#include "rtw_mlme.h" ++#include "rtw_debug.h" ++#include "rtw_rf.h" ++#include "rtw_event.h" ++#include "rtw_led.h" ++#include "rtw_mlme_ext.h" ++#include "rtw_p2p.h" ++#include "rtw_ap.h" ++#include "rtw_mp.h" ++#include "rtw_br_ext.h" ++ ++#define DRIVERVERSION "v4.1.4_6773.20130222" ++ ++#define SPEC_DEV_ID_NONE BIT(0) ++#define SPEC_DEV_ID_DISABLE_HT BIT(1) ++#define SPEC_DEV_ID_ENABLE_PS BIT(2) ++#define SPEC_DEV_ID_RF_CONFIG_1T1R BIT(3) ++#define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4) ++#define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5) ++ ++struct specific_device_id { ++ u32 flags; ++ u16 idVendor; ++ u16 idProduct; ++}; ++ ++struct registry_priv { ++ u8 chip_version; ++ u8 rfintfs; ++ u8 lbkmode; ++ u8 hci; ++ struct ndis_802_11_ssid ssid; ++ u8 network_mode; /* infra, ad-hoc, auto */ ++ u8 channel;/* ad-hoc support requirement */ ++ u8 wireless_mode;/* A, B, G, auto */ ++ u8 scan_mode;/* active, passive */ ++ u8 radio_enable; ++ u8 preamble;/* long, short, auto */ ++ u8 vrtl_carrier_sense;/* Enable, Disable, Auto */ ++ u8 vcs_type;/* RTS/CTS, CTS-to-self */ ++ u16 rts_thresh; ++ u16 frag_thresh; ++ u8 adhoc_tx_pwr; ++ u8 soft_ap; ++ u8 power_mgnt; ++ u8 ips_mode; ++ u8 smart_ps; ++ u8 long_retry_lmt; ++ u8 short_retry_lmt; ++ u16 busy_thresh; ++ u8 ack_policy; ++ u8 mp_mode; ++ u8 software_encrypt; ++ u8 software_decrypt; ++ u8 acm_method; ++ /* UAPSD */ ++ u8 wmm_enable; ++ u8 uapsd_enable; ++ u8 uapsd_max_sp; ++ u8 uapsd_acbk_en; ++ u8 uapsd_acbe_en; ++ u8 uapsd_acvi_en; ++ u8 uapsd_acvo_en; ++ ++ u8 led_enable; ++ ++ struct wlan_bssid_ex dev_network; ++ ++ u8 ht_enable; ++ u8 cbw40_enable; ++ u8 ampdu_enable;/* for tx */ ++ u8 rx_stbc; ++ u8 ampdu_amsdu;/* A-MPDU Supports A-MSDU is permitted */ ++ u8 lowrate_two_xmit; ++ ++ u8 rf_config; ++ u8 low_power; ++ ++ u8 wifi_spec;/* !turbo_mode */ ++ ++ u8 channel_plan; ++ bool bAcceptAddbaReq; ++ ++ u8 antdiv_cfg; ++ u8 antdiv_type; ++ ++ u8 usbss_enable;/* 0:disable,1:enable */ ++ u8 hwpdn_mode;/* 0:disable,1:enable,2:decide by EFUSE config */ ++ u8 hwpwrp_detect;/* 0:disable,1:enable */ ++ ++ u8 hw_wps_pbc;/* 0:disable,1:enable */ ++ ++ u8 max_roaming_times; /* the max number driver will try */ ++ ++ u8 fw_iol; /* enable iol without other concern */ ++ ++ u8 enable80211d; ++ ++ u8 ifname[16]; ++ u8 if2name[16]; ++ ++ u8 notch_filter; ++}; ++ ++/* For registry parameters */ ++#define RGTRY_OFT(field) ((u32)FIELD_OFFSET(struct registry_priv, field)) ++#define RGTRY_SZ(field) sizeof(((struct registry_priv *)0)->field) ++#define BSSID_OFT(field) ((u32)FIELD_OFFSET(struct wlan_bssid_ex, field)) ++#define BSSID_SZ(field) sizeof(((struct wlan_bssid_ex *)0)->field) ++ ++#define MAX_CONTINUAL_URB_ERR 4 ++ ++struct rt_firmware { ++ u8 *szFwBuffer; ++ u32 ulFwLength; ++}; ++ ++struct dvobj_priv { ++ struct adapter *if1; ++ struct adapter *if2; ++ ++ /* For 92D, DMDP have 2 interface. */ ++ u8 InterfaceNumber; ++ u8 NumInterfaces; ++ ++ /* In /Out Pipe information */ ++ int RtInPipe[2]; ++ int RtOutPipe[3]; ++ u8 Queue2Pipe[HW_QUEUE_ENTRY];/* for out pipe mapping */ ++ ++ u8 irq_alloc; ++ ++ struct rt_firmware firmware; ++ ++/*-------- below is for USB INTERFACE --------*/ ++ ++ u8 nr_endpoint; ++ u8 ishighspeed; ++ u8 RtNumInPipes; ++ u8 RtNumOutPipes; ++ int ep_num[5]; /* endpoint number */ ++ int RegUsbSS; ++ struct semaphore usb_suspend_sema; ++ struct mutex usb_vendor_req_mutex; ++ ++ u8 *usb_alloc_vendor_req_buf; ++ u8 *usb_vendor_req_buf; ++ ++ struct usb_interface *pusbintf; ++ struct usb_device *pusbdev; ++ ++ atomic_t continual_urb_error; ++ u8 signal_strength; ++}; ++ ++static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj) ++{ ++ /* todo: get interface type from dvobj and the return ++ * the dev accordingly */ ++ return &dvobj->pusbintf->dev; ++}; ++ ++enum _IFACE_TYPE { ++ IFACE_PORT0, /* mapping to port0 for C/D series chips */ ++ IFACE_PORT1, /* mapping to port1 for C/D series chip */ ++ MAX_IFACE_PORT, ++}; ++ ++enum _ADAPTER_TYPE { ++ PRIMARY_ADAPTER, ++ SECONDARY_ADAPTER, ++ MAX_ADAPTER, ++}; ++ ++enum driver_state { ++ DRIVER_NORMAL = 0, ++ DRIVER_DISAPPEAR = 1, ++ DRIVER_REPLACE_DONGLE = 2, ++}; ++ ++struct adapter { ++ int DriverState;/* for disable driver using module, use dongle toi ++ * replace module. */ ++ int pid[3];/* process id from UI, 0:wps, 1:hostapd, 2:dhcpcd */ ++ int bDongle;/* build-in module or external dongle */ ++ u16 chip_type; ++ u16 HardwareType; ++ u16 interface_type;/* USB,SDIO,SPI,PCI */ ++ ++ struct dvobj_priv *dvobj; ++ struct mlme_priv mlmepriv; ++ struct mlme_ext_priv mlmeextpriv; ++ struct cmd_priv cmdpriv; ++ struct evt_priv evtpriv; ++ struct io_priv iopriv; ++ struct xmit_priv xmitpriv; ++ struct recv_priv recvpriv; ++ struct sta_priv stapriv; ++ struct security_priv securitypriv; ++ struct registry_priv registrypriv; ++ struct pwrctrl_priv pwrctrlpriv; ++ struct eeprom_priv eeprompriv; ++ struct led_priv ledpriv; ++ struct mp_priv mppriv; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ struct hostapd_priv *phostapdpriv; ++#endif ++ ++ struct wifidirect_info wdinfo; ++ ++ void *HalData; ++ u32 hal_data_sz; ++ struct hal_ops HalFunc; ++ ++ s32 bDriverStopped; ++ s32 bSurpriseRemoved; ++ s32 bCardDisableWOHSM; ++ ++ u32 IsrContent; ++ u32 ImrContent; ++ ++ u8 EepromAddressSize; ++ u8 hw_init_completed; ++ u8 bDriverIsGoingToUnload; ++ u8 init_adpt_in_progress; ++ u8 bHaltInProgress; ++ s8 signal_strength; ++ ++ void *cmdThread; ++ void *evtThread; ++ void *xmitThread; ++ void *recvThread; ++ void (*intf_start)(struct adapter *adapter); ++ void (*intf_stop)(struct adapter *adapter); ++ struct net_device *pnetdev; ++ ++ /* used by rtw_rereg_nd_name related function */ ++ struct rereg_nd_name_data { ++ struct net_device *old_pnetdev; ++ char old_ifname[IFNAMSIZ]; ++ u8 old_ips_mode; ++ u8 old_bRegUseLed; ++ } rereg_nd_name_priv; ++ ++ int bup; ++ struct net_device_stats stats; ++ struct iw_statistics iwstats; ++ struct proc_dir_entry *dir_dev;/* for proc directory */ ++ ++ int net_closed; ++ u8 bFWReady; ++ u8 bBTFWReady; ++ u8 bReadPortCancel; ++ u8 bWritePortCancel; ++ u8 bRxRSSIDisplay; ++ /* The driver will show up the desired channel number ++ * when this flag is 1. */ ++ u8 bNotifyChannelChange; ++#ifdef CONFIG_88EU_P2P ++ /* The driver will show the current P2P status when the ++ * upper application reads it. */ ++ u8 bShowGetP2PState; ++#endif ++ struct adapter *pbuddy_adapter; ++ ++ struct mutex *hw_init_mutex; ++ ++ spinlock_t br_ext_lock; ++ struct nat25_network_db_entry *nethash[NAT25_HASH_SIZE]; ++ int pppoe_connection_in_progress; ++ unsigned char pppoe_addr[MACADDRLEN]; ++ unsigned char scdb_mac[MACADDRLEN]; ++ unsigned char scdb_ip[4]; ++ struct nat25_network_db_entry *scdb_entry; ++ unsigned char br_mac[MACADDRLEN]; ++ unsigned char br_ip[4]; ++ struct br_ext_info ethBrExtInfo; ++ ++ u8 fix_rate; ++ ++ unsigned char in_cta_test; ++}; ++ ++#define adapter_to_dvobj(adapter) (adapter->dvobj) ++ ++int rtw_handle_dualmac(struct adapter *adapter, bool init); ++ ++static inline u8 *myid(struct eeprom_priv *peepriv) ++{ ++ return peepriv->mac_addr; ++} ++ ++#endif /* __DRV_TYPES_H__ */ +diff --git a/drivers/staging/r8188eu/include/hal_com.h b/drivers/staging/r8188eu/include/hal_com.h +new file mode 100644 +index 000000000000..95167f0b327f +--- /dev/null ++++ b/drivers/staging/r8188eu/include/hal_com.h +@@ -0,0 +1,156 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __HAL_COMMON_H__ ++#define __HAL_COMMON_H__ ++ ++/* */ ++/* Rate Definition */ ++/* */ ++/* CCK */ ++#define RATR_1M 0x00000001 ++#define RATR_2M 0x00000002 ++#define RATR_55M 0x00000004 ++#define RATR_11M 0x00000008 ++/* OFDM */ ++#define RATR_6M 0x00000010 ++#define RATR_9M 0x00000020 ++#define RATR_12M 0x00000040 ++#define RATR_18M 0x00000080 ++#define RATR_24M 0x00000100 ++#define RATR_36M 0x00000200 ++#define RATR_48M 0x00000400 ++#define RATR_54M 0x00000800 ++/* MCS 1 Spatial Stream */ ++#define RATR_MCS0 0x00001000 ++#define RATR_MCS1 0x00002000 ++#define RATR_MCS2 0x00004000 ++#define RATR_MCS3 0x00008000 ++#define RATR_MCS4 0x00010000 ++#define RATR_MCS5 0x00020000 ++#define RATR_MCS6 0x00040000 ++#define RATR_MCS7 0x00080000 ++/* MCS 2 Spatial Stream */ ++#define RATR_MCS8 0x00100000 ++#define RATR_MCS9 0x00200000 ++#define RATR_MCS10 0x00400000 ++#define RATR_MCS11 0x00800000 ++#define RATR_MCS12 0x01000000 ++#define RATR_MCS13 0x02000000 ++#define RATR_MCS14 0x04000000 ++#define RATR_MCS15 0x08000000 ++ ++/* CCK */ ++#define RATE_1M BIT(0) ++#define RATE_2M BIT(1) ++#define RATE_5_5M BIT(2) ++#define RATE_11M BIT(3) ++/* OFDM */ ++#define RATE_6M BIT(4) ++#define RATE_9M BIT(5) ++#define RATE_12M BIT(6) ++#define RATE_18M BIT(7) ++#define RATE_24M BIT(8) ++#define RATE_36M BIT(9) ++#define RATE_48M BIT(10) ++#define RATE_54M BIT(11) ++/* MCS 1 Spatial Stream */ ++#define RATE_MCS0 BIT(12) ++#define RATE_MCS1 BIT(13) ++#define RATE_MCS2 BIT(14) ++#define RATE_MCS3 BIT(15) ++#define RATE_MCS4 BIT(16) ++#define RATE_MCS5 BIT(17) ++#define RATE_MCS6 BIT(18) ++#define RATE_MCS7 BIT(19) ++/* MCS 2 Spatial Stream */ ++#define RATE_MCS8 BIT(20) ++#define RATE_MCS9 BIT(21) ++#define RATE_MCS10 BIT(22) ++#define RATE_MCS11 BIT(23) ++#define RATE_MCS12 BIT(24) ++#define RATE_MCS13 BIT(25) ++#define RATE_MCS14 BIT(26) ++#define RATE_MCS15 BIT(27) ++ ++/* ALL CCK Rate */ ++#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M) ++#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M | \ ++ RATR_24M | RATR_36M | RATR_48M | RATR_54M) ++#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \ ++ RATR_MCS3 | RATR_MCS4 | RATR_MCS5|RATR_MCS6 | \ ++ RATR_MCS7) ++#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \ ++ RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \ ++ RATR_MCS14 | RATR_MCS15) ++ ++/*------------------------------ Tx Desc definition Macro --------------------*/ ++/* pragma mark -- Tx Desc related definition. -- */ ++/* Rate */ ++/* CCK Rates, TxHT = 0 */ ++#define DESC_RATE1M 0x00 ++#define DESC_RATE2M 0x01 ++#define DESC_RATE5_5M 0x02 ++#define DESC_RATE11M 0x03 ++ ++/* OFDM Rates, TxHT = 0 */ ++#define DESC_RATE6M 0x04 ++#define DESC_RATE9M 0x05 ++#define DESC_RATE12M 0x06 ++#define DESC_RATE18M 0x07 ++#define DESC_RATE24M 0x08 ++#define DESC_RATE36M 0x09 ++#define DESC_RATE48M 0x0a ++#define DESC_RATE54M 0x0b ++ ++/* MCS Rates, TxHT = 1 */ ++#define DESC_RATEMCS0 0x0c ++#define DESC_RATEMCS1 0x0d ++#define DESC_RATEMCS2 0x0e ++#define DESC_RATEMCS3 0x0f ++#define DESC_RATEMCS4 0x10 ++#define DESC_RATEMCS5 0x11 ++#define DESC_RATEMCS6 0x12 ++#define DESC_RATEMCS7 0x13 ++#define DESC_RATEMCS8 0x14 ++#define DESC_RATEMCS9 0x15 ++#define DESC_RATEMCS10 0x16 ++#define DESC_RATEMCS11 0x17 ++#define DESC_RATEMCS12 0x18 ++#define DESC_RATEMCS13 0x19 ++#define DESC_RATEMCS14 0x1a ++#define DESC_RATEMCS15 0x1b ++#define DESC_RATEMCS15_SG 0x1c ++#define DESC_RATEMCS32 0x20 ++ ++/* 1 Byte long (in unit of TU) */ ++#define REG_P2P_CTWIN 0x0572 ++#define REG_NOA_DESC_SEL 0x05CF ++#define REG_NOA_DESC_DURATION 0x05E0 ++#define REG_NOA_DESC_INTERVAL 0x05E4 ++#define REG_NOA_DESC_START 0x05E8 ++#define REG_NOA_DESC_COUNT 0x05EC ++ ++#include "HalVerDef.h" ++void dump_chip_info(struct HAL_VERSION ChipVersion); ++ ++/* return the final channel plan decision */ ++u8 hal_com_get_channel_plan(struct adapter *padapter, ++ u8 hw_channel_plan, ++ u8 sw_channel_plan, ++ u8 def_channel_plan, ++ bool AutoLoadFail ++); ++ ++u8 MRateToHwRate(u8 rate); ++ ++void HalSetBrateCfg(struct adapter *Adapter, u8 *mBratesOS, u16 *pBrateCfg); ++ ++bool Hal_MappingOutPipe(struct adapter *pAdapter, u8 NumOutPipe); ++ ++void hal_init_macaddr(struct adapter *adapter); ++ ++void c2h_evt_clear(struct adapter *adapter); ++s32 c2h_evt_read(struct adapter *adapter, u8 *buf); ++ ++#endif /* __HAL_COMMON_H__ */ +diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h +new file mode 100644 +index 000000000000..fa252540e596 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/hal_intf.h +@@ -0,0 +1,411 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#ifndef __HAL_INTF_H__ ++#define __HAL_INTF_H__ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "Hal8188EPhyCfg.h" ++ ++enum RTL871X_HCI_TYPE { ++ RTW_PCIE = BIT(0), ++ RTW_USB = BIT(1), ++ RTW_SDIO = BIT(2), ++ RTW_GSPI = BIT(3), ++}; ++ ++enum _CHIP_TYPE { ++ NULL_CHIP_TYPE, ++ RTL8712_8188S_8191S_8192S, ++ RTL8188C_8192C, ++ RTL8192D, ++ RTL8723A, ++ RTL8188E, ++ MAX_CHIP_TYPE ++}; ++ ++enum hw_variables { ++ HW_VAR_MEDIA_STATUS, ++ HW_VAR_MEDIA_STATUS1, ++ HW_VAR_SET_OPMODE, ++ HW_VAR_MAC_ADDR, ++ HW_VAR_BSSID, ++ HW_VAR_INIT_RTS_RATE, ++ HW_VAR_BASIC_RATE, ++ HW_VAR_TXPAUSE, ++ HW_VAR_BCN_FUNC, ++ HW_VAR_CORRECT_TSF, ++ HW_VAR_CHECK_BSSID, ++ HW_VAR_MLME_DISCONNECT, ++ HW_VAR_MLME_SITESURVEY, ++ HW_VAR_MLME_JOIN, ++ HW_VAR_BEACON_INTERVAL, ++ HW_VAR_SLOT_TIME, ++ HW_VAR_RESP_SIFS, ++ HW_VAR_ACK_PREAMBLE, ++ HW_VAR_SEC_CFG, ++ HW_VAR_BCN_VALID, ++ HW_VAR_RF_TYPE, ++ HW_VAR_DM_FLAG, ++ HW_VAR_DM_FUNC_OP, ++ HW_VAR_DM_FUNC_SET, ++ HW_VAR_DM_FUNC_CLR, ++ HW_VAR_CAM_EMPTY_ENTRY, ++ HW_VAR_CAM_INVALID_ALL, ++ HW_VAR_CAM_WRITE, ++ HW_VAR_CAM_READ, ++ HW_VAR_AC_PARAM_VO, ++ HW_VAR_AC_PARAM_VI, ++ HW_VAR_AC_PARAM_BE, ++ HW_VAR_AC_PARAM_BK, ++ HW_VAR_ACM_CTRL, ++ HW_VAR_AMPDU_MIN_SPACE, ++ HW_VAR_AMPDU_FACTOR, ++ HW_VAR_RXDMA_AGG_PG_TH, ++ HW_VAR_SET_RPWM, ++ HW_VAR_H2C_FW_PWRMODE, ++ HW_VAR_H2C_FW_JOINBSSRPT, ++ HW_VAR_FWLPS_RF_ON, ++ HW_VAR_H2C_FW_P2P_PS_OFFLOAD, ++ HW_VAR_TDLS_WRCR, ++ HW_VAR_TDLS_INIT_CH_SEN, ++ HW_VAR_TDLS_RS_RCR, ++ HW_VAR_TDLS_DONE_CH_SEN, ++ HW_VAR_INITIAL_GAIN, ++ HW_VAR_TRIGGER_GPIO_0, ++ HW_VAR_BT_SET_COEXIST, ++ HW_VAR_BT_ISSUE_DELBA, ++ HW_VAR_CURRENT_ANTENNA, ++ HW_VAR_ANTENNA_DIVERSITY_LINK, ++ HW_VAR_ANTENNA_DIVERSITY_SELECT, ++ HW_VAR_SWITCH_EPHY_WoWLAN, ++ HW_VAR_EFUSE_USAGE, ++ HW_VAR_EFUSE_BYTES, ++ HW_VAR_EFUSE_BT_USAGE, ++ HW_VAR_EFUSE_BT_BYTES, ++ HW_VAR_FIFO_CLEARN_UP, ++ HW_VAR_CHECK_TXBUF, ++ HW_VAR_APFM_ON_MAC, /* Auto FSM to Turn On, include clock, isolation, ++ * power control for MAC only */ ++ /* The valid upper nav range for the HW updating, if the true value is ++ * larger than the upper range, the HW won't update it. */ ++ /* Unit in microsecond. 0 means disable this function. */ ++ HW_VAR_NAV_UPPER, ++ HW_VAR_RPT_TIMER_SETTING, ++ HW_VAR_TX_RPT_MAX_MACID, ++ HW_VAR_H2C_MEDIA_STATUS_RPT, ++ HW_VAR_CHK_HI_QUEUE_EMPTY, ++}; ++ ++enum hal_def_variable { ++ HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, ++ HAL_DEF_IS_SUPPORT_ANT_DIV, ++ HAL_DEF_CURRENT_ANTENNA, ++ HAL_DEF_DRVINFO_SZ, ++ HAL_DEF_MAX_RECVBUF_SZ, ++ HAL_DEF_RX_PACKET_OFFSET, ++ HAL_DEF_DBG_DUMP_RXPKT,/* for dbg */ ++ HAL_DEF_DBG_DM_FUNC,/* for dbg */ ++ HAL_DEF_RA_DECISION_RATE, ++ HAL_DEF_RA_SGI, ++ HAL_DEF_PT_PWR_STATUS, ++ HW_VAR_MAX_RX_AMPDU_FACTOR, ++ HW_DEF_RA_INFO_DUMP, ++ HAL_DEF_DBG_DUMP_TXPKT, ++}; ++ ++enum hal_odm_variable { ++ HAL_ODM_STA_INFO, ++ HAL_ODM_P2P_STATE, ++ HAL_ODM_WIFI_DISPLAY_STATE, ++}; ++ ++enum hal_intf_ps_func { ++ HAL_USB_SELECT_SUSPEND, ++ HAL_MAX_ID, ++}; ++ ++typedef s32 (*c2h_id_filter)(u8 id); ++ ++struct hal_ops { ++ u32 (*hal_power_on)(struct adapter *padapter); ++ u32 (*hal_init)(struct adapter *padapter); ++ u32 (*hal_deinit)(struct adapter *padapter); ++ ++ void (*free_hal_data)(struct adapter *padapter); ++ ++ u32 (*inirp_init)(struct adapter *padapter); ++ u32 (*inirp_deinit)(struct adapter *padapter); ++ ++ s32 (*init_xmit_priv)(struct adapter *padapter); ++ ++ s32 (*init_recv_priv)(struct adapter *padapter); ++ void (*free_recv_priv)(struct adapter *padapter); ++ ++ void (*InitSwLeds)(struct adapter *padapter); ++ void (*DeInitSwLeds)(struct adapter *padapter); ++ ++ void (*dm_init)(struct adapter *padapter); ++ void (*dm_deinit)(struct adapter *padapter); ++ void (*read_chip_version)(struct adapter *padapter); ++ ++ void (*init_default_value)(struct adapter *padapter); ++ ++ void (*intf_chip_configure)(struct adapter *padapter); ++ ++ void (*read_adapter_info)(struct adapter *padapter); ++ ++ void (*enable_interrupt)(struct adapter *padapter); ++ void (*disable_interrupt)(struct adapter *padapter); ++ s32 (*interrupt_handler)(struct adapter *padapter); ++ ++ void (*set_bwmode_handler)(struct adapter *padapter, ++ enum ht_channel_width Bandwidth, ++ u8 Offset); ++ void (*set_channel_handler)(struct adapter *padapter, u8 channel); ++ ++ void (*hal_dm_watchdog)(struct adapter *padapter); ++ ++ void (*SetHwRegHandler)(struct adapter *padapter, u8 variable, ++ u8 *val); ++ void (*GetHwRegHandler)(struct adapter *padapter, u8 variable, ++ u8 *val); ++ ++ u8 (*GetHalDefVarHandler)(struct adapter *padapter, ++ enum hal_def_variable eVariable, ++ void *pValue); ++ u8 (*SetHalDefVarHandler)(struct adapter *padapter, ++ enum hal_def_variable eVariable, ++ void *pValue); ++ ++ void (*GetHalODMVarHandler)(struct adapter *padapter, ++ enum hal_odm_variable eVariable, ++ void *pValue1, bool bSet); ++ void (*SetHalODMVarHandler)(struct adapter *padapter, ++ enum hal_odm_variable eVariable, ++ void *pValue1, bool bSet); ++ ++ void (*UpdateRAMaskHandler)(struct adapter *padapter, ++ u32 mac_id, u8 rssi_level); ++ void (*SetBeaconRelatedRegistersHandler)(struct adapter *padapter); ++ ++ void (*Add_RateATid)(struct adapter *adapter, u32 bitmap, u8 arg, ++ u8 rssi_level); ++ void (*run_thread)(struct adapter *adapter); ++ void (*cancel_thread)(struct adapter *adapter); ++ ++ u8 (*AntDivBeforeLinkHandler)(struct adapter *adapter); ++ void (*AntDivCompareHandler)(struct adapter *adapter, ++ struct wlan_bssid_ex *dst, ++ struct wlan_bssid_ex *src); ++ u8 (*interface_ps_func)(struct adapter *padapter, ++ enum hal_intf_ps_func efunc_id, u8 *val); ++ ++ s32 (*hal_xmit)(struct adapter *padapter, ++ struct xmit_frame *pxmitframe); ++ s32 (*mgnt_xmit)(struct adapter *padapter, ++ struct xmit_frame *pmgntframe); ++ s32 (*hal_xmitframe_enqueue)(struct adapter *padapter, ++ struct xmit_frame *pxmitframe); ++ ++ u32 (*read_bbreg)(struct adapter *padapter, u32 RegAddr, ++ u32 BitMask); ++ void (*write_bbreg)(struct adapter *padapter, u32 RegAddr, ++ u32 BitMask, u32 Data); ++ u32 (*read_rfreg)(struct adapter *padapter, ++ enum rf_radio_path eRFPath, u32 RegAddr, ++ u32 BitMask); ++ void (*write_rfreg)(struct adapter *padapter, ++ enum rf_radio_path eRFPath, u32 RegAddr, ++ u32 BitMask, u32 Data); ++ ++ void (*EfusePowerSwitch)(struct adapter *padapter, u8 bWrite, ++ u8 PwrState); ++ void (*ReadEFuse)(struct adapter *padapter, u8 efuseType, u16 _offset, ++ u16 _size_byte, u8 *pbuf, bool bPseudoTest); ++ void (*EFUSEGetEfuseDefinition)(struct adapter *padapter, u8 efuseType, ++ u8 type, void *pOut, bool bPseudoTest); ++ u16 (*EfuseGetCurrentSize)(struct adapter *padapter, u8 efuseType, ++ bool bPseudoTest); ++ int (*Efuse_PgPacketRead)(struct adapter *adapter, u8 offset, ++ u8 *data, bool bPseudoTest); ++ int (*Efuse_PgPacketWrite)(struct adapter *padapter, u8 offset, ++ u8 word_en, u8 *data, bool bPseudoTest); ++ u8 (*Efuse_WordEnableDataWrite)(struct adapter *padapter, ++ u16 efuse_addr, u8 word_en, ++ u8 *data, bool bPseudoTest); ++ bool (*Efuse_PgPacketWrite_BT)(struct adapter *padapter, u8 offset, ++ u8 word_en, u8 *data, bool test); ++ ++ void (*sreset_init_value)(struct adapter *padapter); ++ void (*sreset_reset_value)(struct adapter *padapter); ++ void (*silentreset)(struct adapter *padapter); ++ void (*sreset_xmit_status_check)(struct adapter *padapter); ++ void (*sreset_linked_status_check) (struct adapter *padapter); ++ u8 (*sreset_get_wifi_status)(struct adapter *padapter); ++ ++ int (*IOL_exec_cmds_sync)(struct adapter *padapter, ++ struct xmit_frame *frame, u32 max_wait, ++ u32 bndy_cnt); ++ ++ void (*hal_notch_filter)(struct adapter *adapter, bool enable); ++ void (*hal_reset_security_engine)(struct adapter *adapter); ++ s32 (*c2h_handler)(struct adapter *padapter, ++ struct c2h_evt_hdr *c2h_evt); ++ c2h_id_filter c2h_id_filter_ccx; ++}; ++ ++enum rt_eeprom_type { ++ EEPROM_93C46, ++ EEPROM_93C56, ++ EEPROM_BOOT_EFUSE, ++}; ++ ++#define RF_CHANGE_BY_INIT 0 ++#define RF_CHANGE_BY_IPS BIT(28) ++#define RF_CHANGE_BY_PS BIT(29) ++#define RF_CHANGE_BY_HW BIT(30) ++#define RF_CHANGE_BY_SW BIT(31) ++ ++enum hardware_type { ++ HARDWARE_TYPE_RTL8180, ++ HARDWARE_TYPE_RTL8185, ++ HARDWARE_TYPE_RTL8187, ++ HARDWARE_TYPE_RTL8188, ++ HARDWARE_TYPE_RTL8190P, ++ HARDWARE_TYPE_RTL8192E, ++ HARDWARE_TYPE_RTL819xU, ++ HARDWARE_TYPE_RTL8192SE, ++ HARDWARE_TYPE_RTL8192SU, ++ HARDWARE_TYPE_RTL8192CE, ++ HARDWARE_TYPE_RTL8192CU, ++ HARDWARE_TYPE_RTL8192DE, ++ HARDWARE_TYPE_RTL8192DU, ++ HARDWARE_TYPE_RTL8723AE, ++ HARDWARE_TYPE_RTL8723AU, ++ HARDWARE_TYPE_RTL8723AS, ++ HARDWARE_TYPE_RTL8188EE, ++ HARDWARE_TYPE_RTL8188EU, ++ HARDWARE_TYPE_RTL8188ES, ++ HARDWARE_TYPE_MAX, ++}; ++ ++/* RTL8188E Series */ ++#define IS_HARDWARE_TYPE_8188EE(_Adapter) \ ++(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188EE) ++#define IS_HARDWARE_TYPE_8188EU(_Adapter) \ ++(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188EU) ++#define IS_HARDWARE_TYPE_8188ES(_Adapter) \ ++(((struct adapter *)_Adapter)->HardwareType == HARDWARE_TYPE_RTL8188ES) ++#define IS_HARDWARE_TYPE_8188E(_Adapter) \ ++(IS_HARDWARE_TYPE_8188EE(_Adapter) || IS_HARDWARE_TYPE_8188EU(_Adapter) || \ ++ IS_HARDWARE_TYPE_8188ES(_Adapter)) ++ ++#define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv) ++ ++#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse) ++ ++void rtl8188eu_set_hal_ops(struct adapter *padapter); ++void rtw_hal_def_value_init(struct adapter *padapter); ++ ++void rtw_hal_free_data(struct adapter *padapter); ++ ++void rtw_hal_dm_init(struct adapter *padapter); ++void rtw_hal_dm_deinit(struct adapter *padapter); ++void rtw_hal_sw_led_init(struct adapter *padapter); ++void rtw_hal_sw_led_deinit(struct adapter *padapter); ++ ++u32 rtw_hal_power_on(struct adapter *padapter); ++uint rtw_hal_init(struct adapter *padapter); ++uint rtw_hal_deinit(struct adapter *padapter); ++void rtw_hal_stop(struct adapter *padapter); ++void rtw_hal_set_hwreg(struct adapter *padapter, u8 variable, u8 *val); ++void rtw_hal_get_hwreg(struct adapter *padapter, u8 variable, u8 *val); ++ ++void rtw_hal_chip_configure(struct adapter *padapter); ++void rtw_hal_read_chip_info(struct adapter *padapter); ++void rtw_hal_read_chip_version(struct adapter *padapter); ++ ++u8 rtw_hal_set_def_var(struct adapter *padapter, ++ enum hal_def_variable eVariable, void *pValue); ++u8 rtw_hal_get_def_var(struct adapter *padapter, ++ enum hal_def_variable eVariable, void *pValue); ++ ++void rtw_hal_set_odm_var(struct adapter *padapter, ++ enum hal_odm_variable eVariable, void *pValue1, ++ bool bSet); ++void rtw_hal_get_odm_var(struct adapter *padapter, ++ enum hal_odm_variable eVariable, ++ void *pValue1, bool bSet); ++ ++void rtw_hal_enable_interrupt(struct adapter *padapter); ++void rtw_hal_disable_interrupt(struct adapter *padapter); ++ ++u32 rtw_hal_inirp_init(struct adapter *padapter); ++u32 rtw_hal_inirp_deinit(struct adapter *padapter); ++ ++u8 rtw_hal_intf_ps_func(struct adapter *padapter, ++ enum hal_intf_ps_func efunc_id, u8 *val); ++s32 rtw_hal_xmitframe_enqueue(struct adapter *padapter, ++ struct xmit_frame *pxmitframe); ++ ++s32 rtw_hal_xmit(struct adapter *padapter, struct xmit_frame *pxmitframe); ++s32 rtw_hal_mgnt_xmit(struct adapter *padapter, ++ struct xmit_frame *pmgntframe); ++ ++s32 rtw_hal_init_xmit_priv(struct adapter *padapter); ++ ++s32 rtw_hal_init_recv_priv(struct adapter *padapter); ++void rtw_hal_free_recv_priv(struct adapter *padapter); ++ ++void rtw_hal_update_ra_mask(struct adapter *padapter, u32 mac_id, u8 level); ++void rtw_hal_add_ra_tid(struct adapter *adapt, u32 bitmap, u8 arg, u8 level); ++void rtw_hal_clone_data(struct adapter *dst_adapt, ++ struct adapter *src_adapt); ++void rtw_hal_start_thread(struct adapter *padapter); ++void rtw_hal_stop_thread(struct adapter *padapter); ++ ++void rtw_hal_bcn_related_reg_setting(struct adapter *padapter); ++ ++u32 rtw_hal_read_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask); ++void rtw_hal_write_bbreg(struct adapter *padapter, u32 RegAddr, u32 BitMask, ++ u32 Data); ++u32 rtw_hal_read_rfreg(struct adapter *padapter, enum rf_radio_path eRFPath, ++ u32 RegAddr, u32 BitMask); ++void rtw_hal_write_rfreg(struct adapter *padapter, ++ enum rf_radio_path eRFPath, u32 RegAddr, ++ u32 BitMask, u32 Data); ++ ++s32 rtw_hal_interrupt_handler(struct adapter *padapter); ++ ++void rtw_hal_set_bwmode(struct adapter *padapter, ++ enum ht_channel_width Bandwidth, u8 Offset); ++void rtw_hal_set_chan(struct adapter *padapter, u8 channel); ++void rtw_hal_dm_watchdog(struct adapter *padapter); ++ ++u8 rtw_hal_antdiv_before_linked(struct adapter *padapter); ++void rtw_hal_antdiv_rssi_compared(struct adapter *padapter, ++ struct wlan_bssid_ex *dst, ++ struct wlan_bssid_ex *src); ++ ++void rtw_hal_sreset_init(struct adapter *padapter); ++void rtw_hal_sreset_reset(struct adapter *padapter); ++void rtw_hal_sreset_reset_value(struct adapter *padapter); ++void rtw_hal_sreset_xmit_status_check(struct adapter *padapter); ++void rtw_hal_sreset_linked_status_check(struct adapter *padapter); ++u8 rtw_hal_sreset_get_wifi_status(struct adapter *padapter); ++ ++int rtw_hal_iol_cmd(struct adapter *adapter, struct xmit_frame *xmit_frame, ++ u32 max_wating_ms, u32 bndy_cnt); ++ ++void rtw_hal_notch_filter(struct adapter *adapter, bool enable); ++void rtw_hal_reset_security_engine(struct adapter *adapter); ++ ++s32 rtw_hal_c2h_handler(struct adapter *adapter, ++ struct c2h_evt_hdr *c2h_evt); ++c2h_id_filter rtw_hal_c2h_id_filter_ccx(struct adapter *adapter); ++void indicate_wx_scan_complete_event(struct adapter *padapter); ++u8 rtw_do_join(struct adapter *padapter); ++ ++#endif /* __HAL_INTF_H__ */ +diff --git a/drivers/staging/r8188eu/include/ieee80211.h b/drivers/staging/r8188eu/include/ieee80211.h +new file mode 100644 +index 000000000000..bc5b030e9c40 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/ieee80211.h +@@ -0,0 +1,1226 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __IEEE80211_H ++#define __IEEE80211_H ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "wifi.h" ++#include ++ ++#define MGMT_QUEUE_NUM 5 ++ ++#define ETH_ALEN 6 ++#define ETH_TYPE_LEN 2 ++#define PAYLOAD_TYPE_LEN 1 ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++#define RTL_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 28) ++ ++/* RTL871X_IOCTL_HOSTAPD ioctl() cmd: */ ++enum { ++ RTL871X_HOSTAPD_FLUSH = 1, ++ RTL871X_HOSTAPD_ADD_STA = 2, ++ RTL871X_HOSTAPD_REMOVE_STA = 3, ++ RTL871X_HOSTAPD_GET_INFO_STA = 4, ++ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ ++ RTL871X_HOSTAPD_GET_WPAIE_STA = 5, ++ RTL871X_SET_ENCRYPTION = 6, ++ RTL871X_GET_ENCRYPTION = 7, ++ RTL871X_HOSTAPD_SET_FLAGS_STA = 8, ++ RTL871X_HOSTAPD_GET_RID = 9, ++ RTL871X_HOSTAPD_SET_RID = 10, ++ RTL871X_HOSTAPD_SET_ASSOC_AP_ADDR = 11, ++ RTL871X_HOSTAPD_SET_GENERIC_ELEMENT = 12, ++ RTL871X_HOSTAPD_MLME = 13, ++ RTL871X_HOSTAPD_SCAN_REQ = 14, ++ RTL871X_HOSTAPD_STA_CLEAR_STATS = 15, ++ RTL871X_HOSTAPD_SET_BEACON = 16, ++ RTL871X_HOSTAPD_SET_WPS_BEACON = 17, ++ RTL871X_HOSTAPD_SET_WPS_PROBE_RESP = 18, ++ RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP = 19, ++ RTL871X_HOSTAPD_SET_HIDDEN_SSID = 20, ++ RTL871X_HOSTAPD_SET_MACADDR_ACL = 21, ++ RTL871X_HOSTAPD_ACL_ADD_STA = 22, ++ RTL871X_HOSTAPD_ACL_REMOVE_STA = 23, ++}; ++ ++/* STA flags */ ++#define WLAN_STA_AUTH BIT(0) ++#define WLAN_STA_ASSOC BIT(1) ++#define WLAN_STA_PS BIT(2) ++#define WLAN_STA_TIM BIT(3) ++#define WLAN_STA_PERM BIT(4) ++#define WLAN_STA_AUTHORIZED BIT(5) ++#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ ++#define WLAN_STA_SHORT_PREAMBLE BIT(7) ++#define WLAN_STA_PREAUTH BIT(8) ++#define WLAN_STA_WME BIT(9) ++#define WLAN_STA_MFP BIT(10) ++#define WLAN_STA_HT BIT(11) ++#define WLAN_STA_WPS BIT(12) ++#define WLAN_STA_MAYBE_WPS BIT(13) ++#define WLAN_STA_NONERP BIT(31) ++ ++#endif ++ ++#define IEEE_CMD_SET_WPA_PARAM 1 ++#define IEEE_CMD_SET_WPA_IE 2 ++#define IEEE_CMD_SET_ENCRYPTION 3 ++#define IEEE_CMD_MLME 4 ++ ++#define IEEE_PARAM_WPA_ENABLED 1 ++#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 ++#define IEEE_PARAM_DROP_UNENCRYPTED 3 ++#define IEEE_PARAM_PRIVACY_INVOKED 4 ++#define IEEE_PARAM_AUTH_ALGS 5 ++#define IEEE_PARAM_IEEE_802_1X 6 ++#define IEEE_PARAM_WPAX_SELECT 7 ++ ++#define AUTH_ALG_OPEN_SYSTEM 0x1 ++#define AUTH_ALG_SHARED_KEY 0x2 ++#define AUTH_ALG_LEAP 0x00000004 ++ ++#define IEEE_MLME_STA_DEAUTH 1 ++#define IEEE_MLME_STA_DISASSOC 2 ++ ++#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 ++#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 ++#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 ++#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 ++#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 ++#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 ++ ++#define IEEE_CRYPT_ALG_NAME_LEN 16 ++ ++#define WPA_CIPHER_NONE BIT(0) ++#define WPA_CIPHER_WEP40 BIT(1) ++#define WPA_CIPHER_WEP104 BIT(2) ++#define WPA_CIPHER_TKIP BIT(3) ++#define WPA_CIPHER_CCMP BIT(4) ++ ++ ++#define WPA_SELECTOR_LEN 4 ++extern u8 RTW_WPA_OUI_TYPE[]; ++extern u16 RTW_WPA_VERSION; ++extern u8 WPA_AUTH_KEY_MGMT_NONE[]; ++extern u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[]; ++extern u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[]; ++extern u8 WPA_CIPHER_SUITE_NONE[]; ++extern u8 WPA_CIPHER_SUITE_WEP40[]; ++extern u8 WPA_CIPHER_SUITE_TKIP[]; ++extern u8 WPA_CIPHER_SUITE_WRAP[]; ++extern u8 WPA_CIPHER_SUITE_CCMP[]; ++extern u8 WPA_CIPHER_SUITE_WEP104[]; ++ ++#define RSN_HEADER_LEN 4 ++#define RSN_SELECTOR_LEN 4 ++ ++extern u16 RSN_VERSION_BSD; ++extern u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[]; ++extern u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[]; ++extern u8 RSN_CIPHER_SUITE_NONE[]; ++extern u8 RSN_CIPHER_SUITE_WEP40[]; ++extern u8 RSN_CIPHER_SUITE_TKIP[]; ++extern u8 RSN_CIPHER_SUITE_WRAP[]; ++extern u8 RSN_CIPHER_SUITE_CCMP[]; ++extern u8 RSN_CIPHER_SUITE_WEP104[]; ++ ++enum ratr_table_mode { ++ RATR_INX_WIRELESS_NGB = 0, /* BGN 40 Mhz 2SS 1SS */ ++ RATR_INX_WIRELESS_NG = 1, /* GN or N */ ++ RATR_INX_WIRELESS_NB = 2, /* BGN 20 Mhz 2SS 1SS or BN */ ++ RATR_INX_WIRELESS_N = 3, ++ RATR_INX_WIRELESS_GB = 4, ++ RATR_INX_WIRELESS_G = 5, ++ RATR_INX_WIRELESS_B = 6, ++ RATR_INX_WIRELESS_MC = 7, ++ RATR_INX_WIRELESS_AC_N = 8, ++}; ++ ++enum NETWORK_TYPE { ++ WIRELESS_INVALID = 0, ++ /* Sub-Element */ ++ WIRELESS_11B = BIT(0), /* tx:cck only, rx:cck only, hw: cck */ ++ WIRELESS_11G = BIT(1), /* tx:ofdm only, rx:ofdm & cck, hw:cck & ofdm*/ ++ WIRELESS_11_24N = BIT(3), /* tx:MCS only, rx:MCS & cck, hw:MCS & cck */ ++ ++ /* Combination */ ++ /* tx: cck & ofdm, rx: cck & ofdm & MCS, hw: cck & ofdm */ ++ WIRELESS_11BG = (WIRELESS_11B | WIRELESS_11G), ++ /* tx: ofdm & MCS, rx: ofdm & cck & MCS, hw: cck & ofdm */ ++ WIRELESS_11G_24N = (WIRELESS_11G | WIRELESS_11_24N), ++ /* tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */ ++ WIRELESS_11BG_24N = (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N), ++}; ++ ++#define SUPPORTED_24G_NETTYPE_MSK \ ++ (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N) ++ ++#define IsSupported24G(NetType) \ ++ ((NetType) & SUPPORTED_24G_NETTYPE_MSK ? true : false) ++ ++#define IsEnableHWCCK(NetType) \ ++ IsSupported24G(NetType) ++ ++#define IsSupportedRxCCK(NetType) IsEnableHWCCK(NetType) ++ ++#define IsSupportedTxCCK(NetType) \ ++ ((NetType) & (WIRELESS_11B) ? true : false) ++#define IsSupportedTxOFDM(NetType) \ ++ ((NetType) & (WIRELESS_11G) ? true : false) ++#define IsSupportedTxMCS(NetType) \ ++ ((NetType) & (WIRELESS_11_24N) ? true : false) ++ ++struct ieee_param { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ union { ++ struct { ++ u8 name; ++ u32 value; ++ } wpa_param; ++ struct { ++ u32 len; ++ u8 reserved[32]; ++ u8 data[0]; ++ } wpa_ie; ++ struct { ++ int command; ++ int reason_code; ++ } mlme; ++ struct { ++ u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; ++ u8 set_tx; ++ u32 err; ++ u8 idx; ++ u8 seq[8]; /* sequence counter (set: RX, get: TX) */ ++ u16 key_len; ++ u8 key[0]; ++ } crypt; ++#ifdef CONFIG_88EU_AP_MODE ++ struct { ++ u16 aid; ++ u16 capability; ++ int flags; ++ u8 tx_supp_rates[16]; ++ struct ieee80211_ht_cap ht_cap; ++ } add_sta; ++ struct { ++ u8 reserved[2];/* for set max_num_sta */ ++ u8 buf[0]; ++ } bcn_ie; ++#endif ++ ++ } u; ++}; ++ ++#ifdef CONFIG_88EU_AP_MODE ++struct ieee_param_ex { ++ u32 cmd; ++ u8 sta_addr[ETH_ALEN]; ++ u8 data[0]; ++}; ++ ++struct sta_data { ++ u16 aid; ++ u16 capability; ++ int flags; ++ u32 sta_set; ++ u8 tx_supp_rates[16]; ++ u32 tx_supp_rates_len; ++ struct ieee80211_ht_cap ht_cap; ++ u64 rx_pkts; ++ u64 rx_bytes; ++ u64 rx_drops; ++ u64 tx_pkts; ++ u64 tx_bytes; ++ u64 tx_drops; ++}; ++#endif ++ ++#define IEEE80211_DATA_LEN 2304 ++/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section ++ 6.2.1.1.2. ++ ++ The figure in section 7.1.2 suggests a body size of up to 2312 ++ bytes is allowed, which is a bit confusing, I suspect this ++ represents the 2304 bytes of real data, plus a possible 8 bytes of ++ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ ++ ++#define IEEE80211_HLEN 30 ++#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) ++ ++/* this is stolen from ipw2200 driver */ ++#define IEEE_IBSS_MAC_HASH_SIZE 31 ++ ++struct ieee_ibss_seq { ++ u8 mac[ETH_ALEN]; ++ u16 seq_num; ++ u16 frag_num; ++ unsigned long packet_time; ++ struct list_head list; ++}; ++ ++struct rtw_ieee80211_hdr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++} __packed; ++ ++struct rtw_ieee80211_hdr_3addr { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++} __packed; ++ ++struct rtw_ieee80211_hdr_qos { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u8 addr4[ETH_ALEN]; ++ u16 qc; ++} __packed; ++ ++struct rtw_ieee80211_hdr_3addr_qos { ++ __le16 frame_ctl; ++ __le16 duration_id; ++ u8 addr1[ETH_ALEN]; ++ u8 addr2[ETH_ALEN]; ++ u8 addr3[ETH_ALEN]; ++ u16 seq_ctl; ++ u16 qc; ++} __packed; ++ ++struct eapol { ++ u8 snap[6]; ++ u16 ethertype; ++ u8 version; ++ u8 type; ++ u16 length; ++} __packed; ++ ++enum eap_type { ++ EAP_PACKET = 0, ++ EAPOL_START, ++ EAPOL_LOGOFF, ++ EAPOL_KEY, ++ EAPOL_ENCAP_ASF_ALERT ++}; ++ ++#define IEEE80211_3ADDR_LEN 24 ++#define IEEE80211_4ADDR_LEN 30 ++#define IEEE80211_FCS_LEN 4 ++ ++#define MIN_FRAG_THRESHOLD 256U ++#define MAX_FRAG_THRESHOLD 2346U ++ ++/* Frame control field constants */ ++#define RTW_IEEE80211_FCTL_VERS 0x0003 ++#define RTW_IEEE80211_FCTL_FTYPE 0x000c ++#define RTW_IEEE80211_FCTL_STYPE 0x00f0 ++#define RTW_IEEE80211_FCTL_TODS 0x0100 ++#define RTW_IEEE80211_FCTL_FROMDS 0x0200 ++#define RTW_IEEE80211_FCTL_MOREFRAGS 0x0400 ++#define RTW_IEEE80211_FCTL_RETRY 0x0800 ++#define RTW_IEEE80211_FCTL_PM 0x1000 ++#define RTW_IEEE80211_FCTL_MOREDATA 0x2000 ++#define RTW_IEEE80211_FCTL_PROTECTED 0x4000 ++#define RTW_IEEE80211_FCTL_ORDER 0x8000 ++#define RTW_IEEE80211_FCTL_CTL_EXT 0x0f00 ++ ++#define RTW_IEEE80211_FTYPE_MGMT 0x0000 ++#define RTW_IEEE80211_FTYPE_CTL 0x0004 ++#define RTW_IEEE80211_FTYPE_DATA 0x0008 ++#define RTW_IEEE80211_FTYPE_EXT 0x000c ++ ++/* management */ ++#define RTW_IEEE80211_STYPE_ASSOC_REQ 0x0000 ++#define RTW_IEEE80211_STYPE_ASSOC_RESP 0x0010 ++#define RTW_IEEE80211_STYPE_REASSOC_REQ 0x0020 ++#define RTW_IEEE80211_STYPE_REASSOC_RESP 0x0030 ++#define RTW_IEEE80211_STYPE_PROBE_REQ 0x0040 ++#define RTW_IEEE80211_STYPE_PROBE_RESP 0x0050 ++#define RTW_IEEE80211_STYPE_BEACON 0x0080 ++#define RTW_IEEE80211_STYPE_ATIM 0x0090 ++#define RTW_IEEE80211_STYPE_DISASSOC 0x00A0 ++#define RTW_IEEE80211_STYPE_AUTH 0x00B0 ++#define RTW_IEEE80211_STYPE_DEAUTH 0x00C0 ++#define RTW_IEEE80211_STYPE_ACTION 0x00D0 ++ ++/* control */ ++#define RTW_IEEE80211_STYPE_CTL_EXT 0x0060 ++#define RTW_IEEE80211_STYPE_BACK_REQ 0x0080 ++#define RTW_IEEE80211_STYPE_BACK 0x0090 ++#define RTW_IEEE80211_STYPE_PSPOLL 0x00A0 ++#define RTW_IEEE80211_STYPE_RTS 0x00B0 ++#define RTW_IEEE80211_STYPE_CTS 0x00C0 ++#define RTW_IEEE80211_STYPE_ACK 0x00D0 ++#define RTW_IEEE80211_STYPE_CFEND 0x00E0 ++#define RTW_IEEE80211_STYPE_CFENDACK 0x00F0 ++ ++/* data */ ++#define RTW_IEEE80211_STYPE_DATA 0x0000 ++#define RTW_IEEE80211_STYPE_DATA_CFACK 0x0010 ++#define RTW_IEEE80211_STYPE_DATA_CFPOLL 0x0020 ++#define RTW_IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 ++#define RTW_IEEE80211_STYPE_NULLFUNC 0x0040 ++#define RTW_IEEE80211_STYPE_CFACK 0x0050 ++#define RTW_IEEE80211_STYPE_CFPOLL 0x0060 ++#define RTW_IEEE80211_STYPE_CFACKPOLL 0x0070 ++#define RTW_IEEE80211_STYPE_QOS_DATA 0x0080 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFACK 0x0090 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0 ++#define RTW_IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0 ++#define RTW_IEEE80211_STYPE_QOS_NULLFUNC 0x00C0 ++#define RTW_IEEE80211_STYPE_QOS_CFACK 0x00D0 ++#define RTW_IEEE80211_STYPE_QOS_CFPOLL 0x00E0 ++#define RTW_IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 ++ ++/* sequence control field */ ++#define RTW_IEEE80211_SCTL_FRAG 0x000F ++#define RTW_IEEE80211_SCTL_SEQ 0xFFF0 ++ ++#define RTW_ERP_INFO_NON_ERP_PRESENT BIT(0) ++#define RTW_ERP_INFO_USE_PROTECTION BIT(1) ++#define RTW_ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) ++ ++/* QoS, QOS */ ++#define NORMAL_ACK 0 ++#define NO_ACK 1 ++#define NON_EXPLICIT_ACK 2 ++#define BLOCK_ACK 3 ++ ++#ifndef ETH_P_PAE ++#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ ++#endif /* ETH_P_PAE */ ++ ++#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ ++ ++#define ETH_P_ECONET 0x0018 ++ ++#ifndef ETH_P_80211_RAW ++#define ETH_P_80211_RAW (ETH_P_ECONET + 1) ++#endif ++ ++/* IEEE 802.11 defines */ ++ ++#define P80211_OUI_LEN 3 ++ ++struct ieee80211_snap_hdr { ++ u8 dsap; /* always 0xAA */ ++ u8 ssap; /* always 0xAA */ ++ u8 ctrl; /* always 0x03 */ ++ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ ++} __packed; ++ ++#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) ++ ++#define WLAN_FC_GET_TYPE(fc) ((fc) & RTW_IEEE80211_FCTL_FTYPE) ++#define WLAN_FC_GET_STYPE(fc) ((fc) & RTW_IEEE80211_FCTL_STYPE) ++ ++#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f) ++ ++#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTW_IEEE80211_SCTL_FRAG) ++#define WLAN_GET_SEQ_SEQ(seq) ((seq) & RTW_IEEE80211_SCTL_SEQ) ++ ++/* Authentication algorithms */ ++#define WLAN_AUTH_OPEN 0 ++#define WLAN_AUTH_SHARED_KEY 1 ++ ++#define WLAN_AUTH_CHALLENGE_LEN 128 ++ ++#define WLAN_CAPABILITY_BSS (1<<0) ++#define WLAN_CAPABILITY_IBSS (1<<1) ++#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) ++#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) ++#define WLAN_CAPABILITY_PRIVACY (1<<4) ++#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) ++#define WLAN_CAPABILITY_PBCC (1<<6) ++#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) ++#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) ++ ++/* Status codes */ ++#define WLAN_STATUS_SUCCESS 0 ++#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 ++#define WLAN_STATUS_CAPS_UNSUPPORTED 10 ++#define WLAN_STATUS_REASSOC_NO_ASSOC 11 ++#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 ++#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 ++#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 ++#define WLAN_STATUS_CHALLENGE_FAIL 15 ++#define WLAN_STATUS_AUTH_TIMEOUT 16 ++#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 ++#define WLAN_STATUS_ASSOC_DENIED_RATES 18 ++/* 802.11b */ ++#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 ++ ++/* Reason codes */ ++#define WLAN_REASON_UNSPECIFIED 1 ++#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 ++#define WLAN_REASON_DEAUTH_LEAVING 3 ++#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 ++#define WLAN_REASON_DISASSOC_AP_BUSY 5 ++#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 ++#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 ++#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 ++#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 ++#define WLAN_REASON_JOIN_WRONG_CHANNEL 65534 ++#define WLAN_REASON_EXPIRATION_CHK 65535 ++ ++/* Information Element IDs */ ++#define WLAN_EID_SSID 0 ++#define WLAN_EID_SUPP_RATES 1 ++#define WLAN_EID_FH_PARAMS 2 ++#define WLAN_EID_DS_PARAMS 3 ++#define WLAN_EID_CF_PARAMS 4 ++#define WLAN_EID_TIM 5 ++#define WLAN_EID_IBSS_PARAMS 6 ++#define WLAN_EID_CHALLENGE 16 ++/* EIDs defined by IEEE 802.11h - START */ ++#define WLAN_EID_PWR_CONSTRAINT 32 ++#define WLAN_EID_PWR_CAPABILITY 33 ++#define WLAN_EID_TPC_REQUEST 34 ++#define WLAN_EID_TPC_REPORT 35 ++#define WLAN_EID_SUPPORTED_CHANNELS 36 ++#define WLAN_EID_CHANNEL_SWITCH 37 ++#define WLAN_EID_MEASURE_REQUEST 38 ++#define WLAN_EID_MEASURE_REPORT 39 ++#define WLAN_EID_QUITE 40 ++#define WLAN_EID_IBSS_DFS 41 ++/* EIDs defined by IEEE 802.11h - END */ ++#define WLAN_EID_ERP_INFO 42 ++#define WLAN_EID_HT_CAP 45 ++#define WLAN_EID_RSN 48 ++#define WLAN_EID_EXT_SUPP_RATES 50 ++#define WLAN_EID_MOBILITY_DOMAIN 54 ++#define WLAN_EID_FAST_BSS_TRANSITION 55 ++#define WLAN_EID_TIMEOUT_INTERVAL 56 ++#define WLAN_EID_RIC_DATA 57 ++#define WLAN_EID_HT_OPERATION 61 ++#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 ++#define WLAN_EID_20_40_BSS_COEXISTENCE 72 ++#define WLAN_EID_20_40_BSS_INTOLERANT 73 ++#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 ++#define WLAN_EID_MMIE 76 ++#define WLAN_EID_VENDOR_SPECIFIC 221 ++#define WLAN_EID_GENERIC (WLAN_EID_VENDOR_SPECIFIC) ++ ++#define IEEE80211_MGMT_HDR_LEN 24 ++#define IEEE80211_DATA_HDR3_LEN 24 ++#define IEEE80211_DATA_HDR4_LEN 30 ++ ++#define IEEE80211_STATMASK_SIGNAL (1<<0) ++#define IEEE80211_STATMASK_RSSI (1<<1) ++#define IEEE80211_STATMASK_NOISE (1<<2) ++#define IEEE80211_STATMASK_RATE (1<<3) ++#define IEEE80211_STATMASK_WEMASK 0x7 ++ ++#define IEEE80211_CCK_MODULATION (1<<0) ++#define IEEE80211_OFDM_MODULATION (1<<1) ++ ++#define IEEE80211_24GHZ_BAND (1<<0) ++#define IEEE80211_52GHZ_BAND (1<<1) ++ ++#define IEEE80211_CCK_RATE_LEN 4 ++#define IEEE80211_NUM_OFDM_RATESLEN 8 ++ ++#define IEEE80211_CCK_RATE_1MB 0x02 ++#define IEEE80211_CCK_RATE_2MB 0x04 ++#define IEEE80211_CCK_RATE_5MB 0x0B ++#define IEEE80211_CCK_RATE_11MB 0x16 ++#define IEEE80211_OFDM_RATE_LEN 8 ++#define IEEE80211_OFDM_RATE_6MB 0x0C ++#define IEEE80211_OFDM_RATE_9MB 0x12 ++#define IEEE80211_OFDM_RATE_12MB 0x18 ++#define IEEE80211_OFDM_RATE_18MB 0x24 ++#define IEEE80211_OFDM_RATE_24MB 0x30 ++#define IEEE80211_OFDM_RATE_36MB 0x48 ++#define IEEE80211_OFDM_RATE_48MB 0x60 ++#define IEEE80211_OFDM_RATE_54MB 0x6C ++#define IEEE80211_BASIC_RATE_MASK 0x80 ++ ++#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) ++#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) ++#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) ++#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) ++#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) ++#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) ++#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) ++#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) ++#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) ++#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) ++#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) ++#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) ++ ++#define IEEE80211_CCK_RATES_MASK 0x0000000F ++#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ ++ IEEE80211_CCK_RATE_2MB_MASK) ++#define IEEE80211_CCK_DEFAULT_RATES_MASK \ ++ (IEEE80211_CCK_BASIC_RATES_MASK | \ ++ IEEE80211_CCK_RATE_5MB_MASK | \ ++ IEEE80211_CCK_RATE_11MB_MASK) ++ ++#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 ++#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ ++ IEEE80211_OFDM_RATE_12MB_MASK | \ ++ IEEE80211_OFDM_RATE_24MB_MASK) ++#define IEEE80211_OFDM_DEFAULT_RATES_MASK \ ++ (IEEE80211_OFDM_BASIC_RATES_MASK | \ ++ IEEE80211_OFDM_RATE_9MB_MASK | \ ++ IEEE80211_OFDM_RATE_18MB_MASK | \ ++ IEEE80211_OFDM_RATE_36MB_MASK | \ ++ IEEE80211_OFDM_RATE_48MB_MASK | \ ++ IEEE80211_OFDM_RATE_54MB_MASK) ++#define IEEE80211_DEFAULT_RATES_MASK \ ++ (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ ++ IEEE80211_CCK_DEFAULT_RATES_MASK) ++ ++#define IEEE80211_NUM_OFDM_RATES 8 ++#define IEEE80211_NUM_CCK_RATES 4 ++#define IEEE80211_OFDM_SHIFT_MASK_A 4 ++ ++/* NOTE: This data is for statistical purposes; not all hardware provides this ++ * information for frames received. Not setting these will not cause ++ * any adverse affects. */ ++struct ieee80211_rx_stats { ++ /* u32 mac_time[2]; */ ++ s8 rssi; ++ u8 signal; ++ u8 noise; ++ u8 received_channel; ++ u16 rate; /* in 100 kbps */ ++ /* u8 control; */ ++ u8 mask; ++ u8 freq; ++ u16 len; ++}; ++ ++/* IEEE 802.11 requires that STA supports concurrent reception of at least ++ * three fragmented frames. This define can be increased to support more ++ * concurrent frames, but it should be noted that each entry can consume about ++ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ ++#define IEEE80211_FRAG_CACHE_LEN 4 ++ ++struct ieee80211_frag_entry { ++ u32 first_frag_time; ++ uint seq; ++ uint last_frag; ++ uint qos; /* jackson */ ++ uint tid; /* jackson */ ++ struct sk_buff *skb; ++ u8 src_addr[ETH_ALEN]; ++ u8 dst_addr[ETH_ALEN]; ++}; ++ ++struct ieee80211_stats { ++ uint tx_unicast_frames; ++ uint tx_multicast_frames; ++ uint tx_fragments; ++ uint tx_unicast_octets; ++ uint tx_multicast_octets; ++ uint tx_deferred_transmissions; ++ uint tx_single_retry_frames; ++ uint tx_multiple_retry_frames; ++ uint tx_retry_limit_exceeded; ++ uint tx_discards; ++ uint rx_unicast_frames; ++ uint rx_multicast_frames; ++ uint rx_fragments; ++ uint rx_unicast_octets; ++ uint rx_multicast_octets; ++ uint rx_fcs_errors; ++ uint rx_discards_no_buffer; ++ uint tx_discards_wrong_sa; ++ uint rx_discards_undecryptable; ++ uint rx_message_in_msg_fragments; ++ uint rx_message_in_bad_msg_fragments; ++}; ++ ++struct ieee80211_softmac_stats { ++ uint rx_ass_ok; ++ uint rx_ass_err; ++ uint rx_probe_rq; ++ uint tx_probe_rs; ++ uint tx_beacons; ++ uint rx_auth_rq; ++ uint rx_auth_rs_ok; ++ uint rx_auth_rs_err; ++ uint tx_auth_rq; ++ uint no_auth_rs; ++ uint no_ass_rs; ++ uint tx_ass_rq; ++ uint rx_ass_rq; ++ uint tx_probe_rq; ++ uint reassoc; ++ uint swtxstop; ++ uint swtxawake; ++}; ++ ++#define SEC_KEY_1 (1<<0) ++#define SEC_KEY_2 (1<<1) ++#define SEC_KEY_3 (1<<2) ++#define SEC_KEY_4 (1<<3) ++#define SEC_ACTIVE_KEY (1<<4) ++#define SEC_AUTH_MODE (1<<5) ++#define SEC_UNICAST_GROUP (1<<6) ++#define SEC_LEVEL (1<<7) ++#define SEC_ENABLED (1<<8) ++ ++#define SEC_LEVEL_0 0 /* None */ ++#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ ++#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ ++#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ ++#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ ++ ++#define WEP_KEYS 4 ++#define WEP_KEY_LEN 13 ++ ++struct ieee80211_security { ++ u16 active_key:2, ++ enabled:1, ++ auth_mode:2, ++ auth_algo:4, ++ unicast_uses_group:1; ++ u8 key_sizes[WEP_KEYS]; ++ u8 keys[WEP_KEYS][WEP_KEY_LEN]; ++ u8 level; ++ u16 flags; ++} __packed; ++ ++/* ++ ++ 802.11 data frame from AP ++ ++ ,-------------------------------------------------------------------. ++Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | ++ |------|------|---------|---------|---------|------|---------|------| ++Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | ++ | | tion | (BSSID) | | | ence | data | | ++ `-------------------------------------------------------------------' ++ ++Total: 28-2340 bytes ++ ++*/ ++ ++struct ieee80211_header_data { ++ u16 frame_ctl; ++ u16 duration_id; ++ u8 addr1[6]; ++ u8 addr2[6]; ++ u8 addr3[6]; ++ u16 seq_ctrl; ++}; ++ ++#define BEACON_PROBE_SSID_ID_POSITION 12 ++ ++/* Management Frame Information Element Types */ ++#define MFIE_TYPE_SSID 0 ++#define MFIE_TYPE_RATES 1 ++#define MFIE_TYPE_FH_SET 2 ++#define MFIE_TYPE_DS_SET 3 ++#define MFIE_TYPE_CF_SET 4 ++#define MFIE_TYPE_TIM 5 ++#define MFIE_TYPE_IBSS_SET 6 ++#define MFIE_TYPE_CHALLENGE 16 ++#define MFIE_TYPE_ERP 42 ++#define MFIE_TYPE_RSN 48 ++#define MFIE_TYPE_RATES_EX 50 ++#define MFIE_TYPE_GENERIC 221 ++ ++struct ieee80211_info_element_hdr { ++ u8 id; ++ u8 len; ++} __packed; ++ ++struct ieee80211_info_element { ++ u8 id; ++ u8 len; ++ u8 data[0]; ++} __packed; ++ ++/* ++ * These are the data types that can make up management packets ++ * ++ u16 auth_algorithm; ++ u16 auth_sequence; ++ u16 beacon_interval; ++ u16 capability; ++ u8 current_ap[ETH_ALEN]; ++ u16 listen_interval; ++ struct { ++ u16 association_id:14, reserved:2; ++ } __packed; ++ u32 time_stamp[2]; ++ u16 reason; ++ u16 status; ++*/ ++ ++#define IEEE80211_DEFAULT_TX_ESSID "Penguin" ++#define IEEE80211_DEFAULT_BASIC_RATE 10 ++ ++struct ieee80211_authentication { ++ struct ieee80211_header_data header; ++ u16 algorithm; ++ u16 transaction; ++ u16 status; ++ /* struct ieee80211_info_element_hdr info_element; */ ++} __packed; ++ ++struct ieee80211_probe_response { ++ struct ieee80211_header_data header; ++ u32 time_stamp[2]; ++ u16 beacon_interval; ++ u16 capability; ++ struct ieee80211_info_element info_element; ++} __packed; ++ ++struct ieee80211_probe_request { ++ struct ieee80211_header_data header; ++} __packed; ++ ++struct ieee80211_assoc_request_frame { ++ struct rtw_ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 listen_interval; ++ struct ieee80211_info_element_hdr info_element; ++} __packed; ++ ++struct ieee80211_assoc_response_frame { ++ struct rtw_ieee80211_hdr_3addr header; ++ u16 capability; ++ u16 status; ++ u16 aid; ++} __packed; ++ ++struct ieee80211_txb { ++ u8 nr_frags; ++ u8 encrypted; ++ u16 reserved; ++ u16 frag_size; ++ u16 payload_size; ++ struct sk_buff *fragments[0]; ++}; ++ ++/* SWEEP TABLE ENTRIES NUMBER*/ ++#define MAX_SWEEP_TAB_ENTRIES 42 ++#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 ++/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs ++ * only use 8, and then use extended rates for the remaining supported ++ * rates. Other APs, however, stick all of their supported rates on the ++ * main rates information element... */ ++#define MAX_RATES_LENGTH ((u8)12) ++#define MAX_RATES_EX_LENGTH ((u8)16) ++#define MAX_NETWORK_COUNT 128 ++#define MAX_CHANNEL_NUMBER 161 ++#define IEEE80211_SOFTMAC_SCAN_TIME 400 ++/* HZ / 2) */ ++#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) ++ ++#define CRC_LENGTH 4U ++ ++#define MAX_WPA_IE_LEN (256) ++#define MAX_WPS_IE_LEN (512) ++#define MAX_P2P_IE_LEN (256) ++#define MAX_WFD_IE_LEN (128) ++ ++#define NETWORK_EMPTY_ESSID (1<<0) ++#define NETWORK_HAS_OFDM (1<<1) ++#define NETWORK_HAS_CCK (1<<2) ++ ++#define IEEE80211_DTIM_MBCAST 4 ++#define IEEE80211_DTIM_UCAST 2 ++#define IEEE80211_DTIM_VALID 1 ++#define IEEE80211_DTIM_INVALID 0 ++ ++#define IEEE80211_PS_DISABLED 0 ++#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST ++#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST ++#define IW_ESSID_MAX_SIZE 32 ++/* ++join_res: ++-1: authentication fail ++-2: association fail ++> 0: TID ++*/ ++ ++enum ieee80211_state { ++ /* the card is not linked at all */ ++ IEEE80211_NOLINK = 0, ++ ++ /* IEEE80211_ASSOCIATING* are for BSS client mode ++ * the driver shall not perform RX filtering unless ++ * the state is LINKED. ++ * The driver shall just check for the state LINKED and ++ * defaults to NOLINK for ALL the other states (including ++ * LINKED_SCANNING) ++ */ ++ ++ /* the association procedure will start (wq scheduling)*/ ++ IEEE80211_ASSOCIATING, ++ IEEE80211_ASSOCIATING_RETRY, ++ ++ /* the association procedure is sending AUTH request*/ ++ IEEE80211_ASSOCIATING_AUTHENTICATING, ++ ++ /* the association procedure has successfully authentcated ++ * and is sending association request ++ */ ++ IEEE80211_ASSOCIATING_AUTHENTICATED, ++ ++ /* the link is ok. the card associated to a BSS or linked ++ * to a ibss cell or acting as an AP and creating the bss ++ */ ++ IEEE80211_LINKED, ++ ++ /* same as LINKED, but the driver shall apply RX filter ++ * rules as we are in NO_LINK mode. As the card is still ++ * logically linked, but it is doing a syncro site survey ++ * then it will be back to LINKED state. ++ */ ++ IEEE80211_LINKED_SCANNING, ++ ++}; ++ ++#define DEFAULT_MAX_SCAN_AGE (15 * HZ) ++#define DEFAULT_FTS 2346 ++ ++static inline int is_multicast_mac_addr(const u8 *addr) ++{ ++ return ((addr[0] != 0xff) && (0x01 & addr[0])); ++} ++ ++static inline int is_broadcast_mac_addr(const u8 *addr) ++{ ++ return (addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && ++ (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff); ++} ++ ++#define CFG_IEEE80211_RESERVE_FCS (1<<0) ++#define CFG_IEEE80211_COMPUTE_FCS (1<<1) ++ ++struct tx_pending { ++ int frag; ++ struct ieee80211_txb *txb; ++}; ++ ++#define MAXTID 16 ++ ++#define IEEE_A (1<<0) ++#define IEEE_B (1<<1) ++#define IEEE_G (1<<2) ++#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) ++ ++/* Baron move to ieee80211.c */ ++int ieee80211_is_empty_essid(const char *essid, int essid_len); ++int ieee80211_get_hdrlen(u16 fc); ++ ++/* Action category code */ ++enum rtw_ieee80211_category { ++ RTW_WLAN_CATEGORY_SPECTRUM_MGMT = 0, ++ RTW_WLAN_CATEGORY_QOS = 1, ++ RTW_WLAN_CATEGORY_DLS = 2, ++ RTW_WLAN_CATEGORY_BACK = 3, ++ RTW_WLAN_CATEGORY_PUBLIC = 4, /* IEEE 802.11 public action frames */ ++ RTW_WLAN_CATEGORY_RADIO_MEASUREMENT = 5, ++ RTW_WLAN_CATEGORY_FT = 6, ++ RTW_WLAN_CATEGORY_HT = 7, ++ RTW_WLAN_CATEGORY_SA_QUERY = 8, ++ RTW_WLAN_CATEGORY_TDLS = 12, ++ RTW_WLAN_CATEGORY_WMM = 17, ++ RTW_WLAN_CATEGORY_P2P = 0x7f,/* P2P action frames */ ++}; ++ ++/* SPECTRUM_MGMT action code */ ++enum rtw_ieee80211_spectrum_mgmt_actioncode { ++ RTW_WLAN_ACTION_SPCT_MSR_REQ = 0, ++ RTW_WLAN_ACTION_SPCT_MSR_RPRT = 1, ++ RTW_WLAN_ACTION_SPCT_TPC_REQ = 2, ++ RTW_WLAN_ACTION_SPCT_TPC_RPRT = 3, ++ RTW_WLAN_ACTION_SPCT_CHL_SWITCH = 4, ++ RTW_WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5, ++}; ++ ++enum _PUBLIC_ACTION { ++ ACT_PUBLIC_BSSCOEXIST = 0, /* 20/40 BSS Coexistence */ ++ ACT_PUBLIC_DSE_ENABLE = 1, ++ ACT_PUBLIC_DSE_DEENABLE = 2, ++ ACT_PUBLIC_DSE_REG_LOCATION = 3, ++ ACT_PUBLIC_EXT_CHL_SWITCH = 4, ++ ACT_PUBLIC_DSE_MSR_REQ = 5, ++ ACT_PUBLIC_DSE_MSR_RPRT = 6, ++ ACT_PUBLIC_MP = 7, /* Measurement Pilot */ ++ ACT_PUBLIC_DSE_PWR_CONSTRAINT = 8, ++ ACT_PUBLIC_VENDOR = 9, /* for WIFI_DIRECT */ ++ ACT_PUBLIC_GAS_INITIAL_REQ = 10, ++ ACT_PUBLIC_GAS_INITIAL_RSP = 11, ++ ACT_PUBLIC_GAS_COMEBACK_REQ = 12, ++ ACT_PUBLIC_GAS_COMEBACK_RSP = 13, ++ ACT_PUBLIC_TDLS_DISCOVERY_RSP = 14, ++ ACT_PUBLIC_LOCATION_TRACK = 15, ++ ACT_PUBLIC_MAX ++}; ++ ++/* BACK action code */ ++enum rtw_ieee80211_back_actioncode { ++ RTW_WLAN_ACTION_ADDBA_REQ = 0, ++ RTW_WLAN_ACTION_ADDBA_RESP = 1, ++ RTW_WLAN_ACTION_DELBA = 2, ++}; ++ ++/* HT features action code */ ++enum rtw_ieee80211_ht_actioncode { ++ RTW_WLAN_ACTION_NOTIFY_CH_WIDTH = 0, ++ RTW_WLAN_ACTION_SM_PS = 1, ++ RTW_WLAN_ACTION_PSPM = 2, ++ RTW_WLAN_ACTION_PCO_PHASE = 3, ++ RTW_WLAN_ACTION_MIMO_CSI_MX = 4, ++ RTW_WLAN_ACTION_MIMO_NONCP_BF = 5, ++ RTW_WLAN_ACTION_MIMP_CP_BF = 6, ++ RTW_WLAN_ACTION_ASEL_INDICATES_FB = 7, ++ RTW_WLAN_ACTION_HI_INFO_EXCHG = 8, ++}; ++ ++/* BACK (block-ack) parties */ ++enum rtw_ieee80211_back_parties { ++ RTW_WLAN_BACK_RECIPIENT = 0, ++ RTW_WLAN_BACK_INITIATOR = 1, ++ RTW_WLAN_BACK_TIMER = 2, ++}; ++ ++#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) ++ * 00:50:F2 */ ++#define WME_OUI_TYPE 2 ++#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0 ++#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1 ++#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2 ++#define WME_VERSION 1 ++ ++#define WME_ACTION_CODE_SETUP_REQUEST 0 ++#define WME_ACTION_CODE_SETUP_RESPONSE 1 ++#define WME_ACTION_CODE_TEARDOWN 2 ++ ++#define WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED 0 ++#define WME_SETUP_RESPONSE_STATUS_INVALID_PARAMETERS 1 ++#define WME_SETUP_RESPONSE_STATUS_REFUSED 3 ++ ++#define WME_TSPEC_DIRECTION_UPLINK 0 ++#define WME_TSPEC_DIRECTION_DOWNLINK 1 ++#define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3 ++ ++#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */ ++ ++#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */ ++ ++/** ++ * enum rtw_ieee80211_channel_flags - channel flags ++ * ++ * Channel flags set by the regulatory control code. ++ * ++ * @RTW_IEEE80211_CHAN_DISABLED: This channel is disabled. ++ * @RTW_IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted ++ * on this channel. ++ * @RTW_IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. ++ * @RTW_IEEE80211_CHAN_RADAR: Radar detection is required on this channel. ++ * @RTW_IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel ++ * is not permitted. ++ * @RTW_IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel ++ * is not permitted. ++ */ ++enum rtw_ieee80211_channel_flags { ++ RTW_IEEE80211_CHAN_DISABLED = 1<<0, ++ RTW_IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, ++ RTW_IEEE80211_CHAN_NO_IBSS = 1<<2, ++ RTW_IEEE80211_CHAN_RADAR = 1<<3, ++ RTW_IEEE80211_CHAN_NO_HT40PLUS = 1<<4, ++ RTW_IEEE80211_CHAN_NO_HT40MINUS = 1<<5, ++}; ++ ++#define RTW_IEEE80211_CHAN_NO_HT40 \ ++ (RTW_IEEE80211_CHAN_NO_HT40PLUS | RTW_IEEE80211_CHAN_NO_HT40MINUS) ++ ++/* Represent channel details, subset of ieee80211_channel */ ++struct rtw_ieee80211_channel { ++ u16 hw_value; ++ u32 flags; ++}; ++ ++#define CHAN_FMT \ ++ "hw_value:%u, " \ ++ "flags:0x%08x" \ ++ ++#define CHAN_ARG(channel) \ ++ (channel)->hw_value \ ++ , (channel)->flags \ ++ ++/* Parsed Information Elements */ ++struct rtw_ieee802_11_elems { ++ u8 *ssid; ++ u8 ssid_len; ++ u8 *supp_rates; ++ u8 supp_rates_len; ++ u8 *fh_params; ++ u8 fh_params_len; ++ u8 *ds_params; ++ u8 ds_params_len; ++ u8 *cf_params; ++ u8 cf_params_len; ++ u8 *tim; ++ u8 tim_len; ++ u8 *ibss_params; ++ u8 ibss_params_len; ++ u8 *challenge; ++ u8 challenge_len; ++ u8 *erp_info; ++ u8 erp_info_len; ++ u8 *ext_supp_rates; ++ u8 ext_supp_rates_len; ++ u8 *wpa_ie; ++ u8 wpa_ie_len; ++ u8 *rsn_ie; ++ u8 rsn_ie_len; ++ u8 *wme; ++ u8 wme_len; ++ u8 *wme_tspec; ++ u8 wme_tspec_len; ++ u8 *wps_ie; ++ u8 wps_ie_len; ++ u8 *power_cap; ++ u8 power_cap_len; ++ u8 *supp_channels; ++ u8 supp_channels_len; ++ u8 *mdie; ++ u8 mdie_len; ++ u8 *ftie; ++ u8 ftie_len; ++ u8 *timeout_int; ++ u8 timeout_int_len; ++ u8 *ht_capabilities; ++ u8 ht_capabilities_len; ++ u8 *ht_operation; ++ u8 ht_operation_len; ++ u8 *vendor_ht_cap; ++ u8 vendor_ht_cap_len; ++}; ++ ++enum parse_res { ++ ParseOK = 0, ++ ParseUnknown = 1, ++ ParseFailed = -1 ++}; ++ ++enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len, ++ struct rtw_ieee802_11_elems *elems, ++ int show_errors); ++ ++u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, ++ unsigned char *source, unsigned int *frlen); ++u8 *rtw_set_ie(u8 *pbuf, int index, uint len, u8 *source, uint *frlen); ++ ++enum secondary_ch_offset { ++ SCN = 0, /* no secondary channel */ ++ SCA = 1, /* secondary channel above */ ++ SCB = 3, /* secondary channel below */ ++}; ++u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset); ++u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset); ++u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode, ++ u8 new_ch, u8 ch_switch_cnt); ++u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, ++ u8 secondary_ch_offset); ++u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, ++ u8 flags, u16 reason, u16 precedence); ++ ++u8 *rtw_get_ie(u8 *pbuf, int index, int *len, int limit); ++u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, ++ u8 oui_len, u8 *ie, uint *ielen); ++int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, ++ u8 eid, u8 *oui, u8 oui_len); ++ ++void rtw_set_supported_rate(u8 *SupportedRates, uint mode); ++ ++unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit); ++unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit); ++int rtw_get_wpa_cipher_suite(u8 *s); ++int rtw_get_wpa2_cipher_suite(u8 *s); ++int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len); ++int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, ++ int *pairwise_cipher, int *is_8021x); ++int rtw_parse_wpa2_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, ++ int *pairwise_cipher, int *is_8021x); ++ ++int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, ++ u8 *wpa_ie, u16 *wpa_len); ++ ++u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen); ++u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen); ++u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, ++ u8 *buf_attr, u32 *len_attr); ++u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, ++ u8 *buf_content, uint *len_content); ++ ++/** ++ * for_each_ie - iterate over continuous IEs ++ * @ie: ++ * @buf: ++ * @buf_len: ++ */ ++#define for_each_ie(ie, buf, buf_len) \ ++ for (ie = (void *)buf; (((u8 *)ie) - ((u8 *)buf) + 1) < buf_len; \ ++ ie = (void *)(((u8 *)ie) + *(((u8 *)ie)+1) + 2)) ++ ++void dump_ies(u8 *buf, u32 buf_len); ++void dump_wps_ie(u8 *ie, u32 ie_len); ++ ++#ifdef CONFIG_88EU_P2P ++void dump_p2p_ie(u8 *ie, u32 ie_len); ++u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen); ++u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, ++ u8 *buf_attr, u32 *len_attr); ++u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id, ++ u8 *buf_content, uint *len_content); ++u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, ++ u8 *pdata_attr); ++void rtw_wlan_bssid_ex_remove_p2p_attr(struct wlan_bssid_ex *bss_ex, ++ u8 attr_id); ++#endif ++ ++uint rtw_get_rateset_len(u8 *rateset); ++ ++struct registry_priv; ++int rtw_generate_ie(struct registry_priv *pregistrypriv); ++ ++int rtw_get_bit_value_from_ieee_value(u8 val); ++ ++uint rtw_is_cckrates_included(u8 *rate); ++ ++uint rtw_is_cckratesonly_included(u8 *rate); ++ ++int rtw_check_network_type(unsigned char *rate, int ratelen, int channel); ++ ++void rtw_get_bcn_info(struct wlan_network *pnetwork); ++ ++void rtw_macaddr_cfg(u8 *mac_addr); ++ ++u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, ++ unsigned char *MCS_rate); ++ ++int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, ++ u8 *action); ++const char *action_public_str(u8 action); ++ ++#endif /* IEEE80211_H */ +diff --git a/drivers/staging/r8188eu/include/ieee80211_ext.h b/drivers/staging/r8188eu/include/ieee80211_ext.h +new file mode 100644 +index 000000000000..e7ade835d478 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/ieee80211_ext.h +@@ -0,0 +1,271 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __IEEE80211_EXT_H ++#define __IEEE80211_EXT_H ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#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 ++ ++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 */ ++} __packed; ++ ++struct rsn_ie_hdr { ++ u8 elem_id; /* WLAN_EID_RSN */ ++ u8 len; ++ u8 version[2]; /* little endian */ ++} __packed; ++ ++struct wme_ac_parameter { ++#if defined(__LITTLE_ENDIAN) ++ /* byte 1 */ ++ u8 aifsn:4, ++ acm:1, ++ aci:2, ++ reserved:1; ++ ++ /* byte 2 */ ++ u8 eCWmin:4, ++ eCWmax:4; ++#elif defined(__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; ++} __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]; ++ ++} __packed; ++ ++#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)) ++ ++/* 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, ++}; ++ ++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]; ++ } __packed auth; ++ struct { ++ u16 reason_code; ++ } __packed deauth; ++ struct { ++ u16 capab_info; ++ u16 listen_interval; ++ /* followed by SSID and Supported rates */ ++ u8 variable[0]; ++ } __packed assoc_req; ++ struct { ++ u16 capab_info; ++ u16 status_code; ++ u16 aid; ++ /* followed by Supported rates */ ++ u8 variable[0]; ++ } __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]; ++ } __packed reassoc_req; ++ struct { ++ u16 reason_code; ++ } __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]; ++ } __packed beacon; ++ struct { ++ /* only variable items: SSID, Supported rates */ ++ u8 variable[0]; ++ } __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]; ++ } __packed probe_resp; ++ struct { ++ u8 category; ++ union { ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u8 status_code; ++ u8 variable[0]; ++ } __packed wme_action; ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u16 capab; ++ u16 timeout; ++ u16 start_seq_num; ++ } __packed addba_req; ++ struct { ++ u8 action_code; ++ u8 dialog_token; ++ u16 status; ++ u16 capab; ++ u16 timeout; ++ } __packed addba_resp; ++ struct { ++ u8 action_code; ++ u16 params; ++ u16 reason_code; ++ } __packed delba; ++ structi { ++ 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]; ++ } __packed plink_action; ++ struct{ ++ u8 action_code; ++ u8 variable[0]; ++ } __packed mesh_action; ++ } __packed u; ++ } __packed action; ++ } __packed u; ++} __packed; ++ ++/* mgmt header + 1 byte category code */ ++#define IEEE80211_MIN_ACTION_SIZE \ ++ FIELD_OFFSET(struct ieee80211_mgmt, u.action.u) ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/ioctl_cfg80211.h b/drivers/staging/r8188eu/include/ioctl_cfg80211.h +new file mode 100644 +index 000000000000..e22481050ef8 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/ioctl_cfg80211.h +@@ -0,0 +1,91 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. i*/ ++ ++#ifndef __IOCTL_CFG80211_H__ ++#define __IOCTL_CFG80211_H__ ++ ++struct rtw_wdev_invit_info { ++ u8 token; ++ u8 flags; ++ u8 status; ++ u8 req_op_ch; ++ u8 rsp_op_ch; ++}; ++ ++#define rtw_wdev_invit_info_init(invit_info) \ ++ do { \ ++ (invit_info)->token = 0; \ ++ (invit_info)->flags = 0x00; \ ++ (invit_info)->status = 0xff; \ ++ (invit_info)->req_op_ch = 0; \ ++ (invit_info)->rsp_op_ch = 0; \ ++ } while (0) ++ ++struct rtw_wdev_priv { ++ struct wireless_dev *rtw_wdev; ++ ++ struct adapter *padapter; ++ ++ struct cfg80211_scan_request *scan_request; ++ spinlock_t scan_req_lock; ++ ++ struct net_device *pmon_ndev;/* for monitor interface */ ++ char ifname_mon[IFNAMSIZ + 1]; /* name of monitor interface */ ++ ++ u8 p2p_enabled; ++ ++ u8 provdisc_req_issued; ++ ++ struct rtw_wdev_invit_info invit_info; ++ ++ u8 bandroid_scan; ++ bool block; ++ bool power_mgmt; ++}; ++ ++#define wdev_to_priv(w) ((struct rtw_wdev_priv *)(wdev_priv(w))) ++ ++#define wiphy_to_wdev(x) \ ++((struct wireless_dev *)(((struct rtw_wdev_priv *)wiphy_priv(x))->rtw_wdev)) ++ ++int rtw_wdev_alloc(struct adapter *padapter, struct device *dev); ++void rtw_wdev_free(struct wireless_dev *wdev); ++void rtw_wdev_unregister(struct wireless_dev *wdev); ++ ++void rtw_cfg80211_init_wiphy(struct adapter *padapter); ++ ++void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter); ++ ++void rtw_cfg80211_indicate_connect(struct adapter *padapter); ++void rtw_cfg80211_indicate_disconnect(struct adapter *padapter); ++void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv, ++ bool aborted); ++ ++#ifdef CONFIG_88EU_AP_MODE ++void rtw_cfg80211_indicate_sta_assoc(struct adapter *padapter, ++ u8 *pmgmt_frame, uint frame_len); ++void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter, ++ unsigned char *da, ++ unsigned short reason); ++#endif /* CONFIG_88EU_AP_MODE */ ++ ++void rtw_cfg80211_issue_p2p_provision_request(struct adapter *padapter, ++ const u8 *buf, size_t len); ++void rtw_cfg80211_rx_p2p_action_public(struct adapter *padapter, ++ u8 *pmgmt_frame, uint frame_len); ++void rtw_cfg80211_rx_action_p2p(struct adapter *padapter, u8 *pmgmt_frame, ++ uint frame_len); ++void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, ++ uint frame_len, const char *msg); ++ ++int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, ++ char *buf, int len, int type); ++ ++bool rtw_cfg80211_pwr_mgmt(struct adapter *adapter); ++ ++#define rtw_cfg80211_rx_mgmt(dev, freq, sig_dbm, buf, len, gfp) \ ++ cfg80211_rx_mgmt(dev, freq, sig_dbm, buf, len, gfp) ++#define rtw_cfg80211_send_rx_assoc(dev, bss, buf, len) \ ++ cfg80211_send_rx_assoc(dev, bss, buf, len) ++ ++#endif /* __IOCTL_CFG80211_H__ */ +diff --git a/drivers/staging/r8188eu/include/mlme_osdep.h b/drivers/staging/r8188eu/include/mlme_osdep.h +new file mode 100644 +index 000000000000..5b9f688f9424 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/mlme_osdep.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __MLME_OSDEP_H_ ++#define __MLME_OSDEP_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++void rtw_init_mlme_timer(struct adapter *padapter); ++void rtw_os_indicate_disconnect(struct adapter *adapter); ++void rtw_os_indicate_connect(struct adapter *adapter); ++void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted); ++void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie); ++ ++void rtw_reset_securitypriv(struct adapter *adapter); ++void indicate_wx_scan_complete_event(struct adapter *padapter); ++ ++#endif /* _MLME_OSDEP_H_ */ +diff --git a/drivers/staging/r8188eu/include/mp_custom_oid.h b/drivers/staging/r8188eu/include/mp_custom_oid.h +new file mode 100644 +index 000000000000..7bcb857c795d +--- /dev/null ++++ b/drivers/staging/r8188eu/include/mp_custom_oid.h +@@ -0,0 +1,333 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __CUSTOM_OID_H ++#define __CUSTOM_OID_H ++ ++/* by Owen */ ++/* 0xFF818000 - 0xFF81802F RTL8180 Mass Production Kit */ ++/* 0xFF818500 - 0xFF81850F RTL8185 Setup Utility */ ++/* 0xFF818580 - 0xFF81858F RTL8185 Phy Status Utility */ ++ ++/* */ ++ ++/* by Owen for Production Kit */ ++/* For Production Kit with Agilent Equipments */ ++/* in order to make our custom oids hopefully somewhat unique */ ++/* we will use 0xFF (indicating implementation specific OID) */ ++/* 81(first byte of non zero Realtek unique identifier) */ ++/* 80 (second byte of non zero Realtek unique identifier) */ ++/* XX (the custom OID number - providing 255 possible custom oids) */ ++ ++#define OID_RT_PRO_RESET_DUT 0xFF818000 ++#define OID_RT_PRO_SET_DATA_RATE 0xFF818001 ++#define OID_RT_PRO_START_TEST 0xFF818002 ++#define OID_RT_PRO_STOP_TEST 0xFF818003 ++#define OID_RT_PRO_SET_PREAMBLE 0xFF818004 ++#define OID_RT_PRO_SET_SCRAMBLER 0xFF818005 ++#define OID_RT_PRO_SET_FILTER_BB 0xFF818006 ++#define OID_RT_PRO_SET_MANUAL_DIVERSITY_BB 0xFF818007 ++#define OID_RT_PRO_SET_CHANNEL_DIRECT_CALL 0xFF818008 ++#define OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL 0xFF818009 ++#define OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL 0xFF81800A ++ ++#define OID_RT_PRO_SET_TX_ANTENNA_BB 0xFF81800D ++#define OID_RT_PRO_SET_ANTENNA_BB 0xFF81800E ++#define OID_RT_PRO_SET_CR_SCRAMBLER 0xFF81800F ++#define OID_RT_PRO_SET_CR_NEW_FILTER 0xFF818010 ++#define OID_RT_PRO_SET_TX_POWER_CONTROL 0xFF818011 ++#define OID_RT_PRO_SET_CR_TX_CONFIG 0xFF818012 ++#define OID_RT_PRO_GET_TX_POWER_CONTROL 0xFF818013 ++#define OID_RT_PRO_GET_CR_SIGNAL_QUALITY 0xFF818014 ++#define OID_RT_PRO_SET_CR_SETPOINT 0xFF818015 ++#define OID_RT_PRO_SET_INTEGRATOR 0xFF818016 ++#define OID_RT_PRO_SET_SIGNAL_QUALITY 0xFF818017 ++#define OID_RT_PRO_GET_INTEGRATOR 0xFF818018 ++#define OID_RT_PRO_GET_SIGNAL_QUALITY 0xFF818019 ++#define OID_RT_PRO_QUERY_EEPROM_TYPE 0xFF81801A ++#define OID_RT_PRO_WRITE_MAC_ADDRESS 0xFF81801B ++#define OID_RT_PRO_READ_MAC_ADDRESS 0xFF81801C ++#define OID_RT_PRO_WRITE_CIS_DATA 0xFF81801D ++#define OID_RT_PRO_READ_CIS_DATA 0xFF81801E ++#define OID_RT_PRO_WRITE_POWER_CONTROL 0xFF81801F ++#define OID_RT_PRO_READ_POWER_CONTROL 0xFF818020 ++#define OID_RT_PRO_WRITE_EEPROM 0xFF818021 ++#define OID_RT_PRO_READ_EEPROM 0xFF818022 ++#define OID_RT_PRO_RESET_TX_PACKET_SENT 0xFF818023 ++#define OID_RT_PRO_QUERY_TX_PACKET_SENT 0xFF818024 ++#define OID_RT_PRO_RESET_RX_PACKET_RECEIVED 0xFF818025 ++#define OID_RT_PRO_QUERY_RX_PACKET_RECEIVED 0xFF818026 ++#define OID_RT_PRO_QUERY_RX_PACKET_CRC32_ERROR 0xFF818027 ++#define OID_RT_PRO_QUERY_CURRENT_ADDRESS 0xFF818028 ++#define OID_RT_PRO_QUERY_PERMANENT_ADDRESS 0xFF818029 ++#define OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS 0xFF81802A ++#define OID_RT_PRO_RECEIVE_PACKET 0xFF81802C ++/* added by Owen on 04/08/03 for Cameo's request */ ++#define OID_RT_PRO_WRITE_EEPROM_BYTE 0xFF81802D ++#define OID_RT_PRO_READ_EEPROM_BYTE 0xFF81802E ++#define OID_RT_PRO_SET_MODULATION 0xFF81802F ++/* */ ++ ++/* Sean */ ++#define OID_RT_DRIVER_OPTION 0xFF818080 ++#define OID_RT_RF_OFF 0xFF818081 ++#define OID_RT_AUTH_STATUS 0xFF818082 ++ ++/* */ ++#define OID_RT_PRO_SET_CONTINUOUS_TX 0xFF81800B ++#define OID_RT_PRO_SET_SINGLE_CARRIER_TX 0xFF81800C ++#define OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX 0xFF81802B ++#define OID_RT_PRO_SET_SINGLE_TONE_TX 0xFF818043 ++/* */ ++ ++/* by Owen for RTL8185 Phy Status Report Utility */ ++#define OID_RT_UTILITY_false_ALARM_COUNTERS 0xFF818580 ++#define OID_RT_UTILITY_SELECT_DEBUG_MODE 0xFF818581 ++#define OID_RT_UTILITY_SELECT_SUBCARRIER_NUMBER 0xFF818582 ++#define OID_RT_UTILITY_GET_RSSI_STATUS 0xFF818583 ++#define OID_RT_UTILITY_GET_FRAME_DETECTION_STATUS 0xFF818584 ++#define OID_RT_UTILITY_GET_AGC_AND_FREQUENCY_OFFSET_ESTIMATION_STATUS \ ++ 0xFF818585 ++#define OID_RT_UTILITY_GET_CHANNEL_ESTIMATION_STATUS 0xFF818586 ++/* */ ++ ++/* by Owen on 03/09/19-03/09/22 for RTL8185 */ ++#define OID_RT_WIRELESS_MODE 0xFF818500 ++#define OID_RT_SUPPORTED_RATES 0xFF818501 ++#define OID_RT_DESIRED_RATES 0xFF818502 ++#define OID_RT_WIRELESS_MODE_STARTING_ADHOC 0xFF818503 ++/* */ ++ ++#define OID_RT_GET_CONNECT_STATE 0xFF030001 ++#define OID_RT_RESCAN 0xFF030002 ++#define OID_RT_SET_KEY_LENGTH 0xFF030003 ++#define OID_RT_SET_DEFAULT_KEY_ID 0xFF030004 ++ ++#define OID_RT_SET_CHANNEL 0xFF010182 ++#define OID_RT_SET_SNIFFER_MODE 0xFF010183 ++#define OID_RT_GET_SIGNAL_QUALITY 0xFF010184 ++#define OID_RT_GET_SMALL_PACKET_CRC 0xFF010185 ++#define OID_RT_GET_MIDDLE_PACKET_CRC 0xFF010186 ++#define OID_RT_GET_LARGE_PACKET_CRC 0xFF010187 ++#define OID_RT_GET_TX_RETRY 0xFF010188 ++#define OID_RT_GET_RX_RETRY 0xFF010189 ++#define OID_RT_PRO_SET_FW_DIG_STATE 0xFF01018A/* S */ ++#define OID_RT_PRO_SET_FW_RA_STATE 0xFF01018B/* S */ ++ ++#define OID_RT_GET_RX_TOTAL_PACKET 0xFF010190 ++#define OID_RT_GET_TX_BEACON_OK 0xFF010191 ++#define OID_RT_GET_TX_BEACON_ERR 0xFF010192 ++#define OID_RT_GET_RX_ICV_ERR 0xFF010193 ++#define OID_RT_SET_ENCRYPTION_ALGORITHM 0xFF010194 ++#define OID_RT_SET_NO_AUTO_RESCAN 0xFF010195 ++#define OID_RT_GET_PREAMBLE_MODE 0xFF010196 ++#define OID_RT_GET_DRIVER_UP_DELTA_TIME 0xFF010197 ++#define OID_RT_GET_AP_IP 0xFF010198 ++#define OID_RT_GET_CHANNELPLAN 0xFF010199 ++#define OID_RT_SET_PREAMBLE_MODE 0xFF01019A ++#define OID_RT_SET_BCN_INTVL 0xFF01019B ++#define OID_RT_GET_RF_VENDER 0xFF01019C ++#define OID_RT_DEDICATE_PROBE 0xFF01019D ++#define OID_RT_PRO_RX_FILTER_PATTERN 0xFF01019E ++ ++#define OID_RT_GET_DCST_CURRENT_THRESHOLD 0xFF01019F ++ ++#define OID_RT_GET_CCA_ERR 0xFF0101A0 ++#define OID_RT_GET_CCA_UPGRADE_THRESHOLD 0xFF0101A1 ++#define OID_RT_GET_CCA_FALLBACK_THRESHOLD 0xFF0101A2 ++ ++#define OID_RT_GET_CCA_UPGRADE_EVALUATE_TIMES 0xFF0101A3 ++#define OID_RT_GET_CCA_FALLBACK_EVALUATE_TIMES 0xFF0101A4 ++ ++/* by Owen on 03/31/03 for Cameo's request */ ++#define OID_RT_SET_RATE_ADAPTIVE 0xFF0101A5 ++/* */ ++#define OID_RT_GET_DCST_EVALUATE_PERIOD 0xFF0101A5 ++#define OID_RT_GET_DCST_TIME_UNIT_INDEX 0xFF0101A6 ++#define OID_RT_GET_TOTAL_TX_BYTES 0xFF0101A7 ++#define OID_RT_GET_TOTAL_RX_BYTES 0xFF0101A8 ++#define OID_RT_CURRENT_TX_POWER_LEVEL 0xFF0101A9 ++#define OID_RT_GET_ENC_KEY_MISMATCH_COUNT 0xFF0101AA ++#define OID_RT_GET_ENC_KEY_MATCH_COUNT 0xFF0101AB ++#define OID_RT_GET_CHANNEL 0xFF0101AC ++ ++#define OID_RT_SET_CHANNELPLAN 0xFF0101AD ++#define OID_RT_GET_HARDWARE_RADIO_OFF 0xFF0101AE ++#define OID_RT_CHANNELPLAN_BY_COUNTRY 0xFF0101AF ++#define OID_RT_SCAN_AVAILABLE_BSSID 0xFF0101B0 ++#define OID_RT_GET_HARDWARE_VERSION 0xFF0101B1 ++#define OID_RT_GET_IS_ROAMING 0xFF0101B2 ++#define OID_RT_GET_IS_PRIVACY 0xFF0101B3 ++#define OID_RT_GET_KEY_MISMATCH 0xFF0101B4 ++#define OID_RT_SET_RSSI_ROAM_TRAFFIC_TH 0xFF0101B5 ++#define OID_RT_SET_RSSI_ROAM_SIGNAL_TH 0xFF0101B6 ++#define OID_RT_RESET_LOG 0xFF0101B7 ++#define OID_RT_GET_LOG 0xFF0101B8 ++#define OID_RT_SET_INDICATE_HIDDEN_AP 0xFF0101B9 ++#define OID_RT_GET_HEADER_FAIL 0xFF0101BA ++#define OID_RT_SUPPORTED_WIRELESS_MODE 0xFF0101BB ++#define OID_RT_GET_CHANNEL_LIST 0xFF0101BC ++#define OID_RT_GET_SCAN_IN_PROGRESS 0xFF0101BD ++#define OID_RT_GET_TX_INFO 0xFF0101BE ++#define OID_RT_RF_READ_WRITE_OFFSET 0xFF0101BF ++#define OID_RT_RF_READ_WRITE 0xFF0101C0 ++ ++/* For Netgear request. 2005.01.13, by rcnjko. */ ++#define OID_RT_FORCED_DATA_RATE 0xFF0101C1 ++#define OID_RT_WIRELESS_MODE_FOR_SCAN_LIST 0xFF0101C2 ++/* For Netgear request. 2005.02.17, by rcnjko. */ ++#define OID_RT_GET_BSS_WIRELESS_MODE 0xFF0101C3 ++/* For AZ project. 2005.06.27, by rcnjko. */ ++#define OID_RT_SCAN_WITH_MAGIC_PACKET 0xFF0101C4 ++ ++/* Vincent 8185MP */ ++#define OID_RT_PRO_RX_FILTER 0xFF0111C0 ++ ++#define OID_CE_USB_WRITE_REGISTRY 0xFF0111C1 ++#define OID_CE_USB_READ_REGISTRY 0xFF0111C2 ++ ++#define OID_RT_PRO_SET_INITIAL_GA 0xFF0111C3 ++#define OID_RT_PRO_SET_BB_RF_STANDBY_MODE 0xFF0111C4 ++#define OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE 0xFF0111C5 ++#define OID_RT_PRO_SET_TX_CHARGE_PUMP 0xFF0111C6 ++#define OID_RT_PRO_SET_RX_CHARGE_PUMP 0xFF0111C7 ++#define OID_RT_PRO_RF_WRITE_REGISTRY 0xFF0111C8 ++#define OID_RT_PRO_RF_READ_REGISTRY 0xFF0111C9 ++#define OID_RT_PRO_QUERY_RF_TYPE 0xFF0111CA ++ ++/* AP OID */ ++#define OID_RT_AP_GET_ASSOCIATED_STATION_LIST 0xFF010300 ++#define OID_RT_AP_GET_CURRENT_TIME_STAMP 0xFF010301 ++#define OID_RT_AP_SWITCH_INTO_AP_MODE 0xFF010302 ++#define OID_RT_AP_SET_DTIM_PERIOD 0xFF010303 ++/* Determine if driver supports AP mode. */ ++#define OID_RT_AP_SUPPORTED 0xFF010304 ++/* Set WPA-PSK passphrase into authenticator. */ ++#define OID_RT_AP_SET_PASSPHRASE 0xFF010305 ++ ++/* 8187MP. 2004.09.06, by rcnjko. */ ++#define OID_RT_PRO8187_WI_POLL 0xFF818780 ++#define OID_RT_PRO_WRITE_BB_REG 0xFF818781 ++#define OID_RT_PRO_READ_BB_REG 0xFF818782 ++#define OID_RT_PRO_WRITE_RF_REG 0xFF818783 ++#define OID_RT_PRO_READ_RF_REG 0xFF818784 ++ ++/* Meeting House. added by Annie, 2005-07-20. */ ++#define OID_RT_MH_VENDER_ID 0xFFEDC100 ++ ++/* 8711 MP OID added 20051230. */ ++#define OID_RT_PRO8711_JOIN_BSS 0xFF871100/* S */ ++ ++#define OID_RT_PRO_READ_REGISTER 0xFF871101 /* Q */ ++#define OID_RT_PRO_WRITE_REGISTER 0xFF871102 /* S */ ++ ++#define OID_RT_PRO_BURST_READ_REGISTER 0xFF871103 /* Q */ ++#define OID_RT_PRO_BURST_WRITE_REGISTER 0xFF871104 /* S */ ++ ++#define OID_RT_PRO_WRITE_TXCMD 0xFF871105 /* S */ ++ ++#define OID_RT_PRO_READ16_EEPROM 0xFF871106 /* Q */ ++#define OID_RT_PRO_WRITE16_EEPROM 0xFF871107 /* S */ ++ ++#define OID_RT_PRO_H2C_SET_COMMAND 0xFF871108 /* S */ ++#define OID_RT_PRO_H2C_QUERY_RESULT 0xFF871109 /* Q */ ++ ++#define OID_RT_PRO8711_WI_POLL 0xFF87110A /* Q */ ++#define OID_RT_PRO8711_PKT_LOSS 0xFF87110B /* Q */ ++#define OID_RT_RD_ATTRIB_MEM 0xFF87110C/* Q */ ++#define OID_RT_WR_ATTRIB_MEM 0xFF87110D/* S */ ++ ++/* Method 2 for H2C/C2H */ ++#define OID_RT_PRO_H2C_CMD_MODE 0xFF871110 /* S */ ++#define OID_RT_PRO_H2C_CMD_RSP_MODE 0xFF871111 /* Q */ ++#define OID_RT_PRO_H2C_CMD_EVENT_MODE 0xFF871112 /* S */ ++#define OID_RT_PRO_WAIT_C2H_EVENT 0xFF871113 /* Q */ ++#define OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST 0xFF871114/* Q */ ++ ++#define OID_RT_PRO_SCSI_ACCESS_TEST 0xFF871115 /* Q, S */ ++ ++#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT 0xFF871116 /* S */ ++#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN 0xFF871117 /* Q,S */ ++#define OID_RT_RRO_RX_PKT_VIA_IOCTRL 0xFF871118 /* Q */ ++#define OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL 0xFF871119 /* Q */ ++ ++#define OID_RT_RPO_SET_PWRMGT_TEST 0xFF87111A /* S */ ++#define OID_RT_PRO_QRY_PWRMGT_TEST 0XFF87111B /* Q */ ++#define OID_RT_RPO_ASYNC_RWIO_TEST 0xFF87111C /* S */ ++#define OID_RT_RPO_ASYNC_RWIO_POLL 0xFF87111D /* Q */ ++#define OID_RT_PRO_SET_RF_INTFS 0xFF87111E /* S */ ++#define OID_RT_POLL_RX_STATUS 0xFF87111F /* Q */ ++ ++#define OID_RT_PRO_CFG_DEBUG_MESSAGE 0xFF871120 /* Q,S */ ++#define OID_RT_PRO_SET_DATA_RATE_EX 0xFF871121/* S */ ++#define OID_RT_PRO_SET_BASIC_RATE 0xFF871122/* S */ ++#define OID_RT_PRO_READ_TSSI 0xFF871123/* S */ ++#define OID_RT_PRO_SET_POWER_TRACKING 0xFF871124/* S */ ++ ++#define OID_RT_PRO_QRY_PWRSTATE 0xFF871150 /* Q */ ++#define OID_RT_PRO_SET_PWRSTATE 0xFF871151 /* S */ ++ ++/* Method 2 , using workitem */ ++#define OID_RT_SET_READ_REG 0xFF871181 /* S */ ++#define OID_RT_SET_WRITE_REG 0xFF871182 /* S */ ++#define OID_RT_SET_BURST_READ_REG 0xFF871183 /* S */ ++#define OID_RT_SET_BURST_WRITE_REG 0xFF871184 /* S */ ++#define OID_RT_SET_WRITE_TXCMD 0xFF871185 /* S */ ++#define OID_RT_SET_READ16_EEPROM 0xFF871186 /* S */ ++#define OID_RT_SET_WRITE16_EEPROM 0xFF871187 /* S */ ++#define OID_RT_QRY_POLL_WKITEM 0xFF871188 /* Q */ ++ ++/* For SDIO INTERFACE only */ ++#define OID_RT_PRO_SYNCPAGERW_SRAM 0xFF8711A0 /* Q, S */ ++#define OID_RT_PRO_871X_DRV_EXT 0xFF8711A1 ++ ++/* For USB INTERFACE only */ ++#define OID_RT_PRO_USB_VENDOR_REQ 0xFF8711B0 /* Q, S */ ++#define OID_RT_PRO_SCSI_AUTO_TEST 0xFF8711B1 /* S */ ++#define OID_RT_PRO_USB_MAC_AC_FIFO_WRITE 0xFF8711B2 /* S */ ++#define OID_RT_PRO_USB_MAC_RX_FIFO_READ 0xFF8711B3 /* Q */ ++#define OID_RT_PRO_USB_MAC_RX_FIFO_POLLING 0xFF8711B4 /* Q */ ++ ++#define OID_RT_PRO_H2C_SET_RATE_TABLE 0xFF8711FB /* S */ ++#define OID_RT_PRO_H2C_GET_RATE_TABLE 0xFF8711FC /* S */ ++#define OID_RT_PRO_H2C_C2H_LBK_TEST 0xFF8711FE ++ ++#define OID_RT_PRO_ENCRYPTION_CTRL 0xFF871200 /* Q, S */ ++#define OID_RT_PRO_ADD_STA_INFO 0xFF871201 /* S */ ++#define OID_RT_PRO_DELE_STA_INFO 0xFF871202 /* S */ ++#define OID_RT_PRO_QUERY_DR_VARIABLE 0xFF871203 /* Q */ ++ ++#define OID_RT_PRO_RX_PACKET_TYPE 0xFF871204 /* Q, S */ ++ ++#define OID_RT_PRO_READ_EFUSE 0xFF871205 /* Q */ ++#define OID_RT_PRO_WRITE_EFUSE 0xFF871206 /* S */ ++#define OID_RT_PRO_RW_EFUSE_PGPKT 0xFF871207 /* Q, S */ ++#define OID_RT_GET_EFUSE_CURRENT_SIZE 0xFF871208 /* Q */ ++ ++#define OID_RT_SET_BANDWIDTH 0xFF871209 /* S */ ++#define OID_RT_SET_CRYSTAL_CAP 0xFF87120A /* S */ ++ ++#define OID_RT_SET_RX_PACKET_TYPE 0xFF87120B /* S */ ++ ++#define OID_RT_GET_EFUSE_MAX_SIZE 0xFF87120C /* Q */ ++ ++#define OID_RT_PRO_SET_TX_AGC_OFFSET 0xFF87120D /* S */ ++ ++#define OID_RT_PRO_SET_PKT_TEST_MODE 0xFF87120E /* S */ ++ ++#define OID_RT_PRO_FOR_EVM_TEST_SETTING 0xFF87120F /* S */ ++ ++#define OID_RT_PRO_GET_THERMAL_METER 0xFF871210 /* Q */ ++ ++#define OID_RT_RESET_PHY_RX_PACKET_COUNT 0xFF871211 /* S */ ++#define OID_RT_GET_PHY_RX_PACKET_RECEIVED 0xFF871212 /* Q */ ++#define OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR 0xFF871213 /* Q */ ++ ++#define OID_RT_SET_POWER_DOWN 0xFF871214 /* S */ ++ ++#define OID_RT_GET_POWER_MODE 0xFF871215 /* Q */ ++ ++#define OID_RT_PRO_EFUSE 0xFF871216 /* Q, S */ ++#define OID_RT_PRO_EFUSE_MAP 0xFF871217 /* Q, S */ ++ ++#endif /* ifndef __CUSTOM_OID_H */ +diff --git a/drivers/staging/r8188eu/include/odm.h b/drivers/staging/r8188eu/include/odm.h +new file mode 100644 +index 000000000000..d9041ee576bb +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm.h +@@ -0,0 +1,1154 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __HALDMOUTSRC_H__ ++#define __HALDMOUTSRC_H__ ++ ++/* Definition */ ++/* Define all team support ability. */ ++ ++/* Define for all teams. Please Define the constant in your precomp header. */ ++ ++/* define DM_ODM_SUPPORT_AP 0 */ ++/* define DM_ODM_SUPPORT_ADSL 0 */ ++/* define DM_ODM_SUPPORT_CE 0 */ ++/* define DM_ODM_SUPPORT_MP 1 */ ++ ++/* Define ODM SW team support flag. */ ++ ++/* Antenna Switch Relative Definition. */ ++ ++/* Add new function SwAntDivCheck8192C(). */ ++/* This is the main function of Antenna diversity function before link. */ ++/* Mainly, it just retains last scan result and scan again. */ ++/* After that, it compares the scan result to see which one gets better ++ * RSSI. It selects antenna with better receiving power and returns better ++ * scan result. */ ++ ++#define TP_MODE 0 ++#define RSSI_MODE 1 ++#define TRAFFIC_LOW 0 ++#define TRAFFIC_HIGH 1 ++ ++/* 3 Tx Power Tracking */ ++/* 3============================================================ */ ++#define DPK_DELTA_MAPPING_NUM 13 ++#define index_mapping_HP_NUM 15 ++ ++/* */ ++/* 3 PSD Handler */ ++/* 3============================================================ */ ++ ++#define AFH_PSD 1 /* 0:normal PSD scan, 1: only do 20 pts PSD */ ++#define MODE_40M 0 /* 0:20M, 1:40M */ ++#define PSD_TH2 3 ++#define PSD_CHM 20 /* Minimum channel number for BT AFH */ ++#define SIR_STEP_SIZE 3 ++#define Smooth_Size_1 5 ++#define Smooth_TH_1 3 ++#define Smooth_Size_2 10 ++#define Smooth_TH_2 4 ++#define Smooth_Size_3 20 ++#define Smooth_TH_3 4 ++#define Smooth_Step_Size 5 ++#define Adaptive_SIR 1 ++#define PSD_RESCAN 4 ++#define PSD_SCAN_INTERVAL 700 /* ms */ ++ ++/* 8723A High Power IGI Setting */ ++#define DM_DIG_HIGH_PWR_IGI_LOWER_BOUND 0x22 ++#define DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND 0x28 ++#define DM_DIG_HIGH_PWR_THRESHOLD 0x3a ++ ++/* LPS define */ ++#define DM_DIG_FA_TH0_LPS 4 /* 4 in lps */ ++#define DM_DIG_FA_TH1_LPS 15 /* 15 lps */ ++#define DM_DIG_FA_TH2_LPS 30 /* 30 lps */ ++#define RSSI_OFFSET_DIG 0x05; ++ ++/* ANT Test */ ++#define ANTTESTALL 0x00 /* Ant A or B will be Testing */ ++#define ANTTESTA 0x01 /* Ant A will be Testing */ ++#define ANTTESTB 0x02 /* Ant B will be testing */ ++ ++/* structure and define */ ++ ++/* Add for AP/ADSLpseudo DM structuer requirement. */ ++/* We need to remove to other position??? */ ++struct rtl8192cd_priv { ++ u8 temp; ++}; ++ ++struct rtw_dig { ++ u8 Dig_Enable_Flag; ++ u8 Dig_Ext_Port_Stage; ++ ++ int RssiLowThresh; ++ int RssiHighThresh; ++ ++ u32 FALowThresh; ++ u32 FAHighThresh; ++ ++ u8 CurSTAConnectState; ++ u8 PreSTAConnectState; ++ u8 CurMultiSTAConnectState; ++ ++ u8 PreIGValue; ++ u8 CurIGValue; ++ u8 BackupIGValue; ++ ++ s8 BackoffVal; ++ s8 BackoffVal_range_max; ++ s8 BackoffVal_range_min; ++ u8 rx_gain_range_max; ++ u8 rx_gain_range_min; ++ u8 Rssi_val_min; ++ ++ u8 PreCCK_CCAThres; ++ u8 CurCCK_CCAThres; ++ u8 PreCCKPDState; ++ u8 CurCCKPDState; ++ ++ u8 LargeFAHit; ++ u8 ForbiddenIGI; ++ u32 Recover_cnt; ++ ++ u8 DIG_Dynamic_MIN_0; ++ u8 DIG_Dynamic_MIN_1; ++ bool bMediaConnect_0; ++ bool bMediaConnect_1; ++ ++ u32 AntDiv_RSSI_max; ++ u32 RSSI_max; ++}; ++ ++struct rtl_ps { ++ u8 pre_cca_state; ++ u8 cur_cca_state; ++ ++ u8 pre_rf_state; ++ u8 cur_rf_state; ++ ++ int rssi_val_min; ++ ++ u8 initialize; ++ u32 reg_874; ++ u32 reg_c70; ++ u32 reg_85c; ++ u32 reg_a74; ++ ++}; ++ ++struct false_alarm_stats { ++ u32 Cnt_Parity_Fail; ++ u32 Cnt_Rate_Illegal; ++ u32 Cnt_Crc8_fail; ++ u32 Cnt_Mcs_fail; ++ u32 Cnt_Ofdm_fail; ++ u32 Cnt_Cck_fail; ++ u32 Cnt_all; ++ u32 Cnt_Fast_Fsync; ++ u32 Cnt_SB_Search_fail; ++ u32 Cnt_OFDM_CCA; ++ u32 Cnt_CCK_CCA; ++ u32 Cnt_CCA_all; ++ u32 Cnt_BW_USC; /* Gary */ ++ u32 Cnt_BW_LSC; /* Gary */ ++}; ++ ++struct dyn_primary_cca { ++ u8 pri_cca_flag; ++ u8 intf_flag; ++ u8 intf_type; ++ u8 dup_rts_flag; ++ u8 monitor_flag; ++}; ++ ++struct rx_hpc { ++ u8 RXHP_flag; ++ u8 PSD_func_trigger; ++ u8 PSD_bitmap_RXHP[80]; ++ u8 Pre_IGI; ++ u8 Cur_IGI; ++ u8 Pre_pw_th; ++ u8 Cur_pw_th; ++ bool First_time_enter; ++ bool RXHP_enable; ++ u8 TP_Mode; ++ struct timer_list PSDTimer; ++}; ++ ++#define ASSOCIATE_ENTRY_NUM 32 /* Max size of AsocEntry[]. */ ++#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM ++ ++/* This indicates two different steps. */ ++/* In SWAW_STEP_PEAK, driver needs to switch antenna and listen to ++ * the signal on the air. */ ++/* In SWAW_STEP_DETERMINE, driver just compares the signal captured in ++ * SWAW_STEP_PEAK with original RSSI to determine if it is necessary to ++ * switch antenna. */ ++ ++#define SWAW_STEP_PEAK 0 ++#define SWAW_STEP_DETERMINE 1 ++ ++#define TP_MODE 0 ++#define RSSI_MODE 1 ++#define TRAFFIC_LOW 0 ++#define TRAFFIC_HIGH 1 ++ ++struct sw_ant_switch { ++ u8 try_flag; ++ s32 PreRSSI; ++ u8 CurAntenna; ++ u8 PreAntenna; ++ u8 RSSI_Trying; ++ u8 TestMode; ++ u8 bTriggerAntennaSwitch; ++ u8 SelectAntennaMap; ++ u8 RSSI_target; ++ ++ /* Before link Antenna Switch check */ ++ u8 SWAS_NoLink_State; ++ u32 SWAS_NoLink_BK_Reg860; ++ bool ANTA_ON; /* To indicate Ant A is or not */ ++ bool ANTB_ON; /* To indicate Ant B is on or not */ ++ ++ s32 RSSI_sum_A; ++ s32 RSSI_sum_B; ++ s32 RSSI_cnt_A; ++ s32 RSSI_cnt_B; ++ u64 lastTxOkCnt; ++ u64 lastRxOkCnt; ++ u64 TXByteCnt_A; ++ u64 TXByteCnt_B; ++ u64 RXByteCnt_A; ++ u64 RXByteCnt_B; ++ u8 TrafficLoad; ++ struct timer_list SwAntennaSwitchTimer; ++ /* Hybrid Antenna Diversity */ ++ u32 CCK_Ant1_Cnt[ASSOCIATE_ENTRY_NUM]; ++ u32 CCK_Ant2_Cnt[ASSOCIATE_ENTRY_NUM]; ++ u32 OFDM_Ant1_Cnt[ASSOCIATE_ENTRY_NUM]; ++ u32 OFDM_Ant2_Cnt[ASSOCIATE_ENTRY_NUM]; ++ u32 RSSI_Ant1_Sum[ASSOCIATE_ENTRY_NUM]; ++ u32 RSSI_Ant2_Sum[ASSOCIATE_ENTRY_NUM]; ++ u8 TxAnt[ASSOCIATE_ENTRY_NUM]; ++ u8 TargetSTA; ++ u8 antsel; ++ u8 RxIdleAnt; ++}; ++ ++struct edca_turbo { ++ bool bCurrentTurboEDCA; ++ bool bIsCurRDLState; ++ u32 prv_traffic_idx; /* edca turbo */ ++}; ++ ++struct odm_rate_adapt { ++ u8 Type; /* DM_Type_ByFW/DM_Type_ByDriver */ ++ u8 HighRSSIThresh; /* if RSSI > HighRSSIThresh => RATRState is DM_RATR_STA_HIGH */ ++ u8 LowRSSIThresh; /* if RSSI <= LowRSSIThresh => RATRState is DM_RATR_STA_LOW */ ++ u8 RATRState; /* Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW */ ++ u32 LastRATR; /* RATR Register Content */ ++}; ++ ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM_MAX 10 ++#define IQK_BB_REG_NUM 9 ++#define HP_THERMAL_NUM 8 ++ ++#define AVG_THERMAL_NUM 8 ++#define IQK_Matrix_REG_NUM 8 ++#define IQK_Matrix_Settings_NUM 1+24+21 ++ ++#define DM_Type_ByFWi 0 ++#define DM_Type_ByDriver 1 ++ ++/* Declare for common info */ ++ ++struct odm_phy_status_info { ++ u8 RxPWDBAll; ++ u8 SignalQuality; /* in 0-100 index. */ ++ u8 RxMIMOSignalQuality[MAX_PATH_NUM_92CS]; /* EVM */ ++ u8 RxMIMOSignalStrength[MAX_PATH_NUM_92CS];/* in 0~100 index */ ++ s8 RxPower; /* in dBm Translate from PWdB */ ++ s8 RecvSignalPower;/* Real power in dBm for this packet, no ++ * beautification and aggregation. Keep this raw ++ * info to be used for the other procedures. */ ++ u8 BTRxRSSIPercentage; ++ u8 SignalStrength; /* in 0-100 index. */ ++ u8 RxPwr[MAX_PATH_NUM_92CS];/* per-path's pwdb */ ++ u8 RxSNR[MAX_PATH_NUM_92CS];/* per-path's SNR */ ++}; ++ ++struct odm_phy_dbg_info { ++ /* ODM Write,debug info */ ++ s8 RxSNRdB[MAX_PATH_NUM_92CS]; ++ u64 NumQryPhyStatus; ++ u64 NumQryPhyStatusCCK; ++ u64 NumQryPhyStatusOFDM; ++ /* Others */ ++ s32 RxEVM[MAX_PATH_NUM_92CS]; ++}; ++ ++struct odm_per_pkt_info { ++ s8 Rate; ++ u8 StationID; ++ bool bPacketMatchBSSID; ++ bool bPacketToSelf; ++ bool bPacketBeacon; ++}; ++ ++struct odm_mac_status_info { ++ u8 test; ++}; ++ ++enum odm_ability { ++ /* BB Team */ ++ ODM_DIG = 0x00000001, ++ ODM_HIGH_POWER = 0x00000002, ++ ODM_CCK_CCA_TH = 0x00000004, ++ ODM_FA_STATISTICS = 0x00000008, ++ ODM_RAMASK = 0x00000010, ++ ODM_RSSI_MONITOR = 0x00000020, ++ ODM_SW_ANTDIV = 0x00000040, ++ ODM_HW_ANTDIV = 0x00000080, ++ ODM_BB_PWRSV = 0x00000100, ++ ODM_2TPATHDIV = 0x00000200, ++ ODM_1TPATHDIV = 0x00000400, ++ ODM_PSD2AFH = 0x00000800 ++}; ++ ++/* 2011/20/20 MH For MP driver RT_WLAN_STA = struct sta_info */ ++/* Please declare below ODM relative info in your STA info structure. */ ++ ++struct odm_sta_info { ++ /* Driver Write */ ++ bool bUsed; /* record the sta status link or not? */ ++ u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */ ++ ++ /* ODM Write */ ++ /* 1 PHY_STATUS_INFO */ ++ u8 RSSI_Path[4]; /* */ ++ u8 RSSI_Ave; ++ u8 RXEVM[4]; ++ u8 RXSNR[4]; ++}; ++ ++/* 2011/10/20 MH Define Common info enum for all team. */ ++ ++enum odm_common_info_def { ++ /* Fixed value: */ ++ ++ /* HOOK BEFORE REG INIT----------- */ ++ ODM_CMNINFO_PLATFORM = 0, ++ ODM_CMNINFO_ABILITY, /* ODM_ABILITY_E */ ++ ODM_CMNINFO_INTERFACE, /* ODM_INTERFACE_E */ ++ ODM_CMNINFO_MP_TEST_CHIP, ++ ODM_CMNINFO_IC_TYPE, /* ODM_IC_TYPE_E */ ++ ODM_CMNINFO_CUT_VER, /* ODM_CUT_VERSION_E */ ++ ODM_CMNINFO_FAB_VER, /* ODM_FAB_E */ ++ ODM_CMNINFO_RF_TYPE, /* RF_PATH_E or ODM_RF_TYPE_E? */ ++ ODM_CMNINFO_BOARD_TYPE, /* ODM_BOARD_TYPE_E */ ++ ODM_CMNINFO_EXT_LNA, /* true */ ++ ODM_CMNINFO_EXT_PA, ++ ODM_CMNINFO_EXT_TRSW, ++ ODM_CMNINFO_PATCH_ID, /* CUSTOMER ID */ ++ ODM_CMNINFO_BINHCT_TEST, ++ ODM_CMNINFO_BWIFI_TEST, ++ ODM_CMNINFO_SMART_CONCURRENT, ++ /* HOOK BEFORE REG INIT----------- */ ++ ++ /* Dynamic value: */ ++/* POINTER REFERENCE----------- */ ++ ODM_CMNINFO_MAC_PHY_MODE, /* ODM_MAC_PHY_MODE_E */ ++ ODM_CMNINFO_TX_UNI, ++ ODM_CMNINFO_RX_UNI, ++ ODM_CMNINFO_WM_MODE, /* ODM_WIRELESS_MODE_E */ ++ ODM_CMNINFO_BAND, /* ODM_BAND_TYPE_E */ ++ ODM_CMNINFO_SEC_CHNL_OFFSET, /* ODM_SEC_CHNL_OFFSET_E */ ++ ODM_CMNINFO_SEC_MODE, /* ODM_SECURITY_E */ ++ ODM_CMNINFO_BW, /* ODM_BW_E */ ++ ODM_CMNINFO_CHNL, ++ ++ ODM_CMNINFO_DMSP_GET_VALUE, ++ ODM_CMNINFO_BUDDY_ADAPTOR, ++ ODM_CMNINFO_DMSP_IS_MASTER, ++ ODM_CMNINFO_SCAN, ++ ODM_CMNINFO_POWER_SAVING, ++ ODM_CMNINFO_ONE_PATH_CCA, /* ODM_CCA_PATH_E */ ++ ODM_CMNINFO_DRV_STOP, ++ ODM_CMNINFO_PNP_IN, ++ ODM_CMNINFO_INIT_ON, ++ ODM_CMNINFO_ANT_TEST, ++ ODM_CMNINFO_NET_CLOSED, ++ ODM_CMNINFO_MP_MODE, ++/* POINTER REFERENCE----------- */ ++ ++/* CALL BY VALUE------------- */ ++ ODM_CMNINFO_WIFI_DIRECT, ++ ODM_CMNINFO_WIFI_DISPLAY, ++ ODM_CMNINFO_LINK, ++ ODM_CMNINFO_RSSI_MIN, ++ ODM_CMNINFO_RA_THRESHOLD_HIGH, /* u8 */ ++ ODM_CMNINFO_RA_THRESHOLD_LOW, /* u8 */ ++ ODM_CMNINFO_RF_ANTENNA_TYPE, /* u8 */ ++ ODM_CMNINFO_BT_DISABLED, ++ ODM_CMNINFO_BT_OPERATION, ++ ODM_CMNINFO_BT_DIG, ++ ODM_CMNINFO_BT_BUSY, /* Check Bt is using or not */ ++ ODM_CMNINFO_BT_DISABLE_EDCA, ++/* CALL BY VALUE-------------*/ ++ ++ /* Dynamic ptr array hook itms. */ ++ ODM_CMNINFO_STA_STATUS, ++ ODM_CMNINFO_PHY_STATUS, ++ ODM_CMNINFO_MAC_STATUS, ++ ODM_CMNINFO_MAX, ++}; ++ ++/* 2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY */ ++ ++enum odm_ability_def { ++ /* BB ODM section BIT 0-15 */ ++ ODM_BB_DIG = BIT(0), ++ ODM_BB_RA_MASK = BIT(1), ++ ODM_BB_DYNAMIC_TXPWR = BIT(2), ++ ODM_BB_FA_CNT = BIT(3), ++ ODM_BB_RSSI_MONITOR = BIT(4), ++ ODM_BB_CCK_PD = BIT(5), ++ ODM_BB_ANT_DIV = BIT(6), ++ ODM_BB_PWR_SAVE = BIT(7), ++ ODM_BB_PWR_TRA = BIT(8), ++ ODM_BB_RATE_ADAPTIVE = BIT(9), ++ ODM_BB_PATH_DIV = BIT(10), ++ ODM_BB_PSD = BIT(11), ++ ODM_BB_RXHP = BIT(12), ++ ++ /* MAC DM section BIT 16-23 */ ++ ODM_MAC_EDCA_TURBO = BIT(16), ++ ODM_MAC_EARLY_MODE = BIT(17), ++ ++ /* RF ODM section BIT 24-31 */ ++ ODM_RF_TX_PWR_TRACK = BIT(24), ++ ODM_RF_RX_GAIN_TRACK = BIT(25), ++ ODM_RF_CALIBRATION = BIT(26), ++}; ++ ++/* ODM_CMNINFO_INTERFACE */ ++enum odm_interface_def { ++ ODM_ITRF_PCIE = 0x1, ++ ODM_ITRF_USB = 0x2, ++ ODM_ITRF_SDIO = 0x4, ++ ODM_ITRF_ALL = 0x7, ++}; ++ ++/* ODM_CMNINFO_IC_TYPE */ ++enum odm_ic_type { ++ ODM_RTL8192S = BIT(0), ++ ODM_RTL8192C = BIT(1), ++ ODM_RTL8192D = BIT(2), ++ ODM_RTL8723A = BIT(3), ++ ODM_RTL8188E = BIT(4), ++ ODM_RTL8812 = BIT(5), ++ ODM_RTL8821 = BIT(6), ++}; ++ ++#define ODM_IC_11N_SERIES \ ++ (ODM_RTL8192S | ODM_RTL8192C | ODM_RTL8192D | \ ++ ODM_RTL8723A | ODM_RTL8188E) ++#define ODM_IC_11AC_SERIES (ODM_RTL8812) ++ ++/* ODM_CMNINFO_CUT_VER */ ++enum odm_cut_version { ++ ODM_CUT_A = 1, ++ ODM_CUT_B = 2, ++ ODM_CUT_C = 3, ++ ODM_CUT_D = 4, ++ ODM_CUT_E = 5, ++ ODM_CUT_F = 6, ++ ODM_CUT_TEST = 7, ++}; ++ ++/* ODM_CMNINFO_FAB_VER */ ++enum odm_fab_Version { ++ ODM_TSMC = 0, ++ ODM_UMC = 1, ++}; ++ ++/* ODM_CMNINFO_RF_TYPE */ ++/* For example 1T2R (A+AB = BIT(0)|BIT(4)|BIT(5)) */ ++enum odm_rf_path { ++ ODM_RF_TX_A = BIT(0), ++ ODM_RF_TX_B = BIT(1), ++ ODM_RF_TX_C = BIT(2), ++ ODM_RF_TX_D = BIT(3), ++ ODM_RF_RX_A = BIT(4), ++ ODM_RF_RX_B = BIT(5), ++ ODM_RF_RX_C = BIT(6), ++ ODM_RF_RX_D = BIT(7), ++}; ++ ++enum odm_rf_type { ++ ODM_1T1R = 0, ++ ODM_1T2R = 1, ++ ODM_2T2R = 2, ++ ODM_2T3R = 3, ++ ODM_2T4R = 4, ++ ODM_3T3R = 5, ++ ODM_3T4R = 6, ++ ODM_4T4R = 7, ++}; ++ ++/* ODM Dynamic common info value definition */ ++ ++enum odm_mac_phy_mode { ++ ODM_SMSP = 0, ++ ODM_DMSP = 1, ++ ODM_DMDP = 2, ++}; ++ ++enum odm_bt_coexist { ++ ODM_BT_BUSY = 1, ++ ODM_BT_ON = 2, ++ ODM_BT_OFF = 3, ++ ODM_BT_NONE = 4, ++}; ++ ++/* ODM_CMNINFO_OP_MODE */ ++enum odm_operation_mode { ++ ODM_NO_LINK = BIT(0), ++ ODM_LINK = BIT(1), ++ ODM_SCAN = BIT(2), ++ ODM_POWERSAVE = BIT(3), ++ ODM_AP_MODE = BIT(4), ++ ODM_CLIENT_MODE = BIT(5), ++ ODM_AD_HOC = BIT(6), ++ ODM_WIFI_DIRECT = BIT(7), ++ ODM_WIFI_DISPLAY = BIT(8), ++}; ++ ++/* ODM_CMNINFO_WM_MODE */ ++enum odm_wireless_mode { ++ ODM_WM_UNKNOW = 0x0, ++ ODM_WM_B = BIT(0), ++ ODM_WM_G = BIT(1), ++ ODM_WM_N24G = BIT(3), ++ ODM_WM_AUTO = BIT(5), ++}; ++ ++/* ODM_CMNINFO_BAND */ ++enum odm_band_type { ++ ODM_BAND_2_4G = BIT(0), ++}; ++ ++/* ODM_CMNINFO_SEC_CHNL_OFFSET */ ++enum odm_sec_chnl_offset { ++ ODM_DONT_CARE = 0, ++ ODM_BELOW = 1, ++ ODM_ABOVE = 2 ++}; ++ ++/* ODM_CMNINFO_SEC_MODE */ ++enum odm_security { ++ ODM_SEC_OPEN = 0, ++ ODM_SEC_WEP40 = 1, ++ ODM_SEC_TKIP = 2, ++ ODM_SEC_RESERVE = 3, ++ ODM_SEC_AESCCMP = 4, ++ ODM_SEC_WEP104 = 5, ++ ODM_WEP_WPA_MIXED = 6, /* WEP + WPA */ ++ ODM_SEC_SMS4 = 7, ++}; ++ ++/* ODM_CMNINFO_BW */ ++enum odm_bw { ++ ODM_BW20M = 0, ++ ODM_BW40M = 1, ++}; ++ ++/* ODM_CMNINFO_BOARD_TYPE */ ++enum odm_board_type { ++ ODM_BOARD_NORMAL = 0, ++ ODM_BOARD_HIGHPWR = 1, ++ ODM_BOARD_MINICARD = 2, ++ ODM_BOARD_SLIM = 3, ++ ODM_BOARD_COMBO = 4, ++}; ++ ++/* ODM_CMNINFO_ONE_PATH_CCA */ ++enum odm_cca_path { ++ ODM_CCA_2R = 0, ++ ODM_CCA_1R_A = 1, ++ ODM_CCA_1R_B = 2, ++}; ++ ++struct odm_ra_info { ++ u8 RateID; ++ u32 RateMask; ++ u32 RAUseRate; ++ u8 RateSGI; ++ u8 RssiStaRA; ++ u8 PreRssiStaRA; ++ u8 SGIEnable; ++ u8 DecisionRate; ++ u8 PreRate; ++ u8 HighestRate; ++ u8 LowestRate; ++ u32 NscUp; ++ u32 NscDown; ++ u16 RTY[5]; ++ u32 TOTAL; ++ u16 DROP; ++ u8 Active; ++ u16 RptTime; ++ u8 RAWaitingCounter; ++ u8 RAPendingCounter; ++ u8 PTActive; /* on or off */ ++ u8 PTTryState; /* 0 trying state, 1 for decision state */ ++ u8 PTStage; /* 0~6 */ ++ u8 PTStopCount; /* Stop PT counter */ ++ u8 PTPreRate; /* if rate change do PT */ ++ u8 PTPreRssi; /* if RSSI change 5% do PT */ ++ u8 PTModeSS; /* decide whitch rate should do PT */ ++ u8 RAstage; /* StageRA, decide how many times RA will be done ++ * between PT */ ++ u8 PTSmoothFactor; ++}; ++ ++struct ijk_matrix_regs_set { ++ bool bIQKDone; ++ s32 Value[1][IQK_Matrix_REG_NUM]; ++}; ++ ++struct odm_rf_cal { ++ /* for tx power tracking */ ++ u32 RegA24; /* for TempCCK */ ++ s32 RegE94; ++ s32 RegE9C; ++ s32 RegEB4; ++ s32 RegEBC; ++ ++ u8 TXPowercount; ++ bool bTXPowerTrackingInit; ++ bool bTXPowerTracking; ++ u8 TxPowerTrackControl; /* for mp mode, turn off txpwrtracking ++ * as default */ ++ u8 TM_Trigger; ++ u8 InternalPA5G[2]; /* pathA / pathB */ ++ ++ u8 ThermalMeter[2]; /* ThermalMeter, index 0 for RFIC0, ++ * and 1 for RFIC1 */ ++ u8 ThermalValue; ++ u8 ThermalValue_LCK; ++ u8 ThermalValue_IQK; ++ u8 ThermalValue_DPK; ++ u8 ThermalValue_AVG[AVG_THERMAL_NUM]; ++ u8 ThermalValue_AVG_index; ++ u8 ThermalValue_RxGain; ++ u8 ThermalValue_Crystal; ++ u8 ThermalValue_DPKstore; ++ u8 ThermalValue_DPKtrack; ++ bool TxPowerTrackingInProgress; ++ bool bDPKenable; ++ ++ bool bReloadtxpowerindex; ++ u8 bRfPiEnable; ++ u32 TXPowerTrackingCallbackCnt; /* cosa add for debug */ ++ ++ u8 bCCKinCH14; ++ u8 CCK_index; ++ u8 OFDM_index[2]; ++ bool bDoneTxpower; ++ ++ u8 ThermalValue_HP[HP_THERMAL_NUM]; ++ u8 ThermalValue_HP_index; ++ struct ijk_matrix_regs_set IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; ++ ++ u8 Delta_IQK; ++ u8 Delta_LCK; ++ ++ /* for IQK */ ++ u32 RegC04; ++ u32 Reg874; ++ u32 RegC08; ++ u32 RegB68; ++ u32 RegB6C; ++ u32 Reg870; ++ u32 Reg860; ++ u32 Reg864; ++ ++ bool bIQKInitialized; ++ bool bLCKInProgress; ++ bool bAntennaDetected; ++ u32 ADDA_backup[IQK_ADDA_REG_NUM]; ++ u32 IQK_MAC_backup[IQK_MAC_REG_NUM]; ++ u32 IQK_BB_backup_recover[9]; ++ u32 IQK_BB_backup[IQK_BB_REG_NUM]; ++ ++ /* for APK */ ++ u32 APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */ ++ u8 bAPKdone; ++ u8 bAPKThermalMeterIgnore; ++ u8 bDPdone; ++ u8 bDPPathAOK; ++ u8 bDPPathBOK; ++}; ++ ++/* ODM Dynamic common info value definition */ ++ ++struct fast_ant_train { ++ u8 Bssid[6]; ++ u8 antsel_rx_keep_0; ++ u8 antsel_rx_keep_1; ++ u8 antsel_rx_keep_2; ++ u32 antSumRSSI[7]; ++ u32 antRSSIcnt[7]; ++ u32 antAveRSSI[7]; ++ u8 FAT_State; ++ u32 TrainIdx; ++ u8 antsel_a[ODM_ASSOCIATE_ENTRY_NUM]; ++ u8 antsel_b[ODM_ASSOCIATE_ENTRY_NUM]; ++ u8 antsel_c[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 MainAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 AuxAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 MainAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; ++ u32 AuxAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; ++ u8 RxIdleAnt; ++ bool bBecomeLinked; ++}; ++ ++enum fat_state { ++ FAT_NORMAL_STATE = 0, ++ FAT_TRAINING_STATE = 1, ++}; ++ ++enum ant_div_type { ++ NO_ANTDIV = 0xFF, ++ CG_TRX_HW_ANTDIV = 0x01, ++ CGCS_RX_HW_ANTDIV = 0x02, ++ FIXED_HW_ANTDIV = 0x03, ++ CG_TRX_SMART_ANTDIV = 0x04, ++ CGCS_RX_SW_ANTDIV = 0x05, ++}; ++ ++/* Copy from SD4 defined structure. We use to support PHY DM integration. */ ++struct odm_dm_struct { ++ /* Add for different team use temporarily */ ++ struct adapter *Adapter; /* For CE/NIC team */ ++ struct rtl8192cd_priv *priv; /* For AP/ADSL team */ ++ /* WHen you use above pointers, they must be initialized. */ ++ bool odm_ready; ++ ++ struct rtl8192cd_priv *fake_priv; ++ ++/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */ ++ bool bCckHighPower; ++ u8 RFPathRxEnable; /* ODM_CMNINFO_RFPATH_ENABLE */ ++ u8 ControlChannel; ++/* ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */ ++ ++/* 1 COMMON INFORMATION */ ++ /* Init Value */ ++/* HOOK BEFORE REG INIT----------- */ ++ /* ODM Platform info AP/ADSL/CE/MP = 1/2/3/4 */ ++ u8 SupportPlatform; ++ /* ODM Support Ability DIG/RATR/TX_PWR_TRACK/ �K�K = 1/2/3/�K */ ++ u32 SupportAbility; ++ /* ODM PCIE/USB/SDIO/GSPI = 0/1/2/3 */ ++ u8 SupportInterface; ++ /* ODM composite or independent. Bit oriented/ 92C+92D+ .... or any ++ * other type = 1/2/3/... */ ++ u32 SupportICType; ++ /* Cut Version TestChip/A-cut/B-cut... = 0/1/2/3/... */ ++ u8 CutVersion; ++ /* Fab Version TSMC/UMC = 0/1 */ ++ u8 FabVersion; ++ /* RF Type 4T4R/3T3R/2T2R/1T2R/1T1R/... */ ++ u8 RFType; ++ /* Board Type Normal/HighPower/MiniCard/SLIM/Combo/. = 0/1/2/3/4/. */ ++ u8 BoardType; ++ /* with external LNA NO/Yes = 0/1 */ ++ u8 ExtLNA; ++ /* with external PA NO/Yes = 0/1 */ ++ u8 ExtPA; ++ /* with external TRSW NO/Yes = 0/1 */ ++ u8 ExtTRSW; ++ u8 PatchID; /* Customer ID */ ++ bool bInHctTest; ++ bool bWIFITest; ++ ++ bool bDualMacSmartConcurrent; ++ u32 BK_SupportAbility; ++ u8 AntDivType; ++/* HOOK BEFORE REG INIT----------- */ ++ ++ /* Dynamic Value */ ++/* POINTER REFERENCE----------- */ ++ ++ u8 u8_temp; ++ bool bool_temp; ++ struct adapter *adapter_temp; ++ ++ /* MAC PHY Mode SMSP/DMSP/DMDP = 0/1/2 */ ++ u8 *pMacPhyMode; ++ /* TX Unicast byte count */ ++ u64 *pNumTxBytesUnicast; ++ /* RX Unicast byte count */ ++ u64 *pNumRxBytesUnicast; ++ /* Wireless mode B/G/A/N = BIT(0)/BIT(1)/BIT(2)/BIT(3) */ ++ u8 *pWirelessMode; /* ODM_WIRELESS_MODE_E */ ++ /* Frequence band 2.4G/5G = 0/1 */ ++ u8 *pBandType; ++ /* Secondary channel offset don't_care/below/above = 0/1/2 */ ++ u8 *pSecChOffset; ++ /* Security mode Open/WEP/AES/TKIP = 0/1/2/3 */ ++ u8 *pSecurity; ++ /* BW info 20M/40M/80M = 0/1/2 */ ++ u8 *pBandWidth; ++ /* Central channel location Ch1/Ch2/.... */ ++ u8 *pChannel; /* central channel number */ ++ /* Common info for 92D DMSP */ ++ ++ bool *pbGetValueFromOtherMac; ++ struct adapter **pBuddyAdapter; ++ bool *pbMasterOfDMSP; /* MAC0: master, MAC1: slave */ ++ /* Common info for Status */ ++ bool *pbScanInProcess; ++ bool *pbPowerSaving; ++ /* CCA Path 2-path/path-A/path-B = 0/1/2; using ODM_CCA_PATH_E. */ ++ u8 *pOnePathCCA; ++ /* pMgntInfo->AntennaTest */ ++ u8 *pAntennaTest; ++ bool *pbNet_closed; ++/* POINTER REFERENCE----------- */ ++ /* */ ++/* CALL BY VALUE------------- */ ++ bool bWIFI_Direct; ++ bool bWIFI_Display; ++ bool bLinked; ++ u8 RSSI_Min; ++ u8 InterfaceIndex; /* Add for 92D dual MAC: 0--Mac0 1--Mac1 */ ++ bool bIsMPChip; ++ bool bOneEntryOnly; ++ /* Common info for BTDM */ ++ bool bBtDisabled; /* BT is disabled */ ++ bool bBtHsOperation; /* BT HS mode is under progress */ ++ u8 btHsDigVal; /* use BT rssi to decide the DIG value */ ++ bool bBtDisableEdcaTurbo;/* Under some condition, don't enable the ++ * EDCA Turbo */ ++ bool bBtBusy; /* BT is busy. */ ++/* CALL BY VALUE------------- */ ++ ++ /* 2 Define STA info. */ ++ /* _ODM_STA_INFO */ ++ /* For MP, we need to reduce one array pointer for default port.?? */ ++ struct sta_info *pODM_StaInfo[ODM_ASSOCIATE_ENTRY_NUM]; ++ ++ u16 CurrminRptTime; ++ struct odm_ra_info RAInfo[ODM_ASSOCIATE_ENTRY_NUM]; /* Use MacID as ++ * array index. STA MacID=0, ++ * VWiFi Client MacID={1, ODM_ASSOCIATE_ENTRY_NUM-1} */ ++ /* */ ++ /* 2012/02/14 MH Add to share 88E ra with other SW team. */ ++ /* We need to colelct all support abilit to a proper area. */ ++ /* */ ++ bool RaSupport88E; ++ ++ /* Define ........... */ ++ ++ /* Latest packet phy info (ODM write) */ ++ struct odm_phy_dbg_info PhyDbgInfo; ++ ++ /* Latest packet phy info (ODM write) */ ++ struct odm_mac_status_info *pMacInfo; ++ ++ /* Different Team independt structure?? */ ++ ++ /* ODM Structure */ ++ struct fast_ant_train DM_FatTable; ++ struct rtw_dig DM_DigTable; ++ struct rtl_ps DM_PSTable; ++ struct dyn_primary_cca DM_PriCCA; ++ struct rx_hpc DM_RXHP_Table; ++ struct false_alarm_stats FalseAlmCnt; ++ struct false_alarm_stats FlaseAlmCntBuddyAdapter; ++ struct sw_ant_switch DM_SWAT_Table; ++ bool RSSI_test; ++ ++ struct edca_turbo DM_EDCA_Table; ++ u32 WMMEDCA_BE; ++ /* Copy from SD4 structure */ ++ /* */ ++ /* ================================================== */ ++ /* */ ++ ++ bool *pbDriverStopped; ++ bool *pbDriverIsGoingToPnpSetPowerSleep; ++ bool *pinit_adpt_in_progress; ++ ++ /* PSD */ ++ bool bUserAssignLevel; ++ struct timer_list PSDTimer; ++ u8 RSSI_BT; /* come from BT */ ++ bool bPSDinProcess; ++ bool bDMInitialGainEnable; ++ ++ /* for rate adaptive, in fact, 88c/92c fw will handle this */ ++ u8 bUseRAMask; ++ ++ struct odm_rate_adapt RateAdaptive; ++ ++ struct odm_rf_cal RFCalibrateInfo; ++ ++ /* TX power tracking */ ++ u8 BbSwingIdxOfdm; ++ u8 BbSwingIdxOfdmCurrent; ++ u8 BbSwingIdxOfdmBase; ++ bool BbSwingFlagOfdm; ++ u8 BbSwingIdxCck; ++ u8 BbSwingIdxCckCurrent; ++ u8 BbSwingIdxCckBase; ++ bool BbSwingFlagCck; ++ u8 *mp_mode; ++ /* ODM system resource. */ ++ ++ /* ODM relative time. */ ++ struct timer_list PathDivSwitchTimer; ++ /* 2011.09.27 add for Path Diversity */ ++ struct timer_list CCKPathDiversityTimer; ++ struct timer_list FastAntTrainingTimer; ++}; /* DM_Dynamic_Mechanism_Structure */ ++ ++enum ODM_RF_CONTENT { ++ odm_radioa_txt = 0x1000, ++ odm_radiob_txt = 0x1001, ++ odm_radioc_txt = 0x1002, ++ odm_radiod_txt = 0x1003 ++}; ++ ++enum odm_bb_config_type { ++ CONFIG_BB_PHY_REG, ++ CONFIG_BB_AGC_TAB, ++ CONFIG_BB_AGC_TAB_2G, ++ CONFIG_BB_PHY_REG_PG, ++}; ++ ++/* Status code */ ++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, ++}; ++ ++/* 3=========================================================== */ ++/* 3 DIG */ ++/* 3=========================================================== */ ++ ++enum dm_dig_op { ++ RT_TYPE_THRESH_HIGH = 0, ++ RT_TYPE_THRESH_LOW = 1, ++ RT_TYPE_BACKOFF = 2, ++ RT_TYPE_RX_GAIN_MIN = 3, ++ RT_TYPE_RX_GAIN_MAX = 4, ++ RT_TYPE_ENABLE = 5, ++ RT_TYPE_DISABLE = 6, ++ DIG_OP_TYPE_MAX ++}; ++ ++#define DM_DIG_THRESH_HIGH 40 ++#define DM_DIG_THRESH_LOW 35 ++ ++#define DM_SCAN_RSSI_TH 0x14 /* scan return issue for LC */ ++ ++#define DM_false_ALARM_THRESH_LOW 400 ++#define DM_false_ALARM_THRESH_HIGH 1000 ++ ++#define DM_DIG_MAX_NIC 0x4e ++#define DM_DIG_MIN_NIC 0x1e /* 0x22/0x1c */ ++ ++#define DM_DIG_MAX_AP 0x32 ++#define DM_DIG_MIN_AP 0x20 ++ ++#define DM_DIG_MAX_NIC_HP 0x46 ++#define DM_DIG_MIN_NIC_HP 0x2e ++ ++#define DM_DIG_MAX_AP_HP 0x42 ++#define DM_DIG_MIN_AP_HP 0x30 ++ ++/* vivi 92c&92d has different definition, 20110504 */ ++/* this is for 92c */ ++#define DM_DIG_FA_TH0 0x200/* 0x20 */ ++#define DM_DIG_FA_TH1 0x300/* 0x100 */ ++#define DM_DIG_FA_TH2 0x400/* 0x200 */ ++/* this is for 92d */ ++#define DM_DIG_FA_TH0_92D 0x100 ++#define DM_DIG_FA_TH1_92D 0x400 ++#define DM_DIG_FA_TH2_92D 0x600 ++ ++#define DM_DIG_BACKOFF_MAX 12 ++#define DM_DIG_BACKOFF_MIN -4 ++#define DM_DIG_BACKOFF_DEFAULT 10 ++ ++/* 3=========================================================== */ ++/* 3 AGC RX High Power Mode */ ++/* 3=========================================================== */ ++#define LNA_Low_Gain_1 0x64 ++#define LNA_Low_Gain_2 0x5A ++#define LNA_Low_Gain_3 0x58 ++ ++#define FA_RXHP_TH1 5000 ++#define FA_RXHP_TH2 1500 ++#define FA_RXHP_TH3 800 ++#define FA_RXHP_TH4 600 ++#define FA_RXHP_TH5 500 ++ ++/* 3=========================================================== */ ++/* 3 EDCA */ ++/* 3=========================================================== */ ++ ++/* 3=========================================================== */ ++/* 3 Dynamic Tx Power */ ++/* 3=========================================================== */ ++/* Dynamic Tx Power Control Threshold */ ++#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 ++#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 ++#define TX_POWER_NEAR_FIELD_THRESH_AP 0x3F ++ ++#define TxHighPwrLevel_Normal 0 ++#define TxHighPwrLevel_Level1 1 ++#define TxHighPwrLevel_Level2 2 ++#define TxHighPwrLevel_BT1 3 ++#define TxHighPwrLevel_BT2 4 ++#define TxHighPwrLevel_15 5 ++#define TxHighPwrLevel_35 6 ++#define TxHighPwrLevel_50 7 ++#define TxHighPwrLevel_70 8 ++#define TxHighPwrLevel_100 9 ++ ++/* 3=========================================================== */ ++/* 3 Rate Adaptive */ ++/* 3=========================================================== */ ++#define DM_RATR_STA_INIT 0 ++#define DM_RATR_STA_HIGH 1 ++#define DM_RATR_STA_MIDDLE 2 ++#define DM_RATR_STA_LOW 3 ++ ++/* 3=========================================================== */ ++/* 3 BB Power Save */ ++/* 3=========================================================== */ ++ ++enum dm_1r_cca { ++ CCA_1R = 0, ++ CCA_2R = 1, ++ CCA_MAX = 2, ++}; ++ ++enum dm_rf { ++ RF_Save = 0, ++ RF_Normal = 1, ++ RF_MAX = 2, ++}; ++ ++/* 3=========================================================== */ ++/* 3 Antenna Diversity */ ++/* 3=========================================================== */ ++enum dm_swas { ++ Antenna_A = 1, ++ Antenna_B = 2, ++ Antenna_MAX = 3, ++}; ++ ++/* Maximal number of antenna detection mechanism needs to perform. */ ++#define MAX_ANTENNA_DETECTION_CNT 10 ++ ++/* Extern Global Variables. */ ++#define OFDM_TABLE_SIZE_92C 37 ++#define OFDM_TABLE_SIZE_92D 43 ++#define CCK_TABLE_SIZE 33 ++ ++extern u32 OFDMSwingTable[OFDM_TABLE_SIZE_92D]; ++extern u8 CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8]; ++extern u8 CCKSwingTable_Ch14 [CCK_TABLE_SIZE][8]; ++ ++/* check Sta pointer valid or not */ ++#define IS_STA_VALID(pSta) (pSta) ++/* 20100514 Joseph: Add definition for antenna switching test after link. */ ++/* This indicates two different the steps. */ ++/* In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the ++ * signal on the air. */ ++/* In SWAW_STEP_DETERMINE, driver just compares the signal captured in ++ * SWAW_STEP_PEAK */ ++/* with original RSSI to determine if it is necessary to switch antenna. */ ++#define SWAW_STEP_PEAK 0 ++#define SWAW_STEP_DETERMINE 1 ++ ++void ODM_Write_DIG(struct odm_dm_struct *pDM_Odm, u8 CurrentIGI); ++void ODM_Write_CCK_CCA_Thres(struct odm_dm_struct *pDM_Odm, u8 CurCCK_CCAThres); ++ ++void ODM_SetAntenna(struct odm_dm_struct *pDM_Odm, u8 Antenna); ++ ++#define dm_RF_Saving ODM_RF_Saving ++void ODM_RF_Saving(struct odm_dm_struct *pDM_Odm, u8 bForceInNormal); ++ ++#define SwAntDivRestAfterLink ODM_SwAntDivRestAfterLink ++void ODM_SwAntDivRestAfterLink(struct odm_dm_struct *pDM_Odm); ++ ++#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck ++void ODM_TXPowerTrackingCheck(struct odm_dm_struct *pDM_Odm); ++ ++bool ODM_RAStateCheck(struct odm_dm_struct *pDM_Odm, s32 RSSI, ++ bool bForceUpdate, u8 *pRATRState); ++ ++#define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi ++void ODM_SwAntDivChkPerPktRssi(struct odm_dm_struct *pDM_Odm, u8 StationID, ++ struct odm_phy_status_info *pPhyInfo); ++ ++u32 ConvertTo_dB(u32 Value); ++ ++u32 GetPSDData(struct odm_dm_struct *pDM_Odm, unsigned int point, ++ u8 initial_gain_psd); ++ ++void odm_DIGbyRSSI_LPS(struct odm_dm_struct *pDM_Odm); ++ ++u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, ++ u32 ra_mask, u8 rssi_level); ++ ++void ODM_DMInit(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_DMWatchdog(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_CmnInfoInit(struct odm_dm_struct *pDM_Odm, ++ enum odm_common_info_def CmnInfo, u32 Value); ++ ++void ODM_CmnInfoHook(struct odm_dm_struct *pDM_Odm, ++ enum odm_common_info_def CmnInfo, void *pValue); ++ ++void ODM_CmnInfoPtrArrayHook(struct odm_dm_struct *pDM_Odm, ++ enum odm_common_info_def CmnInfo, ++ u16 Index, void *pValue); ++ ++void ODM_CmnInfoUpdate(struct odm_dm_struct *pDM_Odm, u32 CmnInfo, u64 Value); ++ ++void ODM_InitAllTimers(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_CancelAllTimers(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_ReleaseAllTimers(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_AntselStatistics_88C(struct odm_dm_struct *pDM_Odm, u8 MacId, ++ u32 PWDBAll, bool isCCKrate); ++ ++void ODM_SingleDualAntennaDefaultSetting(struct odm_dm_struct *pDM_Odm); ++ ++bool ODM_SingleDualAntennaDetection(struct odm_dm_struct *pDM_Odm, u8 mode); ++ ++void odm_dtc(struct odm_dm_struct *pDM_Odm); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/odm_HWConfig.h b/drivers/staging/r8188eu/include/odm_HWConfig.h +new file mode 100644 +index 000000000000..9b2ab3bcf992 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_HWConfig.h +@@ -0,0 +1,116 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __HALHWOUTSRC_H__ ++#define __HALHWOUTSRC_H__ ++ ++/* Definition */ ++/* CCK Rates, TxHT = 0 */ ++#define DESC92C_RATE1M 0x00 ++#define DESC92C_RATE2M 0x01 ++#define DESC92C_RATE5_5M 0x02 ++#define DESC92C_RATE11M 0x03 ++ ++/* OFDM Rates, TxHT = 0 */ ++#define DESC92C_RATE6M 0x04 ++#define DESC92C_RATE9M 0x05 ++#define DESC92C_RATE12M 0x06 ++#define DESC92C_RATE18M 0x07 ++#define DESC92C_RATE24M 0x08 ++#define DESC92C_RATE36M 0x09 ++#define DESC92C_RATE48M 0x0a ++#define DESC92C_RATE54M 0x0b ++ ++/* MCS Rates, TxHT = 1 */ ++#define DESC92C_RATEMCS0 0x0c ++#define DESC92C_RATEMCS1 0x0d ++#define DESC92C_RATEMCS2 0x0e ++#define DESC92C_RATEMCS3 0x0f ++#define DESC92C_RATEMCS4 0x10 ++#define DESC92C_RATEMCS5 0x11 ++#define DESC92C_RATEMCS6 0x12 ++#define DESC92C_RATEMCS7 0x13 ++#define DESC92C_RATEMCS8 0x14 ++#define DESC92C_RATEMCS9 0x15 ++#define DESC92C_RATEMCS10 0x16 ++#define DESC92C_RATEMCS11 0x17 ++#define DESC92C_RATEMCS12 0x18 ++#define DESC92C_RATEMCS13 0x19 ++#define DESC92C_RATEMCS14 0x1a ++#define DESC92C_RATEMCS15 0x1b ++#define DESC92C_RATEMCS15_SG 0x1c ++#define DESC92C_RATEMCS32 0x20 ++ ++/* structure and define */ ++ ++struct phy_rx_agc_info { ++ #ifdef __LITTLE_ENDIAN ++ u8 gain:7, trsw:1; ++ #else ++ u8 trsw:1, gain:7; ++ #endif ++}; ++ ++struct phy_status_rpt { ++ struct phy_rx_agc_info path_agc[3]; ++ u8 ch_corr[2]; ++ u8 cck_sig_qual_ofdm_pwdb_all; ++ u8 cck_agc_rpt_ofdm_cfosho_a; ++ u8 cck_rpt_b_ofdm_cfosho_b; ++ u8 rsvd_1;/* ch_corr_msb; */ ++ u8 noise_power_db_msb; ++ u8 path_cfotail[2]; ++ u8 pcts_mask[2]; ++ s8 stream_rxevm[2]; ++ u8 path_rxsnr[3]; ++ u8 noise_power_db_lsb; ++ u8 rsvd_2[3]; ++ u8 stream_csi[2]; ++ u8 stream_target_csi[2]; ++ s8 sig_evm; ++ u8 rsvd_3; ++ ++#ifdef __LITTLE_ENDIAN ++ u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ ++ u8 sgi_en:1; ++ u8 rxsc:2; ++ u8 idle_long:1; ++ u8 r_ant_train_en:1; ++ u8 ant_sel_b:1; ++ u8 ant_sel:1; ++#else /* _BIG_ENDIAN_ */ ++ u8 ant_sel:1; ++ u8 ant_sel_b:1; ++ u8 r_ant_train_en:1; ++ u8 idle_long:1; ++ u8 rxsc:2; ++ u8 sgi_en:1; ++ u8 antsel_rx_keep_2:1; /* ex_intf_flg:1; */ ++#endif ++}; ++ ++void odm_Init_RSSIForDM(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_PhyStatusQuery(struct odm_dm_struct *pDM_Odm, ++ struct odm_phy_status_info *pPhyInfo, ++ u8 *pPhyStatus, ++ struct odm_per_pkt_info *pPktinfo, ++ struct adapter *adapt); ++ ++void ODM_MacStatusQuery(struct odm_dm_struct *pDM_Odm, ++ u8 *pMacStatus, ++ u8 MacID, ++ bool bPacketMatchBSSID, ++ bool bPacketToSelf, ++ bool bPacketBeacon); ++ ++enum HAL_STATUS ODM_ConfigRFWithHeaderFile(struct odm_dm_struct *pDM_Odm, ++ enum rf_radio_path Content, ++ enum rf_radio_path eRFPath); ++ ++enum HAL_STATUS ODM_ConfigBBWithHeaderFile(struct odm_dm_struct *pDM_Odm, ++ enum odm_bb_config_type ConfigType); ++ ++enum HAL_STATUS ODM_ConfigMACWithHeaderFile(struct odm_dm_struct *pDM_Odm); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/odm_RTL8188E.h b/drivers/staging/r8188eu/include/odm_RTL8188E.h +new file mode 100644 +index 000000000000..00d2678532f8 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_RTL8188E.h +@@ -0,0 +1,36 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __ODM_RTL8188E_H__ ++#define __ODM_RTL8188E_H__ ++ ++#define MAIN_ANT 0 ++#define AUX_ANT 1 ++#define MAIN_ANT_CG_TRX 1 ++#define AUX_ANT_CG_TRX 0 ++#define MAIN_ANT_CGCS_RX 0 ++#define AUX_ANT_CGCS_RX 1 ++ ++void ODM_DIG_LowerBound_88E(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_AntennaDiversityInit_88E(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_AntennaDiversity_88E(struct odm_dm_struct *pDM_Odm); ++ ++void ODM_SetTxAntByTxInfo_88E(struct odm_dm_struct *pDM_Odm, u8 *pDesc, ++ u8 macId); ++ ++void ODM_UpdateRxIdleAnt_88E(struct odm_dm_struct *pDM_Odm, u8 Ant); ++ ++void ODM_AntselStatistics_88E(struct odm_dm_struct *pDM_Odm, u8 antsel_tr_mux, ++ u32 MacId, u8 RxPWDBAll); ++ ++void odm_FastAntTraining(struct odm_dm_struct *pDM_Odm); ++ ++void odm_FastAntTrainingCallback(struct odm_dm_struct *pDM_Odm); ++ ++void odm_FastAntTrainingWorkItemCallback(struct odm_dm_struct *pDM_Odm); ++ ++void odm_PrimaryCCA_Init(struct odm_dm_struct *pDM_Odm); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/odm_RegConfig8188E.h b/drivers/staging/r8188eu/include/odm_RegConfig8188E.h +new file mode 100644 +index 000000000000..86b5b2d24210 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_RegConfig8188E.h +@@ -0,0 +1,27 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __INC_ODM_REGCONFIG_H_8188E ++#define __INC_ODM_REGCONFIG_H_8188E ++ ++void odm_ConfigRFReg_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u32 Data, ++ enum rf_radio_path RF_PATH, u32 RegAddr); ++ ++void odm_ConfigRF_RadioA_8188E(struct odm_dm_struct *pDM_Odm, ++ u32 Addr, u32 Data); ++ ++void odm_ConfigRF_RadioB_8188E(struct odm_dm_struct *pDM_Odm, ++ u32 Addr, u32 Data); ++ ++void odm_ConfigMAC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, u8 Data); ++ ++void odm_ConfigBB_AGC_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, ++ u32 Bitmask, u32 Data); ++ ++void odm_ConfigBB_PHY_REG_PG_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, ++ u32 Bitmask, u32 Data); ++ ++void odm_ConfigBB_PHY_8188E(struct odm_dm_struct *pDM_Odm, u32 Addr, ++ u32 Bitmask, u32 Data); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/odm_RegDefine11AC.h b/drivers/staging/r8188eu/include/odm_RegDefine11AC.h +new file mode 100644 +index 000000000000..bba7511cf244 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_RegDefine11AC.h +@@ -0,0 +1,29 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __ODM_REGDEFINE11AC_H__ ++#define __ODM_REGDEFINE11AC_H__ ++ ++/* 2 RF REG LIST */ ++ ++/* 2 BB REG LIST */ ++/* PAGE 8 */ ++/* PAGE 9 */ ++#define ODM_REG_OFDM_FA_RST_11AC 0x9A4 ++/* 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 C */ ++#define ODM_REG_IGI_A_11AC 0xC50 ++/* PAGE E */ ++#define ODM_REG_IGI_B_11AC 0xE50 ++/* PAGE F */ ++#define ODM_REG_OFDM_FA_11AC 0xF48 ++ ++/* 2 MAC REG LIST */ ++ ++/* DIG Related */ ++#define ODM_BIT_IGI_11AC 0xFFFFFFFF ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/odm_RegDefine11N.h b/drivers/staging/r8188eu/include/odm_RegDefine11N.h +new file mode 100644 +index 000000000000..5d1d73490c1c +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_RegDefine11N.h +@@ -0,0 +1,143 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#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_RX_DEFUALT_A_11N 0x858 ++#define ODM_REG_RX_DEFUALT_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 ++/* PAGE 9 */ ++#define ODM_REG_ANT_MAPPING1_11N 0x914 ++#define ODM_REG_ANT_MAPPING2_11N 0x918 ++/* PAGE A */ ++#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00 ++#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 ++/* PAGE C */ ++#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00 ++#define ODM_REG_RX_PATH_11N 0xC04 ++#define ODM_REG_TRMUX_11N 0xC08 ++#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C ++#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_BB_PWR_SAV2_11N 0xC70 ++#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_OFDM_FA_TYPE1_11N 0xCF0 ++/* PAGE D */ ++#define ODM_REG_OFDM_FA_RSTD_11N 0xD00 ++#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0 ++#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4 ++#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8 ++/* 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_FPGA0_IQK_11N 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 ++ ++/* 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 ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/odm_interface.h b/drivers/staging/r8188eu/include/odm_interface.h +new file mode 100644 +index 000000000000..6b589413d56c +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_interface.h +@@ -0,0 +1,147 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __ODM_INTERFACE_H__ ++#define __ODM_INTERFACE_H__ ++ ++/* */ ++/* =========== Constant/Structure/Enum/... Define */ ++/* */ ++ ++/* */ ++/* =========== Macro Define */ ++/* */ ++ ++#define _reg_all(_name) ODM_##_name ++#define _reg_ic(_name, _ic) ODM_##_name##_ic ++#define _bit_all(_name) BIT_##_name ++#define _bit_ic(_name, _ic) BIT_##_name##_ic ++ ++/* _cat: implemented by Token-Pasting Operator. */ ++ ++/*=================================== ++ ++#define ODM_REG_DIG_11N 0xC50 ++#define ODM_REG_DIG_11AC 0xDDD ++ ++ODM_REG(DIG,_pDM_Odm) ++=====================================*/ ++ ++#define _reg_11N(_name) ODM_REG_##_name##_11N ++#define _reg_11AC(_name) ODM_REG_##_name##_11AC ++#define _bit_11N(_name) ODM_BIT_##_name##_11N ++#define _bit_11AC(_name) ODM_BIT_##_name##_11AC ++ ++#define _cat(_name, _ic_type, _func) \ ++ ( \ ++ ((_ic_type) & ODM_IC_11N_SERIES) ? _func##_11N(_name) : \ ++ _func##_11AC(_name) \ ++ ) ++ ++/* _name: name of register or bit. */ ++/* Example: "ODM_REG(R_A_AGC_CORE1, pDM_Odm)" */ ++/* gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C", ++ * depends on SupportICType. */ ++#define ODM_REG(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _reg) ++#define ODM_BIT(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _bit) ++ ++enum odm_h2c_cmd { ++ ODM_H2C_RSSI_REPORT = 0, ++ ODM_H2C_PSD_RESULT= 1, ++ ODM_H2C_PathDiv = 2, ++ ODM_MAX_H2CCMD ++}; ++ ++/* 2012/02/17 MH For non-MP compile pass only. Linux does not support workitem. */ ++/* Suggest HW team to use thread instead of workitem. Windows also support the feature. */ ++typedef void (*RT_WORKITEM_CALL_BACK)(void *pContext); ++ ++/* =========== Extern Variable ??? It should be forbidden. */ ++ ++/* =========== EXtern Function Prototype */ ++ ++u8 ODM_Read1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr); ++ ++u16 ODM_Read2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr); ++ ++u32 ODM_Read4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr); ++ ++void ODM_Write1Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u8 Data); ++ ++void ODM_Write2Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u16 Data); ++ ++void ODM_Write4Byte(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 Data); ++ ++void ODM_SetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, ++ u32 BitMask, u32 Data); ++ ++u32 ODM_GetMACReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask); ++ ++void ODM_SetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, ++ u32 BitMask, u32 Data); ++ ++u32 ODM_GetBBReg(struct odm_dm_struct *pDM_Odm, u32 RegAddr, u32 BitMask); ++ ++void ODM_SetRFReg(struct odm_dm_struct *pDM_Odm, enum rf_radio_path eRFPath, ++ u32 RegAddr, u32 BitMask, u32 Data); ++ ++u32 ODM_GetRFReg(struct odm_dm_struct *pDM_Odm, enum rf_radio_path eRFPath, ++ u32 RegAddr, u32 BitMask); ++ ++/* Memory Relative Function. */ ++void ODM_AllocateMemory(struct odm_dm_struct *pDM_Odm, void **pPtr, u32 length); ++void ODM_FreeMemory(struct odm_dm_struct *pDM_Odm, void *pPtr, u32 length); ++ ++s32 ODM_CompareMemory(struct odm_dm_struct *pDM_Odm, void *pBuf1, void *pBuf2, ++ u32 length); ++ ++/* ODM MISC-spin lock relative API. */ ++void ODM_AcquireSpinLock(struct odm_dm_struct *pDM_Odm, ++ enum RT_SPINLOCK_TYPE type); ++ ++void ODM_ReleaseSpinLock(struct odm_dm_struct *pDM_Odm, ++ enum RT_SPINLOCK_TYPE type); ++ ++/* ODM MISC-workitem relative API. */ ++void ODM_InitializeWorkItem(struct odm_dm_struct *pDM_Odm, void *pRtWorkItem, ++ RT_WORKITEM_CALL_BACK RtWorkItemCallback, ++ void *pContext, const char *szID); ++ ++void ODM_StartWorkItem(void *pRtWorkItem); ++ ++void ODM_StopWorkItem(void *pRtWorkItem); ++ ++void ODM_FreeWorkItem(void *pRtWorkItem); ++ ++void ODM_ScheduleWorkItem(void *pRtWorkItem); ++ ++void ODM_IsWorkItemScheduled(void *pRtWorkItem); ++ ++/* ODM Timer relative API. */ ++void ODM_StallExecution(u32 usDelay); ++ ++void ODM_delay_ms(u32 ms); ++ ++void ODM_delay_us(u32 us); ++ ++void ODM_sleep_ms(u32 ms); ++ ++void ODM_sleep_us(u32 us); ++ ++void ODM_SetTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer, ++ u32 msDelay); ++ ++void ODM_InitializeTimer(struct odm_dm_struct *pDM_Odm, ++ struct timer_list *pTimer, void *CallBackFunc, ++ void *pContext, const char *szID); ++ ++void ODM_CancelTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer); ++ ++void ODM_ReleaseTimer(struct odm_dm_struct *pDM_Odm, struct timer_list *pTimer); ++ ++/* ODM FW relative API. */ ++u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum, ++ u32 *pElementID, u32 *pCmdLen, u8 **pCmbBuffer, ++ u8 *CmdStartSeq); ++ ++#endif /* __ODM_INTERFACE_H__ */ +diff --git a/drivers/staging/r8188eu/include/odm_precomp.h b/drivers/staging/r8188eu/include/odm_precomp.h +new file mode 100644 +index 000000000000..a1d6d674bda6 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_precomp.h +@@ -0,0 +1,76 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. i*/ ++ ++#ifndef __ODM_PRECOMP_H__ ++#define __ODM_PRECOMP_H__ ++ ++#include "odm_types.h" ++ ++#define TEST_FALG___ 1 ++ ++/* 2 Config Flags and Structs - defined by each ODM Type */ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "hal_intf.h" ++ ++/* 2 OutSrc Header Files */ ++ ++#include "odm.h" ++#include "odm_HWConfig.h" ++#include "odm_RegDefine11AC.h" ++#include "odm_RegDefine11N.h" ++ ++#include "HalPhyRf_8188e.h"/* for IQK,LCK,Power-tracking */ ++#include "Hal8188ERateAdaptive.h"/* for RA,Power training */ ++#include "rtl8188e_hal.h" ++ ++#include "odm_interface.h" ++#include "odm_reg.h" ++ ++#include "HalHWImg8188E_MAC.h" ++#include "HalHWImg8188E_RF.h" ++#include "HalHWImg8188E_BB.h" ++ ++#include "odm_RegConfig8188E.h" ++#include "odm_RTL8188E.h" ++ ++void odm_DIGInit(struct odm_dm_struct *pDM_Odm); ++void odm_RateAdaptiveMaskInit(struct odm_dm_struct *pDM_Odm); ++void odm_DynamicBBPowerSavingInit(struct odm_dm_struct *pDM_Odm); ++void odm_DynamicTxPowerInit(struct odm_dm_struct *pDM_Odm); ++void odm_TXPowerTrackingInit(struct odm_dm_struct *pDM_Odm); ++void ODM_EdcaTurboInit(struct odm_dm_struct *pDM_Odm); ++void odm_SwAntDivInit_NIC(struct odm_dm_struct *pDM_Odm); ++void odm_GlobalAdapterCheck(void); ++void odm_CommonInfoSelfUpdate(struct odm_dm_struct *pDM_Odm); ++void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm); ++void odm_DIG(struct odm_dm_struct *pDM_Odm); ++void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm); ++void odm_RefreshRateAdaptiveMaskMP(struct odm_dm_struct *pDM_Odm); ++void odm_DynamicBBPowerSaving(struct odm_dm_struct *pDM_Odm); ++void odm_SwAntDivChkAntSwitch(struct odm_dm_struct *pDM_Odm, u8 Step); ++void odm_EdcaTurboCheck(struct odm_dm_struct *pDM_Odm); ++void odm_DynamicTxPower(struct odm_dm_struct *pDM_Odm); ++void odm_CommonInfoSelfInit(struct odm_dm_struct *pDM_Odm); ++void odm_SwAntDivInit(struct odm_dm_struct *pDM_Odm); ++void odm_RSSIMonitorCheck(struct odm_dm_struct *pDM_Odm); ++void odm_RefreshRateAdaptiveMask(struct odm_dm_struct *pDM_Odm); ++void odm_1R_CCA(struct odm_dm_struct *pDM_Odm); ++void odm_RefreshRateAdaptiveMaskCE(struct odm_dm_struct *pDM_Odm); ++void odm_RefreshRateAdaptiveMaskAPADSL(struct odm_dm_struct *pDM_Odm); ++void odm_DynamicTxPowerNIC(struct odm_dm_struct *pDM_Odm); ++void odm_DynamicTxPowerAP(struct odm_dm_struct *pDM_Odm); ++void odm_RSSIMonitorCheckMP(struct odm_dm_struct *pDM_Odm); ++void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm); ++void odm_RSSIMonitorCheckAP(struct odm_dm_struct *pDM_Odm); ++void odm_TXPowerTrackingThermalMeterInit(struct odm_dm_struct *pDM_Odm); ++void odm_EdcaTurboCheckCE(struct odm_dm_struct *pDM_Odm); ++void odm_TXPowerTrackingCheckCE(struct odm_dm_struct *pDM_Odm); ++void odm_TXPowerTrackingCheckMP(struct odm_dm_struct *pDM_Odm); ++void odm_TXPowerTrackingCheckAP(struct odm_dm_struct *pDM_Odm); ++void odm_SwAntDivChkAntSwitchCallback(struct timer_list *t); ++void odm_InitHybridAntDiv(struct odm_dm_struct *pDM_Odm); ++void odm_HwAntDiv(struct odm_dm_struct *pDM_Odm); ++ ++#endif /* __ODM_PRECOMP_H__ */ +diff --git a/drivers/staging/r8188eu/include/odm_reg.h b/drivers/staging/r8188eu/include/odm_reg.h +new file mode 100644 +index 000000000000..78d7e904947c +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_reg.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. i*/ ++ ++#ifndef __HAL_ODM_REG_H__ ++#define __HAL_ODM_REG_H__ ++ ++/* Register Definition */ ++ ++/* MAC REG */ ++#define ODM_BB_RESET 0x002 ++#define ODM_DUMMY 0x4fe ++#define ODM_EDCA_VO_PARAM 0x500 ++#define ODM_EDCA_VI_PARAM 0x504 ++#define ODM_EDCA_BE_PARAM 0x508 ++#define ODM_EDCA_BK_PARAM 0x50C ++#define ODM_TXPAUSE 0x522 ++ ++/* BB REG */ ++#define ODM_FPGA_PHY0_PAGE8 0x800 ++#define ODM_PSD_SETTING 0x808 ++#define ODM_AFE_SETTING 0x818 ++#define ODM_TXAGC_B_6_18 0x830 ++#define ODM_TXAGC_B_24_54 0x834 ++#define ODM_TXAGC_B_MCS32_5 0x838 ++#define ODM_TXAGC_B_MCS0_MCS3 0x83c ++#define ODM_TXAGC_B_MCS4_MCS7 0x848 ++#define ODM_TXAGC_B_MCS8_MCS11 0x84c ++#define ODM_ANALOG_REGISTER 0x85c ++#define ODM_RF_INTERFACE_OUTPUT 0x860 ++#define ODM_TXAGC_B_MCS12_MCS15 0x868 ++#define ODM_TXAGC_B_11_A_2_11 0x86c ++#define ODM_AD_DA_LSB_MASK 0x874 ++#define ODM_ENABLE_3_WIRE 0x88c ++#define ODM_PSD_REPORT 0x8b4 ++#define ODM_R_ANT_SELECT 0x90c ++#define ODM_CCK_ANT_SELECT 0xa07 ++#define ODM_CCK_PD_THRESH 0xa0a ++#define ODM_CCK_RF_REG1 0xa11 ++#define ODM_CCK_MATCH_FILTER 0xa20 ++#define ODM_CCK_RAKE_MAC 0xa2e ++#define ODM_CCK_CNT_RESET 0xa2d ++#define ODM_CCK_TX_DIVERSITY 0xa2f ++#define ODM_CCK_FA_CNT_MSB 0xa5b ++#define ODM_CCK_FA_CNT_LSB 0xa5c ++#define ODM_CCK_NEW_FUNCTION 0xa75 ++#define ODM_OFDM_PHY0_PAGE_C 0xc00 ++#define ODM_OFDM_RX_ANT 0xc04 ++#define ODM_R_A_RXIQI 0xc14 ++#define ODM_R_A_AGC_CORE1 0xc50 ++#define ODM_R_A_AGC_CORE2 0xc54 ++#define ODM_R_B_AGC_CORE1 0xc58 ++#define ODM_R_AGC_PAR 0xc70 ++#define ODM_R_HTSTF_AGC_PAR 0xc7c ++#define ODM_TX_PWR_TRAINING_A 0xc90 ++#define ODM_TX_PWR_TRAINING_B 0xc98 ++#define ODM_OFDM_FA_CNT1 0xcf0 ++#define ODM_OFDM_PHY0_PAGE_D 0xd00 ++#define ODM_OFDM_FA_CNT2 0xda0 ++#define ODM_OFDM_FA_CNT3 0xda4 ++#define ODM_OFDM_FA_CNT4 0xda8 ++#define ODM_TXAGC_A_6_18 0xe00 ++#define ODM_TXAGC_A_24_54 0xe04 ++#define ODM_TXAGC_A_1_MCS32 0xe08 ++#define ODM_TXAGC_A_MCS0_MCS3 0xe10 ++#define ODM_TXAGC_A_MCS4_MCS7 0xe14 ++#define ODM_TXAGC_A_MCS8_MCS11 0xe18 ++#define ODM_TXAGC_A_MCS12_MCS15 0xe1c ++ ++/* RF REG */ ++#define ODM_GAIN_SETTING 0x00 ++#define ODM_CHANNEL 0x18 ++ ++/* Ant Detect Reg */ ++#define ODM_DPDT 0x300 ++ ++/* PSD Init */ ++#define ODM_PSDREG 0x808 ++ ++/* 92D Path Div */ ++#define PATHDIV_REG 0xB30 ++#define PATHDIV_TRI 0xBA0 ++ ++/* */ ++/* Bitmap Definition */ ++/* */ ++ ++#define BIT_FA_RESET BIT(0) ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/odm_types.h b/drivers/staging/r8188eu/include/odm_types.h +new file mode 100644 +index 000000000000..6f4a4bd37ec1 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/odm_types.h +@@ -0,0 +1,45 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __ODM_TYPES_H__ ++#define __ODM_TYPES_H__ ++ ++/* */ ++/* Define Different SW team support */ ++/* */ ++#define ODM_AP 0x01 /* BIT(0) */ ++#define ODM_ADSL 0x02 /* BIT(1) */ ++#define ODM_CE 0x04 /* BIT(2) */ ++#define ODM_MP 0x08 /* BIT(3) */ ++ ++#define RT_PCI_INTERFACE 1 ++#define RT_USB_INTERFACE 2 ++#define RT_SDIO_INTERFACE 3 ++ ++enum HAL_STATUS { ++ HAL_STATUS_SUCCESS, ++ HAL_STATUS_FAILURE, ++}; ++ ++enum RT_SPINLOCK_TYPE { ++ RT_TEMP = 1, ++}; ++ ++#include "basic_types.h" ++ ++#define DEV_BUS_TYPE RT_USB_INTERFACE ++ ++#define SET_TX_DESC_ANTSEL_A_88E(__ptxdesc, __value) \ ++ le32p_replace_bits((__le32 *)(__ptxdesc + 8), __value, BIT(24)) ++#define SET_TX_DESC_ANTSEL_B_88E(__ptxdesc, __value) \ ++ le32p_replace_bits((__le32 *)(__ptxdesc + 8), __value, BIT(25)) ++#define SET_TX_DESC_ANTSEL_C_88E(__ptxdesc, __value) \ ++ le32p_replace_bits((__le32 *)(__ptxdesc + 28), __value, BIT(29)) ++ ++/* define useless flag to avoid compile warning */ ++#define USE_WORKITEM 0 ++#define FOR_BRAZIL_PRETEST 0 ++#define BT_30_SUPPORT 0 ++#define FPGA_TWO_MAC_VERIFICATION 0 ++ ++#endif /* __ODM_TYPES_H__ */ +diff --git a/drivers/staging/r8188eu/include/osdep_intf.h b/drivers/staging/r8188eu/include/osdep_intf.h +new file mode 100644 +index 000000000000..3ea60feee2db +--- /dev/null ++++ b/drivers/staging/r8188eu/include/osdep_intf.h +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __OSDEP_INTF_H_ ++#define __OSDEP_INTF_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++struct intf_priv { ++ u8 *intf_dev; ++ u32 max_iosz; /* USB2.0: 128, USB1.1: 64, SDIO:64 */ ++ u32 max_xmitsz; /* USB2.0: unlimited, SDIO:512 */ ++ u32 max_recvsz; /* USB2.0: unlimited, SDIO:512 */ ++ ++ u8 *io_rwmem; ++ u8 *allocated_io_rwmem; ++ u32 io_wsz; /* unit: 4bytes */ ++ u32 io_rsz;/* unit: 4bytes */ ++ u8 intf_status; ++ ++ void (*_bus_io)(u8 *priv); ++ ++/* ++Under Sync. IRP (SDIO/USB) ++A protection mechanism is necessary for the io_rwmem(read/write protocol) ++ ++Under Async. IRP (SDIO/USB) ++The protection mechanism is through the pending queue. ++*/ ++ struct mutex ioctl_mutex; ++ /* when in USB, IO is through interrupt in/out endpoints */ ++ struct usb_device *udev; ++ struct urb *piorw_urb; ++ u8 io_irp_cnt; ++ u8 bio_irp_pending; ++ struct semaphore io_retevt; ++ struct timer_list io_timer; ++ u8 bio_irp_timeout; ++ u8 bio_timer_cancel; ++}; ++ ++u8 rtw_init_drv_sw(struct adapter *padapter); ++u8 rtw_free_drv_sw(struct adapter *padapter); ++u8 rtw_reset_drv_sw(struct adapter *padapter); ++ ++u32 rtw_start_drv_threads(struct adapter *padapter); ++void rtw_stop_drv_threads (struct adapter *padapter); ++void rtw_cancel_all_timer(struct adapter *padapter); ++ ++int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname); ++struct net_device *rtw_init_netdev(struct adapter *padapter); ++u16 rtw_recv_select_queue(struct sk_buff *skb); ++void rtw_proc_init_one(struct net_device *dev); ++void rtw_proc_remove_one(struct net_device *dev); ++ ++void rtw_ips_dev_unload(struct adapter *padapter); ++ ++int rtw_ips_pwr_up(struct adapter *padapter); ++void rtw_ips_pwr_down(struct adapter *padapter); ++int rtw_hw_suspend(struct adapter *padapter); ++int rtw_hw_resume(struct adapter *padapter); ++ ++#endif /* _OSDEP_INTF_H_ */ +diff --git a/drivers/staging/r8188eu/include/osdep_service.h b/drivers/staging/r8188eu/include/osdep_service.h +new file mode 100644 +index 000000000000..029aa4e92c9b +--- /dev/null ++++ b/drivers/staging/r8188eu/include/osdep_service.h +@@ -0,0 +1,315 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __OSDEP_SERVICE_H_ ++#define __OSDEP_SERVICE_H_ ++ ++#include ++#include "basic_types.h" ++ ++#define _FAIL 0 ++#define _SUCCESS 1 ++#define RTW_RX_HANDLED 2 ++ ++#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 /* Necessary because we use the proc fs */ ++#include /* for struct tasklet_struct */ ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct __queue { ++ struct list_head queue; ++ spinlock_t lock; ++}; ++ ++#define thread_exit() complete_and_exit(NULL, 0) ++ ++static inline struct list_head *get_list_head(struct __queue *queue) ++{ ++ return (&(queue->queue)); ++} ++ ++static inline int _enter_critical_mutex(struct mutex *pmutex, unsigned long *pirqL) ++{ ++ int ret; ++ ++ ret = mutex_lock_interruptible(pmutex); ++ return ret; ++} ++ ++static inline void _exit_critical_mutex(struct mutex *pmutex, unsigned long *pirqL) ++{ ++ mutex_unlock(pmutex); ++} ++ ++static inline void rtw_list_delete(struct list_head *plist) ++{ ++ list_del_init(plist); ++} ++ ++static inline void _set_timer(struct timer_list *ptimer,u32 delay_time) ++{ ++ mod_timer(ptimer , (jiffies+(delay_time*HZ/1000))); ++} ++ ++static inline void _cancel_timer(struct timer_list *ptimer,u8 *bcancelled) ++{ ++ del_timer_sync(ptimer); ++ *bcancelled= true;/* true ==1; false==0 */ ++} ++ ++#define RTW_TIMER_HDL_ARGS void *FunctionContext ++#define RTW_TIMER_HDL_NAME(name) rtw_##name##_timer_hdl ++#define RTW_DECLARE_TIMER_HDL(name) void RTW_TIMER_HDL_NAME(name)(RTW_TIMER_HDL_ARGS) ++ ++static inline void _init_workitem(struct work_struct *pwork, void *pfunc, void * cntx) ++{ ++ INIT_WORK(pwork, pfunc); ++} ++ ++static inline void _set_workitem(struct work_struct *pwork) ++{ ++ schedule_work(pwork); ++} ++ ++static inline void _cancel_workitem_sync(struct work_struct *pwork) ++{ ++ cancel_work_sync(pwork); ++} ++/* */ ++/* Global Mutex: can only be used at PASSIVE level. */ ++/* */ ++ ++#define ACQUIRE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ while (atomic_inc_return((atomic_t *)&(_MutexCounter)) != 1)\ ++ { \ ++ atomic_dec((atomic_t *)&(_MutexCounter)); \ ++ msleep(10); \ ++ } \ ++} ++ ++#define RELEASE_GLOBAL_MUTEX(_MutexCounter) \ ++{ \ ++ atomic_dec((atomic_t *)&(_MutexCounter)); \ ++} ++ ++static inline int rtw_netif_queue_stopped(struct net_device *pnetdev) ++{ ++ return netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 0)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 1)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 2)) && ++ netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 3)); ++} ++ ++static inline void rtw_netif_wake_queue(struct net_device *pnetdev) ++{ ++ netif_tx_wake_all_queues(pnetdev); ++} ++ ++static inline void rtw_netif_start_queue(struct net_device *pnetdev) ++{ ++ netif_tx_start_all_queues(pnetdev); ++} ++ ++static inline void rtw_netif_stop_queue(struct net_device *pnetdev) ++{ ++ netif_tx_stop_all_queues(pnetdev); ++} ++ ++extern int RTW_STATUS_CODE(int error_code); ++ ++extern unsigned char MCS_rate_2R[16]; ++extern unsigned char MCS_rate_1R[16]; ++extern unsigned char RTW_WPA_OUI[]; ++extern unsigned char WPA_TKIP_CIPHER[4]; ++extern unsigned char RSN_TKIP_CIPHER[4]; ++ ++void *rtw_malloc2d(int h, int w, int size); ++ ++u32 _rtw_down_sema(struct semaphore *sema); ++void _rtw_mutex_init(struct mutex *pmutex); ++void _rtw_mutex_free(struct mutex *pmutex); ++ ++void _rtw_init_queue(struct __queue *pqueue); ++ ++u32 rtw_systime_to_ms(u32 systime); ++u32 rtw_ms_to_systime(u32 ms); ++s32 rtw_get_passing_time_ms(u32 start); ++ ++void rtw_usleep_os(int us); ++ ++u32 rtw_atoi(u8 *s); ++ ++static inline unsigned char _cancel_timer_ex(struct timer_list *ptimer) ++{ ++ return del_timer_sync(ptimer); ++} ++ ++static __inline void thread_enter(char *name) ++{ ++#ifdef daemonize ++ daemonize("%s", name); ++#endif ++ allow_signal(SIGTERM); ++} ++ ++static inline void flush_signals_thread(void) ++{ ++ if (signal_pending (current)) ++ flush_signals(current); ++} ++ ++static inline int res_to_status(int res) ++{ ++ return res; ++} ++ ++#define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r)) ++#define RND4(x) (((x >> 2) + (((x & 3) == 0) ? 0: 1)) << 2) ++ ++static inline u32 _RND4(u32 sz) ++{ ++ u32 val; ++ ++ val = ((sz >> 2) + ((sz & 3) ? 1: 0)) << 2; ++ return val; ++} ++ ++static inline u32 _RND8(u32 sz) ++{ ++ u32 val; ++ ++ val = ((sz >> 3) + ((sz & 7) ? 1: 0)) << 3; ++ return val; ++} ++ ++static inline u32 _RND128(u32 sz) ++{ ++ u32 val; ++ ++ val = ((sz >> 7) + ((sz & 127) ? 1: 0)) << 7; ++ return val; ++} ++ ++static inline u32 _RND256(u32 sz) ++{ ++ u32 val; ++ ++ val = ((sz >> 8) + ((sz & 255) ? 1: 0)) << 8; ++ return val; ++} ++ ++static inline u32 _RND512(u32 sz) ++{ ++ u32 val; ++ ++ val = ((sz >> 9) + ((sz & 511) ? 1: 0)) << 9; ++ return val; ++} ++ ++static inline u32 bitshift(u32 bitmask) ++{ ++ u32 i; ++ ++ for (i = 0; i <= 31; i++) ++ if (((bitmask>>i) & 0x1) == 1) break; ++ return i; ++} ++ ++/* limitation of path length */ ++#define PATH_LENGTH_MAX PATH_MAX ++ ++struct rtw_netdev_priv_indicator { ++ void *priv; ++ u32 sizeof_priv; ++}; ++struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, ++ void *old_priv); ++struct net_device *rtw_alloc_etherdev(int sizeof_priv); ++ ++#define rtw_netdev_priv(netdev) \ ++ (((struct rtw_netdev_priv_indicator *)netdev_priv(netdev))->priv) ++void rtw_free_netdev(struct net_device *netdev); ++ ++#define NDEV_FMT "%s" ++#define NDEV_ARG(ndev) ndev->name ++#define ADPT_FMT "%s" ++#define ADPT_ARG(adapter) adapter->pnetdev->name ++#define FUNC_NDEV_FMT "%s(%s)" ++#define FUNC_NDEV_ARG(ndev) __func__, ndev->name ++#define FUNC_ADPT_FMT "%s(%s)" ++#define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name ++ ++#define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)),(sig), 1) ++ ++/* Macros for handling unaligned memory accesses */ ++ ++#define RTW_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) ++#define RTW_PUT_BE16(a, val) \ ++ do { \ ++ (a)[0] = ((u16) (val)) >> 8; \ ++ (a)[1] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define RTW_PUT_LE16(a, val) \ ++ do { \ ++ (a)[1] = ((u16) (val)) >> 8; \ ++ (a)[0] = ((u16) (val)) & 0xff; \ ++ } while (0) ++ ++#define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ ++ ((u32) (a)[2])) ++ ++#define RTW_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) ++ ++void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len); ++ ++struct rtw_cbuf { ++ u32 write; ++ u32 read; ++ u32 size; ++ void *bufs[0]; ++}; ++ ++bool rtw_cbuf_full(struct rtw_cbuf *cbuf); ++bool rtw_cbuf_empty(struct rtw_cbuf *cbuf); ++bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf); ++void *rtw_cbuf_pop(struct rtw_cbuf *cbuf); ++struct rtw_cbuf *rtw_cbuf_alloc(u32 size); ++int wifirate2_ratetbl_inx(unsigned char rate); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/recv_osdep.h b/drivers/staging/r8188eu/include/recv_osdep.h +new file mode 100644 +index 000000000000..72ddf515071e +--- /dev/null ++++ b/drivers/staging/r8188eu/include/recv_osdep.h +@@ -0,0 +1,37 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RECV_OSDEP_H_ ++#define __RECV_OSDEP_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); ++void _rtw_free_recv_priv(struct recv_priv *precvpriv); ++ ++s32 rtw_recv_entry(struct recv_frame *precv_frame); ++int rtw_recv_indicatepkt(struct adapter *adapter, struct recv_frame *recv_frame); ++void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *retpkt); ++ ++void rtw_hostapd_mlme_rx(struct adapter *padapter, struct recv_frame *recv_fr); ++void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup); ++ ++int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); ++void rtw_free_recv_priv(struct recv_priv *precvpriv); ++ ++int rtw_os_recv_resource_init(struct recv_priv *recvpr, struct adapter *adapt); ++int rtw_os_recv_resource_alloc(struct adapter *adapt, struct recv_frame *recvfr); ++void rtw_os_recv_resource_free(struct recv_priv *precvpriv); ++ ++int rtw_os_recvbuf_resource_alloc(struct adapter *adapt, struct recv_buf *buf); ++int rtw_os_recvbuf_resource_free(struct adapter *adapt, struct recv_buf *buf); ++ ++void rtw_os_read_port(struct adapter *padapter, struct recv_buf *precvbuf); ++ ++void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl); ++int _netdev_open(struct net_device *pnetdev); ++int netdev_open(struct net_device *pnetdev); ++int netdev_close(struct net_device *pnetdev); ++ ++#endif /* */ +diff --git a/drivers/staging/r8188eu/include/rtl8188e_cmd.h b/drivers/staging/r8188eu/include/rtl8188e_cmd.h +new file mode 100644 +index 000000000000..6fbf9a47430b +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_cmd.h +@@ -0,0 +1,106 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTL8188E_CMD_H__ ++#define __RTL8188E_CMD_H__ ++ ++enum RTL8188E_H2C_CMD_ID { ++ /* Class Common */ ++ H2C_COM_RSVD_PAGE = 0x00, ++ H2C_COM_MEDIA_STATUS_RPT = 0x01, ++ H2C_COM_SCAN = 0x02, ++ H2C_COM_KEEP_ALIVE = 0x03, ++ H2C_COM_DISCNT_DECISION = 0x04, ++ H2C_COM_INIT_OFFLOAD = 0x06, ++ H2C_COM_REMOTE_WAKE_CTL = 0x07, ++ H2C_COM_AP_OFFLOAD = 0x08, ++ H2C_COM_BCN_RSVD_PAGE = 0x09, ++ H2C_COM_PROB_RSP_RSVD_PAGE = 0x0A, ++ ++ /* Class PS */ ++ H2C_PS_PWR_MODE = 0x20, ++ H2C_PS_TUNE_PARA = 0x21, ++ H2C_PS_TUNE_PARA_2 = 0x22, ++ H2C_PS_LPS_PARA = 0x23, ++ H2C_PS_P2P_OFFLOAD = 0x24, ++ ++ /* Class DM */ ++ H2C_DM_MACID_CFG = 0x40, ++ H2C_DM_TXBF = 0x41, ++ ++ /* Class BT */ ++ H2C_BT_COEX_MASK = 0x60, ++ H2C_BT_COEX_GPIO_MODE = 0x61, ++ H2C_BT_DAC_SWING_VAL = 0x62, ++ H2C_BT_PSD_RST = 0x63, ++ ++ /* Class */ ++ H2C_RESET_TSF = 0xc0, ++}; ++ ++struct cmd_msg_parm { ++ u8 eid; /* element id */ ++ u8 sz; /* sz */ ++ u8 buf[6]; ++}; ++ ++enum { ++ PWRS ++}; ++ ++struct setpwrmode_parm { ++ u8 Mode;/* 0:Active,1:LPS,2:WMMPS */ ++ u8 SmartPS_RLBM;/* LPS= 0:PS_Poll,1:PS_Poll,2:NullData,WMM= 0:PS_Poll,1:NullData */ ++ u8 AwakeInterval; /* unit: beacon interval */ ++ u8 bAllQueueUAPSD; ++ u8 PwrState;/* AllON(0x0c),RFON(0x04),RFOFF(0x00) */ ++}; ++ ++struct H2C_SS_RFOFF_PARAM { ++ u8 ROFOn; /* 1: on, 0:off */ ++ u16 gpio_period; /* unit: 1024 us */ ++} __packed; ++ ++struct joinbssrpt_parm { ++ u8 OpMode; /* RT_MEDIA_STATUS */ ++}; ++ ++struct rsvdpage_loc { ++ u8 LocProbeRsp; ++ u8 LocPsPoll; ++ u8 LocNullData; ++ u8 LocQosNull; ++ u8 LocBTQosNull; ++}; ++ ++struct P2P_PS_Offload_t { ++ u8 Offload_En:1; ++ u8 role:1; /* 1: Owner, 0: Client */ ++ u8 CTWindow_En:1; ++ u8 NoA0_En:1; ++ u8 NoA1_En:1; ++ u8 AllStaSleep:1; /* Only valid in Owner */ ++ u8 discovery:1; ++ u8 rsvd:1; ++}; ++ ++struct P2P_PS_CTWPeriod_t { ++ u8 CTWPeriod; /* TU */ ++}; ++ ++/* host message to firmware cmd */ ++void rtl8188e_set_FwPwrMode_cmd(struct adapter *padapter, u8 Mode); ++void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *padapter, u8 mstatus); ++u8 rtl8188e_set_rssi_cmd(struct adapter *padapter, u8 *param); ++u8 rtl8188e_set_raid_cmd(struct adapter *padapter, u32 mask); ++void rtl8188e_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 arg, ++ u8 rssi_level); ++ ++#ifdef CONFIG_88EU_P2P ++void rtl8188e_set_p2p_ps_offload_cmd(struct adapter *adapt, u8 p2p_ps_state); ++#endif /* CONFIG_88EU_P2P */ ++ ++void CheckFwRsvdPageContent(struct adapter *adapt); ++void rtl8188e_set_FwMediaStatus_cmd(struct adapter *adapt, __le16 mstatus_rpt); ++ ++#endif/* __RTL8188E_CMD_H__ */ +diff --git a/drivers/staging/r8188eu/include/rtl8188e_dm.h b/drivers/staging/r8188eu/include/rtl8188e_dm.h +new file mode 100644 +index 000000000000..3ead20b321a9 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_dm.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTL8188E_DM_H__ ++#define __RTL8188E_DM_H__ ++ ++enum{ ++ UP_LINK, ++ DOWN_LINK, ++}; ++/* duplicate code,will move to ODM ######### */ ++#define IQK_MAC_REG_NUM 4 ++#define IQK_ADDA_REG_NUM 16 ++#define IQK_BB_REG_NUM 9 ++#define HP_THERMAL_NUM 8 ++/* duplicate code,will move to ODM ######### */ ++struct dm_priv { ++ u8 DM_Type; ++ u8 DMFlag; ++ u8 InitDMFlag; ++ u32 InitODMFlag; ++ ++ /* Upper and Lower Signal threshold for Rate Adaptive*/ ++ int UndecoratedSmoothedPWDB; ++ int UndecoratedSmoothedCCK; ++ int EntryMinUndecoratedSmoothedPWDB; ++ int EntryMaxUndecoratedSmoothedPWDB; ++ int MinUndecoratedPWDBForDM; ++ int LastMinUndecoratedPWDBForDM; ++ ++ /* for High Power */ ++ u8 bDynamicTxPowerEnable; ++ u8 LastDTPLvl; ++ u8 DynamicTxHighPowerLvl;/* Tx Power Control for Near/Far Range */ ++ u8 PowerIndex_backup[6]; ++}; ++ ++void rtl8188e_init_dm_priv(struct adapter *adapt); ++void rtl8188e_deinit_dm_priv(struct adapter *adapt); ++void rtl8188e_InitHalDm(struct adapter *adapt); ++void rtl8188e_HalDmWatchDog(struct adapter *adapt); ++ ++void AntDivCompare8188E(struct adapter *adapt, struct wlan_bssid_ex *dst, ++ struct wlan_bssid_ex *src); ++u8 AntDivBeforeLink8188E(struct adapter *adapt); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtl8188e_hal.h b/drivers/staging/r8188eu/include/rtl8188e_hal.h +new file mode 100644 +index 000000000000..3939bf053de1 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_hal.h +@@ -0,0 +1,452 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTL8188E_HAL_H__ ++#define __RTL8188E_HAL_H__ ++ ++/* include HAL Related header after HAL Related compiling flags */ ++#include "rtl8188e_spec.h" ++#include "Hal8188EPhyReg.h" ++#include "Hal8188EPhyCfg.h" ++#include "rtl8188e_rf.h" ++#include "rtl8188e_dm.h" ++#include "rtl8188e_recv.h" ++#include "rtl8188e_xmit.h" ++#include "rtl8188e_cmd.h" ++#include "Hal8188EPwrSeq.h" ++#include "rtl8188e_sreset.h" ++#include "rtw_efuse.h" ++ ++#include "odm_precomp.h" ++ ++/* Fw Array */ ++#define Rtl8188E_FwImageArray Rtl8188EFwImgArray ++#define Rtl8188E_FWImgArrayLength Rtl8188EFWImgArrayLength ++ ++#define RTL8188E_FW_UMC_IMG "rtl8188E\\rtl8188efw.bin" ++#define RTL8188E_PHY_REG "rtl8188E\\PHY_REG_1T.txt" ++#define RTL8188E_PHY_RADIO_A "rtl8188E\\radio_a_1T.txt" ++#define RTL8188E_PHY_RADIO_B "rtl8188E\\radio_b_1T.txt" ++#define RTL8188E_AGC_TAB "rtl8188E\\AGC_TAB_1T.txt" ++#define RTL8188E_PHY_MACREG "rtl8188E\\MAC_REG.txt" ++#define RTL8188E_PHY_REG_PG "rtl8188E\\PHY_REG_PG.txt" ++#define RTL8188E_PHY_REG_MP "rtl8188E\\PHY_REG_MP.txt" ++ ++/* RTL8188E Power Configuration CMDs for USB/SDIO interfaces */ ++#define Rtl8188E_NIC_PWR_ON_FLOW rtl8188E_power_on_flow ++#define Rtl8188E_NIC_RF_OFF_FLOW rtl8188E_radio_off_flow ++#define Rtl8188E_NIC_DISABLE_FLOW rtl8188E_card_disable_flow ++#define Rtl8188E_NIC_ENABLE_FLOW rtl8188E_card_enable_flow ++#define Rtl8188E_NIC_SUSPEND_FLOW rtl8188E_suspend_flow ++#define Rtl8188E_NIC_RESUME_FLOW rtl8188E_resume_flow ++#define Rtl8188E_NIC_PDN_FLOW rtl8188E_hwpdn_flow ++#define Rtl8188E_NIC_LPS_ENTER_FLOW rtl8188E_enter_lps_flow ++#define Rtl8188E_NIC_LPS_LEAVE_FLOW rtl8188E_leave_lps_flow ++ ++#define DRVINFO_SZ 4 /* unit is 8bytes */ ++#define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len) & 0x7F ? 1 : 0)) ++ ++/* download firmware related data structure */ ++#define FW_8188E_SIZE 0x4000 /* 16384,16k */ ++#define FW_8188E_START_ADDRESS 0x1000 ++#define FW_8188E_END_ADDRESS 0x1FFF /* 0x5FFF */ ++ ++#define MAX_PAGE_SIZE 4096 /* @ page : 4k bytes */ ++ ++#define IS_FW_HEADER_EXIST(_pFwHdr) \ ++ ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 || \ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 || \ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300 || \ ++ (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88E0) ++ ++/* This structure must be careful with byte-ordering */ ++ ++struct rt_firmware_hdr { ++ /* 8-byte alinment required */ ++ /* LONG WORD 0 ---- */ ++ __le16 Signature; /* 92C0: test chip; 92C, ++ * 88C0: test chip; 88C1: MP A-cut; ++ * 92C1: MP A-cut */ ++ u8 Category; /* AP/NIC and USB/PCI */ ++ u8 Function; /* Reserved for different FW function ++ * indcation, for further use when ++ * driver needs to download different ++ * FW for different conditions */ ++ __le16 Version; /* FW Version */ ++ u8 Subversion; /* FW Subversion, default 0x00 */ ++ u16 Rsvd1; ++ ++ /* LONG WORD 1 ---- */ ++ u8 Month; /* Release time Month field */ ++ u8 Date; /* Release time Date field */ ++ u8 Hour; /* Release time Hour field */ ++ u8 Minute; /* Release time Minute field */ ++ __le16 RamCodeSize; /* The size of RAM code */ ++ u8 Foundry; ++ u8 Rsvd2; ++ ++ /* LONG WORD 2 ---- */ ++ __le32 SvnIdx; /* The SVN entry index */ ++ u32 Rsvd3; ++ ++ /* LONG WORD 3 ---- */ ++ u32 Rsvd4; ++ u32 Rsvd5; ++}; ++ ++#define DRIVER_EARLY_INT_TIME 0x05 ++#define BCN_DMA_ATIME_INT_TIME 0x02 ++ ++enum usb_rx_agg_mode { ++ USB_RX_AGG_DISABLE, ++ USB_RX_AGG_DMA, ++ USB_RX_AGG_USB, ++ USB_RX_AGG_MIX ++}; ++ ++#define MAX_RX_DMA_BUFFER_SIZE_88E \ ++ 0x2400 /* 9k for 88E nornal chip , MaxRxBuff=10k-max(TxReportSize(64*8), ++ * WOLPattern(16*24)) */ ++ ++#define MAX_TX_REPORT_BUFFER_SIZE 0x0400 /* 1k */ ++ ++/* BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */ ++#define MAX_TX_QUEUE 9 ++ ++#define TX_SELE_HQ BIT(0) /* High Queue */ ++#define TX_SELE_LQ BIT(1) /* Low Queue */ ++#define TX_SELE_NQ BIT(2) /* Normal Queue */ ++ ++/* Note: We will divide number of page equally for each queue other ++ * than public queue! */ ++/* 22k = 22528 bytes = 176 pages (@page = 128 bytes) */ ++/* must reserved about 7 pages for LPS => 176-7 = 169 (0xA9) */ ++/* 2*BCN / 1*ps-poll / 1*null-data /1*prob_rsp /1*QOS null-data /1*BT QOS ++ * null-data */ ++ ++#define TX_TOTAL_PAGE_NUMBER_88E 0xA9/* 169 (21632=> 21k) */ ++ ++#define TX_PAGE_BOUNDARY_88E (TX_TOTAL_PAGE_NUMBER_88E + 1) ++ ++/* Note: For Normal Chip Setting ,modify later */ ++#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER \ ++ TX_TOTAL_PAGE_NUMBER_88E /* 0xA9 , 0xb0=>176=>22k */ ++#define WMM_NORMAL_TX_PAGE_BOUNDARY_88E \ ++ (WMM_NORMAL_TX_TOTAL_PAGE_NUMBER + 1) /* 0xA9 */ ++ ++/* Chip specific */ ++#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) ++#define CHIP_BONDING_92C_1T2R 0x1 ++#define CHIP_BONDING_88C_USB_MCARD 0x2 ++#define CHIP_BONDING_88C_USB_HP 0x1 ++#include "HalVerDef.h" ++#include "hal_com.h" ++ ++/* Channel Plan */ ++enum ChannelPlan { ++ CHPL_FCC = 0, ++ CHPL_IC = 1, ++ CHPL_ETSI = 2, ++ CHPL_SPA = 3, ++ CHPL_FRANCE = 4, ++ CHPL_MKK = 5, ++ CHPL_MKK1 = 6, ++ CHPL_ISRAEL = 7, ++ CHPL_TELEC = 8, ++ CHPL_GLOBAL = 9, ++ CHPL_WORLD = 10, ++}; ++ ++struct txpowerinfo24g { ++ u8 IndexCCK_Base[RF_PATH_MAX][MAX_CHNL_GROUP_24G]; ++ u8 IndexBW40_Base[RF_PATH_MAX][MAX_CHNL_GROUP_24G]; ++ /* If only one tx, only BW20 and OFDM are used. */ ++ s8 CCK_Diff[RF_PATH_MAX][MAX_TX_COUNT]; ++ s8 OFDM_Diff[RF_PATH_MAX][MAX_TX_COUNT]; ++ s8 BW20_Diff[RF_PATH_MAX][MAX_TX_COUNT]; ++ s8 BW40_Diff[RF_PATH_MAX][MAX_TX_COUNT]; ++}; ++ ++#define EFUSE_REAL_CONTENT_LEN 512 ++#define EFUSE_MAX_SECTION 16 ++#define EFUSE_IC_ID_OFFSET 506 /* For some inferior IC purpose*/ ++#define AVAILABLE_EFUSE_ADDR(addr) (addr < EFUSE_REAL_CONTENT_LEN) ++/* To prevent out of boundary programming case, */ ++/* leave 1byte and program full section */ ++/* 9bytes + 1byt + 5bytes and pre 1byte. */ ++/* For worst case: */ ++/* | 1byte|----8bytes----|1byte|--5bytes--| */ ++/* | | Reserved(14bytes) | */ ++ ++/* PG data exclude header, dummy 6 bytes frome CP test and reserved 1byte. */ ++#define EFUSE_OOB_PROTECT_BYTES 15 ++ ++#define HWSET_MAX_SIZE_88E 512 ++ ++#define EFUSE_REAL_CONTENT_LEN_88E 256 ++#define EFUSE_MAP_LEN_88E 512 ++#define EFUSE_MAP_LEN EFUSE_MAP_LEN_88E ++#define EFUSE_MAX_SECTION_88E 64 ++#define EFUSE_MAX_WORD_UNIT_88E 4 ++#define EFUSE_IC_ID_OFFSET_88E 506 ++#define AVAILABLE_EFUSE_ADDR_88E(addr) \ ++ (addr < EFUSE_REAL_CONTENT_LEN_88E) ++/* To prevent out of boundary programming case, leave 1byte and program ++ * full section */ ++/* 9bytes + 1byt + 5bytes and pre 1byte. */ ++/* For worst case: */ ++/* | 2byte|----8bytes----|1byte|--7bytes--| 92D */ ++/* PG data exclude header, dummy 7 bytes frome CP test and reserved 1byte. */ ++#define EFUSE_OOB_PROTECT_BYTES_88E 18 ++#define EFUSE_PROTECT_BYTES_BANK_88E 16 ++ ++/* EFUSE for BT definition */ ++#define EFUSE_BT_REAL_CONTENT_LEN 1536 /* 512*3 */ ++#define EFUSE_BT_MAP_LEN 1024 /* 1k bytes */ ++#define EFUSE_BT_MAX_SECTION 128 /* 1024/8 */ ++ ++#define EFUSE_PROTECT_BYTES_BANK 16 ++ ++/* For RTL8723 WiFi/BT/GPS multi-function configuration. */ ++enum rt_multi_func { ++ RT_MULTI_FUNC_NONE = 0x00, ++ RT_MULTI_FUNC_WIFI = 0x01, ++ RT_MULTI_FUNC_BT = 0x02, ++ RT_MULTI_FUNC_GPS = 0x04, ++}; ++ ++/* For RTL8723 regulator mode. */ ++enum rt_regulator_mode { ++ RT_SWITCHING_REGULATOR = 0, ++ RT_LDO_REGULATOR = 1, ++}; ++ ++struct hal_data_8188e { ++ struct HAL_VERSION VersionID; ++ enum rt_multi_func MultiFunc; /* For multi-function consideration. */ ++ enum rt_regulator_mode RegulatorMode; /* switching regulator or LDO */ ++ u16 CustomerID; ++ ++ u16 FirmwareVersion; ++ u16 FirmwareVersionRev; ++ u16 FirmwareSubVersion; ++ u16 FirmwareSignature; ++ u8 PGMaxGroup; ++ /* current WIFI_PHY values */ ++ u32 ReceiveConfig; ++ enum wireless_mode CurrentWirelessMode; ++ enum ht_channel_width CurrentChannelBW; ++ u8 CurrentChannel; ++ u8 nCur40MhzPrimeSC;/* Control channel sub-carrier */ ++ ++ u16 BasicRateSet; ++ ++ /* rf_ctrl */ ++ u8 rf_chip; ++ u8 rf_type; ++ u8 NumTotalRFPath; ++ ++ u8 BoardType; ++ ++ /* EEPROM setting. */ ++ u16 EEPROMVID; ++ u16 EEPROMPID; ++ u16 EEPROMSVID; ++ u16 EEPROMSDID; ++ u8 EEPROMCustomerID; ++ u8 EEPROMSubCustomerID; ++ u8 EEPROMVersion; ++ u8 EEPROMRegulatory; ++ ++ u8 bTXPowerDataReadFromEEPORM; ++ u8 EEPROMThermalMeter; ++ u8 bAPKThermalMeterIgnore; ++ ++ bool EepromOrEfuse; ++ struct efuse_hal EfuseHal; ++ ++ u8 Index24G_CCK_Base[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 Index24G_BW40_Base[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ /* If only one tx, only BW20 and OFDM are used. */ ++ s8 CCK_24G_Diff[RF_PATH_MAX][MAX_TX_COUNT]; ++ s8 OFDM_24G_Diff[RF_PATH_MAX][MAX_TX_COUNT]; ++ s8 BW20_24G_Diff[RF_PATH_MAX][MAX_TX_COUNT]; ++ s8 BW40_24G_Diff[RF_PATH_MAX][MAX_TX_COUNT]; ++ ++ u8 TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ /* For HT 40MHZ pwr */ ++ u8 TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ /* For HT 40MHZ pwr */ ++ u8 TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ /* HT 20<->40 Pwr diff */ ++ u8 TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ /* For HT<->legacy pwr diff */ ++ u8 TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ /* For power group */ ++ u8 PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ u8 PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER]; ++ ++ u8 LegacyHTTxPowerDiff;/* Legacy to HT rate power diff */ ++ /* The current Tx Power Level */ ++ u8 CurrentCckTxPwrIdx; ++ u8 CurrentOfdm24GTxPwrIdx; ++ u8 CurrentBW2024GTxPwrIdx; ++ u8 CurrentBW4024GTxPwrIdx; ++ ++ /* Read/write are allow for following hardware information variables */ ++ u8 framesync; ++ u32 framesyncC34; ++ u8 framesyncMonitor; ++ u8 DefaultInitialGain[4]; ++ u8 pwrGroupCnt; ++ u32 MCSTxPowerLevelOriginalOffset[MAX_PG_GROUP][16]; ++ u32 CCKTxPowerLevelOriginalOffset; ++ ++ u8 CrystalCap; ++ u32 AntennaTxPath; /* Antenna path Tx */ ++ u32 AntennaRxPath; /* Antenna path Rx */ ++ u8 BluetoothCoexist; ++ u8 ExternalPA; ++ ++ u8 bLedOpenDrain; /* Open-drain support for controlling the LED.*/ ++ ++ u8 b1x1RecvCombine; /* for 1T1R receive combining */ ++ ++ u32 AcParam_BE; /* Original parameter for BE, use for EDCA turbo. */ ++ ++ struct bb_reg_def PHYRegDef[4]; /* Radio A/B/C/D */ ++ ++ u32 RfRegChnlVal[2]; ++ ++ /* RDG enable */ ++ bool bRDGEnable; ++ ++ /* for host message to fw */ ++ u8 LastHMEBoxNum; ++ ++ u8 fw_ractrl; ++ u8 RegTxPause; ++ /* Beacon function related global variable. */ ++ u32 RegBcnCtrlVal; ++ u8 RegFwHwTxQCtrl; ++ u8 RegReg542; ++ u8 RegCR_1; ++ ++ struct dm_priv dmpriv; ++ struct odm_dm_struct odmpriv; ++ struct sreset_priv srestpriv; ++ ++ u8 CurAntenna; ++ u8 AntDivCfg; ++ u8 TRxAntDivType; ++ ++ u8 bDumpRxPkt;/* for debug */ ++ u8 bDumpTxPkt;/* for debug */ ++ u8 FwRsvdPageStartOffset; /* Reserve page start offset except ++ * beacon in TxQ. */ ++ ++ /* 2010/08/09 MH Add CU power down mode. */ ++ bool pwrdown; ++ ++ /* Add for dual MAC 0--Mac0 1--Mac1 */ ++ u32 interfaceIndex; ++ ++ u8 OutEpQueueSel; ++ u8 OutEpNumber; ++ ++ /* Add for USB aggreation mode dynamic shceme. */ ++ bool UsbRxHighSpeedMode; ++ ++ /* 2010/11/22 MH Add for slim combo debug mode selective. */ ++ /* This is used for fix the drawback of CU TSMC-A/UMC-A cut. ++ * HW auto suspend ability. Close BT clock. */ ++ bool SlimComboDbg; ++ ++ u16 EfuseUsedBytes; ++ ++#ifdef CONFIG_88EU_P2P ++ struct P2P_PS_Offload_t p2p_ps_offload; ++#endif ++ ++ /* Auto FSM to Turn On, include clock, isolation, power control ++ * for MAC only */ ++ u8 bMacPwrCtrlOn; ++ ++ u32 UsbBulkOutSize; ++ ++ /* Interrupt relatd register information. */ ++ u32 IntArray[3];/* HISR0,HISR1,HSISR */ ++ u32 IntrMask[3]; ++ u8 C2hArray[16]; ++ u8 UsbTxAggMode; ++ u8 UsbTxAggDescNum; ++ u16 HwRxPageSize; /* Hardware setting */ ++ u32 MaxUsbRxAggBlock; ++ ++ enum usb_rx_agg_mode UsbRxAggMode; ++ u8 UsbRxAggBlockCount; /* USB Block count. Block size is ++ * 512-byte in high speed and 64-byte ++ * in full speed */ ++ u8 UsbRxAggBlockTimeout; ++ u8 UsbRxAggPageCount; /* 8192C DMA page count */ ++ u8 UsbRxAggPageTimeout; ++}; ++ ++#define GET_HAL_DATA(__pAdapter) \ ++ ((struct hal_data_8188e *)((__pAdapter)->HalData)) ++#define GET_RF_TYPE(priv) (GET_HAL_DATA(priv)->rf_type) ++ ++#define INCLUDE_MULTI_FUNC_BT(_Adapter) \ ++ (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT) ++#define INCLUDE_MULTI_FUNC_GPS(_Adapter) \ ++ (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS) ++ ++/* rtl8188e_hal_init.c */ ++s32 rtl8188e_FirmwareDownload(struct adapter *padapter); ++void _8051Reset88E(struct adapter *padapter); ++void rtl8188e_InitializeFirmwareVars(struct adapter *padapter); ++ ++s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy); ++ ++/* EFuse */ ++u8 GetEEPROMSize8188E(struct adapter *padapter); ++void Hal_InitPGData88E(struct adapter *padapter); ++void Hal_EfuseParseIDCode88E(struct adapter *padapter, u8 *hwinfo); ++void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *hwinfo, ++ bool AutoLoadFail); ++ ++void Hal_EfuseParseEEPROMVer88E(struct adapter *padapter, u8 *hwinfo, ++ bool AutoLoadFail); ++void rtl8188e_EfuseParseChnlPlan(struct adapter *padapter, u8 *hwinfo, ++ bool AutoLoadFail); ++void Hal_EfuseParseCustomerID88E(struct adapter *padapter, u8 *hwinfo, ++ bool AutoLoadFail); ++void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter,u8 *PROMContent, ++ bool AutoLoadFail); ++void Hal_ReadThermalMeter_88E(struct adapter * dapter, u8 *PROMContent, ++ bool AutoloadFail); ++void Hal_EfuseParseXtal_8188E(struct adapter *pAdapter, u8 *hwinfo, ++ bool AutoLoadFail); ++void Hal_EfuseParseBoardType88E(struct adapter *pAdapter, u8 *hwinfo, ++ bool AutoLoadFail); ++void Hal_ReadPowerSavingMode88E(struct adapter *pAdapter, u8 *hwinfo, ++ bool AutoLoadFail); ++ ++bool HalDetectPwrDownMode88E(struct adapter *Adapter); ++ ++void Hal_InitChannelPlan(struct adapter *padapter); ++void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc); ++ ++/* register */ ++void SetBcnCtrlReg(struct adapter *padapter, u8 SetBits, u8 ClearBits); ++ ++void rtl8188e_clone_haldata(struct adapter *dst, struct adapter *src); ++void rtl8188e_start_thread(struct adapter *padapter); ++void rtl8188e_stop_thread(struct adapter *padapter); ++ ++void rtw_IOL_cmd_tx_pkt_buf_dump(struct adapter *Adapter, int len); ++s32 rtl8188e_iol_efuse_patch(struct adapter *padapter); ++void rtw_cancel_all_timer(struct adapter *padapter); ++void _ps_open_RF(struct adapter *adapt); ++ ++#endif /* __RTL8188E_HAL_H__ */ +diff --git a/drivers/staging/r8188eu/include/rtl8188e_led.h b/drivers/staging/r8188eu/include/rtl8188e_led.h +new file mode 100644 +index 000000000000..b00954198764 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_led.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTL8188E_LED_H__ ++#define __RTL8188E_LED_H__ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++/* */ ++/* Interface to manipulate LED objects. */ ++/* */ ++void rtl8188eu_InitSwLeds(struct adapter *padapter); ++void rtl8188eu_DeInitSwLeds(struct adapter *padapter); ++void SwLedOn(struct adapter *padapter, struct LED_871x *pLed); ++void SwLedOff(struct adapter *padapter, struct LED_871x *pLed); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtl8188e_recv.h b/drivers/staging/r8188eu/include/rtl8188e_recv.h +new file mode 100644 +index 000000000000..a91daf84d6c3 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_recv.h +@@ -0,0 +1,53 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTL8188E_RECV_H__ ++#define __RTL8188E_RECV_H__ ++ ++#define TX_RPT1_PKT_LEN 8 ++ ++#define RECV_BLK_SZ 512 ++#define RECV_BLK_CNT 16 ++#define RECV_BLK_TH RECV_BLK_CNT ++#define RECV_BULK_IN_ADDR 0x80 ++#define RECV_INT_IN_ADDR 0x81 ++ ++#define NR_PREALLOC_RECV_SKB (8) ++ ++#define NR_RECVBUFF (4) ++ ++#define MAX_RECVBUF_SZ (15360) /* 15k < 16k */ ++ ++struct phy_stat { ++ unsigned int phydw0; ++ unsigned int phydw1; ++ unsigned int phydw2; ++ unsigned int phydw3; ++ unsigned int phydw4; ++ unsigned int phydw5; ++ unsigned int phydw6; ++ unsigned int phydw7; ++}; ++ ++/* Rx smooth factor */ ++#define Rx_Smooth_Factor (20) ++ ++enum rx_packet_type { ++ NORMAL_RX,/* Normal rx packet */ ++ TX_REPORT1,/* CCX */ ++ TX_REPORT2,/* TX RPT */ ++ HIS_REPORT,/* USB HISR RPT */ ++}; ++ ++#define INTERRUPT_MSG_FORMAT_LEN 60 ++void rtl8188eu_init_recvbuf(struct adapter *padapter, struct recv_buf *buf); ++s32 rtl8188eu_init_recv_priv(struct adapter *padapter); ++void rtl8188eu_free_recv_priv(struct adapter * padapter); ++void rtl8188eu_recv_hdl(struct adapter * padapter, struct recv_buf *precvbuf); ++void rtl8188eu_recv_tasklet(unsigned long priv); ++void rtl8188e_query_rx_phy_status(struct recv_frame *fr, struct phy_stat *phy); ++void rtl8188e_process_phy_info(struct adapter * padapter, void *prframe); ++void update_recvframe_phyinfo_88e(struct recv_frame *fra, struct phy_stat *phy); ++void update_recvframe_attrib_88e(struct recv_frame *fra, struct recv_stat *stat); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtl8188e_rf.h b/drivers/staging/r8188eu/include/rtl8188e_rf.h +new file mode 100644 +index 000000000000..da6b7f8212a3 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_rf.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTL8188E_RF_H__ ++#define __RTL8188E_RF_H__ ++ ++#define RF6052_MAX_TX_PWR 0x3F ++#define RF6052_MAX_REG 0x3F ++#define RF6052_MAX_PATH 2 ++ ++int PHY_RF6052_Config8188E(struct adapter *Adapter); ++void rtl8188e_RF_ChangeTxPath(struct adapter *Adapter, u16 DataRate); ++void rtl8188e_PHY_RF6052SetBandwidth(struct adapter *Adapter, ++ enum ht_channel_width Bandwidth); ++void rtl8188e_PHY_RF6052SetCckTxPower(struct adapter *Adapter, u8 *level); ++void rtl8188e_PHY_RF6052SetOFDMTxPower(struct adapter *Adapter, u8 *ofdm, ++ u8 *pwrbw20, u8 *pwrbw40, u8 channel); ++ ++#endif/* __RTL8188E_RF_H__ */ +diff --git a/drivers/staging/r8188eu/include/rtl8188e_spec.h b/drivers/staging/r8188eu/include/rtl8188e_spec.h +new file mode 100644 +index 000000000000..1c96f7b81245 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_spec.h +@@ -0,0 +1,1381 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTL8188E_SPEC_H__ ++#define __RTL8188E_SPEC_H__ ++ ++/* 8192C Regsiter offset definition */ ++ ++#define HAL_PS_TIMER_INT_DELAY 50 /* 50 microseconds */ ++#define HAL_92C_NAV_UPPER_UNIT 128 /* micro-second */ ++ ++#define MAC_ADDR_LEN 6 ++/* 8188E PKT_BUFF_ACCESS_CTRL value */ ++#define TXPKT_BUF_SELECT 0x69 ++#define RXPKT_BUF_SELECT 0xA5 ++#define DISABLE_TRXPKT_BUF_ACCESS 0x0 ++ ++/* 0x0000h ~ 0x00FFh System Configuration */ ++#define REG_SYS_ISO_CTRL 0x0000 ++#define REG_SYS_FUNC_EN 0x0002 ++#define REG_APS_FSMCO 0x0004 ++#define REG_SYS_CLKR 0x0008 ++#define REG_9346CR 0x000A ++#define REG_EE_VPD 0x000C ++#define REG_AFE_MISC 0x0010 ++#define REG_SPS0_CTRL 0x0011 ++#define REG_SPS_OCP_CFG 0x0018 ++#define REG_RSV_CTRL 0x001C ++#define REG_RF_CTRL 0x001F ++#define REG_LDOA15_CTRL 0x0020 ++#define REG_LDOV12D_CTRL 0x0021 ++#define REG_LDOHCI12_CTRL 0x0022 ++#define REG_LPLDO_CTRL 0x0023 ++#define REG_AFE_XTAL_CTRL 0x0024 ++#define REG_AFE_PLL_CTRL 0x0028 ++#define REG_APE_PLL_CTRL_EXT 0x002c ++#define REG_EFUSE_CTRL 0x0030 ++#define REG_EFUSE_TEST 0x0034 ++#define REG_GPIO_MUXCFG 0x0040 ++#define REG_GPIO_IO_SEL 0x0042 ++#define REG_MAC_PINMUX_CFG 0x0043 ++#define REG_GPIO_PIN_CTRL 0x0044 ++#define REG_GPIO_INTM 0x0048 ++#define REG_LEDCFG0 0x004C ++#define REG_LEDCFG1 0x004D ++#define REG_LEDCFG2 0x004E ++#define REG_LEDCFG3 0x004F ++#define REG_FSIMR 0x0050 ++#define REG_FSISR 0x0054 ++#define REG_HSIMR 0x0058 ++#define REG_HSISR 0x005c ++#define REG_GPIO_PIN_CTRL_2 0x0060 /* RTL8723 WIFI/BT/GPS ++ * Multi-Function GPIO Pin Control. */ ++#define REG_GPIO_IO_SEL_2 0x0062 /* RTL8723 WIFI/BT/GPS ++ * Multi-Function GPIO Select. */ ++#define REG_BB_PAD_CTRL 0x0064 ++#define REG_MULTI_FUNC_CTRL 0x0068 /* RTL8723 WIFI/BT/GPS ++ * Multi-Function control source. */ ++#define REG_GPIO_OUTPUT 0x006c ++#define REG_AFE_XTAL_CTRL_EXT 0x0078 /* RTL8188E */ ++#define REG_XCK_OUT_CTRL 0x007c /* RTL8188E */ ++#define REG_MCUFWDL 0x0080 ++#define REG_WOL_EVENT 0x0081 /* RTL8188E */ ++#define REG_MCUTSTCFG 0x0084 ++#define REG_HMEBOX_E0 0x0088 ++#define REG_HMEBOX_E1 0x008A ++#define REG_HMEBOX_E2 0x008C ++#define REG_HMEBOX_E3 0x008E ++#define REG_HMEBOX_EXT_0 0x01F0 ++#define REG_HMEBOX_EXT_1 0x01F4 ++#define REG_HMEBOX_EXT_2 0x01F8 ++#define REG_HMEBOX_EXT_3 0x01FC ++#define REG_HIMR_88E 0x00B0 ++#define REG_HISR_88E 0x00B4 ++#define REG_HIMRE_88E 0x00B8 ++#define REG_HISRE_88E 0x00BC ++#define REG_EFUSE_ACCESS 0x00CF /* Efuse access protection ++ * for RTL8723 */ ++#define REG_BIST_SCAN 0x00D0 ++#define REG_BIST_RPT 0x00D4 ++#define REG_BIST_ROM_RPT 0x00D8 ++#define REG_USB_SIE_INTF 0x00E0 ++#define REG_PCIE_MIO_INTF 0x00E4 ++#define REG_PCIE_MIO_INTD 0x00E8 ++#define REG_HPON_FSM 0x00EC ++#define REG_SYS_CFG 0x00F0 ++#define REG_GPIO_OUTSTS 0x00F4 /* For RTL8723 only. */ ++#define REG_TYPE_ID 0x00FC ++ ++#define REG_MAC_PHY_CTRL_NORMAL 0x00f8 ++ ++/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ ++#define REG_CR 0x0100 ++#define REG_PBP 0x0104 ++#define REG_PKT_BUFF_ACCESS_CTRL 0x0106 ++#define REG_TRXDMA_CTRL 0x010C ++#define REG_TRXFF_BNDY 0x0114 ++#define REG_TRXFF_STATUS 0x0118 ++#define REG_RXFF_PTR 0x011C ++/* define REG_HIMR 0x0120 */ ++/* define REG_HISR 0x0124 */ ++#define REG_HIMRE 0x0128 ++#define REG_HISRE 0x012C ++#define REG_CPWM 0x012F ++#define REG_FWIMR 0x0130 ++#define REG_FTIMR 0x0138 ++#define REG_FWISR 0x0134 ++#define REG_PKTBUF_DBG_CTRL 0x0140 ++#define REG_PKTBUF_DBG_ADDR (REG_PKTBUF_DBG_CTRL) ++#define REG_RXPKTBUF_DBG (REG_PKTBUF_DBG_CTRL+2) ++#define REG_TXPKTBUF_DBG (REG_PKTBUF_DBG_CTRL+3) ++#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL+2) ++#define REG_PKTBUF_DBG_DATA_L 0x0144 ++#define REG_PKTBUF_DBG_DATA_H 0x0148 ++ ++#define REG_TC0_CTRL 0x0150 ++#define REG_TC1_CTRL 0x0154 ++#define REG_TC2_CTRL 0x0158 ++#define REG_TC3_CTRL 0x015C ++#define REG_TC4_CTRL 0x0160 ++#define REG_TCUNIT_BASE 0x0164 ++#define REG_MBIST_START 0x0174 ++#define REG_MBIST_DONE 0x0178 ++#define REG_MBIST_FAIL 0x017C ++#define REG_32K_CTRL 0x0194 /* RTL8188E */ ++#define REG_C2HEVT_MSG_NORMAL 0x01A0 ++#define REG_C2HEVT_CLEAR 0x01AF ++#define REG_MCUTST_1 0x01c0 ++#define REG_FMETHR 0x01C8 ++#define REG_HMETFR 0x01CC ++#define REG_HMEBOX_0 0x01D0 ++#define REG_HMEBOX_1 0x01D4 ++#define REG_HMEBOX_2 0x01D8 ++#define REG_HMEBOX_3 0x01DC ++ ++#define REG_LLT_INIT 0x01E0 ++ ++/* 0x0200h ~ 0x027Fh TXDMA Configuration */ ++#define REG_RQPN 0x0200 ++#define REG_FIFOPAGE 0x0204 ++#define REG_TDECTRL 0x0208 ++#define REG_TXDMA_OFFSET_CHK 0x020C ++#define REG_TXDMA_STATUS 0x0210 ++#define REG_RQPN_NPQ 0x0214 ++ ++/* 0x0280h ~ 0x02FFh RXDMA Configuration */ ++#define REG_RXDMA_AGG_PG_TH 0x0280 ++#define REG_RXPKT_NUM 0x0284 ++#define REG_RXDMA_STATUS 0x0288 ++ ++/* 0x0300h ~ 0x03FFh PCIe */ ++#define REG_PCIE_CTRL_REG 0x0300 ++#define REG_INT_MIG 0x0304 /* Interrupt Migration */ ++#define REG_BCNQ_DESA 0x0308 /* TX Beacon Descr Address */ ++#define REG_HQ_DESA 0x0310 /* TX High Queue Descr Addr */ ++#define REG_MGQ_DESA 0x0318 /* TX Manage Queue Descr Addr*/ ++#define REG_VOQ_DESA 0x0320 /* TX VO Queue Descr Addr */ ++#define REG_VIQ_DESA 0x0328 /* TX VI Queue Descr Addr */ ++#define REG_BEQ_DESA 0x0330 /* TX BE Queue Descr Addr */ ++#define REG_BKQ_DESA 0x0338 /* TX BK Queue Descr Addr */ ++#define REG_RX_DESA 0x0340 /* RX Queue Descr Addr */ ++#define REG_MDIO 0x0354 /* MDIO for Access PCIE PHY */ ++#define REG_DBG_SEL 0x0360 /* Debug Selection Register */ ++#define REG_PCIE_HRPWM 0x0361 /* PCIe RPWM */ ++#define REG_PCIE_HCPWM 0x0363 /* PCIe CPWM */ ++#define REG_WATCH_DOG 0x0368 ++ ++/* RTL8723 series ------------------------------ */ ++#define REG_PCIE_HISR 0x03A0 ++ ++/* spec version 11 */ ++/* 0x0400h ~ 0x047Fh Protocol Configuration */ ++#define REG_VOQ_INFORMATION 0x0400 ++#define REG_VIQ_INFORMATION 0x0404 ++#define REG_BEQ_INFORMATION 0x0408 ++#define REG_BKQ_INFORMATION 0x040C ++#define REG_MGQ_INFORMATION 0x0410 ++#define REG_HGQ_INFORMATION 0x0414 ++#define REG_BCNQ_INFORMATION 0x0418 ++#define REG_TXPKT_EMPTY 0x041A ++ ++#define REG_CPU_MGQ_INFORMATION 0x041C ++#define REG_FWHW_TXQ_CTRL 0x0420 ++#define REG_HWSEQ_CTRL 0x0423 ++#define REG_TXPKTBUF_BCNQ_BDNY 0x0424 ++#define REG_TXPKTBUF_MGQ_BDNY 0x0425 ++#define REG_LIFETIME_EN 0x0426 ++#define REG_MULTI_BCNQ_OFFSET 0x0427 ++#define REG_SPEC_SIFS 0x0428 ++#define REG_RL 0x042A ++#define REG_DARFRC 0x0430 ++#define REG_RARFRC 0x0438 ++#define REG_RRSR 0x0440 ++#define REG_ARFR0 0x0444 ++#define REG_ARFR1 0x0448 ++#define REG_ARFR2 0x044C ++#define REG_ARFR3 0x0450 ++#define REG_AGGLEN_LMT 0x0458 ++#define REG_AMPDU_MIN_SPACE 0x045C ++#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D ++#define REG_FAST_EDCA_CTRL 0x0460 ++#define REG_RD_RESP_PKT_TH 0x0463 ++#define REG_INIRTS_RATE_SEL 0x0480 ++/* define REG_INIDATA_RATE_SEL 0x0484 */ ++#define REG_POWER_STATUS 0x04A4 ++#define REG_POWER_STAGE1 0x04B4 ++#define REG_POWER_STAGE2 0x04B8 ++#define REG_PKT_VO_VI_LIFE_TIME 0x04C0 ++#define REG_PKT_BE_BK_LIFE_TIME 0x04C2 ++#define REG_STBC_SETTING 0x04C4 ++#define REG_PROT_MODE_CTRL 0x04C8 ++#define REG_MAX_AGGR_NUM 0x04CA ++#define REG_RTS_MAX_AGGR_NUM 0x04CB ++#define REG_BAR_MODE_CTRL 0x04CC ++#define REG_RA_TRY_RATE_AGG_LMT 0x04CF ++#define REG_EARLY_MODE_CONTROL 0x4D0 ++#define REG_NQOS_SEQ 0x04DC ++#define REG_QOS_SEQ 0x04DE ++#define REG_NEED_CPU_HANDLE 0x04E0 ++#define REG_PKT_LOSE_RPT 0x04E1 ++#define REG_PTCL_ERR_STATUS 0x04E2 ++#define REG_TX_RPT_CTRL 0x04EC ++#define REG_TX_RPT_TIME 0x04F0 /* 2 byte */ ++#define REG_DUMMY 0x04FC ++ ++/* 0x0500h ~ 0x05FFh EDCA Configuration */ ++#define REG_EDCA_VO_PARAM 0x0500 ++#define REG_EDCA_VI_PARAM 0x0504 ++#define REG_EDCA_BE_PARAM 0x0508 ++#define REG_EDCA_BK_PARAM 0x050C ++#define REG_BCNTCFG 0x0510 ++#define REG_PIFS 0x0512 ++#define REG_RDG_PIFS 0x0513 ++#define REG_SIFS_CTX 0x0514 ++#define REG_SIFS_TRX 0x0516 ++#define REG_TSFTR_SYN_OFFSET 0x0518 ++#define REG_AGGR_BREAK_TIME 0x051A ++#define REG_SLOT 0x051B ++#define REG_TX_PTCL_CTRL 0x0520 ++#define REG_TXPAUSE 0x0522 ++#define REG_DIS_TXREQ_CLR 0x0523 ++#define REG_RD_CTRL 0x0524 ++/* Format for offset 540h-542h: */ ++/* [3:0]: TBTT prohibit setup in unit of 32us. The time for HW getting ++ * beacon content before TBTT. */ ++/* [7:4]: Reserved. */ ++/* [19:8]: TBTT prohibit hold in unit of 32us. The time for HW holding ++ * to send the beacon packet. */ ++/* [23:20]: Reserved */ ++/* Description: */ ++/* | */ ++/* |<--Setup--|--Hold------------>| */ ++/* --------------|---------------------- */ ++/* | */ ++/* TBTT */ ++/* Note: We cannot update beacon content to HW or send any AC packets during ++ * the time between Setup and Hold. */ ++#define REG_TBTT_PROHIBIT 0x0540 ++#define REG_RD_NAV_NXT 0x0544 ++#define REG_NAV_PROT_LEN 0x0546 ++#define REG_BCN_CTRL 0x0550 ++#define REG_BCN_CTRL_1 0x0551 ++#define REG_MBID_NUM 0x0552 ++#define REG_DUAL_TSF_RST 0x0553 ++#define REG_BCN_INTERVAL 0x0554 ++#define REG_DRVERLYINT 0x0558 ++#define REG_BCNDMATIM 0x0559 ++#define REG_ATIMWND 0x055A ++#define REG_BCN_MAX_ERR 0x055D ++#define REG_RXTSF_OFFSET_CCK 0x055E ++#define REG_RXTSF_OFFSET_OFDM 0x055F ++#define REG_TSFTR 0x0560 ++#define REG_TSFTR1 0x0568 ++#define REG_ATIMWND_1 0x0570 ++#define REG_PSTIMER 0x0580 ++#define REG_TIMER0 0x0584 ++#define REG_TIMER1 0x0588 ++#define REG_ACMHWCTRL 0x05C0 ++ ++/* define REG_FW_TSF_SYNC_CNT 0x04A0 */ ++#define REG_FW_RESET_TSF_CNT_1 0x05FC ++#define REG_FW_RESET_TSF_CNT_0 0x05FD ++#define REG_FW_BCN_DIS_CNT 0x05FE ++ ++/* 0x0600h ~ 0x07FFh WMAC Configuration */ ++#define REG_APSD_CTRL 0x0600 ++#define REG_BWOPMODE 0x0603 ++#define REG_TCR 0x0604 ++#define REG_RCR 0x0608 ++#define REG_RX_PKT_LIMIT 0x060C ++#define REG_RX_DLK_TIME 0x060D ++#define REG_RX_DRVINFO_SZ 0x060F ++ ++#define REG_MACID 0x0610 ++#define REG_BSSID 0x0618 ++#define REG_MAR 0x0620 ++#define REG_MBIDCAMCFG 0x0628 ++ ++#define REG_USTIME_EDCA 0x0638 ++#define REG_MAC_SPEC_SIFS 0x063A ++ ++/* 20100719 Joseph: Hardware register definition change. (HW datasheet v54) */ ++/* [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */ ++#define REG_R2T_SIFS 0x063C ++/* [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */ ++#define REG_T2T_SIFS 0x063E ++#define REG_ACKTO 0x0640 ++#define REG_CTS2TO 0x0641 ++#define REG_EIFS 0x0642 ++ ++/* RXERR_RPT */ ++#define RXERR_TYPE_OFDM_PPDU 0 ++#define RXERR_TYPE_OFDM_false_ALARM 1 ++#define RXERR_TYPE_OFDM_MPDU_OK 2 ++#define RXERR_TYPE_OFDM_MPDU_FAIL 3 ++#define RXERR_TYPE_CCK_PPDU 4 ++#define RXERR_TYPE_CCK_false_ALARM 5 ++#define RXERR_TYPE_CCK_MPDU_OK 6 ++#define RXERR_TYPE_CCK_MPDU_FAIL 7 ++#define RXERR_TYPE_HT_PPDU 8 ++#define RXERR_TYPE_HT_false_ALARM 9 ++#define RXERR_TYPE_HT_MPDU_TOTAL 10 ++#define RXERR_TYPE_HT_MPDU_OK 11 ++#define RXERR_TYPE_HT_MPDU_FAIL 12 ++#define RXERR_TYPE_RX_FULL_DROP 15 ++ ++#define RXERR_COUNTER_MASK 0xFFFFF ++#define RXERR_RPT_RST BIT(27) ++#define _RXERR_RPT_SEL(type) ((type) << 28) ++ ++/* Note: */ ++/* The NAV upper value is very important to WiFi 11n 5.2.3 NAV test. ++ * The default value is always too small, but the WiFi TestPlan test ++ * by 25,000 microseconds of NAV through sending CTS in the air. ++ * We must update this value greater than 25,000 microseconds to pass ++ * the item. The offset of NAV_UPPER in 8192C Spec is incorrect, and ++ * the offset should be 0x0652. */ ++#define REG_NAV_UPPER 0x0652 /* unit of 128 */ ++ ++/* WMA, BA, CCX */ ++/* define REG_NAV_CTRL 0x0650 */ ++#define REG_BACAMCMD 0x0654 ++#define REG_BACAMCONTENT 0x0658 ++#define REG_LBDLY 0x0660 ++#define REG_FWDLY 0x0661 ++#define REG_RXERR_RPT 0x0664 ++#define REG_WMAC_TRXPTCL_CTL 0x0668 ++ ++/* Security */ ++#define REG_CAMCMD 0x0670 ++#define REG_CAMWRITE 0x0674 ++#define REG_CAMREAD 0x0678 ++#define REG_CAMDBG 0x067C ++#define REG_SECCFG 0x0680 ++ ++/* Power */ ++#define REG_WOW_CTRL 0x0690 ++#define REG_PS_RX_INFO 0x0692 ++#define REG_UAPSD_TID 0x0693 ++#define REG_WKFMCAM_CMD 0x0698 ++#define REG_WKFMCAM_NUM_88E 0x698 ++#define REG_RXFLTMAP0 0x06A0 ++#define REG_RXFLTMAP1 0x06A2 ++#define REG_RXFLTMAP2 0x06A4 ++#define REG_BCN_PSR_RPT 0x06A8 ++#define REG_BT_COEX_TABLE 0x06C0 ++ ++/* Hardware Port 2 */ ++#define REG_MACID1 0x0700 ++#define REG_BSSID1 0x0708 ++ ++/* 0xFE00h ~ 0xFE55h USB Configuration */ ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++/* For normal chip */ ++#define REG_NORMAL_SIE_VID 0xFE60 /* 0xFE60~0xFE61 */ ++#define REG_NORMAL_SIE_PID 0xFE62 /* 0xFE62~0xFE63 */ ++#define REG_NORMAL_SIE_OPTIONAL 0xFE64 ++#define REG_NORMAL_SIE_EP 0xFE65 /* 0xFE65~0xFE67 */ ++#define REG_NORMAL_SIE_PHY 0xFE68 /* 0xFE68~0xFE6B */ ++#define REG_NORMAL_SIE_OPTIONAL2 0xFE6C ++#define REG_NORMAL_SIE_GPS_EP 0xFE6D /* 0xFE6D, for RTL8723 only. */ ++#define REG_NORMAL_SIE_MAC_ADDR 0xFE70 /* 0xFE70~0xFE75 */ ++#define REG_NORMAL_SIE_STRING 0xFE80 /* 0xFE80~0xFEDF */ ++ ++/* TODO: use these definition when using REG_xxx naming rule. */ ++/* NOTE: DO NOT Remove these definition. Use later. */ ++ ++#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ ++#define EFUSE_TEST REG_EFUSE_TEST /* E-Fuse Test. */ ++#define MSR (REG_CR + 2) /* Media Status reg */ ++#define ISR REG_HISR_88E ++/* Timing Sync Function Timer Register. */ ++#define TSFR REG_TSFTR ++ ++#define PBP REG_PBP ++ ++/* Redifine MACID register, to compatible prior ICs. */ ++/* MAC ID Register, Offset 0x0050-0x0053 */ ++#define IDR0 REG_MACID ++/* MAC ID Register, Offset 0x0054-0x0055 */ ++#define IDR4 (REG_MACID + 4) ++ ++/* 9. Security Control Registers (Offset: ) */ ++/* IN 8190 Data Sheet is called CAMcmd */ ++#define RWCAM REG_CAMCMD ++/* Software write CAM input content */ ++#define WCAMI REG_CAMWRITE ++/* Software read/write CAM config */ ++#define RCAMO REG_CAMREAD ++#define CAMDBG REG_CAMDBG ++/* Security Configuration Register */ ++#define SECR REG_SECCFG ++ ++/* Unused register */ ++#define UnusedRegister 0x1BF ++#define DCAM UnusedRegister ++#define PSR UnusedRegister ++#define BBAddr UnusedRegister ++#define PhyDataR UnusedRegister ++ ++/* Min Spacing related settings. */ ++#define MAX_MSS_DENSITY_2T 0x13 ++#define MAX_MSS_DENSITY_1T 0x0A ++ ++/* EEPROM enable when set 1 */ ++#define CmdEEPROM_En BIT(5) ++/* System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 */ ++#define CmdEERPOMSEL BIT(4) ++#define Cmd9346CR_9356SEL BIT(4) ++ ++/* 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) */ ++#define GPIOSEL_GPIO 0 ++#define GPIOSEL_ENBT BIT(5) ++ ++/* 8192C GPIO PIN Control Register (offset 0x44, 4 byte) */ ++/* GPIO pins input value */ ++#define GPIO_IN REG_GPIO_PIN_CTRL ++/* GPIO pins output value */ ++#define GPIO_OUT (REG_GPIO_PIN_CTRL+1) ++/* GPIO pins output enable when a bit is set to "1"; otherwise, ++ * input is configured. */ ++#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2) ++#define GPIO_MOD (REG_GPIO_PIN_CTRL+3) ++ ++/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */ ++#define HSIMR_GPIO12_0_INT_EN BIT(0) ++#define HSIMR_SPS_OCP_INT_EN BIT(5) ++#define HSIMR_RON_INT_EN BIT(6) ++#define HSIMR_PDN_INT_EN BIT(7) ++#define HSIMR_GPIO9_INT_EN BIT(25) ++ ++/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */ ++#define HSISR_GPIO12_0_INT BIT(0) ++#define HSISR_SPS_OCP_INT BIT(5) ++#define HSISR_RON_INT_EN BIT(6) ++#define HSISR_PDNINT BIT(7) ++#define HSISR_GPIO9_INT BIT(25) ++ ++/* 8192C (MSR) Media Status Register (Offset 0x4C, 8 bits) */ ++/* ++Network Type ++00: No link ++01: Link in ad hoc network ++10: Link in infrastructure network ++11: AP mode ++Default: 00b. ++*/ ++#define MSR_NOLINK 0x00 ++#define MSR_ADHOC 0x01 ++#define MSR_INFRA 0x02 ++#define MSR_AP 0x03 ++ ++/* 88EU (MSR) Media Status Register (Offset 0x4C, 8 bits) */ ++#define USB_INTR_CONTENT_C2H_OFFSET 0 ++#define USB_INTR_CONTENT_CPWM1_OFFSET 16 ++#define USB_INTR_CONTENT_CPWM2_OFFSET 20 ++#define USB_INTR_CONTENT_HISR_OFFSET 48 ++#define USB_INTR_CONTENT_HISRE_OFFSET 52 ++ ++/* 88E Driver Initialization Offload REG_FDHM0(Offset 0x88, 8 bits) */ ++/* IOL config for REG_FDHM0(Reg0x88) */ ++#define CMD_INIT_LLT BIT(0) ++#define CMD_READ_EFUSE_MAP BIT(1) ++#define CMD_EFUSE_PATCH BIT(2) ++#define CMD_IOCONFIG BIT(3) ++#define CMD_INIT_LLT_ERR BIT(4) ++#define CMD_READ_EFUSE_MAP_ERR BIT(5) ++#define CMD_EFUSE_PATCH_ERR BIT(6) ++#define CMD_IOCONFIG_ERR BIT(7) ++ ++/* 6. Adaptive Control Registers (Offset: 0x0160 - 0x01CF) */ ++/* 8192C Response Rate Set Register (offset 0x181, 24bits) */ ++#define RRSR_1M BIT(0) ++#define RRSR_2M BIT(1) ++#define RRSR_5_5M BIT(2) ++#define RRSR_11M BIT(3) ++#define RRSR_6M BIT(4) ++#define RRSR_9M BIT(5) ++#define RRSR_12M BIT(6) ++#define RRSR_18M BIT(7) ++#define RRSR_24M BIT(8) ++#define RRSR_36M BIT(9) ++#define RRSR_48M BIT(10) ++#define RRSR_54M BIT(11) ++#define RRSR_MCS0 BIT(12) ++#define RRSR_MCS1 BIT(13) ++#define RRSR_MCS2 BIT(14) ++#define RRSR_MCS3 BIT(15) ++#define RRSR_MCS4 BIT(16) ++#define RRSR_MCS5 BIT(17) ++#define RRSR_MCS6 BIT(18) ++#define RRSR_MCS7 BIT(19) ++ ++/* 8192C Response Rate Set Register (offset 0x1BF, 8bits) */ ++/* WOL bit information */ ++#define HAL92C_WOL_PTK_UPDATE_EVENT BIT(0) ++#define HAL92C_WOL_GTK_UPDATE_EVENT BIT(1) ++ ++/* 8192C BW_OPMODE bits (Offset 0x203, 8bit) */ ++#define BW_OPMODE_20MHZ BIT(2) ++ ++/* 8192C CAM Config Setting (offset 0x250, 1 byte) */ ++#define CAM_VALID BIT(15) ++#define CAM_NOTVALID 0x0000 ++#define CAM_USEDK BIT(5) ++ ++#define CAM_CONTENT_COUNT 8 ++ ++#define CAM_NONE 0x0 ++#define CAM_WEP40 0x01 ++#define CAM_TKIP 0x02 ++#define CAM_AES 0x04 ++#define CAM_WEP104 0x05 ++#define CAM_SMS4 0x6 ++ ++#define TOTAL_CAM_ENTRY 32 ++#define HALF_CAM_ENTRY 16 ++ ++#define CAM_CONFIG_USEDK true ++#define CAM_CONFIG_NO_USEDK false ++ ++#define CAM_WRITE BIT(16) ++#define CAM_READ 0x00000000 ++#define CAM_POLLINIG BIT(31) ++ ++#define SCR_UseDK 0x01 ++#define SCR_TxSecEnable 0x02 ++#define SCR_RxSecEnable 0x04 ++ ++/* 10. Power Save Control Registers (Offset: 0x0260 - 0x02DF) */ ++#define WOW_PMEN BIT(0) /* Power management Enable. */ ++#define WOW_WOMEN BIT(1) /* WoW function on or off. */ ++#define WOW_MAGIC BIT(2) /* Magic packet */ ++#define WOW_UWF BIT(3) /* Unicast Wakeup frame. */ ++ ++/* 12. Host Interrupt Status Registers (Offset: 0x0300 - 0x030F) */ ++/* 8188 IMR/ISR bits */ ++#define IMR_DISABLED_88E 0x0 ++/* IMR DW0(0x0060-0063) Bit 0-31 */ ++#define IMR_TXCCK_88E BIT(30) /* TXRPT interrupt when CCX bit of the packet is set */ ++#define IMR_PSTIMEOUT_88E BIT(29) /* Power Save Time Out Interrupt */ ++#define IMR_GTINT4_88E BIT(28) /* When GTIMER4 expires, this bit is set to 1 */ ++#define IMR_GTINT3_88E BIT(27) /* When GTIMER3 expires, this bit is set to 1 */ ++#define IMR_TBDER_88E BIT(26) /* Transmit Beacon0 Error */ ++#define IMR_TBDOK_88E BIT(25) /* Transmit Beacon0 OK */ ++#define IMR_TSF_BIT32_TOGGLE_88E BIT(24) /* TSF Timer BIT32 toggle indication interrupt */ ++#define IMR_BCNDMAINT0_88E BIT(20) /* Beacon DMA Interrupt 0 */ ++#define IMR_BCNDERR0_88E BIT(16) /* Beacon Queue DMA Error 0 */ ++#define IMR_HSISR_IND_ON_INT_88E BIT(15) /* HSISR Indicator (HSIMR & HSISR is true, this bit is set to 1) */ ++#define IMR_BCNDMAINT_E_88E BIT(14) /* Beacon DMA Interrupt Extension for Win7 */ ++#define IMR_ATIMEND_88E BIT(12) /* CTWidnow End or ATIM Window End */ ++#define IMR_HISR1_IND_INT_88E BIT(11) /* HISR1 Indicator (HISR1 & HIMR1 is true, this bit is set to 1) */ ++#define IMR_C2HCMD_88E BIT(10) /* CPU to Host Command INT Status, Write 1 clear */ ++#define IMR_CPWM2_88E BIT(9) /* CPU power Mode exchange INT Status, Write 1 clear */ ++#define IMR_CPWM_88E BIT(8) /* CPU power Mode exchange INT Status, Write 1 clear */ ++#define IMR_HIGHDOK_88E BIT(7) /* High Queue DMA OK */ ++#define IMR_MGNTDOK_88E BIT(6) /* Management Queue DMA OK */ ++#define IMR_BKDOK_88E BIT(5) /* AC_BK DMA OK */ ++#define IMR_BEDOK_88E BIT(4) /* AC_BE DMA OK */ ++#define IMR_VIDOK_88E BIT(3) /* AC_VI DMA OK */ ++#define IMR_VODOK_88E BIT(2) /* AC_VO DMA OK */ ++#define IMR_RDU_88E BIT(1) /* Rx Descriptor Unavailable */ ++#define IMR_ROK_88E BIT(0) /* Receive DMA OK */ ++ ++/* IMR DW1(0x00B4-00B7) Bit 0-31 */ ++#define IMR_BCNDMAINT7_88E BIT(27) /* Beacon DMA Interrupt 7 */ ++#define IMR_BCNDMAINT6_88E BIT(26) /* Beacon DMA Interrupt 6 */ ++#define IMR_BCNDMAINT5_88E BIT(25) /* Beacon DMA Interrupt 5 */ ++#define IMR_BCNDMAINT4_88E BIT(24) /* Beacon DMA Interrupt 4 */ ++#define IMR_BCNDMAINT3_88E BIT(23) /* Beacon DMA Interrupt 3 */ ++#define IMR_BCNDMAINT2_88E BIT(22) /* Beacon DMA Interrupt 2 */ ++#define IMR_BCNDMAINT1_88E BIT(21) /* Beacon DMA Interrupt 1 */ ++#define IMR_BCNDERR7_88E BIT(20) /* Beacon DMA Error Int 7 */ ++#define IMR_BCNDERR6_88E BIT(19) /* Beacon DMA Error Int 6 */ ++#define IMR_BCNDERR5_88E BIT(18) /* Beacon DMA Error Int 5 */ ++#define IMR_BCNDERR4_88E BIT(17) /* Beacon DMA Error Int 4 */ ++#define IMR_BCNDERR3_88E BIT(16) /* Beacon DMA Error Int 3 */ ++#define IMR_BCNDERR2_88E BIT(15) /* Beacon DMA Error Int 2 */ ++#define IMR_BCNDERR1_88E BIT(14) /* Beacon DMA Error Int 1 */ ++#define IMR_ATIMEND_E_88E BIT(13) /* ATIM Window End Ext for Win7 */ ++#define IMR_TXERR_88E BIT(11) /* Tx Err Flag Int Status, write 1 clear. */ ++#define IMR_RXERR_88E BIT(10) /* Rx Err Flag INT Status, Write 1 clear */ ++#define IMR_TXFOVW_88E BIT(9) /* Transmit FIFO Overflow */ ++#define IMR_RXFOVW_88E BIT(8) /* Receive FIFO Overflow */ ++ ++#define HAL_NIC_UNPLUG_ISR 0xFFFFFFFF /* The value when the NIC is unplugged for PCI. */ ++ ++/* 8192C EFUSE */ ++#define HWSET_MAX_SIZE 256 ++#define HWSET_MAX_SIZE_88E 512 ++ ++/*=================================================================== ++===================================================================== ++Here the register defines are for 92C. When the define is as same with 92C, ++we will use the 92C's define for the consistency ++So the following defines for 92C is not entire!!!!!! ++===================================================================== ++=====================================================================*/ ++/* ++Based on Datasheet V33---090401 ++Register Summary ++Current IOREG MAP ++0x0000h ~ 0x00FFh System Configuration (256 Bytes) ++0x0100h ~ 0x01FFh MACTOP General Configuration (256 Bytes) ++0x0200h ~ 0x027Fh TXDMA Configuration (128 Bytes) ++0x0280h ~ 0x02FFh RXDMA Configuration (128 Bytes) ++0x0300h ~ 0x03FFh PCIE EMAC Reserved Region (256 Bytes) ++0x0400h ~ 0x04FFh Protocol Configuration (256 Bytes) ++0x0500h ~ 0x05FFh EDCA Configuration (256 Bytes) ++0x0600h ~ 0x07FFh WMAC Configuration (512 Bytes) ++0x2000h ~ 0x3FFFh 8051 FW Download Region (8196 Bytes) ++*/ ++/* 8192C (TXPAUSE) transmission pause (Offset 0x522, 8 bits) */ ++/* Note: */ ++/* The bits of stopping AC(VO/VI/BE/BK) queue in datasheet ++ * RTL8192S/RTL8192C are wrong, */ ++/* the correct arragement is VO - Bit0, VI - Bit1, BE - Bit2, ++ * and BK - Bit3. */ ++/* 8723 and 88E may be not correct either in the earlier version. */ ++#define StopBecon BIT(6) ++#define StopHigh BIT(5) ++#define StopMgt BIT(4) ++#define StopBK BIT(3) ++#define StopBE BIT(2) ++#define StopVI BIT(1) ++#define StopVO BIT(0) ++ ++/* 8192C (RCR) Receive Configuration Register(Offset 0x608, 32 bits) */ ++#define RCR_APPFCS BIT(31) /* WMAC append FCS after payload */ ++#define RCR_APP_MIC BIT(30) ++#define RCR_APP_PHYSTS BIT(28) ++#define RCR_APP_ICV BIT(29) ++#define RCR_APP_PHYST_RXFF BIT(28) ++#define RCR_APP_BA_SSN BIT(27) /* Accept BA SSN */ ++#define RCR_ENMBID BIT(24) /* Enable Multiple BssId. */ ++#define RCR_LSIGEN BIT(23) ++#define RCR_MFBEN BIT(22) ++#define RCR_HTC_LOC_CTRL BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */ ++#define RCR_AMF BIT(13) /* Accept management type frame */ ++#define RCR_ACF BIT(12) /* Accept control type frame */ ++#define RCR_ADF BIT(11) /* Accept data type frame */ ++#define RCR_AICV BIT(9) /* Accept ICV error packet */ ++#define RCR_ACRC32 BIT(8) /* Accept CRC32 error packet */ ++#define RCR_CBSSID_BCN BIT(7) /* Accept BSSID match packet ++ * (Rx beacon, probe rsp) */ ++#define RCR_CBSSID_DATA BIT(6) /* Accept BSSID match (Data)*/ ++#define RCR_CBSSID RCR_CBSSID_DATA /* Accept BSSID match */ ++#define RCR_APWRMGT BIT(5) /* Accept power management pkt*/ ++#define RCR_ADD3 BIT(4) /* Accept address 3 match pkt */ ++#define RCR_AB BIT(3) /* Accept broadcast packet */ ++#define RCR_AM BIT(2) /* Accept multicast packet */ ++#define RCR_APM BIT(1) /* Accept physical match pkt */ ++#define RCR_AAP BIT(0) /* Accept all unicast packet */ ++#define RCR_MXDMA_OFFSET 8 ++#define RCR_FIFO_OFFSET 13 ++ ++/* 0xFE00h ~ 0xFE55h USB Configuration */ ++#define REG_USB_INFO 0xFE17 ++#define REG_USB_SPECIAL_OPTION 0xFE55 ++#define REG_USB_DMA_AGG_TO 0xFE5B ++#define REG_USB_AGG_TO 0xFE5C ++#define REG_USB_AGG_TH 0xFE5D ++ ++#define REG_USB_HRPWM 0xFE58 ++#define REG_USB_HCPWM 0xFE57 ++/* 8192C Regsiter Bit and Content definition */ ++/* 0x0000h ~ 0x00FFh System Configuration */ ++ ++/* 2 SYS_ISO_CTRL */ ++#define ISO_MD2PP BIT(0) ++#define ISO_UA2USB BIT(1) ++#define ISO_UD2CORE BIT(2) ++#define ISO_PA2PCIE BIT(3) ++#define ISO_PD2CORE BIT(4) ++#define ISO_IP2MAC BIT(5) ++#define ISO_DIOP BIT(6) ++#define ISO_DIOE BIT(7) ++#define ISO_EB2CORE BIT(8) ++#define ISO_DIOR BIT(9) ++#define PWC_EV12V BIT(15) ++ ++/* 2 SYS_FUNC_EN */ ++#define FEN_BBRSTB BIT(0) ++#define FEN_BB_GLB_RSTn BIT(1) ++#define FEN_USBA BIT(2) ++#define FEN_UPLL BIT(3) ++#define FEN_USBD BIT(4) ++#define FEN_DIO_PCIE BIT(5) ++#define FEN_PCIEA BIT(6) ++#define FEN_PPLL BIT(7) ++#define FEN_PCIED BIT(8) ++#define FEN_DIOE BIT(9) ++#define FEN_CPUEN BIT(10) ++#define FEN_DCORE BIT(11) ++#define FEN_ELDR BIT(12) ++#define FEN_DIO_RF BIT(13) ++#define FEN_HWPDN BIT(14) ++#define FEN_MREGEN BIT(15) ++ ++/* 2 APS_FSMCO */ ++#define PFM_LDALL BIT(0) ++#define PFM_ALDN BIT(1) ++#define PFM_LDKP BIT(2) ++#define PFM_WOWL BIT(3) ++#define EnPDN BIT(4) ++#define PDN_PL BIT(5) ++#define APFM_ONMAC BIT(8) ++#define APFM_OFF BIT(9) ++#define APFM_RSM BIT(10) ++#define AFSM_HSUS BIT(11) ++#define AFSM_PCIE BIT(12) ++#define APDM_MAC BIT(13) ++#define APDM_HOST BIT(14) ++#define APDM_HPDN BIT(15) ++#define RDY_MACON BIT(16) ++#define SUS_HOST BIT(17) ++#define ROP_ALD BIT(20) ++#define ROP_PWR BIT(21) ++#define ROP_SPS BIT(22) ++#define SOP_MRST BIT(25) ++#define SOP_FUSE BIT(26) ++#define SOP_ABG BIT(27) ++#define SOP_AMB BIT(28) ++#define SOP_RCK BIT(29) ++#define SOP_A8M BIT(30) ++#define XOP_BTCK BIT(31) ++ ++/* 2 SYS_CLKR */ ++#define ANAD16V_EN BIT(0) ++#define ANA8M BIT(1) ++#define MACSLP BIT(4) ++#define LOADER_CLK_EN BIT(5) ++ ++/* 2 9346CR */ ++ ++#define BOOT_FROM_EEPROM BIT(4) ++#define EEPROM_EN BIT(5) ++ ++/* 2 SPS0_CTRL */ ++ ++/* 2 SPS_OCP_CFG */ ++ ++/* 2 RF_CTRL */ ++#define RF_EN BIT(0) ++#define RF_RSTB BIT(1) ++#define RF_SDMRSTB BIT(2) ++ ++/* 2 LDOV12D_CTRL */ ++#define LDV12_EN BIT(0) ++#define LDV12_SDBY BIT(1) ++#define LPLDO_HSM BIT(2) ++#define LPLDO_LSM_DIS BIT(3) ++#define _LDV12_VADJ(x) (((x) & 0xF) << 4) ++ ++/* 2EFUSE_CTRL */ ++#define ALD_EN BIT(18) ++#define EF_PD BIT(19) ++#define EF_FLAG BIT(31) ++ ++/* 2 EFUSE_TEST (For RTL8723 partially) */ ++#define EF_TRPT BIT(7) ++/* 00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */ ++#define EF_CELL_SEL (BIT(8)|BIT(9)) ++#define LDOE25_EN BIT(31) ++#define EFUSE_SEL(x) (((x) & 0x3) << 8) ++#define EFUSE_SEL_MASK 0x300 ++#define EFUSE_WIFI_SEL_0 0x0 ++#define EFUSE_BT_SEL_0 0x1 ++#define EFUSE_BT_SEL_1 0x2 ++#define EFUSE_BT_SEL_2 0x3 ++ ++#define EFUSE_ACCESS_ON 0x69 /* For RTL8723 only. */ ++#define EFUSE_ACCESS_OFF 0x00 /* For RTL8723 only. */ ++ ++/* 2 8051FWDL */ ++/* 2 MCUFWDL */ ++#define MCUFWDL_EN BIT(0) ++#define MCUFWDL_RDY BIT(1) ++#define FWDL_ChkSum_rpt BIT(2) ++#define MACINI_RDY BIT(3) ++#define BBINI_RDY BIT(4) ++#define RFINI_RDY BIT(5) ++#define WINTINI_RDY BIT(6) ++#define RAM_DL_SEL BIT(7) /* 1:RAM, 0:ROM */ ++#define ROM_DLEN BIT(19) ++#define CPRST BIT(23) ++ ++/* 2 REG_SYS_CFG */ ++#define XCLK_VLD BIT(0) ++#define ACLK_VLD BIT(1) ++#define UCLK_VLD BIT(2) ++#define PCLK_VLD BIT(3) ++#define PCIRSTB BIT(4) ++#define V15_VLD BIT(5) ++#define SW_OFFLOAD_EN BIT(7) ++#define SIC_IDLE BIT(8) ++#define BD_MAC2 BIT(9) ++#define BD_MAC1 BIT(10) ++#define IC_MACPHY_MODE BIT(11) ++#define CHIP_VER (BIT(12)|BIT(13)|BIT(14)|BIT(15)) ++#define BT_FUNC BIT(16) ++#define VENDOR_ID BIT(19) ++#define PAD_HWPD_IDN BIT(22) ++#define TRP_VAUX_EN BIT(23) /* RTL ID */ ++#define TRP_BT_EN BIT(24) ++#define BD_PKG_SEL BIT(25) ++#define BD_HCI_SEL BIT(26) ++#define TYPE_ID BIT(27) ++ ++#define CHIP_VER_RTL_MASK 0xF000 /* Bit 12 ~ 15 */ ++#define CHIP_VER_RTL_SHIFT 12 ++ ++/* 2REG_GPIO_OUTSTS (For RTL8723 only) */ ++#define EFS_HCI_SEL (BIT(0)|BIT(1)) ++#define PAD_HCI_SEL (BIT(2)|BIT(3)) ++#define HCI_SEL (BIT(4)|BIT(5)) ++#define PKG_SEL_HCI BIT(6) ++#define FEN_GPS BIT(7) ++#define FEN_BT BIT(8) ++#define FEN_WL BIT(9) ++#define FEN_PCI BIT(10) ++#define FEN_USB BIT(11) ++#define BTRF_HWPDN_N BIT(12) ++#define WLRF_HWPDN_N BIT(13) ++#define PDN_BT_N BIT(14) ++#define PDN_GPS_N BIT(15) ++#define BT_CTL_HWPDN BIT(16) ++#define GPS_CTL_HWPDN BIT(17) ++#define PPHY_SUSB BIT(20) ++#define UPHY_SUSB BIT(21) ++#define PCI_SUSEN BIT(22) ++#define USB_SUSEN BIT(23) ++#define RF_RL_ID (BIT(31)|BIT(30)|BIT(29)|BIT(28)) ++ ++/* 2SYS_CFG */ ++#define RTL_ID BIT(23) /* TestChip ID, 1:Test(RLE); 0:MP(RL) */ ++ ++/* 0x0100h ~ 0x01FFh MACTOP General Configuration */ ++ ++/* 2 Function Enable Registers */ ++/* 2 CR */ ++ ++#define HCI_TXDMA_EN BIT(0) ++#define HCI_RXDMA_EN BIT(1) ++#define TXDMA_EN BIT(2) ++#define RXDMA_EN BIT(3) ++#define PROTOCOL_EN BIT(4) ++#define SCHEDULE_EN BIT(5) ++#define MACTXEN BIT(6) ++#define MACRXEN BIT(7) ++#define ENSWBCN BIT(8) ++#define ENSEC BIT(9) ++#define CALTMR_EN BIT(10) /* 32k CAL TMR enable */ ++ ++/* Network type */ ++#define _NETTYPE(x) (((x) & 0x3) << 16) ++#define MASK_NETTYPE 0x30000 ++#define NT_NO_LINK 0x0 ++#define NT_LINK_AD_HOC 0x1 ++#define NT_LINK_AP 0x2 ++#define NT_AS_AP 0x3 ++ ++/* 2 PBP - Page Size Register */ ++#define GET_RX_PAGE_SIZE(value) ((value) & 0xF) ++#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4) ++#define _PSRX_MASK 0xF ++#define _PSTX_MASK 0xF0 ++#define _PSRX(x) (x) ++#define _PSTX(x) ((x) << 4) ++ ++#define PBP_64 0x0 ++#define PBP_128 0x1 ++#define PBP_256 0x2 ++#define PBP_512 0x3 ++#define PBP_1024 0x4 ++ ++/* 2 TX/RXDMA */ ++#define RXDMA_ARBBW_EN BIT(0) ++#define RXSHFT_EN BIT(1) ++#define RXDMA_AGG_EN BIT(2) ++#define QS_VO_QUEUE BIT(8) ++#define QS_VI_QUEUE BIT(9) ++#define QS_BE_QUEUE BIT(10) ++#define QS_BK_QUEUE BIT(11) ++#define QS_MANAGER_QUEUE BIT(12) ++#define QS_HIGH_QUEUE BIT(13) ++ ++#define HQSEL_VOQ BIT(0) ++#define HQSEL_VIQ BIT(1) ++#define HQSEL_BEQ BIT(2) ++#define HQSEL_BKQ BIT(3) ++#define HQSEL_MGTQ BIT(4) ++#define HQSEL_HIQ BIT(5) ++ ++/* For normal driver, 0x10C */ ++#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14) ++#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12) ++#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10) ++#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8 ) ++#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6 ) ++#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4 ) ++ ++#define QUEUE_LOW 1 ++#define QUEUE_NORMAL 2 ++#define QUEUE_HIGH 3 ++ ++/* 2 TRXFF_BNDY */ ++ ++/* 2 LLT_INIT */ ++#define _LLT_NO_ACTIVE 0x0 ++#define _LLT_WRITE_ACCESS 0x1 ++#define _LLT_READ_ACCESS 0x2 ++ ++#define _LLT_INIT_DATA(x) ((x) & 0xFF) ++#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8) ++#define _LLT_OP(x) (((x) & 0x3) << 30) ++#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3) ++ ++/* 0x0200h ~ 0x027Fh TXDMA Configuration */ ++/* 2RQPN */ ++#define _HPQ(x) ((x) & 0xFF) ++#define _LPQ(x) (((x) & 0xFF) << 8) ++#define _PUBQ(x) (((x) & 0xFF) << 16) ++/* NOTE: in RQPN_NPQ register */ ++#define _NPQ(x) ((x) & 0xFF) ++ ++#define HPQ_PUBLIC_DIS BIT(24) ++#define LPQ_PUBLIC_DIS BIT(25) ++#define LD_RQPN BIT(31) ++ ++/* 2TDECTRL */ ++#define BCN_VALID BIT(16) ++#define BCN_HEAD(x) (((x) & 0xFF) << 8) ++#define BCN_HEAD_MASK 0xFF00 ++ ++/* 2 TDECTL */ ++#define BLK_DESC_NUM_SHIFT 4 ++#define BLK_DESC_NUM_MASK 0xF ++ ++/* 2 TXDMA_OFFSET_CHK */ ++#define DROP_DATA_EN BIT(9) ++ ++/* 0x0280h ~ 0x028Bh RX DMA Configuration */ ++ ++/* REG_RXDMA_CONTROL, 0x0286h */ ++ ++/* 2 REG_RXPKT_NUM, 0x0284 */ ++#define RXPKT_RELEASE_POLL BIT(16) ++#define RXDMA_IDLE BIT(17) ++#define RW_RELEASE_EN BIT(18) ++ ++/* 0x0400h ~ 0x047Fh Protocol Configuration */ ++/* 2 FWHW_TXQ_CTRL */ ++#define EN_AMPDU_RTY_NEW BIT(7) ++ ++/* 2 SPEC SIFS */ ++#define _SPEC_SIFS_CCK(x) ((x) & 0xFF) ++#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8) ++ ++/* 2 RL */ ++#define RETRY_LIMIT_SHORT_SHIFT 8 ++#define RETRY_LIMIT_LONG_SHIFT 0 ++ ++/* 0x0500h ~ 0x05FFh EDCA Configuration */ ++ ++/* 2 EDCA setting */ ++#define AC_PARAM_TXOP_LIMIT_OFFSET 16 ++#define AC_PARAM_ECW_MAX_OFFSET 12 ++#define AC_PARAM_ECW_MIN_OFFSET 8 ++#define AC_PARAM_AIFS_OFFSET 0 ++ ++#define _LRL(x) ((x) & 0x3F) ++#define _SRL(x) (((x) & 0x3F) << 8) ++ ++/* 2 BCN_CTRL */ ++#define EN_MBSSID BIT(1) ++#define EN_TXBCN_RPT BIT(2) ++#define EN_BCN_FUNCTION BIT(3) ++#define DIS_TSF_UPDATE BIT(3) ++ ++/* The same function but different bit field. */ ++#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4) ++#define DIS_TSF_UDT0_TEST_CHIP BIT(5) ++#define STOP_BCNQ BIT(6) ++ ++/* 2 ACMHWCTRL */ ++#define AcmHw_HwEn BIT(0) ++#define AcmHw_BeqEn BIT(1) ++#define AcmHw_ViqEn BIT(2) ++#define AcmHw_VoqEn BIT(3) ++#define AcmHw_BeqStatus BIT(4) ++#define AcmHw_ViqStatus BIT(5) ++#define AcmHw_VoqStatus BIT(6) ++ ++/* 0x0600h ~ 0x07FFh WMAC Configuration */ ++/* 2APSD_CTRL */ ++#define APSDOFF BIT(6) ++#define APSDOFF_STATUS BIT(7) ++ ++#define RATE_BITMAP_ALL 0xFFFFF ++ ++/* Only use CCK 1M rate for ACK */ ++#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1 ++ ++/* 2 TCR */ ++#define TSFRST BIT(0) ++#define DIS_GCLK BIT(1) ++#define PAD_SEL BIT(2) ++#define PWR_ST BIT(6) ++#define PWRBIT_OW_EN BIT(7) ++#define ACRC BIT(8) ++#define CFENDFORM BIT(9) ++#define ICV BIT(10) ++ ++/* 2 RCR */ ++#define AAP BIT(0) ++#define APM BIT(1) ++#define AM BIT(2) ++#define AB BIT(3) ++#define ADD3 BIT(4) ++#define APWRMGT BIT(5) ++#define CBSSID BIT(6) ++#define CBSSID_DATA BIT(6) ++#define CBSSID_BCN BIT(7) ++#define ACRC32 BIT(8) ++#define AICV BIT(9) ++#define ADF BIT(11) ++#define ACF BIT(12) ++#define AMF BIT(13) ++#define HTC_LOC_CTRL BIT(14) ++#define UC_DATA_EN BIT(16) ++#define BM_DATA_EN BIT(17) ++#define MFBEN BIT(22) ++#define LSIGEN BIT(23) ++#define EnMBID BIT(24) ++#define APP_BASSN BIT(27) ++#define APP_PHYSTS BIT(28) ++#define APP_ICV BIT(29) ++#define APP_MIC BIT(30) ++#define APP_FCS BIT(31) ++ ++/* 2 SECCFG */ ++#define SCR_TxUseDK BIT(0) /* Force Tx Use Default Key */ ++#define SCR_RxUseDK BIT(1) /* Force Rx Use Default Key */ ++#define SCR_TxEncEnable BIT(2) /* Enable Tx Encryption */ ++#define SCR_RxDecEnable BIT(3) /* Enable Rx Decryption */ ++#define SCR_SKByA2 BIT(4) /* Search kEY BY A2 */ ++#define SCR_NoSKMC BIT(5) /* No Key Search Multicast */ ++#define SCR_TXBCUSEDK BIT(6) /* Force Tx Bcast pkt Use Default Key */ ++#define SCR_RXBCUSEDK BIT(7) /* Force Rx Bcast pkt Use Default Key */ ++ ++/* RTL8188E SDIO Configuration */ ++ ++/* I/O bus domain address mapping */ ++#define SDIO_LOCAL_BASE 0x10250000 ++#define WLAN_IOREG_BASE 0x10260000 ++#define FIRMWARE_FIFO_BASE 0x10270000 ++#define TX_HIQ_BASE 0x10310000 ++#define TX_MIQ_BASE 0x10320000 ++#define TX_LOQ_BASE 0x10330000 ++#define RX_RX0FF_BASE 0x10340000 ++ ++/* SDIO host local register space mapping. */ ++#define SDIO_LOCAL_MSK 0x0FFF ++#define WLAN_IOREG_MSK 0x7FFF ++#define WLAN_FIFO_MSK 0x1FFF /* Aggregation Length[12:0] */ ++#define WLAN_RX0FF_MSK 0x0003 ++ ++/* Without ref to the SDIO Device ID */ ++#define SDIO_WITHOUT_REF_DEVICE_ID 0 ++#define SDIO_LOCAL_DEVICE_ID 0 /* 0b[16], 000b[15:13] */ ++#define WLAN_TX_HIQ_DEVICE_ID 4 /* 0b[16], 100b[15:13] */ ++#define WLAN_TX_MIQ_DEVICE_ID 5 /* 0b[16], 101b[15:13] */ ++#define WLAN_TX_LOQ_DEVICE_ID 6 /* 0b[16], 110b[15:13] */ ++#define WLAN_RX0FF_DEVICE_ID 7 /* 0b[16], 111b[15:13] */ ++#define WLAN_IOREG_DEVICE_ID 8 /* 1b[16] */ ++ ++/* SDIO Tx Free Page Index */ ++#define HI_QUEUE_IDX 0 ++#define MID_QUEUE_IDX 1 ++#define LOW_QUEUE_IDX 2 ++#define PUBLIC_QUEUE_IDX 3 ++ ++#define SDIO_MAX_TX_QUEUE 3 /* HIQ, MIQ and LOQ */ ++#define SDIO_MAX_RX_QUEUE 1 ++ ++/* SDIO Tx Control */ ++#define SDIO_REG_TX_CTRL 0x0000 ++/* SDIO Host Interrupt Mask */ ++#define SDIO_REG_HIMR 0x0014 ++/* SDIO Host Interrupt Service Routine */ ++#define SDIO_REG_HISR 0x0018 ++/* HCI Current Power Mode */ ++#define SDIO_REG_HCPWM 0x0019 ++/* RXDMA Request Length */ ++#define SDIO_REG_RX0_REQ_LEN 0x001C ++/* Free Tx Buffer Page */ ++#define SDIO_REG_FREE_TXPG 0x0020 ++/* HCI Current Power Mode 1 */ ++#define SDIO_REG_HCPWM1 0x0024 ++/* HCI Current Power Mode 2 */ ++#define SDIO_REG_HCPWM2 0x0026 ++/* HTSF Informaion */ ++#define SDIO_REG_HTSFR_INFO 0x0030 ++/* HCI Request Power Mode 1 */ ++#define SDIO_REG_HRPWM1 0x0080 ++/* HCI Request Power Mode 2 */ ++#define SDIO_REG_HRPWM2 0x0082 ++/* HCI Power Save Clock */ ++#define SDIO_REG_HPS_CLKR 0x0084 ++/* SDIO HCI Suspend Control */ ++#define SDIO_REG_HSUS_CTRL 0x0086 ++/* SDIO Host Extension Interrupt Mask Always */ ++#define SDIO_REG_HIMR_ON 0x0090 ++/* SDIO Host Extension Interrupt Status Always */ ++#define SDIO_REG_HISR_ON 0x0091 ++ ++#define SDIO_HIMR_DISABLED 0 ++ ++/* RTL8188E SDIO Host Interrupt Mask Register */ ++#define SDIO_HIMR_RX_REQUEST_MSK BIT(0) ++#define SDIO_HIMR_AVAL_MSK BIT(1) ++#define SDIO_HIMR_TXERR_MSK BIT(2) ++#define SDIO_HIMR_RXERR_MSK BIT(3) ++#define SDIO_HIMR_TXFOVW_MSK BIT(4) ++#define SDIO_HIMR_RXFOVW_MSK BIT(5) ++#define SDIO_HIMR_TXBCNOK_MSK BIT(6) ++#define SDIO_HIMR_TXBCNERR_MSK BIT(7) ++#define SDIO_HIMR_BCNERLY_INT_MSK BIT(16) ++#define SDIO_HIMR_C2HCMD_MSK BIT(17) ++#define SDIO_HIMR_CPWM1_MSK BIT(18) ++#define SDIO_HIMR_CPWM2_MSK BIT(19) ++#define SDIO_HIMR_HSISR_IND_MSK BIT(20) ++#define SDIO_HIMR_GTINT3_IND_MSK BIT(21) ++#define SDIO_HIMR_GTINT4_IND_MSK BIT(22) ++#define SDIO_HIMR_PSTIMEOUT_MSK BIT(23) ++#define SDIO_HIMR_OCPINT_MSK BIT(24) ++#define SDIO_HIMR_ATIMEND_MSK BIT(25) ++#define SDIO_HIMR_ATIMEND_E_MSK BIT(26) ++#define SDIO_HIMR_CTWEND_MSK BIT(27) ++ ++/* RTL8188E SDIO Specific */ ++#define SDIO_HIMR_MCU_ERR_MSK BIT(28) ++#define SDIO_HIMR_TSF_BIT32_TOGGLE_MSK BIT(29) ++ ++/* SDIO Host Interrupt Service Routine */ ++#define SDIO_HISR_RX_REQUEST BIT(0) ++#define SDIO_HISR_AVAL BIT(1) ++#define SDIO_HISR_TXERR BIT(2) ++#define SDIO_HISR_RXERR BIT(3) ++#define SDIO_HISR_TXFOVW BIT(4) ++#define SDIO_HISR_RXFOVW BIT(5) ++#define SDIO_HISR_TXBCNOK BIT(6) ++#define SDIO_HISR_TXBCNERR BIT(7) ++#define SDIO_HISR_BCNERLY_INT BIT(16) ++#define SDIO_HISR_C2HCMD BIT(17) ++#define SDIO_HISR_CPWM1 BIT(18) ++#define SDIO_HISR_CPWM2 BIT(19) ++#define SDIO_HISR_HSISR_IND BIT(20) ++#define SDIO_HISR_GTINT3_IND BIT(21) ++#define SDIO_HISR_GTINT4_IND BIT(22) ++#define SDIO_HISR_PSTIME BIT(23) ++#define SDIO_HISR_OCPINT BIT(24) ++#define SDIO_HISR_ATIMEND BIT(25) ++#define SDIO_HISR_ATIMEND_E BIT(26) ++#define SDIO_HISR_CTWEND BIT(27) ++ ++/* RTL8188E SDIO Specific */ ++#define SDIO_HISR_MCU_ERR BIT(28) ++#define SDIO_HISR_TSF_BIT32_TOGGLE BIT(29) ++ ++#define MASK_SDIO_HISR_CLEAR \ ++ (SDIO_HISR_TXERR | SDIO_HISR_RXERR | SDIO_HISR_TXFOVW |\ ++ SDIO_HISR_RXFOVW | SDIO_HISR_TXBCNOK | SDIO_HISR_TXBCNERR |\ ++ SDIO_HISR_C2HCMD | SDIO_HISR_CPWM1 | SDIO_HISR_CPWM2 |\ ++ SDIO_HISR_HSISR_IND | SDIO_HISR_GTINT3_IND | SDIO_HISR_GTINT4_IND |\ ++ SDIO_HISR_PSTIMEOUT | SDIO_HISR_OCPINT) ++ ++/* SDIO HCI Suspend Control Register */ ++#define HCI_RESUME_PWR_RDY BIT(1) ++#define HCI_SUS_CTRL BIT(0) ++ ++/* SDIO Tx FIFO related */ ++/* The number of Tx FIFO free page */ ++#define SDIO_TX_FREE_PG_QUEUE 4 ++#define SDIO_TX_FIFO_PAGE_SZ 128 ++ ++/* 0xFE00h ~ 0xFE55h USB Configuration */ ++ ++/* 2 USB Information (0xFE17) */ ++#define USB_IS_HIGH_SPEED 0 ++#define USB_IS_FULL_SPEED 1 ++#define USB_SPEED_MASK BIT(5) ++ ++#define USB_NORMAL_SIE_EP_MASK 0xF ++#define USB_NORMAL_SIE_EP_SHIFT 4 ++ ++/* 2 Special Option */ ++#define USB_AGG_EN BIT(3) ++ ++/* 0; Use interrupt endpoint to upload interrupt pkt */ ++/* 1; Use bulk endpoint to upload interrupt pkt, */ ++#define INT_BULK_SEL BIT(4) ++ ++/* 2REG_C2HEVT_CLEAR */ ++/* Set by driver and notify FW that the driver has read ++ * the C2H command message */ ++#define C2H_EVT_HOST_CLOSE 0x00 ++/* Set by FW indicating that FW had set the C2H command ++ * message and it's not yet read by driver. */ ++#define C2H_EVT_FW_CLOSE 0xFF ++ ++/* 2REG_MULTI_FUNC_CTRL(For RTL8723 Only) */ ++/* Enable GPIO[9] as WiFi HW PDn source */ ++#define WL_HWPDN_EN BIT(0) ++/* WiFi HW PDn polarity control */ ++#define WL_HWPDN_SL BIT(1) ++/* WiFi function enable */ ++#define WL_FUNC_EN BIT(2) ++/* Enable GPIO[9] as WiFi RF HW PDn source */ ++#define WL_HWROF_EN BIT(3) ++/* Enable GPIO[11] as BT HW PDn source */ ++#define BT_HWPDN_EN BIT(16) ++/* BT HW PDn polarity control */ ++#define BT_HWPDN_SL BIT(17) ++/* BT function enable */ ++#define BT_FUNC_EN BIT(18) ++/* Enable GPIO[11] as BT/GPS RF HW PDn source */ ++#define BT_HWROF_EN BIT(19) ++/* Enable GPIO[10] as GPS HW PDn source */ ++#define GPS_HWPDN_EN BIT(20) ++/* GPS HW PDn polarity control */ ++#define GPS_HWPDN_SL BIT(21) ++/* GPS function enable */ ++#define GPS_FUNC_EN BIT(22) ++ ++/* 3 REG_LIFECTRL_CTRL */ ++#define HAL92C_EN_PKT_LIFE_TIME_BK BIT(3) ++#define HAL92C_EN_PKT_LIFE_TIME_BE BIT(2) ++#define HAL92C_EN_PKT_LIFE_TIME_VI BIT(1) ++#define HAL92C_EN_PKT_LIFE_TIME_VO BIT(0) ++ ++#define HAL92C_MSDU_LIFE_TIME_UNIT 128 /* in us */ ++ ++/* General definitions */ ++#define LAST_ENTRY_OF_TX_PKT_BUFFER 176 /* 22k 22528 bytes */ ++ ++#define POLLING_LLT_THRESHOLD 20 ++#define POLLING_READY_TIMEOUT_COUNT 1000 ++/* GPIO BIT */ ++#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) ++ ++/* 8192C EEPROM/EFUSE share register definition. */ ++ ++/* EEPROM/Efuse PG Offset for 88EE/88EU/88ES */ ++#define EEPROM_TX_PWR_INX_88E 0x10 ++ ++#define EEPROM_ChannelPlan_88E 0xB8 ++#define EEPROM_XTAL_88E 0xB9 ++#define EEPROM_THERMAL_METER_88E 0xBA ++#define EEPROM_IQK_LCK_88E 0xBB ++ ++#define EEPROM_RF_BOARD_OPTION_88E 0xC1 ++#define EEPROM_RF_FEATURE_OPTION_88E 0xC2 ++#define EEPROM_RF_BT_SETTING_88E 0xC3 ++#define EEPROM_VERSION_88E 0xC4 ++#define EEPROM_CUSTOMERID_88E 0xC5 ++#define EEPROM_RF_ANTENNA_OPT_88E 0xC9 ++ ++/* RTL88EE */ ++#define EEPROM_MAC_ADDR_88EE 0xD0 ++#define EEPROM_VID_88EE 0xD6 ++#define EEPROM_DID_88EE 0xD8 ++#define EEPROM_SVID_88EE 0xDA ++#define EEPROM_SMID_88EE 0xDC ++ ++/* RTL88EU */ ++#define EEPROM_MAC_ADDR_88EU 0xD7 ++#define EEPROM_VID_88EU 0xD0 ++#define EEPROM_PID_88EU 0xD2 ++#define EEPROM_USB_OPTIONAL_FUNCTION0 0xD4 ++ ++/* RTL88ES */ ++#define EEPROM_MAC_ADDR_88ES 0x11A ++ ++/* EEPROM/Efuse Value Type */ ++#define EETYPE_TX_PWR 0x0 ++ ++/* Default Value for EEPROM or EFUSE!!! */ ++#define EEPROM_Default_TSSI 0x0 ++#define EEPROM_Default_TxPowerDiff 0x0 ++#define EEPROM_Default_CrystalCap 0x5 ++/* Default: 2X2, RTL8192CE(QFPN68) */ ++#define EEPROM_Default_BoardType 0x02 ++#define EEPROM_Default_TxPower 0x1010 ++#define EEPROM_Default_HT2T_TxPwr 0x10 ++ ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 ++#define EEPROM_Default_ThermalMeter 0x12 ++ ++#define EEPROM_Default_AntTxPowerDiff 0x0 ++#define EEPROM_Default_TxPwDiff_CrystalCap 0x5 ++#define EEPROM_Default_TxPowerLevel 0x2A ++ ++#define EEPROM_Default_HT40_2SDiff 0x0 ++/* HT20<->40 default Tx Power Index Difference */ ++#define EEPROM_Default_HT20_Diff 2 ++#define EEPROM_Default_LegacyHTTxPowerDiff 0x3 ++#define EEPROM_Default_HT40_PwrMaxOffset 0 ++#define EEPROM_Default_HT20_PwrMaxOffset 0 ++ ++#define EEPROM_Default_CrystalCap_88E 0x20 ++#define EEPROM_Default_ThermalMeter_88E 0x18 ++ ++/* New EFUSE deafult value */ ++#define EEPROM_DEFAULT_24G_INDEX 0x2D ++#define EEPROM_DEFAULT_24G_HT20_DIFF 0X02 ++#define EEPROM_DEFAULT_24G_OFDM_DIFF 0X04 ++ ++#define EEPROM_DEFAULT_DIFF 0XFE ++#define EEPROM_DEFAULT_CHANNEL_PLAN 0x7F ++#define EEPROM_DEFAULT_BOARD_OPTION 0x00 ++#define EEPROM_DEFAULT_FEATURE_OPTION 0x00 ++#define EEPROM_DEFAULT_BT_OPTION 0x10 ++ ++/* For debug */ ++#define EEPROM_Default_PID 0x1234 ++#define EEPROM_Default_VID 0x5678 ++#define EEPROM_Default_CustomerID 0xAB ++#define EEPROM_Default_CustomerID_8188E 0x00 ++#define EEPROM_Default_SubCustomerID 0xCD ++#define EEPROM_Default_Version 0 ++ ++#define EEPROM_CHANNEL_PLAN_FCC 0x0 ++#define EEPROM_CHANNEL_PLAN_IC 0x1 ++#define EEPROM_CHANNEL_PLAN_ETSI 0x2 ++#define EEPROM_CHANNEL_PLAN_SPA 0x3 ++#define EEPROM_CHANNEL_PLAN_FRANCE 0x4 ++#define EEPROM_CHANNEL_PLAN_MKK 0x5 ++#define EEPROM_CHANNEL_PLAN_MKK1 0x6 ++#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7 ++#define EEPROM_CHANNEL_PLAN_TELEC 0x8 ++#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMA 0x9 ++#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA ++#define EEPROM_CHANNEL_PLAN_NCC 0xB ++#define EEPROM_USB_OPTIONAL1 0xE ++#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 ++ ++#define EEPROM_CID_DEFAULT 0x0 ++#define EEPROM_CID_TOSHIBA 0x4 ++#define EEPROM_CID_CCX 0x10 /* CCX test. */ ++#define EEPROM_CID_QMI 0x0D ++#define EEPROM_CID_WHQL 0xFE ++#define RTL_EEPROM_ID 0x8129 ++ ++#endif /* __RTL8188E_SPEC_H__ */ +diff --git a/drivers/staging/r8188eu/include/rtl8188e_sreset.h b/drivers/staging/r8188eu/include/rtl8188e_sreset.h +new file mode 100644 +index 000000000000..880c5792d5dd +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_sreset.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTL8188E_SRESET_H_ ++#define _RTL8188E_SRESET_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "rtw_sreset.h" ++ ++void rtl8188e_silentreset_for_specific_platform(struct adapter *padapter); ++void rtl8188e_sreset_xmit_status_check(struct adapter *padapter); ++void rtl8188e_sreset_linked_status_check(struct adapter *padapter); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtl8188e_xmit.h b/drivers/staging/r8188eu/include/rtl8188e_xmit.h +new file mode 100644 +index 000000000000..f1f2ccfc765e +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtl8188e_xmit.h +@@ -0,0 +1,150 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTL8188E_XMIT_H__ ++#define __RTL8188E_XMIT_H__ ++ ++#define MAX_TX_AGG_PACKET_NUMBER 0xFF ++/* */ ++/* Queue Select Value in TxDesc */ ++/* */ ++#define QSLT_BK 0x2/* 0x01 */ ++#define QSLT_BE 0x0 ++#define QSLT_VI 0x5/* 0x4 */ ++#define QSLT_VO 0x7/* 0x6 */ ++#define QSLT_BEACON 0x10 ++#define QSLT_HIGH 0x11 ++#define QSLT_MGNT 0x12 ++#define QSLT_CMD 0x13 ++ ++/* For 88e early mode */ ++#define SET_EARLYMODE_PKTNUM(__paddr, __value) \ ++ le32p_replace_bits((__le32 *)__paddr, __value, GENMASK(2, 0)) ++#define SET_EARLYMODE_LEN0(__pAddr, __Value) \ ++ le32p_replace_bits((__le32 *)__paddr, __value, GENMASK(15, 4)) ++#define SET_EARLYMODE_LEN1(__paddr, __value) \ ++ le32p_replace_bits((__le32 *)__paddr, __value, GENMASK(27, 16)) ++#define SET_EARLYMODE_LEN2_1(__pdr, __vValue) \ ++ le32p_replace_bits((__le32 *)__paddr, __value, GENMASK(31, 28)) ++#define SET_EARLYMODE_LEN2_2(__paddr, __value) \ ++ le32p_replace_bits((__le32 *)(__paddr + 4), __value, GENMASK(7, 0)) ++#define SET_EARLYMODE_LEN3(__pAddr, __Value) \ ++ le32p_replace_bits((__le32 *)(__paddr + 4), __value, GENMASK(19, 8)) ++#define SET_EARLYMODE_LEN4(__paAddr, __vValue) \ ++ le32p_replace_bits((__le32 *)(__paddr + 4), __value, GENMASK(31, 20)) ++ ++/* defined for TX DESC Operation */ ++ ++#define MAX_TID (15) ++ ++/* OFFSET 0 */ ++#define OFFSET_SZ 0 ++#define OFFSET_SHT 16 ++#define BMC BIT(24) ++#define LSG BIT(26) ++#define FSG BIT(27) ++#define OWN BIT(31) ++ ++/* OFFSET 4 */ ++#define PKT_OFFSET_SZ 0 ++#define QSEL_SHT 8 ++#define RATE_ID_SHT 16 ++#define NAVUSEHDR BIT(20) ++#define SEC_TYPE_SHT 22 ++#define PKT_OFFSET_SHT 26 ++ ++/* OFFSET 8 */ ++#define AGG_EN BIT(12) ++#define AGG_BK BIT(16) ++#define AMPDU_DENSITY_SHT 20 ++#define ANTSEL_A BIT(24) ++#define ANTSEL_B BIT(25) ++#define TX_ANT_CCK_SHT 26 ++#define TX_ANTL_SHT 28 ++#define TX_ANT_HT_SHT 30 ++ ++/* OFFSET 12 */ ++#define SEQ_SHT 16 ++#define EN_HWSEQ BIT(31) ++ ++/* OFFSET 16 */ ++#define QOS BIT(6) ++#define HW_SSN BIT(7) ++#define USERATE BIT(8) ++#define DISDATAFB BIT(10) ++#define CTS_2_SELF BIT(11) ++#define RTS_EN BIT(12) ++#define HW_RTS_EN BIT(13) ++#define DATA_SHORT BIT(24) ++#define PWR_STATUS_SHT 15 ++#define DATA_SC_SHT 20 ++#define DATA_BW BIT(25) ++ ++/* OFFSET 20 */ ++#define RTY_LMT_EN BIT(17) ++ ++enum TXDESC_SC { ++ SC_DONT_CARE = 0x00, ++ SC_UPPER = 0x01, ++ SC_LOWER = 0x02, ++ SC_DUPLICATE = 0x03 ++}; ++/* OFFSET 20 */ ++#define SGI BIT(6) ++#define USB_TXAGG_NUM_SHT 24 ++ ++#define txdesc_set_ccx_sw_88e(txdesc, value) \ ++ do { \ ++ ((struct txdesc_88e *)(txdesc))->sw1 = (((value)>>8) & 0x0f); \ ++ ((struct txdesc_88e *)(txdesc))->sw0 = ((value) & 0xff); \ ++ } while (0) ++ ++struct txrpt_ccx_88e { ++ /* offset 0 */ ++ u8 tag1:1; ++ u8 pkt_num:3; ++ u8 txdma_underflow:1; ++ u8 int_bt:1; ++ u8 int_tri:1; ++ u8 int_ccx:1; ++ ++ /* offset 1 */ ++ u8 mac_id:6; ++ u8 pkt_ok:1; ++ u8 bmc:1; ++ ++ /* offset 2 */ ++ u8 retry_cnt:6; ++ u8 lifetime_over:1; ++ u8 retry_over:1; ++ ++ /* offset 3 */ ++ u8 ccx_qtime0; ++ u8 ccx_qtime1; ++ ++ /* offset 5 */ ++ u8 final_data_rate; ++ ++ /* offset 6 */ ++ u8 sw1:4; ++ u8 qsel:4; ++ ++ /* offset 7 */ ++ u8 sw0; ++}; ++ ++void rtl8188e_fill_fake_txdesc(struct adapter *padapter, u8 *pDesc, ++ u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull); ++s32 rtl8188eu_init_xmit_priv(struct adapter *padapter); ++s32 rtl8188eu_hal_xmit(struct adapter *padapter, struct xmit_frame *frame); ++s32 rtl8188eu_mgnt_xmit(struct adapter *padapter, struct xmit_frame *frame); ++s32 rtl8188eu_xmit_buf_handler(struct adapter *padapter); ++#define hal_xmit_handler rtl8188eu_xmit_buf_handler ++void rtl8188eu_xmit_tasklet(unsigned long priv); ++s32 rtl8188eu_xmitframe_complete(struct adapter *padapter, ++ struct xmit_priv *pxmitpriv, ++ struct xmit_buf *pxmitbuf); ++ ++void handle_txrpt_ccx_88e(struct adapter *adapter, u8 *buf); ++ ++#endif /* __RTL8188E_XMIT_H__ */ +diff --git a/drivers/staging/r8188eu/include/rtw_ap.h b/drivers/staging/r8188eu/include/rtw_ap.h +new file mode 100644 +index 000000000000..2eb556968509 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_ap.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#ifndef __RTW_AP_H_ ++#define __RTW_AP_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++/* external function */ ++void rtw_indicate_sta_assoc_event(struct adapter *padapter, ++ struct sta_info *psta); ++void rtw_indicate_sta_disassoc_event(struct adapter *padapter, ++ struct sta_info *psta); ++void init_mlme_ap_info(struct adapter *padapter); ++void free_mlme_ap_info(struct adapter *padapter); ++void update_beacon(struct adapter *padapter, u8 ie_id, ++ u8 *oui, u8 tx); ++void add_RATid(struct adapter *padapter, struct sta_info *psta, ++ u8 rssi_level); ++void expire_timeout_chk(struct adapter *padapter); ++void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta); ++int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len); ++void rtw_ap_restore_network(struct adapter *padapter); ++void rtw_set_macaddr_acl(struct adapter *padapter, int mode); ++int rtw_acl_add_sta(struct adapter *padapter, u8 *addr); ++int rtw_acl_remove_sta(struct adapter *padapter, u8 *addr); ++ ++#ifdef CONFIG_88EU_AP_MODE ++void associated_clients_update(struct adapter *padapter, u8 updated); ++void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta); ++u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta); ++void sta_info_update(struct adapter *padapter, struct sta_info *psta); ++void ap_sta_info_defer_update(struct adapter *padapter, struct sta_info *psta); ++u8 ap_free_sta(struct adapter *padapter, struct sta_info *psta, ++ bool active, u16 reason); ++int rtw_sta_flush(struct adapter *padapter); ++int rtw_ap_inform_ch_switch(struct adapter *padapter, u8 new_ch, u8 ch_offset); ++void start_ap_mode(struct adapter *padapter); ++void stop_ap_mode(struct adapter *padapter); ++#endif ++#endif /* end of CONFIG_88EU_AP_MODE */ ++void update_bmc_sta(struct adapter *padapter); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtw_br_ext.h b/drivers/staging/r8188eu/include/rtw_br_ext.h +new file mode 100644 +index 000000000000..69905d30c191 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_br_ext.h +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_BR_EXT_H_ ++#define _RTW_BR_EXT_H_ ++ ++#define MACADDRLEN 6 ++#define _DEBUG_ERR DBG_88E ++#define _DEBUG_INFO DBG_88E ++#define DEBUG_WARN DBG_88E ++#define DEBUG_INFO DBG_88E ++#define DEBUG_ERR DBG_88E ++#define GET_MY_HWADDR(padapter) ((padapter)->eeprompriv.mac_addr) ++ ++#define NAT25_HASH_BITS 4 ++#define NAT25_HASH_SIZE (1 << NAT25_HASH_BITS) ++#define NAT25_AGEING_TIME 300 ++ ++#define MAX_NETWORK_ADDR_LEN 17 ++ ++struct nat25_network_db_entry { ++ struct nat25_network_db_entry *next_hash; ++ struct nat25_network_db_entry **pprev_hash; ++ atomic_t use_count; ++ unsigned char macAddr[6]; ++ unsigned long ageing_timer; ++ unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; ++}; ++ ++enum NAT25_METHOD { ++ NAT25_MIN, ++ NAT25_CHECK, ++ NAT25_INSERT, ++ NAT25_PARSE, ++ NAT25_MAX ++}; ++ ++struct br_ext_info { ++ unsigned int nat25_disable; ++ unsigned int macclone_enable; ++ unsigned int dhcp_bcst_disable; ++ int addPPPoETag; /* 1: Add PPPoE relay-SID, 0: disable */ ++ unsigned char nat25_dmzMac[MACADDRLEN]; ++ unsigned int nat25sc_disable; ++}; ++ ++void nat25_db_cleanup(struct adapter *priv); ++ ++#endif /* _RTW_BR_EXT_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_cmd.h b/drivers/staging/r8188eu/include/rtw_cmd.h +new file mode 100644 +index 000000000000..c14d9052b997 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_cmd.h +@@ -0,0 +1,975 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_CMD_H_ ++#define __RTW_CMD_H_ ++ ++#include "wlan_bssdef.h" ++#include "rtw_rf.h" ++#include "rtw_led.h" ++ ++#define C2H_MEM_SZ (16*1024) ++ ++#include "osdep_service.h" ++#include "ieee80211.h" /* */ ++ ++#define FREE_CMDOBJ_SZ 128 ++ ++#define MAX_CMDSZ 1024 ++#define MAX_RSPSZ 512 ++#define MAX_EVTSZ 1024 ++ ++#define CMDBUFF_ALIGN_SZ 512 ++ ++struct cmd_obj { ++ struct adapter *padapter; ++ u16 cmdcode; ++ u8 res; ++ u8 *parmbuf; ++ u32 cmdsz; ++ u8 *rsp; ++ u32 rspsz; ++ struct list_head list; ++}; ++ ++struct cmd_priv { ++ struct semaphore cmd_queue_sema; ++ struct semaphore terminate_cmdthread_sema; ++ struct __queue cmd_queue; ++ u8 cmd_seq; ++ u8 *cmd_buf; /* shall be non-paged, and 4 bytes aligned */ ++ u8 *cmd_allocated_buf; ++ u8 *rsp_buf; /* shall be non-paged, and 4 bytes aligned */ ++ u8 *rsp_allocated_buf; ++ u32 cmd_issued_cnt; ++ u32 cmd_done_cnt; ++ u32 rsp_cnt; ++ u8 cmdthd_running; ++ struct adapter *padapter; ++}; ++ ++struct evt_priv { ++ struct work_struct c2h_wk; ++ bool c2h_wk_alive; ++ struct rtw_cbuf *c2h_queue; ++ #define C2H_QUEUE_MAX_LEN 10 ++ atomic_t event_seq; ++ u8 *evt_buf; /* shall be non-paged, and 4 bytes aligned */ ++ u8 *evt_allocated_buf; ++ u32 evt_done_cnt; ++}; ++ ++#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \ ++do {\ ++ INIT_LIST_HEAD(&pcmd->list);\ ++ pcmd->cmdcode = code;\ ++ pcmd->parmbuf = (u8 *)(pparm);\ ++ pcmd->cmdsz = sizeof(*pparm);\ ++ pcmd->rsp = NULL;\ ++ pcmd->rspsz = 0;\ ++} while (0) ++ ++struct c2h_evt_hdr { ++ u8 id:4; ++ u8 plen:4; ++ u8 seq; ++ u8 payload[0]; ++}; ++ ++#define c2h_evt_exist(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen) ++ ++u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *obj); ++struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv); ++void rtw_free_cmd_obj(struct cmd_obj *pcmd); ++ ++int rtw_cmd_thread(void *context); ++ ++u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv); ++void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv); ++ ++u32 rtw_init_evt_priv(struct evt_priv *pevtpriv); ++void rtw_free_evt_priv(struct evt_priv *pevtpriv); ++void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv); ++void rtw_evt_notify_isr(struct evt_priv *pevtpriv); ++#ifdef CONFIG_88EU_P2P ++u8 p2p_protocol_wk_cmd(struct adapter *padapter, int intCmdType); ++#endif /* CONFIG_88EU_P2P */ ++ ++enum rtw_drvextra_cmd_id { ++ NONE_WK_CID, ++ DYNAMIC_CHK_WK_CID, ++ DM_CTRL_WK_CID, ++ PBC_POLLING_WK_CID, ++ POWER_SAVING_CTRL_WK_CID,/* IPS,AUTOSuspend */ ++ LPS_CTRL_WK_CID, ++ ANT_SELECT_WK_CID, ++ P2P_PS_WK_CID, ++ P2P_PROTO_WK_CID, ++ CHECK_HIQ_WK_CID,/* for softap mode, check hi queue if empty */ ++ INTEl_WIDI_WK_CID, ++ C2H_WK_CID, ++ RTP_TIMER_CFG_WK_CID, ++ MAX_WK_CID ++}; ++ ++enum LPS_CTRL_TYPE { ++ LPS_CTRL_SCAN = 0, ++ LPS_CTRL_JOINBSS = 1, ++ LPS_CTRL_CONNECT = 2, ++ LPS_CTRL_DISCONNECT = 3, ++ LPS_CTRL_SPECIAL_PACKET = 4, ++ LPS_CTRL_LEAVE = 5, ++}; ++ ++enum RFINTFS { ++ SWSI, ++ HWSI, ++ HWPI, ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC(C) ++ ++Notes: To enter USB suspend mode ++ ++Command Mode ++ ++*/ ++struct usb_suspend_parm { ++ u32 action;/* 1: sleep, 0:resume */ ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC ++ ++Notes: To join a known BSS. ++ ++Command-Event Mode ++ ++*/ ++ ++/* ++Caller Mode: Infra, Ad-Hoc ++ ++Notes: To join the specified bss ++ ++Command Event Mode ++ ++*/ ++struct joinbss_parm { ++ struct wlan_bssid_ex network; ++}; ++ ++/* ++Caller Mode: Infra, Ad-HoC(C) ++ ++Notes: To disconnect the current associated BSS ++ ++Command Mode ++ ++*/ ++struct disconnect_parm { ++ u32 deauth_timeout_ms; ++}; ++ ++/* ++Caller Mode: AP, Ad-HoC(M) ++ ++Notes: To create a BSS ++ ++Command Mode ++*/ ++struct createbss_parm { ++ struct wlan_bssid_ex network; ++}; ++ ++struct setopmode_parm { ++ u8 mode; ++ u8 rsvd[3]; ++}; ++ ++/* ++Caller Mode: AP, Ad-HoC, Infra ++ ++Notes: To ask RTL8711 performing site-survey ++ ++Command-Event Mode ++ ++*/ ++ ++#define RTW_SSID_SCAN_AMOUNT 9 /* for WEXT_CSCAN_AMOUNT 9 */ ++#define RTW_CHANNEL_SCAN_AMOUNT (14+37) ++struct sitesurvey_parm { ++ int scan_mode; /* active: 1, passive: 0 */ ++ u8 ssid_num; ++ u8 ch_num; ++ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; ++ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To set the auth type of RTL8711. open/shared/802.1x ++ ++Command Mode ++ ++*/ ++struct setauth_parm { ++ u8 mode; /* 0: legacy open, 1: legacy shared 2: 802.1x */ ++ u8 _1x; /* 0: PSK, 1: TLS */ ++ u8 rsvd[2]; ++}; ++ ++/* ++Caller Mode: Infra ++ ++a. algorithm: wep40, wep104, tkip & aes ++b. keytype: grp key/unicast key ++c. key contents ++ ++when shared key ==> keyid is the camid ++when 802.1x ==> keyid [0:1] ==> grp key ++when 802.1x ==> keyid > 2 ==> unicast key ++ ++*/ ++struct setkey_parm { ++ u8 algorithm; /* could be none, wep40, TKIP, CCMP, wep104 */ ++ u8 keyid; ++ u8 grpkey; /* 1: this is the grpkey for 802.1x. ++ * 0: this is the unicast key for 802.1x */ ++ u8 set_tx; /* 1: main tx key for wep. 0: other key. */ ++ u8 key[16]; /* this could be 40 or 104 */ ++}; ++ ++/* ++When in AP or Ad-Hoc mode, this is used to ++allocate an sw/hw entry for a newly associated sta. ++ ++Command ++ ++when shared key ==> algorithm/keyid ++ ++*/ ++struct set_stakey_parm { ++ u8 addr[ETH_ALEN]; ++ u8 algorithm; ++ u8 id;/* currently for erasing cam entry if ++ * algorithm == _NO_PRIVACY_ */ ++ u8 key[16]; ++}; ++ ++struct set_stakey_rsp { ++ u8 addr[ETH_ALEN]; ++ u8 keyid; ++ u8 rsvd; ++}; ++ ++/* ++Caller Ad-Hoc/AP ++ ++Command -Rsp(AID == CAMID) mode ++ ++This is to force fw to add an sta_data entry per driver's request. ++ ++FW will write an cam entry associated with it. ++ ++*/ ++struct set_assocsta_parm { ++ u8 addr[ETH_ALEN]; ++}; ++ ++struct set_assocsta_rsp { ++ u8 cam_id; ++ u8 rsvd[3]; ++}; ++ ++/* ++ Caller Ad-Hoc/AP ++ ++ Command mode ++ ++ This is to force fw to del an sta_data entry per driver's request ++ ++ FW will invalidate the cam entry associated with it. ++ ++*/ ++struct del_assocsta_parm { ++ u8 addr[ETH_ALEN]; ++}; ++ ++/* ++Caller Mode: AP/Ad-HoC(M) ++ ++Notes: To notify fw that given staid has changed its power state ++ ++Command Mode ++ ++*/ ++struct setstapwrstate_parm { ++ u8 staid; ++ u8 status; ++ u8 hwaddr[6]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To setup the basic rate of RTL8711 ++ ++Command Mode ++ ++*/ ++struct setbasicrate_parm { ++ u8 basicrates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To read the current basic rate ++ ++Command-Rsp Mode ++ ++*/ ++struct getbasicrate_parm { ++ u32 rsvd; ++}; ++ ++struct getbasicrate_rsp { ++ u8 basicrates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To setup the data rate of RTL8711 ++ ++Command Mode ++ ++*/ ++struct setdatarate_parm { ++ u8 mac_id; ++ u8 datarates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To read the current data rate ++ ++Command-Rsp Mode ++ ++*/ ++struct getdatarate_parm { ++ u32 rsvd; ++ ++}; ++struct getdatarate_rsp { ++ u8 datarates[NumRates]; ++}; ++ ++/* ++Caller Mode: Any ++AP: AP can use the info for the contents of beacon frame ++Infra: STA can use the info when sitesurveying ++Ad-HoC(M): Like AP ++Ad-HoC(C): Like STA ++ ++Notes: To set the phy capability of the NIC ++ ++Command Mode ++ ++*/ ++ ++struct setphyinfo_parm { ++ struct regulatory_class class_sets[NUM_REGULATORYS]; ++ u8 status; ++}; ++ ++struct getphyinfo_parm { ++ u32 rsvd; ++}; ++ ++struct getphyinfo_rsp { ++ struct regulatory_class class_sets[NUM_REGULATORYS]; ++ u8 status; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To set the channel/modem/band ++This command will be used when channel/modem/band is changed. ++ ++Command Mode ++ ++*/ ++struct setphy_parm { ++ u8 rfchannel; ++ u8 modem; ++}; ++ ++/* ++Caller Mode: Any ++ ++Notes: To get the current setting of channel/modem/band ++ ++Command-Rsp Mode ++ ++*/ ++struct getphy_parm { ++ u32 rsvd; ++ ++}; ++struct getphy_rsp { ++ u8 rfchannel; ++ u8 modem; ++}; ++ ++struct readBB_parm { ++ u8 offset; ++}; ++struct readBB_rsp { ++ u8 value; ++}; ++ ++struct readTSSI_parm { ++ u8 offset; ++}; ++struct readTSSI_rsp { ++ u8 value; ++}; ++ ++struct writeBB_parm { ++ u8 offset; ++ u8 value; ++}; ++ ++struct readRF_parm { ++ u8 offset; ++}; ++struct readRF_rsp { ++ u32 value; ++}; ++ ++struct writeRF_parm { ++ u32 offset; ++ u32 value; ++}; ++ ++struct getrfintfs_parm { ++ u8 rfintfs; ++}; ++ ++struct Tx_Beacon_param ++{ ++ struct wlan_bssid_ex network; ++}; ++ ++/* ++ Notes: This command is used for H2C/C2H loopback testing ++ ++ mac[0] == 0 ++ ==> CMD mode, return H2C_SUCCESS. ++ The following condition must be ture under CMD mode ++ mac[1] == mac[4], mac[2] == mac[3], mac[0]=mac[5]= 0; ++ s0 == 0x1234, s1 == 0xabcd, w0 == 0x78563412, w1 == 0x5aa5def7; ++ s2 == (b1 << 8 | b0); ++ ++ mac[0] == 1 ++ ==> CMD_RSP mode, return H2C_SUCCESS_RSP ++ ++ The rsp layout shall be: ++ rsp: parm: ++ mac[0] = mac[5]; ++ mac[1] = mac[4]; ++ mac[2] = mac[3]; ++ mac[3] = mac[2]; ++ mac[4] = mac[1]; ++ mac[5] = mac[0]; ++ s0 = s1; ++ s1 = swap16(s0); ++ w0 = swap32(w1); ++ b0 = b1 ++ s2 = s0 + s1 ++ b1 = b0 ++ w1 = w0 ++ ++ mac[0] == 2 ++ ==> CMD_EVENT mode, return H2C_SUCCESS ++ The event layout shall be: ++ event: parm: ++ mac[0] = mac[5]; ++ mac[1] = mac[4]; ++ mac[2] = event's seq no, starting from 1 to parm's marc[3] ++ mac[3] = mac[2]; ++ mac[4] = mac[1]; ++ mac[5] = mac[0]; ++ s0 = swap16(s0) - event.mac[2]; ++ s1 = s1 + event.mac[2]; ++ w0 = swap32(w0); ++ b0 = b1 ++ s2 = s0 + event.mac[2] ++ b1 = b0 ++ w1 = swap32(w1) - event.mac[2]; ++ ++ parm->mac[3] is the total event counts that host requested. ++ event will be the same with the cmd's param. ++*/ ++ ++/* CMD param Format for driver extra cmd handler */ ++struct drvextra_cmd_parm { ++ int ec_id; /* extra cmd id */ ++ int type_size; /* Can use this field as the type id or command size */ ++ unsigned char *pbuf; ++}; ++ ++/*------------------- Below are used for RF/BB tunning ---------------------*/ ++ ++struct setantenna_parm { ++ u8 tx_antset; ++ u8 rx_antset; ++ u8 tx_antenna; ++ u8 rx_antenna; ++}; ++ ++struct enrateadaptive_parm { ++ u32 en; ++}; ++ ++struct settxagctbl_parm { ++ u32 txagc[MAX_RATES_LENGTH]; ++}; ++ ++struct gettxagctbl_parm { ++ u32 rsvd; ++}; ++struct gettxagctbl_rsp { ++ u32 txagc[MAX_RATES_LENGTH]; ++}; ++ ++struct setagcctrl_parm { ++ u32 agcctrl; /* 0: pure hw, 1: fw */ ++}; ++ ++struct setssup_parm { ++ u32 ss_ForceUp[MAX_RATES_LENGTH]; ++}; ++ ++struct getssup_parm { ++ u32 rsvd; ++}; ++ ++struct getssup_rsp { ++ u8 ss_ForceUp[MAX_RATES_LENGTH]; ++}; ++ ++struct setssdlevel_parm { ++ u8 ss_DLevel[MAX_RATES_LENGTH]; ++}; ++ ++struct getssdlevel_parm { ++ u32 rsvd; ++}; ++ ++struct getssdlevel_rsp { ++ u8 ss_DLevel[MAX_RATES_LENGTH]; ++}; ++ ++struct setssulevel_parm { ++ u8 ss_ULevel[MAX_RATES_LENGTH]; ++}; ++ ++struct getssulevel_parm { ++ u32 rsvd; ++}; ++ ++struct getssulevel_rsp { ++ u8 ss_ULevel[MAX_RATES_LENGTH]; ++}; ++ ++struct setcountjudge_parm { ++ u8 count_judge[MAX_RATES_LENGTH]; ++}; ++ ++struct getcountjudge_parm { ++ u32 rsvd; ++}; ++ ++struct getcountjudge_rsp { ++ u8 count_judge[MAX_RATES_LENGTH]; ++}; ++ ++struct setratable_parm { ++ u8 ss_ForceUp[NumRates]; ++ u8 ss_ULevel[NumRates]; ++ u8 ss_DLevel[NumRates]; ++ u8 count_judge[NumRates]; ++}; ++ ++struct getratable_parm { ++ uint rsvd; ++}; ++ ++struct getratable_rsp { ++ u8 ss_ForceUp[NumRates]; ++ u8 ss_ULevel[NumRates]; ++ u8 ss_DLevel[NumRates]; ++ u8 count_judge[NumRates]; ++}; ++ ++/* to get TX,RX retry count */ ++ ++struct gettxretrycnt_parm { ++ unsigned int rsvd; ++}; ++ ++struct gettxretrycnt_rsp { ++ unsigned long tx_retrycnt; ++}; ++ ++struct getrxretrycnt_parm { ++ unsigned int rsvd; ++}; ++ ++struct getrxretrycnt_rsp { ++ unsigned long rx_retrycnt; ++}; ++ ++/* to get BCNOK,BCNERR count */ ++struct getbcnokcnt_parm { ++ unsigned int rsvd; ++}; ++ ++struct getbcnokcnt_rsp { ++ unsigned long bcnokcnt; ++}; ++ ++struct getbcnerrcnt_parm { ++ unsigned int rsvd; ++}; ++ ++struct getbcnerrcnt_rsp { ++ unsigned long bcnerrcnt; ++}; ++ ++/* to get current TX power level */ ++struct getcurtxpwrlevel_parm { ++ unsigned int rsvd; ++}; ++struct getcurtxpwrlevel_rspi { ++ unsigned short tx_power; ++}; ++ ++struct setprobereqextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setassocreqextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setproberspextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct setassocrspextraie_parm { ++ unsigned char e_id; ++ unsigned char ie_len; ++ unsigned char ie[0]; ++}; ++ ++struct addBaReq_parm { ++ unsigned int tid; ++ u8 addr[ETH_ALEN]; ++}; ++ ++/*H2C Handler index: 46 */ ++struct set_ch_parm { ++ u8 ch; ++ u8 bw; ++ u8 ch_offset; ++}; ++ ++/*H2C Handler index: 59 */ ++struct SetChannelPlan_param ++{ ++ u8 channel_plan; ++}; ++ ++/*H2C Handler index: 60 */ ++struct LedBlink_param ++{ ++ struct LED_871x *pLed; ++}; ++ ++/*H2C Handler index: 61 */ ++struct SetChannelSwitch_param ++{ ++ u8 new_ch_no; ++}; ++ ++/*H2C Handler index: 62 */ ++struct TDLSoption_param ++{ ++ u8 addr[ETH_ALEN]; ++ u8 option; ++}; ++ ++#define GEN_CMD_CODE(cmd) cmd ## _CMD_ ++ ++/* ++ ++Result: ++0x00: success ++0x01: success, and check Response. ++0x02: cmd ignored due to duplicated sequcne number ++0x03: cmd dropped due to invalid cmd code ++0x04: reserved. ++ ++*/ ++ ++#define H2C_RSP_OFFSET 512 ++ ++#define H2C_SUCCESS 0x00 ++#define H2C_SUCCESS_RSP 0x01 ++#define H2C_DUPLICATED 0x02 ++#define H2C_DROPPED 0x03 ++#define H2C_PARAMETERS_ERROR 0x04 ++#define H2C_REJECTED 0x05 ++#define H2C_CMD_OVERFLOW 0x06 ++#define H2C_RESERVED 0x07 ++ ++u8 rtw_setassocsta_cmd(struct adapter *padapter, u8 *mac_addr); ++u8 rtw_setstandby_cmd(struct adapter *padapter, uint action); ++u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, ++ int ssid_num, struct rtw_ieee80211_channel *ch, ++ int ch_num); ++u8 rtw_createbss_cmd(struct adapter *padapter); ++u8 rtw_createbss_cmd_ex(struct adapter *padapter, unsigned char *pbss, ++ unsigned int sz); ++u8 rtw_setphy_cmd(struct adapter *padapter, u8 modem, u8 ch); ++u8 rtw_setstakey_cmd(struct adapter *padapter, u8 *psta, u8 unicast_key); ++u8 rtw_clearstakey_cmd(struct adapter *padapter, u8 *psta, u8 entry, u8 enqueue); ++u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network* pnetwork); ++u8 rtw_disassoc_cmd(struct adapter *padapter, u32 deauth_timeout_ms, bool enqueue); ++u8 rtw_setopmode_cmd(struct adapter *padapter, enum ndis_802_11_network_infra networktype); ++u8 rtw_setdatarate_cmd(struct adapter *padapter, u8 *rateset); ++u8 rtw_setbasicrate_cmd(struct adapter *padapter, u8 *rateset); ++u8 rtw_setbbreg_cmd(struct adapter * padapter, u8 offset, u8 val); ++u8 rtw_setrfreg_cmd(struct adapter * padapter, u8 offset, u32 val); ++u8 rtw_getbbreg_cmd(struct adapter * padapter, u8 offset, u8 * pval); ++u8 rtw_getrfreg_cmd(struct adapter * padapter, u8 offset, u8 * pval); ++u8 rtw_setrfintfs_cmd(struct adapter *padapter, u8 mode); ++u8 rtw_setrttbl_cmd(struct adapter *padapter, struct setratable_parm *prate_table); ++u8 rtw_getrttbl_cmd(struct adapter *padapter, struct getratable_rsp *pval); ++ ++u8 rtw_gettssi_cmd(struct adapter *padapter, u8 offset,u8 *pval); ++u8 rtw_setfwdig_cmd(struct adapter*padapter, u8 type); ++u8 rtw_setfwra_cmd(struct adapter*padapter, u8 type); ++ ++u8 rtw_addbareq_cmd(struct adapter*padapter, u8 tid, u8 *addr); ++ ++u8 rtw_dynamic_chk_wk_cmd(struct adapter *adapter); ++ ++u8 rtw_lps_ctrl_wk_cmd(struct adapter*padapter, u8 lps_ctrl_type, u8 enqueue); ++u8 rtw_rpt_timer_cfg_cmd(struct adapter*padapter, u16 minRptTime); ++ ++ u8 rtw_antenna_select_cmd(struct adapter*padapter, u8 antenna,u8 enqueue); ++u8 rtw_ps_cmd(struct adapter*padapter); ++ ++#ifdef CONFIG_88EU_AP_MODE ++u8 rtw_chk_hi_queue_cmd(struct adapter*padapter); ++#endif ++ ++u8 rtw_set_ch_cmd(struct adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue); ++u8 rtw_set_chplan_cmd(struct adapter*padapter, u8 chplan, u8 enqueue); ++u8 rtw_led_blink_cmd(struct adapter*padapter, struct LED_871x * pLed); ++u8 rtw_set_csa_cmd(struct adapter*padapter, u8 new_ch_no); ++u8 rtw_tdls_cmd(struct adapter *padapter, u8 *addr, u8 option); ++ ++u8 rtw_c2h_wk_cmd(struct adapter *padapter, u8 *c2h_evt); ++ ++u8 rtw_drvextra_cmd_hdl(struct adapter *padapter, unsigned char *pbuf); ++ ++void rtw_survey_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++void rtw_disassoc_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++void rtw_joinbss_cmd_callback(struct adapter *padapter, struct cmd_obj *pcmd); ++void rtw_createbss_cmd_callback(struct adapter *adapt, struct cmd_obj *pcmd); ++void rtw_getbbrfreg_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd); ++void rtw_readtssi_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd); ++ ++void rtw_setstaKey_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd); ++void rtw_setassocsta_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cm); ++void rtw_getrttbl_cmdrsp_callback(struct adapter *adapt, struct cmd_obj *cmd); ++ ++struct _cmd_callback { ++ u32 cmd_code; ++ void (*callback)(struct adapter *padapter, struct cmd_obj *cmd); ++}; ++ ++enum rtw_h2c_cmd { ++ GEN_CMD_CODE(_Read_MACREG), /*0*/ ++ GEN_CMD_CODE(_Write_MACREG), ++ GEN_CMD_CODE(_Read_BBREG), ++ GEN_CMD_CODE(_Write_BBREG), ++ GEN_CMD_CODE(_Read_RFREG), ++ GEN_CMD_CODE(_Write_RFREG), /*5*/ ++ GEN_CMD_CODE(_Read_EEPROM), ++ GEN_CMD_CODE(_Write_EEPROM), ++ GEN_CMD_CODE(_Read_EFUSE), ++ GEN_CMD_CODE(_Write_EFUSE), ++ ++ GEN_CMD_CODE(_Read_CAM), /*10*/ ++ GEN_CMD_CODE(_Write_CAM), ++ GEN_CMD_CODE(_setBCNITV), ++ GEN_CMD_CODE(_setMBIDCFG), ++ GEN_CMD_CODE(_JoinBss), /*14*/ ++ GEN_CMD_CODE(_DisConnect), /*15*/ ++ GEN_CMD_CODE(_CreateBss), ++ GEN_CMD_CODE(_SetOpMode), ++ GEN_CMD_CODE(_SiteSurvey), /*18*/ ++ GEN_CMD_CODE(_SetAuth), ++ ++ GEN_CMD_CODE(_SetKey), /*20*/ ++ GEN_CMD_CODE(_SetStaKey), ++ GEN_CMD_CODE(_SetAssocSta), ++ GEN_CMD_CODE(_DelAssocSta), ++ GEN_CMD_CODE(_SetStaPwrState), ++ GEN_CMD_CODE(_SetBasicRate), /*25*/ ++ GEN_CMD_CODE(_GetBasicRate), ++ GEN_CMD_CODE(_SetDataRate), ++ GEN_CMD_CODE(_GetDataRate), ++ GEN_CMD_CODE(_SetPhyInfo), ++ ++ GEN_CMD_CODE(_GetPhyInfo), /*30*/ ++ GEN_CMD_CODE(_SetPhy), ++ GEN_CMD_CODE(_GetPhy), ++ GEN_CMD_CODE(_readRssi), ++ GEN_CMD_CODE(_readGain), ++ GEN_CMD_CODE(_SetAtim), /*35*/ ++ GEN_CMD_CODE(_SetPwrMode), ++ GEN_CMD_CODE(_JoinbssRpt), ++ GEN_CMD_CODE(_SetRaTable), ++ GEN_CMD_CODE(_GetRaTable), ++ ++ GEN_CMD_CODE(_GetCCXReport), /*40*/ ++ GEN_CMD_CODE(_GetDTMReport), ++ GEN_CMD_CODE(_GetTXRateStatistics), ++ GEN_CMD_CODE(_SetUsbSuspend), ++ GEN_CMD_CODE(_SetH2cLbk), ++ GEN_CMD_CODE(_AddBAReq), /*45*/ ++ GEN_CMD_CODE(_SetChannel), /*46*/ ++ GEN_CMD_CODE(_SetTxPower), ++ GEN_CMD_CODE(_SwitchAntenna), ++ GEN_CMD_CODE(_SetCrystalCap), ++ GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/ ++ ++ GEN_CMD_CODE(_SetSingleToneTx),/*51*/ ++ GEN_CMD_CODE(_SetCarrierSuppressionTx), ++ GEN_CMD_CODE(_SetContinuousTx), ++ GEN_CMD_CODE(_SwitchBandwidth), /*54*/ ++ GEN_CMD_CODE(_TX_Beacon), /*55*/ ++ ++ GEN_CMD_CODE(_Set_MLME_EVT), /*56*/ ++ GEN_CMD_CODE(_Set_Drv_Extra), /*57*/ ++ GEN_CMD_CODE(_Set_H2C_MSG), /*58*/ ++ ++ GEN_CMD_CODE(_SetChannelPlan), /*59*/ ++ GEN_CMD_CODE(_LedBlink), /*60*/ ++ ++ GEN_CMD_CODE(_SetChannelSwitch), /*61*/ ++ GEN_CMD_CODE(_TDLS), /*62*/ ++ ++ MAX_H2CCMD ++}; ++ ++#define _GetBBReg_CMD_ _Read_BBREG_CMD_ ++#define _SetBBReg_CMD_ _Write_BBREG_CMD_ ++#define _GetRFReg_CMD_ _Read_RFREG_CMD_ ++#define _SetRFReg_CMD_ _Write_RFREG_CMD_ ++ ++#ifdef _RTW_CMD_C_ ++static struct _cmd_callback rtw_cmd_callback[] = ++{ ++ {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ ++ {GEN_CMD_CODE(_Write_MACREG), NULL}, ++ {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback}, ++ {GEN_CMD_CODE(_Write_BBREG), NULL}, ++ {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback}, ++ {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/ ++ {GEN_CMD_CODE(_Read_EEPROM), NULL}, ++ {GEN_CMD_CODE(_Write_EEPROM), NULL}, ++ {GEN_CMD_CODE(_Read_EFUSE), NULL}, ++ {GEN_CMD_CODE(_Write_EFUSE), NULL}, ++ ++ {GEN_CMD_CODE(_Read_CAM), NULL}, /*10*/ ++ {GEN_CMD_CODE(_Write_CAM), NULL}, ++ {GEN_CMD_CODE(_setBCNITV), NULL}, ++ {GEN_CMD_CODE(_setMBIDCFG), NULL}, ++ {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd_callback}, /*14*/ ++ {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd_callback}, /*15*/ ++ {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd_callback}, ++ {GEN_CMD_CODE(_SetOpMode), NULL}, ++ {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback}, /*18*/ ++ {GEN_CMD_CODE(_SetAuth), NULL}, ++ ++ {GEN_CMD_CODE(_SetKey), NULL}, /*20*/ ++ {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback}, ++ {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback}, ++ {GEN_CMD_CODE(_DelAssocSta), NULL}, ++ {GEN_CMD_CODE(_SetStaPwrState), NULL}, ++ {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/ ++ {GEN_CMD_CODE(_GetBasicRate), NULL}, ++ {GEN_CMD_CODE(_SetDataRate), NULL}, ++ {GEN_CMD_CODE(_GetDataRate), NULL}, ++ {GEN_CMD_CODE(_SetPhyInfo), NULL}, ++ ++ {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/ ++ {GEN_CMD_CODE(_SetPhy), NULL}, ++ {GEN_CMD_CODE(_GetPhy), NULL}, ++ {GEN_CMD_CODE(_readRssi), NULL}, ++ {GEN_CMD_CODE(_readGain), NULL}, ++ {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/ ++ {GEN_CMD_CODE(_SetPwrMode), NULL}, ++ {GEN_CMD_CODE(_JoinbssRpt), NULL}, ++ {GEN_CMD_CODE(_SetRaTable), NULL}, ++ {GEN_CMD_CODE(_GetRaTable), NULL}, ++ ++ {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/ ++ {GEN_CMD_CODE(_GetDTMReport), NULL}, ++ {GEN_CMD_CODE(_GetTXRateStatistics), NULL}, ++ {GEN_CMD_CODE(_SetUsbSuspend), NULL}, ++ {GEN_CMD_CODE(_SetH2cLbk), NULL}, ++ {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/ ++ {GEN_CMD_CODE(_SetChannel), NULL}, /*46*/ ++ {GEN_CMD_CODE(_SetTxPower), NULL}, ++ {GEN_CMD_CODE(_SwitchAntenna), NULL}, ++ {GEN_CMD_CODE(_SetCrystalCap), NULL}, ++ {GEN_CMD_CODE(_SetSingleCarrierTx), NULL}, /*50*/ ++ ++ {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/ ++ {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL}, ++ {GEN_CMD_CODE(_SetContinuousTx), NULL}, ++ {GEN_CMD_CODE(_SwitchBandwidth), NULL}, /*54*/ ++ {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/ ++ ++ {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/ ++ {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/ ++ {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/ ++ {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/ ++ {GEN_CMD_CODE(_LedBlink), NULL},/*60*/ ++ ++ {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/ ++ {GEN_CMD_CODE(_TDLS), NULL},/*62*/ ++}; ++#endif ++ ++#endif /* _CMD_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_debug.h b/drivers/staging/r8188eu/include/rtw_debug.h +new file mode 100644 +index 000000000000..3c3bf2a4f30e +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_debug.h +@@ -0,0 +1,231 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_DEBUG_H__ ++#define __RTW_DEBUG_H__ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#define _drv_always_ 1 ++#define _drv_emerg_ 2 ++#define _drv_alert_ 3 ++#define _drv_crit_ 4 ++#define _drv_err_ 5 ++#define _drv_warning_ 6 ++#define _drv_notice_ 7 ++#define _drv_info_ 8 ++#define _drv_debug_ 9 ++ ++#define _module_rtl871x_xmit_c_ BIT(0) ++#define _module_xmit_osdep_c_ BIT(1) ++#define _module_rtl871x_recv_c_ BIT(2) ++#define _module_recv_osdep_c_ BIT(3) ++#define _module_rtl871x_mlme_c_ BIT(4) ++#define _module_mlme_osdep_c_ BIT(5) ++#define _module_rtl871x_sta_mgt_c_ BIT(6) ++#define _module_rtl871x_cmd_c_ BIT(7) ++#define _module_cmd_osdep_c_ BIT(8) ++#define _module_rtl871x_io_c_ BIT(9) ++#define _module_io_osdep_c_ BIT(10) ++#define _module_os_intfs_c_ BIT(11) ++#define _module_rtl871x_security_c_ BIT(12) ++#define _module_rtl871x_eeprom_c_ BIT(13) ++#define _module_hal_init_c_ BIT(14) ++#define _module_hci_hal_init_c_ BIT(15) ++#define _module_rtl871x_ioctl_c_ BIT(16) ++#define _module_rtl871x_ioctl_set_c_ BIT(17) ++#define _module_rtl871x_ioctl_query_c_ BIT(18) ++#define _module_rtl871x_pwrctrl_c_ BIT(19) ++#define _module_hci_intfs_c_ BIT(20) ++#define _module_hci_ops_c_ BIT(21) ++#define _module_osdep_service_c_ BIT(22) ++#define _module_mp_ BIT(23) ++#define _module_hci_ops_os_c_ BIT(24) ++#define _module_rtl871x_ioctl_os_c BIT(25) ++#define _module_rtl8712_cmd_c_ BIT(26) ++#define _module_rtl8192c_xmit_c_ BIT(27) ++#define _module_hal_xmit_c_ BIT(28) ++#define _module_efuse_ BIT(29) ++#define _module_rtl8712_recv_c_ BIT(30) ++#define _module_rtl8712_led_c_ BIT(31) ++ ++#define DRIVER_PREFIX "R8188EU: " ++ ++extern u32 GlobalDebugLevel; ++ ++#define DBG_88E_LEVEL(_level, fmt, arg...) \ ++ do { \ ++ if (_level <= GlobalDebugLevel) \ ++ pr_info(DRIVER_PREFIX"INFO " fmt, ##arg); \ ++ } while (0) ++ ++#define DBG_88E(...) \ ++ do { \ ++ if (_drv_err_ <= GlobalDebugLevel) \ ++ pr_info(DRIVER_PREFIX __VA_ARGS__); \ ++ } while (0) ++ ++#define MSG_88E(...) \ ++ do { \ ++ if (_drv_err_ <= GlobalDebugLevel) \ ++ pr_info(DRIVER_PREFIX __VA_ARGS__); \ ++ } while (0) ++ ++int proc_get_drv_version(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_write_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_write_reg(struct file *file, const char __user *buffer, ++ unsigned long count, void *data); ++int proc_get_read_reg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_read_reg(struct file *file, const char __user *buffer, ++ unsigned long count, void *data); ++ ++int proc_get_fwstate(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++int proc_get_sec_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++int proc_get_mlmext_state(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_qos_option(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++int proc_get_ht_option(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++int proc_get_rf_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++int proc_get_ap_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_adapter_state(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_trx_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_mac_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_mac_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_mac_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_bb_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_bb_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_bb_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_rf_reg_dump1(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_rf_reg_dump2(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_rf_reg_dump3(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_rf_reg_dump4(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++int proc_get_all_sta_info(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++#endif ++ ++int proc_get_best_channel(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_rx_signal(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_rx_signal(struct file *file, const char __user *buffer, ++ unsigned long count, void *data); ++ ++int proc_get_ht_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_ht_enable(struct file *file, const char __user *buffer, ++ unsigned long count, void *data); ++ ++int proc_get_cbw40_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_cbw40_enable(struct file *file, const char __user *buffer, ++ unsigned long count, void *data); ++ ++int proc_get_ampdu_enable(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_ampdu_enable(struct file *file, const char __user *buffer, ++ unsigned long count, void *data); ++ ++int proc_get_rx_stbc(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_rx_stbc(struct file *file, const char __user *buffer, ++ unsigned long count, void *data); ++ ++int proc_get_two_path_rssi(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_get_rssi_disp(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_rssi_disp(struct file *file, const char __user *buffer, ++ unsigned long count, void *data); ++ ++#ifdef CONFIG_BT_COEXIST ++int proc_get_btcoex_dbg(char *page, char **start, ++ off_t offset, int count, ++ int *eof, void *data); ++ ++int proc_set_btcoex_dbg(struct file *file, const char *buffer, ++ signed long count, void *data); ++ ++#endif /* CONFIG_BT_COEXIST */ ++ ++#endif /* __RTW_DEBUG_H__ */ +diff --git a/drivers/staging/r8188eu/include/rtw_eeprom.h b/drivers/staging/r8188eu/include/rtw_eeprom.h +new file mode 100644 +index 000000000000..9f8a9c070339 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_eeprom.h +@@ -0,0 +1,114 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_EEPROM_H__ ++#define __RTW_EEPROM_H__ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#define RTL8712_EEPROM_ID 0x8712 ++ ++#define HWSET_MAX_SIZE_512 512 ++#define EEPROM_MAX_SIZE HWSET_MAX_SIZE_512 ++ ++#define CLOCK_RATE 50 /* 100us */ ++ ++/* EEPROM opcodes */ ++#define EEPROM_READ_OPCODE 06 ++#define EEPROM_WRITE_OPCODE 05 ++#define EEPROM_ERASE_OPCODE 07 ++#define EEPROM_EWEN_OPCODE 19 /* Erase/write enable */ ++#define EEPROM_EWDS_OPCODE 16 /* Erase/write disable */ ++ ++/* Country codes */ ++#define USA 0x555320 ++#define EUROPE 0x1 /* temp, should be provided later */ ++#define JAPAN 0x2 /* temp, should be provided later */ ++ ++#define EEPROM_CID_DEFAULT 0x0 ++#define EEPROM_CID_ALPHA 0x1 ++#define EEPROM_CID_Senao 0x3 ++#define EEPROM_CID_NetCore 0x5 ++#define EEPROM_CID_CAMEO 0X8 ++#define EEPROM_CID_SITECOM 0x9 ++#define EEPROM_CID_COREGA 0xB ++#define EEPROM_CID_EDIMAX_BELK 0xC ++#define EEPROM_CID_SERCOMM_BELK 0xE ++#define EEPROM_CID_CAMEO1 0xF ++#define EEPROM_CID_WNC_COREGA 0x12 ++#define EEPROM_CID_CLEVO 0x13 ++#define EEPROM_CID_WHQL 0xFE ++ ++/* Customer ID, note that: */ ++/* This variable is initiailzed through EEPROM or registry, */ ++/* however, its definition may be different with that in EEPROM for */ ++/* EEPROM size consideration. So, we have to perform proper translation ++ * between them. */ ++/* Besides, CustomerID of registry has precedence of that of EEPROM. */ ++/* defined below. 060703, by rcnjko. */ ++enum RT_CUSTOMER_ID { ++ RT_CID_DEFAULT = 0, ++ RT_CID_8187_ALPHA0 = 1, ++ RT_CID_8187_SERCOMM_PS = 2, ++ RT_CID_8187_HW_LED = 3, ++ RT_CID_8187_NETGEAR = 4, ++ RT_CID_WHQL = 5, ++ RT_CID_819x_CAMEO = 6, ++ RT_CID_819x_RUNTOP = 7, ++ RT_CID_819x_Senao = 8, ++ RT_CID_TOSHIBA = 9, /* Merge by Jacken, 2008/01/31. */ ++ RT_CID_819x_Netcore = 10, ++ RT_CID_Nettronix = 11, ++ RT_CID_DLINK = 12, ++ RT_CID_PRONET = 13, ++ RT_CID_COREGA = 14, ++ RT_CID_CHINA_MOBILE = 15, ++ RT_CID_819x_ALPHA = 16, ++ RT_CID_819x_Sitecom = 17, ++ RT_CID_CCX = 18, /* It's set under CCX logo test and isn't demanded ++ * for CCX functions, but for test behavior like retry ++ * limit and tx report. By Bruce, 2009-02-17. */ ++ RT_CID_819x_Lenovo = 19, ++ RT_CID_819x_QMI = 20, ++ RT_CID_819x_Edimax_Belkin = 21, ++ RT_CID_819x_Sercomm_Belkin = 22, ++ RT_CID_819x_CAMEO1 = 23, ++ RT_CID_819x_MSI = 24, ++ RT_CID_819x_Acer = 25, ++ RT_CID_819x_AzWave_ASUS = 26, ++ RT_CID_819x_AzWave = 27, /* For AzWave in PCIe,i ++ * The ID is AzWave use and not only Asus */ ++ RT_CID_819x_HP = 28, ++ RT_CID_819x_WNC_COREGA = 29, ++ RT_CID_819x_Arcadyan_Belkin = 30, ++ RT_CID_819x_SAMSUNG = 31, ++ RT_CID_819x_CLEVO = 32, ++ RT_CID_819x_DELL = 33, ++ RT_CID_819x_PRONETS = 34, ++ RT_CID_819x_Edimax_ASUS = 35, ++ RT_CID_819x_CAMEO_NETGEAR = 36, ++ RT_CID_PLANEX = 37, ++ RT_CID_CC_C = 38, ++ RT_CID_819x_Xavi = 39, ++ RT_CID_819x_FUNAI_TV = 40, ++ RT_CID_819x_ALPHA_WD=41, ++}; ++ ++struct eeprom_priv { ++ u8 bautoload_fail_flag; ++ u8 bloadfile_fail_flag; ++ u8 bloadmac_fail_flag; ++ u8 mac_addr[6]; /* PermanentAddress */ ++ u16 channel_plan; ++ u8 EepromOrEfuse; ++ u8 efuse_eeprom_data[HWSET_MAX_SIZE_512] __aligned(4); ++}; ++ ++void eeprom_write16(struct adapter *padapter, u16 reg, u16 data); ++u16 eeprom_read16(struct adapter *padapter, u16 reg); ++void read_eeprom_content(struct adapter *padapter); ++void eeprom_read_sz(struct adapter *adapt, u16 reg, u8 *data, u32 sz); ++void read_eeprom_content_by_attrib(struct adapter *padapter); ++ ++#endif /* __RTL871X_EEPROM_H__ */ +diff --git a/drivers/staging/r8188eu/include/rtw_efuse.h b/drivers/staging/r8188eu/include/rtw_efuse.h +new file mode 100644 +index 000000000000..b3ff46db2091 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_efuse.h +@@ -0,0 +1,134 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_EFUSE_H__ ++#define __RTW_EFUSE_H__ ++ ++#include "osdep_service.h" ++ ++#define EFUSE_ERROE_HANDLE 1 ++ ++#define PG_STATE_HEADER 0x01 ++#define PG_STATE_WORD_0 0x02 ++#define PG_STATE_WORD_1 0x04 ++#define PG_STATE_WORD_2 0x08 ++#define PG_STATE_WORD_3 0x10 ++#define PG_STATE_DATA 0x20 ++ ++#define PG_SWBYTE_H 0x01 ++#define PG_SWBYTE_L 0x02 ++ ++#define PGPKT_DATA_SIZE 8 ++ ++#define EFUSE_WIFI 0 ++#define EFUSE_BT 1 ++ ++enum _EFUSE_DEF_TYPE { ++ TYPE_EFUSE_MAX_SECTION = 0, ++ TYPE_EFUSE_REAL_CONTENT_LEN = 1, ++ TYPE_AVAILABLE_EFUSE_BYTES_BANK = 2, ++ TYPE_AVAILABLE_EFUSE_BYTES_TOTAL = 3, ++ TYPE_EFUSE_MAP_LEN = 4, ++ TYPE_EFUSE_PROTECT_BYTES_BANK = 5, ++ TYPE_EFUSE_CONTENT_LEN_BANK = 6, ++}; ++ ++/* E-Fuse */ ++#define EFUSE_MAP_SIZE 512 ++#define EFUSE_MAX_SIZE 256 ++/* end of E-Fuse */ ++ ++#define EFUSE_MAX_MAP_LEN 512 ++#define EFUSE_MAX_HW_SIZE 512 ++#define EFUSE_MAX_SECTION_BASE 16 ++ ++#define EXT_HEADER(header) ((header & 0x1F) == 0x0F) ++#define ALL_WORDS_DISABLED(wde) ((wde & 0x0F) == 0x0F) ++#define GET_HDR_OFFSET_2_0(header) ((header & 0xE0) >> 5) ++ ++#define EFUSE_REPEAT_THRESHOLD_ 3 ++ ++/* The following is for BT Efuse definition */ ++#define EFUSE_BT_MAX_MAP_LEN 1024 ++#define EFUSE_MAX_BANK 4 ++#define EFUSE_MAX_BT_BANK (EFUSE_MAX_BANK-1) ++/*--------------------------Define Parameters-------------------------------*/ ++#define EFUSE_MAX_WORD_UNIT 4 ++ ++/*------------------------------Define structure----------------------------*/ ++struct pgpkt { ++ u8 offset; ++ u8 word_en; ++ u8 data[8]; ++ u8 word_cnts; ++}; ++ ++/*------------------------------Define structure----------------------------*/ ++struct efuse_hal { ++ u8 fakeEfuseBank; ++ u32 fakeEfuseUsedBytes; ++ u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE]; ++ u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN]; ++ u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN]; ++ ++ u16 BTEfuseUsedBytes; ++ u8 BTEfuseUsedPercentage; ++ u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++ u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; ++ u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; ++ ++ u16 fakeBTEfuseUsedBytes; ++ u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++ u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN]; ++ u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN]; ++}; ++ ++/*------------------------Export global variable----------------------------*/ ++extern u8 fakeEfuseBank; ++extern u32 fakeEfuseUsedBytes; ++extern u8 fakeEfuseContent[]; ++extern u8 fakeEfuseInitMap[]; ++extern u8 fakeEfuseModifiedMap[]; ++ ++extern u32 BTEfuseUsedBytes; ++extern u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++extern u8 BTEfuseInitMap[]; ++extern u8 BTEfuseModifiedMap[]; ++ ++extern u32 fakeBTEfuseUsedBytes; ++extern u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; ++extern u8 fakeBTEfuseInitMap[]; ++extern u8 fakeBTEfuseModifiedMap[]; ++/*------------------------Export global variable----------------------------*/ ++ ++u8 efuse_GetCurrentSize(struct adapter *adapter, u16 *size); ++u16 efuse_GetMaxSize(struct adapter *adapter); ++u8 rtw_efuse_access(struct adapter *adapter, u8 read, u16 start_addr, ++ u16 cnts, u8 *data); ++u8 rtw_efuse_map_read(struct adapter *adapter, u16 addr, u16 cnts, u8 *data); ++u8 rtw_efuse_map_write(struct adapter *adapter, u16 addr, u16 cnts, u8 *data); ++u8 rtw_BT_efuse_map_read(struct adapter *adapter, u16 addr, ++ u16 cnts, u8 *data); ++u8 rtw_BT_efuse_map_write(struct adapter *adapter, u16 addr, ++ u16 cnts, u8 *data); ++u16 Efuse_GetCurrentSize(struct adapter *adapter, u8 efusetype, bool test); ++u8 Efuse_CalculateWordCnts(u8 word_en); ++void ReadEFuseByte(struct adapter *adapter, u16 _offset, u8 *pbuf, bool test); ++void EFUSE_GetEfuseDefinition(struct adapter *adapt, u8 type, u8 type1, ++ void *out, bool bPseudoTest); ++u8 efuse_OneByteRead(struct adapter *adapter, u16 addr, u8 *data, bool test); ++u8 efuse_OneByteWrite(struct adapter *adapter, u16 addr, u8 data, bool test); ++ ++void Efuse_PowerSwitch(struct adapter *adapt,u8 bWrite,u8 PwrState); ++int Efuse_PgPacketRead(struct adapter *adapt, u8 offset, u8 *data, bool test); ++int Efuse_PgPacketWrite(struct adapter *adapter, u8 offset, u8 word, u8 *data, ++ bool test); ++void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata); ++u8 Efuse_WordEnableDataWrite(struct adapter *adapter, u16 efuse_addr, ++ u8 word_en, u8 *data, bool test); ++ ++u8 EFUSE_Read1Byte(struct adapter *adapter, u16 address); ++void EFUSE_ShadowMapUpdate(struct adapter *adapter, u8 efusetype, bool test); ++void EFUSE_ShadowRead(struct adapter *adapt, u8 type, u16 offset, u32 *val); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtw_event.h b/drivers/staging/r8188eu/include/rtw_event.h +new file mode 100644 +index 000000000000..54dc1ea437fc +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_event.h +@@ -0,0 +1,97 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_EVENT_H_ ++#define _RTW_EVENT_H_ ++ ++#include "osdep_service.h" ++ ++#include "wlan_bssdef.h" ++#include ++#include ++ ++/* ++Used to report a bss has been scanned ++*/ ++struct survey_event { ++ struct wlan_bssid_ex bss; ++}; ++ ++/* ++Used to report that the requested site survey has been done. ++ ++bss_cnt indicates the number of bss that has been reported. ++ ++*/ ++struct surveydone_event { ++ unsigned int bss_cnt; ++ ++}; ++ ++/* ++Used to report the link result of joinning the given bss ++ ++join_res: ++-1: authentication fail ++-2: association fail ++> 0: TID ++ ++*/ ++struct joinbss_event { ++ struct wlan_network network; ++}; ++ ++/* ++Used to report a given STA has joinned the created BSS. ++It is used in AP/Ad-HoC(M) mode. ++*/ ++ ++struct stassoc_event { ++ unsigned char macaddr[6]; ++ unsigned char rsvd[2]; ++ int cam_id; ++}; ++ ++struct stadel_event { ++ unsigned char macaddr[6]; ++ unsigned char rsvd[2]; /* for reason */ ++ int mac_id; ++}; ++ ++struct addba_event { ++ unsigned int tid; ++}; ++ ++#define GEN_EVT_CODE(event) event ## _EVT_ ++ ++struct fwevent { ++ u32 parmsize; ++ void (*event_callback)(struct adapter *dev, u8 *pbuf); ++}; ++ ++#define C2HEVENT_SZ 32 ++ ++struct event_node { ++ unsigned char *node; ++ unsigned char evt_code; ++ unsigned short evt_sz; ++ int *caller_ff_tail; ++ int caller_ff_sz; ++}; ++ ++struct c2hevent_queue { ++ int head; ++ int tail; ++ struct event_node nodes[C2HEVENT_SZ]; ++ unsigned char seq; ++}; ++ ++#define NETWORK_QUEUE_SZ 4 ++ ++struct network_queue { ++ int head; ++ int tail; ++ struct wlan_bssid_ex networks[NETWORK_QUEUE_SZ]; ++}; ++ ++#endif /* _WLANEVENT_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_ht.h b/drivers/staging/r8188eu/include/rtw_ht.h +new file mode 100644 +index 000000000000..2b56b7c38c86 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_ht.h +@@ -0,0 +1,28 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_HT_H_ ++#define _RTW_HT_H_ ++ ++#include "osdep_service.h" ++#include "wifi.h" ++ ++struct ht_priv { ++ u32 ht_option; ++ u32 ampdu_enable;/* for enable Tx A-MPDU */ ++ u32 tx_amsdu_enable;/* for enable Tx A-MSDU */ ++ u32 tx_amdsu_maxlen; /* 1: 8k, 0:4k ; default:8k, for tx */ ++ u32 rx_ampdu_maxlen; /* for rx reordering ctrl win_sz, ++ * updated when join_callback. */ ++ u8 bwmode;/* */ ++ u8 ch_offset;/* PRIME_CHNL_OFFSET */ ++ u8 sgi;/* short GI */ ++ ++ /* for processing Tx A-MPDU */ ++ u8 agg_enable_bitmap; ++ u8 candidate_tid_bitmap; ++ ++ struct ieee80211_ht_cap ht_cap; ++}; ++ ++#endif /* _RTL871X_HT_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_io.h b/drivers/staging/r8188eu/include/rtw_io.h +new file mode 100644 +index 000000000000..4b41c7b03972 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_io.h +@@ -0,0 +1,367 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_IO_H_ ++#define _RTW_IO_H_ ++ ++#include "osdep_service.h" ++#include "osdep_intf.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define rtw_usb_buffer_alloc(dev, size, dma) \ ++ usb_alloc_coherent((dev), (size), (in_interrupt() ? \ ++ GFP_ATOMIC : GFP_KERNEL), (dma)) ++#define rtw_usb_buffer_free(dev, size, addr, dma) \ ++ usb_free_coherent((dev), (size), (addr), (dma)) ++ ++#define NUM_IOREQ 8 ++ ++#define MAX_PROT_SZ (64-16) ++ ++#define _IOREADY 0 ++#define _IO_WAIT_COMPLETE 1 ++#define _IO_WAIT_RSP 2 ++ ++/* IO COMMAND TYPE */ ++#define _IOSZ_MASK_ (0x7F) ++#define _IO_WRITE_ BIT(7) ++#define _IO_FIXED_ BIT(8) ++#define _IO_BURST_ BIT(9) ++#define _IO_BYTE_ BIT(10) ++#define _IO_HW_ BIT(11) ++#define _IO_WORD_ BIT(12) ++#define _IO_SYNC_ BIT(13) ++#define _IO_CMDMASK_ (0x1F80) ++ ++/* ++ For prompt mode accessing, caller shall free io_req ++ Otherwise, io_handler will free io_req ++*/ ++ ++/* IO STATUS TYPE */ ++#define _IO_ERR_ BIT(2) ++#define _IO_SUCCESS_ BIT(1) ++#define _IO_DONE_ BIT(0) ++ ++#define IO_RD32 (_IO_SYNC_ | _IO_WORD_) ++#define IO_RD16 (_IO_SYNC_ | _IO_HW_) ++#define IO_RD8 (_IO_SYNC_ | _IO_BYTE_) ++ ++#define IO_RD32_ASYNC (_IO_WORD_) ++#define IO_RD16_ASYNC (_IO_HW_) ++#define IO_RD8_ASYNC (_IO_BYTE_) ++ ++#define IO_WR32 (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_) ++#define IO_WR16 (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_) ++#define IO_WR8 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_) ++ ++#define IO_WR32_ASYNC (_IO_WRITE_ | _IO_WORD_) ++#define IO_WR16_ASYNC (_IO_WRITE_ | _IO_HW_) ++#define IO_WR8_ASYNC (_IO_WRITE_ | _IO_BYTE_) ++ ++/* ++ Only Sync. burst accessing is provided. ++*/ ++ ++#define IO_WR_BURST(x) \ ++ (_IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_)) ++#define IO_RD_BURST(x) \ ++ (_IO_SYNC_ | _IO_BURST_ | ((x) & _IOSZ_MASK_)) ++ ++/* below is for the intf_option bit defition... */ ++ ++#define _INTF_ASYNC_ BIT(0) /* support async io */ ++ ++struct intf_priv; ++struct intf_hdl; ++struct io_queue; ++ ++struct _io_ops { ++ u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr); ++ u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr); ++ u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr); ++ int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, ++ u8 *pdata); ++ int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); ++ int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); ++ int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); ++ void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, ++ u8 *pmem); ++ void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, ++ u8 *pmem); ++ u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, ++ u8 *pmem); ++ u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, ++ u8 *pmem); ++ void (*_read_port_cancel)(struct intf_hdl *pintfhdl); ++ void (*_write_port_cancel)(struct intf_hdl *pintfhdl); ++}; ++ ++struct io_req { ++ struct list_head list; ++ u32 addr; ++ u32 val; ++ u32 command; ++ u32 status; ++ u8 *pbuf; ++ struct semaphore sema; ++ ++ void (*_async_io_callback)(struct adapter *padater, ++ struct io_req *pio_req, u8 *cnxt); ++ u8 *cnxt; ++}; ++ ++struct intf_hdl { ++ struct adapter *padapter; ++ struct dvobj_priv *pintf_dev; ++ struct _io_ops io_ops; ++}; ++ ++struct reg_protocol_rd { ++#ifdef __LITTLE_ENDIAN ++ /* DW1 */ ++ u32 NumOfTrans:4; ++ u32 Reserved1:4; ++ u32 Reserved2:24; ++ /* DW2 */ ++ u32 ByteCount:7; ++ u32 WriteEnable:1; /* 0:read, 1:write */ ++ u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */ ++ u32 BurstMode:1; ++ u32 Byte1Access:1; ++ u32 Byte2Access:1; ++ u32 Byte4Access:1; ++ u32 Reserved3:3; ++ u32 Reserved4:16; ++ /* DW3 */ ++ u32 BusAddress; ++ /* DW4 */ ++ /* u32 Value; */ ++#else ++/* DW1 */ ++ u32 Reserved1:4; ++ u32 NumOfTrans:4; ++ u32 Reserved2:24; ++ /* DW2 */ ++ u32 WriteEnable:1; ++ u32 ByteCount:7; ++ u32 Reserved3:3; ++ u32 Byte4Access:1; ++ ++ u32 Byte2Access:1; ++ u32 Byte1Access:1; ++ u32 BurstMode:1; ++ u32 FixOrContinuous:1; ++ u32 Reserved4:16; ++ /* DW3 */ ++ u32 BusAddress; ++ ++ /* DW4 */ ++#endif ++}; ++ ++struct reg_protocol_wt { ++#ifdef __LITTLE_ENDIAN ++ /* DW1 */ ++ u32 NumOfTrans:4; ++ u32 Reserved1:4; ++ u32 Reserved2:24; ++ /* DW2 */ ++ u32 ByteCount:7; ++ u32 WriteEnable:1; /* 0:read, 1:write */ ++ u32 FixOrContinuous:1; /* 0:continuous, 1: Fix */ ++ u32 BurstMode:1; ++ u32 Byte1Access:1; ++ u32 Byte2Access:1; ++ u32 Byte4Access:1; ++ u32 Reserved3:3; ++ u32 Reserved4:16; ++ /* DW3 */ ++ u32 BusAddress; ++ /* DW4 */ ++ u32 Value; ++#else ++ /* DW1 */ ++ u32 Reserved1 :4; ++ u32 NumOfTrans:4; ++ u32 Reserved2:24; ++ /* DW2 */ ++ u32 WriteEnable:1; ++ u32 ByteCount:7; ++ u32 Reserved3:3; ++ u32 Byte4Access:1; ++ u32 Byte2Access:1; ++ u32 Byte1Access:1; ++ u32 BurstMode:1; ++ u32 FixOrContinuous:1; ++ u32 Reserved4:16; ++ /* DW3 */ ++ u32 BusAddress; ++ /* DW4 */ ++ u32 Value; ++#endif ++}; ++ ++/* ++Below is the data structure used by _io_handler ++*/ ++ ++struct io_queue { ++ spinlock_t lock; ++ struct list_head free_ioreqs; ++ struct list_head pending; /* The io_req list that will be served ++ * in the single protocol read/write.*/ ++ struct list_head processing; ++ u8 *free_ioreqs_buf; /* 4-byte aligned */ ++ u8 *pallocated_free_ioreqs_buf; ++ struct intf_hdl intf; ++}; ++ ++struct io_priv { ++ struct adapter *padapter; ++ struct intf_hdl intf; ++}; ++ ++uint ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue); ++void sync_ioreq_enqueue(struct io_req *preq,struct io_queue *ioqueue); ++uint sync_ioreq_flush(struct adapter *adapter, struct io_queue *ioqueue); ++uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue); ++struct io_req *alloc_ioreq(struct io_queue *pio_q); ++ ++uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl); ++void unregister_intf_hdl(struct intf_hdl *pintfhdl); ++ ++void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++u8 _rtw_read8(struct adapter *adapter, u32 addr); ++u16 _rtw_read16(struct adapter *adapter, u32 addr); ++u32 _rtw_read32(struct adapter *adapter, u32 addr); ++void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++void _rtw_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++void _rtw_read_port_cancel(struct adapter *adapter); ++ ++int _rtw_write8(struct adapter *adapter, u32 addr, u8 val); ++int _rtw_write16(struct adapter *adapter, u32 addr, u16 val); ++int _rtw_write32(struct adapter *adapter, u32 addr, u32 val); ++int _rtw_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata); ++ ++int _rtw_write8_async(struct adapter *adapter, u32 addr, u8 val); ++int _rtw_write16_async(struct adapter *adapter, u32 addr, u16 val); ++int _rtw_write32_async(struct adapter *adapter, u32 addr, u32 val); ++ ++void _rtw_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++u32 _rtw_write_port_and_wait(struct adapter *adapter, u32 addr, u32 cnt, ++ u8 *pmem, int timeout_ms); ++void _rtw_write_port_cancel(struct adapter *adapter); ++ ++#define rtw_read8(adapter, addr) _rtw_read8((adapter), (addr)) ++#define rtw_read16(adapter, addr) _rtw_read16((adapter), (addr)) ++#define rtw_read32(adapter, addr) _rtw_read32((adapter), (addr)) ++#define rtw_read_mem(adapter, addr, cnt, mem) \ ++ _rtw_read_mem((adapter), (addr), (cnt), (mem)) ++#define rtw_read_port(adapter, addr, cnt, mem) \ ++ _rtw_read_port((adapter), (addr), (cnt), (mem)) ++#define rtw_read_port_cancel(adapter) _rtw_read_port_cancel((adapter)) ++ ++#define rtw_write8(adapter, addr, val) \ ++ _rtw_write8((adapter), (addr), (val)) ++#define rtw_write16(adapter, addr, val) \ ++ _rtw_write16((adapter), (addr), (val)) ++#define rtw_write32(adapter, addr, val) \ ++ _rtw_write32((adapter), (addr), (val)) ++#define rtw_writeN(adapter, addr, length, data) \ ++ _rtw_writeN((adapter), (addr), (length), (data)) ++#define rtw_write8_async(adapter, addr, val) \ ++ _rtw_write8_async((adapter), (addr), (val)) ++#define rtw_write16_async(adapter, addr, val) \ ++ _rtw_write16_async((adapter), (addr), (val)) ++#define rtw_write32_async(adapter, addr, val) \ ++ _rtw_write32_async((adapter), (addr), (val)) ++#define rtw_write_mem(adapter, addr, cnt, mem) \ ++ _rtw_write_mem((adapter), (addr), (cnt), (mem)) ++#define rtw_write_port(adapter, addr, cnt, mem) \ ++ _rtw_write_port((adapter), (addr), (cnt), (mem)) ++#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) \ ++ _rtw_write_port_and_wait((adapter), (addr), (cnt), (mem), (timeout_ms)) ++#define rtw_write_port_cancel(adapter) _rtw_write_port_cancel((adapter)) ++ ++void rtw_write_scsi(struct adapter *adapter, u32 cnt, u8 *pmem); ++ ++/* ioreq */ ++void ioreq_read8(struct adapter *adapter, u32 addr, u8 *pval); ++void ioreq_read16(struct adapter *adapter, u32 addr, u16 *pval); ++void ioreq_read32(struct adapter *adapter, u32 addr, u32 *pval); ++void ioreq_write8(struct adapter *adapter, u32 addr, u8 val); ++void ioreq_write16(struct adapter *adapter, u32 addr, u16 val); ++void ioreq_write32(struct adapter *adapter, u32 addr, u32 val); ++ ++uint async_read8(struct adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(struct adapter *padater, ++ struct io_req *pio_req, ++ u8 *cnxt), u8 *cnxt); ++uint async_read16(struct adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(struct adapter *padater, ++ struct io_req *pio_req, ++ u8 *cnxt), u8 *cnxt); ++uint async_read32(struct adapter *adapter, u32 addr, u8 *pbuff, ++ void (*_async_io_callback)(struct adapter *padater, ++ struct io_req *pio_req, ++ u8 *cnxt), u8 *cnxt); ++ ++void async_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++void async_read_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++void async_write8(struct adapter *adapter, u32 addr, u8 val, ++ void (*_async_io_callback)(struct adapter *padater, ++ struct io_req *pio_req, ++ u8 *cnxt), u8 *cnxt); ++void async_write16(struct adapter *adapter, u32 addr, u16 val, ++ void (*_async_io_callback)(struct adapter *padater, ++ struct io_req *pio_req, ++ u8 *cnxt), u8 *cnxt); ++void async_write32(struct adapter *adapter, u32 addr, u32 val, ++ void (*_async_io_callback)(struct adapter *padater, ++ struct io_req *pio_req, ++ u8 *cnxt), u8 *cnxt); ++ ++void async_write_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++void async_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); ++ ++int rtw_init_io_priv(struct adapter *padapter, ++ void (*set_intf_ops)(struct _io_ops *pops)); ++ ++uint alloc_io_queue(struct adapter *adapter); ++void free_io_queue(struct adapter *adapter); ++void async_bus_io(struct io_queue *pio_q); ++void bus_sync_io(struct io_queue *pio_q); ++u32 _ioreq2rwmem(struct io_queue *pio_q); ++void dev_power_down(struct adapter * Adapter, u8 bpwrup); ++ ++#define PlatformEFIOWrite1Byte(_a,_b,_c) \ ++ rtw_write8(_a,_b,_c) ++#define PlatformEFIOWrite2Byte(_a,_b,_c) \ ++ rtw_write16(_a,_b,_c) ++#define PlatformEFIOWrite4Byte(_a,_b,_c) \ ++ rtw_write32(_a,_b,_c) ++ ++#define PlatformEFIORead1Byte(_a,_b) \ ++ rtw_read8(_a,_b) ++#define PlatformEFIORead2Byte(_a,_b) \ ++ rtw_read16(_a,_b) ++#define PlatformEFIORead4Byte(_a,_b) \ ++ rtw_read32(_a,_b) ++ ++#endif /* _RTL8711_IO_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_ioctl.h b/drivers/staging/r8188eu/include/rtw_ioctl.h +new file mode 100644 +index 000000000000..a36bd7313755 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_ioctl.h +@@ -0,0 +1,92 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_IOCTL_H_ ++#define _RTW_IOCTL_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#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 */ ++ int (*oidfuns)(struct oid_par_priv *poid_par_priv); ++}; ++ ++extern struct iw_handler_def rtw_handlers_def; ++ ++int drv_query_info(struct net_device *miniportadaptercontext, NDIS_OID oid, ++ void *informationbuffer, u32 informationbufferlength, ++ u32 *byteswritten, u32 *bytesneeded); ++ ++int drv_set_info(struct net_device *MiniportAdapterContext, ++ NDIS_OID oid, void *informationbuffer, ++ u32 informationbufferlength, u32 *bytesread, ++ u32 *bytesneeded); ++ ++extern int ui_pid[3]; ++ ++#endif /* #ifndef __INC_CEINFO_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_ioctl_rtl.h b/drivers/staging/r8188eu/include/rtw_ioctl_rtl.h +new file mode 100644 +index 000000000000..6d3d1ef923f6 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_ioctl_rtl.h +@@ -0,0 +1,63 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_IOCTL_RTL_H_ ++#define _RTW_IOCTL_RTL_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++/* oid_rtl_seg_01_01 ************** */ ++int oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv);/* 84 */ ++int oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv); ++ ++int oid_rt_pro_set_fw_dig_state_hdl(struct oid_par_priv *poid_par_priv);/* 8a */ ++int oid_rt_pro_set_fw_ra_state_hdl(struct oid_par_priv *poid_par_priv); /* 8b */ ++ ++int oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv);/* 93 */ ++int oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_set_channelplan_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_set_preamble_mode_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_dedicate_probe_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_current_tx_power_level_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_supported_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* oid_rtl_seg_01_03 section start ************** */ ++int oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv *priv); ++int oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* oid_rtl_seg_01_11 */ ++int oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* oid_rtl_seg_03_00 section start ************** */ ++int oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv); ++int oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtw_ioctl_set.h b/drivers/staging/r8188eu/include/rtw_ioctl_set.h +new file mode 100644 +index 000000000000..6216b8ab3a79 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_ioctl_set.h +@@ -0,0 +1,33 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_IOCTL_SET_H_ ++#define __RTW_IOCTL_SET_H_ ++ ++#include "drv_types.h" ++ ++typedef u8 NDIS_802_11_PMKID_VALUE[16]; ++ ++u8 rtw_set_802_11_add_key(struct adapter *adapt, struct ndis_802_11_key *key); ++u8 rtw_set_802_11_authentication_mode(struct adapter *adapt, ++ enum ndis_802_11_auth_mode authmode); ++u8 rtw_set_802_11_bssid(struct adapter*adapter, u8 *bssid); ++u8 rtw_set_802_11_add_wep(struct adapter *adapter, struct ndis_802_11_wep *wep); ++u8 rtw_set_802_11_disassociate(struct adapter *adapter); ++u8 rtw_set_802_11_bssid_list_scan(struct adapter*adapter, ++ struct ndis_802_11_ssid *pssid, ++ int ssid_max_num); ++u8 rtw_set_802_11_infrastructure_mode(struct adapter *adapter, ++ enum ndis_802_11_network_infra type); ++u8 rtw_set_802_11_remove_wep(struct adapter *adapter, u32 keyindex); ++u8 rtw_set_802_11_ssid(struct adapter *adapt, struct ndis_802_11_ssid *ssid); ++u8 rtw_set_802_11_remove_key(struct adapter *adapt, ++ struct ndis_802_11_remove_key *key); ++u8 rtw_validate_ssid(struct ndis_802_11_ssid *ssid); ++u16 rtw_get_cur_max_rate(struct adapter *adapter); ++int rtw_set_scan_mode(struct adapter *adapter, enum rt_scan_type scan_mode); ++int rtw_set_channel_plan(struct adapter *adapter, u8 channel_plan); ++int rtw_set_country(struct adapter *adapter, const char *country_code); ++int rtw_change_ifname(struct adapter *padapter, const char *ifname); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtw_iol.h b/drivers/staging/r8188eu/include/rtw_iol.h +new file mode 100644 +index 000000000000..471f9ca092a8 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_iol.h +@@ -0,0 +1,68 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_IOL_H_ ++#define __RTW_IOL_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#define IOREG_CMD_END_LEN 4 ++ ++struct ioreg_cfg { ++ u8 length; ++ u8 cmd_id; ++ __le16 address; ++ __le32 data; ++ __le32 mask; ++}; ++ ++enum ioreg_cmd { ++ IOREG_CMD_LLT = 0x01, ++ IOREG_CMD_REFUSE = 0x02, ++ IOREG_CMD_EFUSE_PATH = 0x03, ++ IOREG_CMD_WB_REG = 0x04, ++ IOREG_CMD_WW_REG = 0x05, ++ IOREG_CMD_WD_REG = 0x06, ++ IOREG_CMD_W_RF = 0x07, ++ IOREG_CMD_DELAY_US = 0x10, ++ IOREG_CMD_DELAY_MS = 0x11, ++ IOREG_CMD_END = 0xFF, ++}; ++ ++struct xmit_frame *rtw_IOL_accquire_xmit_frame(struct adapter *adapter); ++int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, ++ u32 cmd_len); ++int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary); ++int rtw_IOL_exec_cmds_sync(struct adapter *adapter, ++ struct xmit_frame *xmit_frame, u32 max_wating_ms, ++ u32 bndy_cnt); ++bool rtw_IOL_applied(struct adapter *adapter); ++int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us); ++int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms); ++int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame); ++ ++void read_efuse_from_txpktbuf(struct adapter *adapter, int bcnhead, ++ u8 *content, u16 *size); ++ ++int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, ++ u8 value, u8 mask); ++int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, ++ u16 value, u16 mask); ++int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, ++ u32 value, u32 mask); ++int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, ++ u16 addr, u32 value, u32 mask); ++#define rtw_IOL_append_WB_cmd(xmit_frame, addr, value, mask) \ ++ _rtw_IOL_append_WB_cmd((xmit_frame), (addr), (value) ,(mask)) ++#define rtw_IOL_append_WW_cmd(xmit_frame, addr, value, mask) \ ++ _rtw_IOL_append_WW_cmd((xmit_frame), (addr), (value),(mask)) ++#define rtw_IOL_append_WD_cmd(xmit_frame, addr, value, mask) \ ++ _rtw_IOL_append_WD_cmd((xmit_frame), (addr), (value), (mask)) ++#define rtw_IOL_append_WRF_cmd(xmit_frame, rf_path, addr, value, mask) \ ++ _rtw_IOL_append_WRF_cmd((xmit_frame),(rf_path), (addr), (value), (mask)) ++ ++u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame); ++void rtw_IOL_cmd_buf_dump(struct adapter *Adapter,int buf_len,u8 *pbuf); ++ ++#endif /* __RTW_IOL_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_led.h b/drivers/staging/r8188eu/include/rtw_led.h +new file mode 100644 +index 000000000000..f0965aa5b470 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_led.h +@@ -0,0 +1,181 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_LED_H_ ++#define __RTW_LED_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#define MSECS(t) (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000) ++ ++#define LED_BLINK_NORMAL_INTERVAL 100 ++#define LED_BLINK_SLOWLY_INTERVAL 200 ++#define LED_BLINK_LONG_INTERVAL 400 ++ ++#define LED_BLINK_NO_LINK_INTERVAL_ALPHA 1000 ++#define LED_BLINK_LINK_INTERVAL_ALPHA 500 /* 500 */ ++#define LED_BLINK_SCAN_INTERVAL_ALPHA 180 /* 150 */ ++#define LED_BLINK_FASTER_INTERVAL_ALPHA 50 ++#define LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA 5000 ++ ++#define LED_BLINK_NORMAL_INTERVAL_NETTRONIX 100 ++#define LED_BLINK_SLOWLY_INTERVAL_NETTRONIX 2000 ++ ++#define LED_BLINK_SLOWLY_INTERVAL_PORNET 1000 ++#define LED_BLINK_NORMAL_INTERVAL_PORNET 100 ++ ++#define LED_BLINK_FAST_INTERVAL_BITLAND 30 ++ ++/* 060403, rcnjko: Customized for AzWave. */ ++#define LED_CM2_BLINK_ON_INTERVAL 250 ++#define LED_CM2_BLINK_OFF_INTERVAL 4750 ++ ++#define LED_CM8_BLINK_INTERVAL 500 /* for QMI */ ++#define LED_CM8_BLINK_OFF_INTERVAL 3750 /* for QMI */ ++ ++/* 080124, lanhsin: Customized for RunTop */ ++#define LED_RunTop_BLINK_INTERVAL 300 ++ ++/* 060421, rcnjko: Customized for Sercomm Printer Server case. */ ++#define LED_CM3_BLINK_INTERVAL 1500 ++ ++enum LED_CTL_MODE { ++ LED_CTL_POWER_ON = 1, ++ LED_CTL_LINK = 2, ++ LED_CTL_NO_LINK = 3, ++ LED_CTL_TX = 4, ++ LED_CTL_RX = 5, ++ LED_CTL_SITE_SURVEY = 6, ++ LED_CTL_POWER_OFF = 7, ++ LED_CTL_START_TO_LINK = 8, ++ LED_CTL_START_WPS = 9, ++ LED_CTL_STOP_WPS = 10, ++ LED_CTL_START_WPS_BOTTON = 11, /* added for runtop */ ++ LED_CTL_STOP_WPS_FAIL = 12, /* added for ALPHA */ ++ LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, /* added for BELKIN */ ++ LED_CTL_CONNECTION_NO_TRANSFER = 14, ++}; ++ ++enum LED_STATE_871x { ++ LED_UNKNOWN = 0, ++ RTW_LED_ON = 1, ++ RTW_LED_OFF = 2, ++ LED_BLINK_NORMAL = 3, ++ LED_BLINK_SLOWLY = 4, ++ LED_BLINK_POWER_ON = 5, ++ LED_BLINK_SCAN = 6, /* LED is blinking during scanning period, ++ * the # of times to blink is depend on time ++ * for scanning. */ ++ LED_BLINK_NO_LINK = 7, /* LED is blinking during no link state. */ ++ LED_BLINK_StartToBlink = 8,/* Customzied for Sercomm Printer ++ * Server case */ ++ LED_BLINK_TXRX = 9, ++ LED_BLINK_WPS = 10, /* LED is blinkg during WPS communication */ ++ LED_BLINK_WPS_STOP = 11, /* for ALPHA */ ++ LED_BLINK_WPS_STOP_OVERLAP = 12, /* for BELKIN */ ++ LED_BLINK_RUNTOP = 13, /* Customized for RunTop */ ++ LED_BLINK_CAMEO = 14, ++ LED_BLINK_XAVI = 15, ++ LED_BLINK_ALWAYS_ON = 16, ++}; ++ ++enum LED_PIN_871x { ++ LED_PIN_NULL = 0, ++ LED_PIN_LED0 = 1, ++ LED_PIN_LED1 = 2, ++ LED_PIN_LED2 = 3, ++ LED_PIN_GPIO0 = 4, ++}; ++ ++struct LED_871x { ++ struct adapter *padapter; ++ ++ enum LED_PIN_871x LedPin; /* Identify how to implement this ++ * SW led. */ ++ enum LED_STATE_871x CurrLedState; /* Current LED state. */ ++ enum LED_STATE_871x BlinkingLedState; /* Next state for blinking, ++ * either RTW_LED_ON or RTW_LED_OFF are. */ ++ ++ u8 bLedOn; /* true if LED is ON, false if LED is OFF. */ ++ ++ u8 bLedBlinkInProgress; /* true if it is blinking, false o.w.. */ ++ ++ u8 bLedWPSBlinkInProgress; ++ ++ u32 BlinkTimes; /* Number of times to toggle led state for blinking. */ ++ ++ struct timer_list BlinkTimer; /* Timer object for led blinking. */ ++ ++ u8 bSWLedCtrl; ++ ++ /* ALPHA, added by chiyoko, 20090106 */ ++ u8 bLedNoLinkBlinkInProgress; ++ u8 bLedLinkBlinkInProgress; ++ u8 bLedStartToLinkBlinkInProgress; ++ u8 bLedScanBlinkInProgress; ++ struct work_struct BlinkWorkItem; /* Workitem used by BlinkTimer to ++ * manipulate H/W to blink LED. */ ++}; ++ ++#define IS_LED_WPS_BLINKING(_LED_871x) \ ++ (((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS || \ ++ ((struct LED_871x *)_LED_871x)->CurrLedState == LED_BLINK_WPS_STOP || \ ++ ((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress) ++ ++#define IS_LED_BLINKING(_LED_871x) \ ++ (((struct LED_871x *)_LED_871x)->bLedWPSBlinkInProgress || \ ++ ((struct LED_871x *)_LED_871x)->bLedScanBlinkInProgress) ++ ++/* LED customization. */ ++ ++enum LED_STRATEGY_871x { ++ SW_LED_MODE0 = 0, /* SW control 1 LED via GPIO0. It is default option.*/ ++ SW_LED_MODE1= 1, /* 2 LEDs, through LED0 and LED1. For ALPHA. */ ++ SW_LED_MODE2 = 2, /* SW control 1 LED via GPIO0, customized for AzWave ++ * 8187 minicard. */ ++ SW_LED_MODE3 = 3, /* SW control 1 LED via GPIO0, customized for Sercomm ++ * Printer Server case. */ ++ SW_LED_MODE4 = 4, /* for Edimax / Belkin */ ++ SW_LED_MODE5 = 5, /* for Sercomm / Belkin */ ++ SW_LED_MODE6 = 6, /* for 88CU minicard, porting from ce SW_LED_MODE7 */ ++ HW_LED = 50, /* HW control 2 LEDs, LED0 and LED1 (there are 4 ++ * different control modes, see MAC.CONFIG1 for details.)*/ ++ LED_ST_NONE = 99, ++}; ++ ++void LedControl8188eu(struct adapter *padapter, enum LED_CTL_MODE LedAction); ++ ++struct led_priv{ ++ /* add for led control */ ++ struct LED_871x SwLed0; ++ struct LED_871x SwLed1; ++ enum LED_STRATEGY_871x LedStrategy; ++ u8 bRegUseLed; ++ void (*LedControlHandler)(struct adapter *padapter, ++ enum LED_CTL_MODE LedAction); ++ /* add for led control */ ++}; ++ ++#define rtw_led_control(adapt, action) \ ++ do { \ ++ if ((adapt)->ledpriv.LedControlHandler) \ ++ (adapt)->ledpriv.LedControlHandler((adapt), (action)); \ ++ } while (0) ++ ++void BlinkTimerCallback(struct timer_list *t); ++void BlinkWorkItemCallback(struct work_struct *work); ++ ++void ResetLedStatus(struct LED_871x * pLed); ++ ++void InitLed871x(struct adapter *padapter, struct LED_871x *pLed, ++ enum LED_PIN_871x LedPin); ++ ++void DeInitLed871x(struct LED_871x *pLed); ++ ++/* hal... */ ++void BlinkHandler(struct LED_871x * pLed); ++void SwLedOn(struct adapter *padapter, struct LED_871x *pLed); ++void SwLedOff(struct adapter *padapter, struct LED_871x *pLed); ++ ++#endif /* __RTW_LED_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_mlme.h b/drivers/staging/r8188eu/include/rtw_mlme.h +new file mode 100644 +index 000000000000..bbb41471472d +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_mlme.h +@@ -0,0 +1,632 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_MLME_H_ ++#define __RTW_MLME_H_ ++ ++#include "osdep_service.h" ++#include "mlme_osdep.h" ++#include "drv_types.h" ++#include "wlan_bssdef.h" ++ ++#define MAX_BSS_CNT 128 ++#define MAX_JOIN_TIMEOUT 6500 ++ ++/* Increase the scanning timeout because of increasing the SURVEY_TO value. */ ++ ++#define SCANNING_TIMEOUT 8000 ++ ++#define SCAN_INTERVAL (30) /* unit:2sec, 30*2=60sec */ ++ ++#define SCANQUEUE_LIFETIME 20 /* unit:sec */ ++ ++#define WIFI_NULL_STATE 0x00000000 ++ ++#define WIFI_ASOC_STATE 0x00000001 /* Under Linked state */ ++#define WIFI_REASOC_STATE 0x00000002 ++#define WIFI_SLEEP_STATE 0x00000004 ++#define WIFI_STATION_STATE 0x00000008 ++ ++#define WIFI_AP_STATE 0x00000010 ++#define WIFI_ADHOC_STATE 0x00000020 ++#define WIFI_ADHOC_MASTER_STATE 0x00000040 ++#define WIFI_UNDER_LINKING 0x00000080 ++ ++#define WIFI_UNDER_WPS 0x00000100 ++#define WIFI_STA_ALIVE_CHK_STATE 0x00000400 ++#define WIFI_SITE_MONITOR 0x00000800 /* to indicate the station is under site surveying */ ++ ++#define WIFI_MP_STATE 0x00010000 ++#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continuous tx background */ ++#define WIFI_MP_CTX_ST 0x00040000 /* in continuous tx with single-tone */ ++#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continuous tx background due to out of skb */ ++#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continuous tx */ ++#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in continuous tx with carrier suppression */ ++#define WIFI_MP_LPBK_STATE 0x00400000 ++ ++#define _FW_UNDER_LINKING WIFI_UNDER_LINKING ++#define _FW_LINKED WIFI_ASOC_STATE ++#define _FW_UNDER_SURVEY WIFI_SITE_MONITOR ++ ++enum dot11AuthAlgrthmNum { ++ dot11AuthAlgrthm_Open = 0, ++ dot11AuthAlgrthm_Shared, ++ dot11AuthAlgrthm_8021X, ++ dot11AuthAlgrthm_Auto, ++ dot11AuthAlgrthm_WAPI, ++ dot11AuthAlgrthm_MaxNum ++}; ++ ++/* Scan type including active and passive scan. */ ++enum rt_scan_type { ++ SCAN_PASSIVE, ++ SCAN_ACTIVE, ++ SCAN_MIX, ++}; ++ ++enum SCAN_RESULT_TYPE { ++ SCAN_RESULT_P2P_ONLY = 0, /* Will return all the P2P devices. */ ++ SCAN_RESULT_ALL = 1, /* Will return all the scanned device, ++ * include AP. */ ++ SCAN_RESULT_WFD_TYPE = 2 /* Will just return the correct WFD ++ * device. */ ++ /* If this device is Miracast sink ++ * device, it will just return all the ++ * Miracast source devices. */ ++}; ++ ++/* ++there are several "locks" in mlme_priv, ++since mlme_priv is a shared resource between many threads, ++like ISR/Call-Back functions, the OID handlers, and even timer functions. ++ ++Each _queue has its own locks, already. ++Other items are protected by mlme_priv.lock. ++ ++To avoid possible dead lock, any thread trying to modifiying mlme_priv ++SHALL not lock up more than one lock at a time! ++*/ ++ ++#define traffic_threshold 10 ++#define traffic_scan_period 500 ++ ++struct sitesurvey_ctrl { ++ u64 last_tx_pkts; ++ uint last_rx_pkts; ++ int traffic_busy; ++ struct timer_list sitesurvey_ctrl_timer; ++}; ++ ++struct rt_link_detect { ++ u32 NumTxOkInPeriod; ++ u32 NumRxOkInPeriod; ++ u32 NumRxUnicastOkInPeriod; ++ bool bBusyTraffic; ++ bool bTxBusyTraffic; ++ bool bRxBusyTraffic; ++ bool bHigherBusyTraffic; /* For interrupt migration purpose. */ ++ bool bHigherBusyRxTraffic; /* We may disable Tx interrupt according ++ * to Rx traffic. */ ++ bool bHigherBusyTxTraffic; /* We may disable Tx interrupt according ++ * to Tx traffic. */ ++}; ++ ++struct profile_info { ++ u8 ssidlen; ++ u8 ssid[ WLAN_SSID_MAXLEN ]; ++ u8 peermac[ ETH_ALEN ]; ++}; ++ ++struct tx_invite_req_info { ++ u8 token; ++ u8 benable; ++ u8 go_ssid[ WLAN_SSID_MAXLEN ]; ++ u8 ssidlen; ++ u8 go_bssid[ ETH_ALEN ]; ++ u8 peer_macaddr[ ETH_ALEN ]; ++ u8 operating_ch; /* This information will be set by using the ++ * p2p_set op_ch=x */ ++ u8 peer_ch; /* The listen channel for peer P2P device */ ++}; ++ ++struct tx_invite_resp_info { ++ u8 token; /* Used to record the dialog token of p2p invitation ++ * request frame. */ ++}; ++ ++struct tx_provdisc_req_info { ++ u16 wps_config_method_request; /* Used when sending the ++ * provisioning request frame*/ ++ u16 peer_channel_num[2]; /* The channel number which the ++ * receiver stands. */ ++ struct ndis_802_11_ssid ssid; ++ u8 peerDevAddr[ETH_ALEN]; /* Peer device address */ ++ u8 peerIFAddr[ETH_ALEN]; /* Peer interface address */ ++ u8 benable; /* This provision discovery ++ * request frame is trigger ++ * to send or not */ ++}; ++ ++/* When peer device issue prov_disc_req first, we should store the following ++ * information */ ++/* The UI must know this information to know which config method the ++ * remote p2p device needs. */ ++struct rx_provdisc_req_info { ++ u8 peerDevAddr[ETH_ALEN]; /* Peer device address */ ++ u8 strconfig_method_desc_of_prov_disc_req[4]; /* description ++ * for the config method located in the provisioning ++ * discovery request frame. */ ++}; ++ ++struct tx_nego_req_info { ++ u16 peer_channel_num[2]; /* The channel number. */ ++ u8 peerDevAddr[ETH_ALEN]; /* Peer device address */ ++ u8 benable; /* This negotiation request frame is ++ * trigger to send or not */ ++}; ++ ++struct group_id_info { ++ u8 go_device_addr[ ETH_ALEN ]; /* The GO's device address of ++ * this P2P group */ ++ u8 ssid[ WLAN_SSID_MAXLEN ]; /* The SSID of this P2P group */ ++}; ++ ++struct scan_limit_info { ++ u8 scan_op_ch_only; /* When this flag is set, the driver ++ * should only scan the op. channel */ ++ u8 operation_ch[2]; /* Store the op. chan of invitation */ ++}; ++ ++struct wifidirect_info { ++ struct adapter *padapter; ++ struct timer_list find_phase_timer; ++ struct timer_list restore_p2p_state_timer; ++ ++ /* Used to do the scanning. After confirming the peer is availalble, ++ * the driver transmits the P2P frame to peer. */ ++ struct timer_list pre_tx_scan_timer; ++ struct timer_list reset_ch_sitesurvey; ++ struct timer_list reset_ch_sitesurvey2; /* Just for resetting the scan ++ * limit function by using p2p nego */ ++ struct tx_provdisc_req_info tx_prov_disc_info; ++ struct rx_provdisc_req_info rx_prov_disc_info; ++ struct tx_invite_req_info invitereq_info; ++ /* Store the profile information of persistent group */ ++ struct profile_info profileinfo[P2P_MAX_PERSISTENT_GROUP_NUM]; ++ struct tx_invite_resp_info inviteresp_info; ++ struct tx_nego_req_info nego_req_info; ++ /* Store the group id info when doing the group negot handshake. */ ++ struct group_id_info groupid_info; ++ /* Used for get the limit scan channel from the Invitation procedure */ ++ struct scan_limit_info rx_invitereq_info; ++ /* Used for get the limit scan chan from the P2P negotiation handshake*/ ++ struct scan_limit_info p2p_info; ++ enum P2P_ROLE role; ++ enum P2P_STATE pre_p2p_state; ++ enum P2P_STATE p2p_state; ++ /* The device address should be the mac address of this device. */ ++ u8 device_addr[ETH_ALEN]; ++ u8 interface_addr[ETH_ALEN]; ++ u8 social_chan[4]; ++ u8 listen_channel; ++ u8 operating_channel; ++ u8 listen_dwell; /* This value should be between 1 and 3 */ ++ u8 support_rate[8]; ++ u8 p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN]; ++ u8 intent; /* should only include the intent value. */ ++ u8 p2p_peer_interface_addr[ETH_ALEN]; ++ u8 p2p_peer_device_addr[ETH_ALEN]; ++ u8 peer_intent; /* Included the intent value and tie breaker value. */ ++ /* Device name for displaying on searching device screen */ ++ u8 device_name[WPS_MAX_DEVICE_NAME_LEN]; ++ u8 device_name_len; ++ u8 profileindex; /* Used to point to the index of profileinfo array */ ++ u8 peer_operating_ch; ++ u8 find_phase_state_exchange_cnt; ++ /* The device password ID for group negotiation */ ++ u16 device_password_id_for_nego; ++ u8 negotiation_dialog_token; ++ /* SSID information for group negotitation */ ++ u8 nego_ssid[WLAN_SSID_MAXLEN]; ++ u8 nego_ssidlen; ++ u8 p2p_group_ssid[WLAN_SSID_MAXLEN]; ++ u8 p2p_group_ssid_len; ++ /* Flag to know if the persistent function should be supported or not.*/ ++ u8 persistent_supported; ++ /* In the Sigma test, the Sigma will provide this enable from the ++ * sta_set_p2p CAPI. */ ++ /* 0: disable */ ++ /* 1: enable */ ++ u8 session_available; /* Flag to set the WFD session available to ++ * enable or disable "by Sigma" */ ++ /* In the Sigma test, the Sigma will disable the session available ++ * by using the sta_preset CAPI. */ ++ /* 0: disable */ ++ /* 1: enable */ ++ u8 wfd_tdls_enable; /* Flag to enable or disable the TDLS by WFD Sigma*/ ++ /* 0: disable */ ++ /* 1: enable */ ++ u8 wfd_tdls_weaksec; /* Flag to enable or disable the weak security ++ * function for TDLS by WFD Sigma */ ++ /* 0: disable */ ++ /* In this case, the driver can't issue the tdsl ++ * setup request frame. */ ++ /* 1: enable */ ++ /* In this case, the driver can issue the tdls ++ * setup request frame */ ++ /* even the current security is weak security. */ ++ ++ /* This field will store the WPS value (PIN value or PBC) that UI had ++ * got from the user. */ ++ enum P2P_WPSINFO ui_got_wps_info; ++ u16 supported_wps_cm; /* This field describes the WPS config method ++ * which this driver supported. */ ++ /* The value should be the combination of config ++ * method defined in page104 of WPS v2.0 spec.*/ ++ /* This field will contain the length of body of P2P Channel List ++ * attribute of group negotiation response frame. */ ++ uint channel_list_attr_len; ++ /* This field will contain the body of P2P Channel List attribute of ++ * group negotitation response frame. */ ++ /* We will use the channel_cnt and channel_list fields when constructing ++ * the group negotiation confirm frame. */ ++ u8 channel_list_attr[100]; ++ enum P2P_PS_MODE p2p_ps_mode; /* indicate p2p ps mode */ ++ enum P2P_PS_STATE p2p_ps_state; /* indicate p2p ps state */ ++ u8 noa_index; /* Identifies and instance of Notice of Absence timing. */ ++ u8 ctwindow; /* Client traffic window. A period of time in TU after TBTT. */ ++ u8 opp_ps; /* opportunistic power save. */ ++ u8 noa_num; /* number of NoA descriptor in P2P IE. */ ++ u8 noa_count[P2P_MAX_NOA_NUM]; /* Count for owner, Type of client. */ ++ /* Max duration for owner, preferred or min acceptable duration for ++ * client. */ ++ u32 noa_duration[P2P_MAX_NOA_NUM]; ++ /* Length of interval for owner, preferred or max acceptable interval ++ * of client. */ ++ u32 noa_interval[P2P_MAX_NOA_NUM]; ++ /* schedule expressed in terms of the lower 4 bytes of the TSF timer. */ ++ u32 noa_start_time[P2P_MAX_NOA_NUM]; ++}; ++ ++struct tdls_ss_record { /* signal strength record */ ++ u8 macaddr[ETH_ALEN]; ++ u8 RxPWDBAll; ++ u8 is_tdls_sta; /* true: direct link sta, false: else */ ++}; ++ ++struct tdls_info { ++ u8 ap_prohibited; ++ uint setup_state; ++ u8 sta_cnt; ++ u8 sta_maximum; /* 1:tdls sta is equal (NUM_STA-1), reach max direct link number; 0: else; */ ++ struct tdls_ss_record ss_record; ++ u8 macid_index; /* macid entry that is ready to write */ ++ u8 clear_cam; /* cam entry that is trying to clear, using it in direct link teardown */ ++ u8 ch_sensing; ++ u8 cur_channel; ++ u8 candidate_ch; ++ u8 collect_pkt_num[MAX_CHANNEL_NUM]; ++ spinlock_t cmd_lock; ++ spinlock_t hdl_lock; ++ u8 watchdog_count; ++ u8 dev_discovered; /* WFD_TDLS: for sigma test */ ++ u8 enable; ++}; ++ ++struct qos_priv { ++ /* bit mask option: u-apsd, ++ * s-apsd, ts, block ack... */ ++ unsigned int qos_option; ++}; ++ ++struct mlme_priv { ++ spinlock_t lock; ++ int fw_state; /* shall we protect this variable? maybe not necessarily... */ ++ u8 bScanInProcess; ++ u8 to_join; /* flag */ ++ u8 to_roaming; /* roaming trying times */ ++ ++ u8 *nic_hdl; ++ ++ u8 not_indic_disco; ++ struct list_head *pscanned; ++ struct __queue free_bss_pool; ++ struct __queue scanned_queue; ++ u8 *free_bss_buf; ++ u8 key_mask; /* use to restore wep key after hal_init */ ++ u32 num_of_scanned; ++ ++ struct ndis_802_11_ssid assoc_ssid; ++ u8 assoc_bssid[6]; ++ ++ struct wlan_network cur_network; ++ struct wlan_network *cur_network_scanned; ++ ++ u32 scan_interval; ++ ++ struct timer_list assoc_timer; ++ ++ uint assoc_by_bssid; ++ uint assoc_by_rssi; ++ ++ struct timer_list scan_to_timer; /* driver itself handles scan_timeout status. */ ++ u32 scan_start_time; /* used to evaluate the time spent in scanning */ ++ ++ struct qos_priv qospriv; ++ ++ /* Number of non-HT AP/stations */ ++ int num_sta_no_ht; ++ ++ /* Number of HT AP/stations 20 MHz */ ++ /* int num_sta_ht_20mhz; */ ++ ++ int num_FortyMHzIntolerant; ++ struct ht_priv htpriv; ++ struct rt_link_detect LinkDetectInfo; ++ struct timer_list dynamic_chk_timer; /* dynamic/periodic check timer */ ++ ++ u8 acm_mask; /* for wmm acm mask */ ++ u8 ChannelPlan; ++ enum rt_scan_type scan_mode; /* active: 1, passive: 0 */ ++ ++ /* u8 probereq_wpsie[MAX_WPS_IE_LEN];added in probe req */ ++ /* int probereq_wpsie_len; */ ++ u8 *wps_probe_req_ie; ++ u32 wps_probe_req_ie_len; ++ ++ u8 *assoc_req; ++ u32 assoc_req_len; ++ u8 *assoc_rsp; ++ u32 assoc_rsp_len; ++ ++#if defined (CONFIG_88EU_AP_MODE) ++ /* Number of associated Non-ERP stations (i.e., stations using 802.11b ++ * in 802.11g BSS) */ ++ int num_sta_non_erp; ++ ++ /* Number of associated stations that do not support Short Slot Time */ ++ int num_sta_no_short_slot_time; ++ ++ /* Number of associated stations that do not support Short Preamble */ ++ int num_sta_no_short_preamble; ++ ++ int olbc; /* Overlapping Legacy BSS Condition */ ++ ++ /* Number of HT assoc sta that do not support greenfield */ ++ int num_sta_ht_no_gf; ++ ++ /* Number of associated non-HT stations */ ++ /* int num_sta_no_ht; */ ++ ++ /* Number of HT associated stations 20 MHz */ ++ int num_sta_ht_20mhz; ++ ++ /* Overlapping BSS information */ ++ int olbc_ht; ++ ++ u16 ht_op_mode; ++ ++ u8 *wps_beacon_ie; ++ /* u8 *wps_probe_req_ie; */ ++ u8 *wps_probe_resp_ie; ++ u8 *wps_assoc_resp_ie; ++ ++ u32 wps_beacon_ie_len; ++ u32 wps_probe_resp_ie_len; ++ u32 wps_assoc_resp_ie_len; ++ ++ u8 *p2p_beacon_ie; ++ u8 *p2p_probe_req_ie; ++ u8 *p2p_probe_resp_ie; ++ u8 *p2p_go_probe_resp_ie; /* for GO */ ++ u8 *p2p_assoc_req_ie; ++ ++ u32 p2p_beacon_ie_len; ++ u32 p2p_probe_req_ie_len; ++ u32 p2p_probe_resp_ie_len; ++ u32 p2p_go_probe_resp_ie_len; /* for GO */ ++ u32 p2p_assoc_req_ie_len; ++ spinlock_t bcn_update_lock; ++ u8 update_bcn; ++#endif /* if defined (CONFIG_88EU_AP_MODE) */ ++}; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++struct hostapd_priv { ++ struct adapter *padapter; ++}; ++ ++int hostapd_mode_init(struct adapter *padapter); ++void hostapd_mode_unload(struct adapter *padapter); ++#endif ++ ++extern unsigned char WPA_TKIP_CIPHER[4]; ++extern unsigned char RSN_TKIP_CIPHER[4]; ++extern unsigned char REALTEK_96B_IE[]; ++extern unsigned char MCS_rate_2R[16]; ++extern unsigned char MCS_rate_1R[16]; ++ ++void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf); ++void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf); ++void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf); ++void rtw_joinbss_event_callback(struct adapter *adapter, u8 *pbuf); ++void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf); ++void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf); ++void indicate_wx_scan_complete_event(struct adapter *padapter); ++void rtw_indicate_wx_assoc_event(struct adapter *padapter); ++void rtw_indicate_wx_disassoc_event(struct adapter *padapter); ++int event_thread(void *context); ++void rtw_join_timeout_handler (struct timer_list *t); ++void _rtw_scan_timeout_handler (struct timer_list *t); ++void rtw_free_network_queue(struct adapter *adapter, u8 isfreeall); ++int rtw_init_mlme_priv(struct adapter *adapter); ++void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv); ++int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv); ++int rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, ++ int keyid, u8 set_tx); ++int rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv); ++ ++static inline u8 *get_bssid(struct mlme_priv *pmlmepriv) ++{ /* if sta_mode:pmlmepriv->cur_network.network.MacAddress=> bssid */ ++ /* if adhoc_mode:pmlmepriv->cur_network.network.MacAddress=> ibss mac address */ ++ return pmlmepriv->cur_network.network.MacAddress; ++} ++ ++static inline int check_fwstate(struct mlme_priv *pmlmepriv, int state) ++{ ++ if (pmlmepriv->fw_state & state) ++ return true; ++ ++ return false; ++} ++ ++static inline int get_fwstate(struct mlme_priv *pmlmepriv) ++{ ++ return pmlmepriv->fw_state; ++} ++ ++/* ++ * No Limit on the calling context, ++ * therefore set it to be the critical section... ++ * ++ * ### NOTE:#### (!!!!) ++ * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock ++ */ ++static inline void set_fwstate(struct mlme_priv *pmlmepriv, int state) ++{ ++ pmlmepriv->fw_state |= state; ++ /* FOR HW integration */ ++ if (_FW_UNDER_SURVEY==state) ++ pmlmepriv->bScanInProcess = true; ++} ++ ++static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, int state) ++{ ++ pmlmepriv->fw_state &= ~state; ++ /* FOR HW integration */ ++ if (_FW_UNDER_SURVEY==state) ++ pmlmepriv->bScanInProcess = false; ++} ++ ++/* ++ * No Limit on the calling context, ++ * therefore set it to be the critical section... ++ */ ++static inline void clr_fwstate(struct mlme_priv *pmlmepriv, int state) ++{ ++ spin_lock_bh(&pmlmepriv->lock); ++ if (check_fwstate(pmlmepriv, state)) ++ pmlmepriv->fw_state ^= state; ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++static inline void clr_fwstate_ex(struct mlme_priv *pmlmepriv, int state) ++{ ++ spin_lock_bh(&pmlmepriv->lock); ++ _clr_fwstate_(pmlmepriv, state); ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++static inline void up_scanned_network(struct mlme_priv *pmlmepriv) ++{ ++ spin_lock_bh(&pmlmepriv->lock); ++ pmlmepriv->num_of_scanned++; ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++static inline void down_scanned_network(struct mlme_priv *pmlmepriv) ++{ ++ spin_lock_bh(&pmlmepriv->lock); ++ pmlmepriv->num_of_scanned--; ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, int val) ++{ ++ spin_lock_bh(&pmlmepriv->lock); ++ pmlmepriv->num_of_scanned = val; ++ spin_unlock_bh(&pmlmepriv->lock); ++} ++ ++u16 rtw_get_capability(struct wlan_bssid_ex *bss); ++void rtw_update_scanned_network(struct adapter *adapter, ++ struct wlan_bssid_ex *target); ++void rtw_disconnect_hdl_under_linked(struct adapter *adapter, ++ struct sta_info *psta, u8 free_assoc); ++void rtw_generate_random_ibss(u8 *pibss); ++struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr); ++struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue); ++ ++void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue); ++void rtw_indicate_disconnect(struct adapter *adapter); ++void rtw_indicate_connect(struct adapter *adapter); ++void rtw_indicate_scan_done( struct adapter *padapter, bool aborted); ++void rtw_scan_abort(struct adapter *adapter); ++ ++int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, ++ uint in_len); ++int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, ++ uint in_len, uint initial_out_len); ++void rtw_init_registrypriv_dev_network(struct adapter *adapter); ++ ++void rtw_update_registrypriv_dev_network(struct adapter *adapter); ++ ++void rtw_get_encrypt_decrypt_from_registrypriv(struct adapter *adapter); ++ ++void _rtw_join_timeout_handler(struct adapter *adapter); ++void rtw_scan_timeout_handler(struct adapter *adapter); ++ ++ void rtw_dynamic_check_timer_handlder(struct adapter *adapter); ++#define rtw_is_scan_deny(adapter) false ++#define rtw_clear_scan_deny(adapter) do {} while (0) ++#define rtw_set_scan_deny_timer_hdl(adapter) do {} while (0) ++#define rtw_set_scan_deny(adapter, ms) do {} while (0) ++ ++int _rtw_init_mlme_priv(struct adapter *padapter); ++ ++void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv); ++ ++void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv); ++ ++int _rtw_enqueue_network(struct __queue *queue, struct wlan_network *pnetwork); ++ ++struct wlan_network *_rtw_dequeue_network(struct __queue *queue); ++ ++ struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv); ++ ++void _rtw_free_network(struct mlme_priv *pmlmepriv, ++ struct wlan_network *pnetwork, u8 isfreeall); ++void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, ++ struct wlan_network *pnetwork); ++ ++struct wlan_network* _rtw_find_network(struct __queue *scanned_queue, u8 *addr); ++ ++void _rtw_free_network_queue(struct adapter *padapter, u8 isfreeall); ++ ++int rtw_if_up(struct adapter *padapter); ++ ++u8 *rtw_get_capability_from_ie(u8 *ie); ++u8 *rtw_get_timestampe_from_ie(u8 *ie); ++u8 *rtw_get_beacon_interval_from_ie(u8 *ie); ++ ++void rtw_joinbss_reset(struct adapter *padapter); ++ ++unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, ++ u8 *out_ie, uint in_len, uint *pout_len); ++void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len); ++void rtw_issue_addbareq_cmd(struct adapter *padapter, ++ struct xmit_frame *pxmitframe); ++ ++int rtw_is_same_ibss(struct adapter *adapter, struct wlan_network *pnetwork); ++int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst); ++ ++void rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network); ++void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network); ++void rtw_set_roaming(struct adapter *adapter, u8 to_roaming); ++u8 rtw_to_roaming(struct adapter *adapter); ++ ++void rtw_sta_media_status_rpt(struct adapter *adapter, struct sta_info *psta, ++ u32 mstatus); ++ ++#endif /* __RTL871X_MLME_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h +new file mode 100644 +index 000000000000..d2f4d3ce7b90 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h +@@ -0,0 +1,857 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_MLME_EXT_H_ ++#define __RTW_MLME_EXT_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "wlan_bssdef.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) ++ ++#define ROAMING_LIMIT 8 ++ ++#define DYNAMIC_FUNC_DISABLE (0x0) ++ ++/* ====== ODM_ABILITY_E ======== */ ++/* BB ODM section BIT 0-15 */ ++#define DYNAMIC_BB_DIG BIT(0) ++#define DYNAMIC_BB_RA_MASK BIT(1) ++#define DYNAMIC_BB_DYNAMIC_TXPWR BIT(2) ++#define DYNAMIC_BB_BB_FA_CNT BIT(3) ++ ++#define DYNAMIC_BB_RSSI_MONITOR BIT(4) ++#define DYNAMIC_BB_CCK_PD BIT(5) ++#define DYNAMIC_BB_ANT_DIV BIT(6) ++#define DYNAMIC_BB_PWR_SAVE BIT(7) ++#define DYNAMIC_BB_PWR_TRA BIT(8) ++#define DYNAMIC_BB_RATE_ADAPTIVE BIT(9) ++#define DYNAMIC_BB_PATH_DIV BIT(10) ++#define DYNAMIC_BB_PSD BIT(11) ++ ++/* MAC DM section BIT 16-23 */ ++#define DYNAMIC_MAC_EDCA_TURBO BIT(16) ++#define DYNAMIC_MAC_EARLY_MODE BIT(17) ++ ++/* RF ODM section BIT 24-31 */ ++#define DYNAMIC_RF_TX_PWR_TRACK BIT(24) ++#define DYNAMIC_RF_RX_GAIN_TRACK BIT(25) ++#define DYNAMIC_RF_CALIBRATION BIT(26) ++ ++#define DYNAMIC_ALL_FUNC_ENABLE 0xFFFFFFF ++ ++#define _HW_STATE_NOLINK_ 0x00 ++#define _HW_STATE_ADHOC_ 0x01 ++#define _HW_STATE_STATION_ 0x02 ++#define _HW_STATE_AP_ 0x03 ++ ++#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 ++ ++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[]; ++ ++/* Channel Plan Type. */ ++/* Note: */ ++/* We just add new channel plan when the new channel plan is different ++ * from any of the following channel plan. */ ++/* If you just want to customize the actions(scan period or join actions) ++ * about one of the channel plan, */ ++/* customize them in struct rt_channel_info in the RT_CHANNEL_LIST. */ ++enum RT_CHANNEL_DOMAIN { ++ /* old channel plan mapping ===== */ ++ RT_CHANNEL_DOMAIN_FCC = 0x00, ++ RT_CHANNEL_DOMAIN_IC = 0x01, ++ RT_CHANNEL_DOMAIN_ETSI = 0x02, ++ RT_CHANNEL_DOMAIN_SPAIN = 0x03, ++ RT_CHANNEL_DOMAIN_FRANCE = 0x04, ++ RT_CHANNEL_DOMAIN_MKK = 0x05, ++ RT_CHANNEL_DOMAIN_MKK1 = 0x06, ++ RT_CHANNEL_DOMAIN_ISRAEL = 0x07, ++ RT_CHANNEL_DOMAIN_TELEC = 0x08, ++ RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 0x09, ++ RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 0x0A, ++ RT_CHANNEL_DOMAIN_TAIWAN = 0x0B, ++ RT_CHANNEL_DOMAIN_CHINA = 0x0C, ++ RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO = 0x0D, ++ RT_CHANNEL_DOMAIN_KOREA = 0x0E, ++ RT_CHANNEL_DOMAIN_TURKEY = 0x0F, ++ RT_CHANNEL_DOMAIN_JAPAN = 0x10, ++ RT_CHANNEL_DOMAIN_FCC_NO_DFS = 0x11, ++ RT_CHANNEL_DOMAIN_JAPAN_NO_DFS = 0x12, ++ RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS = 0x14, ++ ++ /* new channel plan mapping, (2GDOMAIN_5GDOMAIN) ===== */ ++ RT_CHANNEL_DOMAIN_WORLD_NULL = 0x20, ++ RT_CHANNEL_DOMAIN_ETSI1_NULL = 0x21, ++ RT_CHANNEL_DOMAIN_FCC1_NULL = 0x22, ++ RT_CHANNEL_DOMAIN_MKK1_NULL = 0x23, ++ RT_CHANNEL_DOMAIN_ETSI2_NULL = 0x24, ++ RT_CHANNEL_DOMAIN_FCC1_FCC1 = 0x25, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI1 = 0x26, ++ RT_CHANNEL_DOMAIN_MKK1_MKK1 = 0x27, ++ RT_CHANNEL_DOMAIN_WORLD_KCC1 = 0x28, ++ RT_CHANNEL_DOMAIN_WORLD_FCC2 = 0x29, ++ RT_CHANNEL_DOMAIN_WORLD_FCC3 = 0x30, ++ RT_CHANNEL_DOMAIN_WORLD_FCC4 = 0x31, ++ RT_CHANNEL_DOMAIN_WORLD_FCC5 = 0x32, ++ RT_CHANNEL_DOMAIN_WORLD_FCC6 = 0x33, ++ RT_CHANNEL_DOMAIN_FCC1_FCC7 = 0x34, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI2 = 0x35, ++ RT_CHANNEL_DOMAIN_WORLD_ETSI3 = 0x36, ++ RT_CHANNEL_DOMAIN_MKK1_MKK2 = 0x37, ++ RT_CHANNEL_DOMAIN_MKK1_MKK3 = 0x38, ++ RT_CHANNEL_DOMAIN_FCC1_NCC1 = 0x39, ++ RT_CHANNEL_DOMAIN_FCC1_NCC2 = 0x40, ++ RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G = 0x41, ++ /* Add new channel plan above this line=============== */ ++ RT_CHANNEL_DOMAIN_MAX, ++ RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F, ++}; ++ ++enum RT_CHANNEL_DOMAIN_2G { ++ RT_CHANNEL_DOMAIN_2G_WORLD = 0x00, /* Worldwide 13 */ ++ RT_CHANNEL_DOMAIN_2G_ETSI1 = 0x01, /* Europe */ ++ RT_CHANNEL_DOMAIN_2G_FCC1 = 0x02, /* US */ ++ RT_CHANNEL_DOMAIN_2G_MKK1 = 0x03, /* Japan */ ++ RT_CHANNEL_DOMAIN_2G_ETSI2 = 0x04, /* France */ ++ RT_CHANNEL_DOMAIN_2G_NULL = 0x05, ++ /* Add new channel plan above this line=============== */ ++ RT_CHANNEL_DOMAIN_2G_MAX, ++}; ++ ++#define rtw_is_channel_plan_valid(chplan) \ ++ (chplan < RT_CHANNEL_DOMAIN_MAX || \ ++ chplan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE) ++ ++struct rt_channel_plan { ++ unsigned char Channel[MAX_CHANNEL_NUM]; ++ unsigned char Len; ++}; ++ ++struct rt_channel_plan_2g { ++ unsigned char Channel[MAX_CHANNEL_NUM_2G]; ++ unsigned char Len; ++}; ++ ++struct rt_channel_plan_map { ++ unsigned char Index2G; ++}; ++ ++enum Associated_AP { ++ atherosAP = 0, ++ broadcomAP = 1, ++ ciscoAP = 2, ++ marvellAP = 3, ++ ralinkAP = 4, ++ realtekAP = 5, ++ airgocapAP = 6, ++ unknownAP = 7, ++ maxAP, ++}; ++ ++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 */ ++ 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_TENDA = 16, ++ HT_IOT_PEER_MAX = 17 ++}; ++ ++enum SCAN_STATE { ++ SCAN_DISABLE = 0, ++ SCAN_START = 1, ++ SCAN_TXNULL = 2, ++ SCAN_PROCESS = 3, ++ SCAN_COMPLETE = 4, ++ SCAN_STATE_MAX, ++}; ++ ++struct mlme_handler { ++ unsigned int num; ++ char *str; ++ unsigned int (*func)(struct adapter *adapt, struct recv_frame *frame); ++}; ++ ++struct action_handler { ++ unsigned int num; ++ char* str; ++ unsigned int (*func)(struct adapter *adapt, struct recv_frame *frame); ++}; ++ ++struct ss_res { ++ int state; ++ int bss_cnt; ++ int channel_idx; ++ int scan_mode; ++ u8 ssid_num; ++ u8 ch_num; ++ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; ++ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; ++}; ++ ++/* 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_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) ++ ++struct FW_Sta_Info { ++ struct sta_info *psta; ++ u32 status; ++ u32 rx_pkt; ++ u32 retry; ++ unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX]; ++}; ++ ++/* ++ * 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_STAY_AP_CH_MILLISECOND * SURVEY_TO milliseconds. ++ * Example: ++ * For chip supports 2.4G + 5GHz and AP mode is operating in channel 1, ++ * RTW_SCAN_NUM_OF_CH is 8, RTW_STAY_AP_CH_MS is 3 and SURVEY_TO is 100. ++ * 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. ++ */ ++ ++struct mlme_ext_info { ++ u32 state; ++ u32 reauth_count; ++ u32 reassoc_count; ++ u32 link_count; ++ u32 auth_seq; ++ u32 auth_algo; /* 802.11 auth, could be open, shared, auto */ ++ u32 authModeToggle; ++ u32 enc_algo;/* encrypt algorithm; */ ++ u32 key_index; /* this is only valid for legacy 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 */ ++ bool bAcceptAddbaReq; ++ u8 bwmode_updated; ++ u8 hidden_ssid_mode; ++ ++ struct ADDBA_request ADDBA_req; ++ struct WMM_para_element WMM_param; ++ struct HT_caps_element HT_caps; ++ struct HT_info_element HT_info; ++ struct wlan_bssid_ex network;/* join network or bss_network, ++ * if in ap mode, it is the same ++ * as cur_network.network */ ++ struct FW_Sta_Info FW_sta_info[NUM_STA]; ++}; ++ ++/* The channel information about this channel including joining, ++ * scanning, and power constraints. */ ++struct rt_channel_info { ++ u8 ChannelNum; /* The channel number. */ ++ enum rt_scan_type ScanType; /* Scan type such as passive ++ * or active scan. */ ++ u32 rx_count; ++}; ++ ++int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, 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 chan 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} mode; ++ u8 op_class; ++ u8 min_chan; ++ u8 max_chan; ++ u8 inc; ++ enum {BW20, BW40PLUS, BW40MINUS} bw; ++}; ++ ++struct mlme_ext_priv { ++ struct adapter *padapter; ++ u8 mlmeext_init; ++ atomic_t event_seq; ++ u16 mgnt_seq; ++ ++ 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 oper_channel; /* saved chan info when call ++ * set_channel_bw */ ++ unsigned char oper_bwmode; ++ unsigned char oper_ch_offset;/* PRIME_CHNL_OFFSET */ ++ ++ unsigned char max_chan_nums; ++ struct rt_channel_info channel_set[MAX_CHANNEL_NUM]; ++ struct p2p_channels channel_list; ++ unsigned char basicrate[NumRates]; ++ unsigned char datarate[NumRates]; ++ ++ struct ss_res sitesurvey_res; ++ struct mlme_ext_info mlmext_info;/* for sta/adhoc mode, including ++ * current scan/connecting/connected ++ * related info. For ap mode, ++ * network includes ap's cap_info*/ ++ struct timer_list survey_timer; ++ struct timer_list link_timer; ++ u16 chan_scan_time; ++ ++ u8 scan_abort; ++ u8 tx_rate; /* TXRATE when USERATE is set. */ ++ ++ u32 retry; /* retry for issue probereq */ ++ ++ u64 TSFValue; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ unsigned char bstart_bss; ++#endif ++ u8 update_channel_plan_by_ap_done; ++ /* recv_decache check for Action_public frame */ ++ u8 action_public_dialog_token; ++ u16 action_public_rxseq; ++ u8 active_keep_alive_check; ++}; ++ ++int init_mlme_ext_priv(struct adapter *adapter); ++int init_hw_mlme_ext(struct adapter *padapter); ++void free_mlme_ext_priv (struct mlme_ext_priv *pmlmeext); ++extern void init_mlme_ext_timer(struct adapter *padapter); ++extern void init_addba_retry_timer(struct adapter *adapt, struct sta_info *sta); ++extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv); ++ ++unsigned char networktype_to_raid(unsigned char network_type); ++u8 judge_network_type(struct adapter *padapter, unsigned char *rate, int len); ++void get_rate_set(struct adapter *padapter, unsigned char *pbssrate, int *len); ++void UpdateBrateTbl(struct adapter *padapter, u8 *mBratesOS); ++void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen); ++ ++void Save_DM_Func_Flag(struct adapter *padapter); ++void Restore_DM_Func_Flag(struct adapter *padapter); ++void Switch_DM_Func(struct adapter *padapter, u32 mode, u8 enable); ++ ++void Set_MSR(struct adapter *padapter, u8 type); ++ ++u8 rtw_get_oper_ch(struct adapter *adapter); ++void rtw_set_oper_ch(struct adapter *adapter, u8 ch); ++u8 rtw_get_oper_bw(struct adapter *adapter); ++void rtw_set_oper_bw(struct adapter *adapter, u8 bw); ++u8 rtw_get_oper_choffset(struct adapter *adapter); ++void rtw_set_oper_choffset(struct adapter *adapter, u8 offset); ++ ++void set_channel_bwmode(struct adapter *padapter, unsigned char channel, ++ unsigned char channel_offset, unsigned short bwmode); ++void SelectChannel(struct adapter *padapter, unsigned char channel); ++void SetBWMode(struct adapter *padapter, unsigned short bwmode, ++ unsigned char channel_offset); ++ ++unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval); ++ ++void write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key); ++void clear_cam_entry(struct adapter *padapter, u8 entry); ++ ++void invalidate_cam_all(struct adapter *padapter); ++void CAM_empty_entry(struct adapter * Adapter, u8 ucIndex); ++ ++int allocate_fw_sta_entry(struct adapter *padapter); ++void flush_all_cam_entry(struct adapter *padapter); ++ ++void site_survey(struct adapter *padapter); ++u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame, ++ struct wlan_bssid_ex *bssid); ++void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, ++ struct adapter *adapter, bool update_ie); ++ ++int get_bsstype(unsigned short capability); ++u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork); ++u16 get_beacon_interval(struct wlan_bssid_ex *bss); ++ ++int is_client_associated_to_ap(struct adapter *padapter); ++int is_client_associated_to_ibss(struct adapter *padapter); ++int is_IBSS_empty(struct adapter *padapter); ++ ++unsigned char check_assoc_AP(u8 *pframe, uint len); ++ ++int WMM_param_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE); ++void WMMOnAssocRsp(struct adapter *padapter); ++ ++void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE); ++void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE); ++void HTOnAssocRsp(struct adapter *padapter); ++ ++void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE); ++void VCS_update(struct adapter *padapter, struct sta_info *psta); ++ ++void update_beacon_info(struct adapter *padapter, u8 *pframe, uint len, ++ struct sta_info *psta); ++int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len); ++void update_IOT_info(struct adapter *padapter); ++void update_capinfo(struct adapter *adapter, u16 updatecap); ++void update_wireless_mode(struct adapter *padapter); ++void update_tx_basic_rate(struct adapter *padapter, u8 modulation); ++void update_bmc_sta_support_rate(struct adapter *padapter, u32 mac_id); ++int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, ++ uint var_ie_len, int cam_idx); ++ ++/* for sta/adhoc mode */ ++void update_sta_info(struct 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); ++unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps); ++void Update_RA_Entry(struct adapter *padapter, u32 mac_id); ++void set_sta_rate(struct adapter *padapter, struct sta_info *psta); ++ ++unsigned int receive_disconnect(struct adapter *padapter, ++ unsigned char *macaddr, unsigned short reason); ++ ++unsigned char get_highest_rate_idx(u32 mask); ++int support_short_GI(struct adapter *padapter, struct HT_caps_element *caps); ++unsigned int is_ap_in_tkip(struct adapter *padapter); ++unsigned int is_ap_in_wep(struct adapter *padapter); ++unsigned int should_forbid_n_rate(struct adapter *padapter); ++ ++void report_join_res(struct adapter *padapter, int res); ++void report_survey_event(struct adapter *padapter, struct recv_frame *precv_frame); ++void report_surveydone_event(struct adapter *padapter); ++void report_del_sta_event(struct adapter *padapter, ++ unsigned char *addr, unsigned short reason); ++void report_add_sta_event(struct adapter *padapter, unsigned char* addr, ++ int cam_idx); ++ ++void beacon_timing_control(struct adapter *padapter); ++extern u8 set_tx_beacon_cmd(struct adapter*padapter); ++unsigned int setup_beacon_frame(struct adapter *padapter, ++ unsigned char *beacon_frame); ++void update_mgnt_tx_rate(struct adapter *padapter, u8 rate); ++void update_mgntframe_attrib(struct adapter *padapter, ++ struct pkt_attrib *pattrib); ++void dump_mgntframe(struct adapter *padapter, struct xmit_frame *pmgntframe); ++s32 dump_mgntframe_and_wait(struct adapter *padapter, ++ struct xmit_frame *pmgntframe, int timeout_ms); ++s32 dump_mgntframe_and_wait_ack(struct adapter *padapter, ++ struct xmit_frame *pmgntframe); ++ ++#ifdef CONFIG_88EU_P2P ++void issue_probersp_p2p(struct adapter *padapter, unsigned char *da); ++void issue_p2p_provision_request(struct adapter *padapter, u8 *pssid, ++ u8 ussidlen, u8 *pdev_raddr); ++void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr); ++void issue_probereq_p2p(struct adapter *padapter, u8 *da); ++int issue_probereq_p2p_ex(struct adapter *adapter, u8 *da, int try_cnt, ++ int wait_ms); ++void issue_p2p_invitation_response(struct adapter *padapter, u8 *raddr, ++ u8 dialogToken, u8 success); ++void issue_p2p_invitation_request(struct adapter *padapter, u8* raddr); ++#endif /* CONFIG_88EU_P2P */ ++void issue_beacon(struct adapter *padapter, int timeout_ms); ++void issue_probersp(struct adapter *padapter, unsigned char *da, ++ u8 is_valid_p2p_probereq); ++void issue_assocreq(struct adapter *padapter); ++void issue_asocrsp(struct adapter *padapter, unsigned short status, ++ struct sta_info *pstat, int pkt_type); ++void issue_auth(struct adapter *padapter, struct sta_info *psta, ++ unsigned short status); ++void issue_probereq(struct adapter *padapter, struct ndis_802_11_ssid *pssid, ++ u8 *da); ++s32 issue_probereq_ex(struct adapter *adapter, struct ndis_802_11_ssid *pssid, ++ u8* da, int try_cnt, int wait_ms); ++int issue_nulldata(struct adapter *padapter, unsigned char *da, ++ unsigned int power_mode, int try_cnt, int wait_ms); ++int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, ++ u16 tid, int try_cnt, int wait_ms); ++int issue_deauth(struct adapter *padapter, unsigned char *da, ++ unsigned short reason); ++int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, ++ int try_cnt, int wait_ms); ++void issue_action_spct_ch_switch(struct adapter *padapter, u8 *ra, u8 new_ch, ++ u8 ch_offset); ++void issue_action_BA(struct adapter *padapter, unsigned char *raddr, ++ unsigned char action, unsigned short status); ++unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr); ++unsigned int send_beacon(struct adapter *padapter); ++ ++void start_clnt_assoc(struct adapter *padapter); ++void start_clnt_auth(struct adapter *padapter); ++void start_clnt_join(struct adapter *padapter); ++void start_create_ibss(struct adapter *padapter); ++ ++unsigned int OnAssocReq(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAssocRsp(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnProbeReq(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnProbeRsp(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int DoReserved(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnBeacon(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAtim(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnDisassoc(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAuth(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAuthClient(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnDeAuth(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAction(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++ ++unsigned int on_action_spct(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAction_qos(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAction_dls(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAction_back(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int on_action_public(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAction_ht(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAction_wmm(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++unsigned int OnAction_p2p(struct adapter *padapter, ++ struct recv_frame *precv_frame); ++ ++void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res); ++void mlmeext_sta_del_event_callback(struct adapter *padapter); ++void mlmeext_sta_add_event_callback(struct adapter *padapter, ++ struct sta_info *psta); ++ ++void linked_status_chk(struct adapter *padapter); ++ ++void survey_timer_hdl (struct adapter *padapter); ++void link_timer_hdl (struct adapter *padapter); ++void addba_timer_hdl(struct sta_info *psta); ++ ++#define set_survey_timer(mlmeext, ms) \ ++ do { \ ++ _set_timer(&(mlmeext)->survey_timer, (ms)); \ ++ } while (0) ++ ++#define set_link_timer(mlmeext, ms) \ ++ do { \ ++ _set_timer(&(mlmeext)->link_timer, (ms)); \ ++ } while (0) ++ ++int cckrates_included(unsigned char *rate, int ratelen); ++int cckratesonly_included(unsigned char *rate, int ratelen); ++ ++void process_addba_req(struct adapter *padapter, u8 *paddba_req, u8 *addr); ++ ++void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); ++void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext); ++ ++struct cmd_hdl { ++ uint parmsize; ++ u8 (*h2cfuns)(struct adapter *padapter, u8 *pbuf); ++}; ++ ++u8 read_macreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 write_macreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 read_bbreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 write_bbreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 read_rfreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 write_rfreg_hdl(struct adapter *padapter, u8 *pbuf); ++u8 NULL_hdl(struct adapter *padapter, u8 *pbuf); ++u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf); ++u8 disconnect_hdl(struct adapter *padapter, u8 *pbuf); ++u8 createbss_hdl(struct adapter *padapter, u8 *pbuf); ++u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf); ++u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf); ++u8 setauth_hdl(struct adapter *padapter, u8 *pbuf); ++u8 setkey_hdl(struct adapter *padapter, u8 *pbuf); ++u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf); ++u8 set_assocsta_hdl(struct adapter *padapter, u8 *pbuf); ++u8 del_assocsta_hdl(struct adapter *padapter, u8 *pbuf); ++u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf); ++ ++u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 h2c_msg_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 tx_beacon_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 set_ch_hdl(struct adapter *padapter, u8 *pbuf); ++u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 led_blink_hdl(struct adapter *padapter, unsigned char *pbuf); ++/* Handling DFS channel switch announcement ie. */ ++u8 set_csa_hdl(struct adapter *padapter, unsigned char *pbuf); ++u8 tdls_hdl(struct adapter *padapter, unsigned char *pbuf); ++ ++#define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl}, ++#define GEN_MLME_EXT_HANDLER(size, cmd) {size, cmd}, ++ ++#ifdef _RTW_CMD_C_ ++ ++static struct cmd_hdl wlancmds[] = { ++ GEN_DRV_CMD_HANDLER(0, NULL) /*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(sizeof (struct setphyinfo_parm), NULL) ++ GEN_MLME_EXT_HANDLER(sizeof (struct getphyinfo_parm), 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), set_ch_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(sizeof(struct SetChannelSwitch_param), ++ set_csa_hdl) /*61*/ ++ GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), ++ tdls_hdl) /*62*/ ++}; ++ ++#endif ++ ++struct C2HEvent_Header { ++#ifdef __LITTLE_ENDIAN ++ unsigned int len:16; ++ unsigned int ID:8; ++ unsigned int seq:8; ++#elif defined(__BIG_ENDIAN) ++ unsigned int seq:8; ++ unsigned int ID:8; ++ unsigned int len:16; ++#endif ++ unsigned int rsvd; ++}; ++ ++void rtw_dummy_event_callback(struct adapter *adapter, u8 *pbuf); ++void rtw_fwdbg_event_callback(struct 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 */ ++ 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, NULL}, ++ {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, NULL}, ++ {0, NULL}, ++}; ++ ++#endif/* _RTL_MLME_EXT_C_ */ ++ ++#endif /* __RTW_MLME_EXT_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_mp.h b/drivers/staging/r8188eu/include/rtw_mp.h +new file mode 100644 +index 000000000000..3a259d991348 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_mp.h +@@ -0,0 +1,474 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_MP_H_ ++#define _RTW_MP_H_ ++ ++/* 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 ((int)STATUS_SUCCESS) ++#define NDIS_STATUS_PENDING ((int)STATUS_PENDING) ++#define NDIS_STATUS_NOT_RECOGNIZED ((int)0x00010001L) ++#define NDIS_STATUS_NOT_COPIED ((int)0x00010002L) ++#define NDIS_STATUS_NOT_ACCEPTED ((int)0x00010003L) ++#define NDIS_STATUS_CALL_ACTIVE ((int)0x00010007L) ++ ++#define NDIS_STATUS_FAILURE ((int)STATUS_UNSUCCESSFUL) ++#define NDIS_STATUS_RESOURCES ((int)STATUS_INSUFFICIENT_RESOURCES) ++#define NDIS_STATUS_CLOSING ((int)0xC0010002L) ++#define NDIS_STATUS_BAD_VERSION ((int)0xC0010004L) ++#define NDIS_STATUS_BAD_CHARACTERISTICS ((int)0xC0010005L) ++#define NDIS_STATUS_ADAPTER_NOT_FOUND ((int)0xC0010006L) ++#define NDIS_STATUS_OPEN_FAILED ((int)0xC0010007L) ++#define NDIS_STATUS_DEVICE_FAILED ((int)0xC0010008L) ++#define NDIS_STATUS_MULTICAST_FULL ((int)0xC0010009L) ++#define NDIS_STATUS_MULTICAST_EXISTS ((int)0xC001000AL) ++#define NDIS_STATUS_MULTICAST_NOT_FOUND ((int)0xC001000BL) ++#define NDIS_STATUS_REQUEST_ABORTED ((int)0xC001000CL) ++#define NDIS_STATUS_RESET_IN_PROGRESS ((int)0xC001000DL) ++#define NDIS_STATUS_CLOSING_INDICATING ((int)0xC001000EL) ++#define NDIS_STATUS_NOT_SUPPORTED ((int)STATUS_NOT_SUPPORTED) ++#define NDIS_STATUS_INVALID_PACKET ((int)0xC001000FL) ++#define NDIS_STATUS_OPEN_LIST_FULL ((int)0xC0010010L) ++#define NDIS_STATUS_ADAPTER_NOT_READY ((int)0xC0010011L) ++#define NDIS_STATUS_ADAPTER_NOT_OPEN ((int)0xC0010012L) ++#define NDIS_STATUS_NOT_INDICATING ((int)0xC0010013L) ++#define NDIS_STATUS_INVALID_LENGTH ((int)0xC0010014L) ++#define NDIS_STATUS_INVALID_DATA ((int)0xC0010015L) ++#define NDIS_STATUS_BUFFER_TOO_SHORT ((int)0xC0010016L) ++#define NDIS_STATUS_INVALID_OID ((int)0xC0010017L) ++#define NDIS_STATUS_ADAPTER_REMOVED ((int)0xC0010018L) ++#define NDIS_STATUS_UNSUPPORTED_MEDIA ((int)0xC0010019L) ++#define NDIS_STATUS_GROUP_ADDRESS_IN_USE ((int)0xC001001AL) ++#define NDIS_STATUS_FILE_NOT_FOUND ((int)0xC001001BL) ++#define NDIS_STATUS_ERROR_READING_FILE ((int)0xC001001CL) ++#define NDIS_STATUS_ALREADY_MAPPED ((int)0xC001001DL) ++#define NDIS_STATUS_RESOURCE_CONFLICT ((int)0xC001001EL) ++#define NDIS_STATUS_NO_CABLE ((int)0xC001001FL) ++ ++#define NDIS_STATUS_INVALID_SAP ((int)0xC0010020L) ++#define NDIS_STATUS_SAP_IN_USE ((int)0xC0010021L) ++#define NDIS_STATUS_INVALID_ADDRESS ((int)0xC0010022L) ++#define NDIS_STATUS_VC_NOT_ACTIVATED ((int)0xC0010023L) ++#define NDIS_STATUS_DEST_OUT_OF_ORDER ((int)0xC0010024L) /*cause 27*/ ++#define NDIS_STATUS_VC_NOT_AVAILABLE ((int)0xC0010025L) /*cause 35,45 */ ++#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE ((int)0xC0010026L) /*cause 37*/ ++#define NDIS_STATUS_INCOMPATABLE_QOS ((int)0xC0010027L) /*cause 49*/ ++#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED ((int)0xC0010028L) /*cause 93*/ ++#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION ((int)0xC0010029L) /*cause 3 */ ++ ++enum antenna_path { ++ ANTENNA_NONE = 0x00, ++ ANTENNA_D, ++ ANTENNA_C, ++ ANTENNA_CD, ++ ANTENNA_B, ++ ANTENNA_BD, ++ ANTENNA_BC, ++ ANTENNA_BCD, ++ ANTENNA_A, ++ ANTENNA_AD, ++ ANTENNA_AC, ++ ANTENNA_ACD, ++ ANTENNA_AB, ++ ANTENNA_ABD, ++ ANTENNA_ABC, ++ ANTENNA_ABCD ++}; ++ ++#define MAX_MP_XMITBUF_SZ 2048 ++#define NR_MP_XMITFRAME 8 ++ ++struct mp_xmit_frame { ++ struct list_head list; ++ struct pkt_attrib attrib; ++ struct sk_buff *pkt; ++ int frame_tag; ++ struct adapter *padapter; ++ struct urb *pxmit_urb[8]; ++ /* insert urb, irp, and irpcnt info below... */ ++ u8 *mem_addr; ++ u32 sz[8]; ++ u8 bpending[8]; ++ int ac_tag[8]; ++ int last[8]; ++ uint irpcnt; ++ uint fragcnt; ++ uint mem[(MAX_MP_XMITBUF_SZ >> 2)]; ++}; ++ ++struct mp_wiparam { ++ u32 bcompleted; ++ u32 act_type; ++ u32 io_offset; ++ u32 io_value; ++}; ++ ++typedef void(*wi_act_func)(void *padapter); ++ ++struct mp_tx { ++ u8 stop; ++ u32 count, sended; ++ u8 payload; ++ struct pkt_attrib attrib; ++ struct tx_desc desc; ++ u8 *pallocated_buf; ++ u8 *buf; ++ u32 buf_size, write_size; ++ void *PktTxThread; ++}; ++ ++#include "Hal8188EPhyCfg.h" ++ ++#define MP_MAX_LINES 1000 ++#define MP_MAX_LINES_BYTES 256 ++ ++typedef void (*MPT_WORK_ITEM_HANDLER)(void *Adapter); ++ ++struct mpt_context { ++ /* Indicate if we have started Mass Production Test. */ ++ bool bMassProdTest; ++ ++ /* Indicate if the driver is unloading or unloaded. */ ++ bool bMptDrvUnload; ++ ++ struct semaphore MPh2c_Sema; ++ struct timer_list MPh2c_timeout_timer; ++/* Event used to sync H2c for BT control */ ++ ++ bool MptH2cRspEvent; ++ bool MptBtC2hEvent; ++ bool bMPh2c_timeout; ++ ++ /* 8190 PCI does not support NDIS_WORK_ITEM. */ ++ /* Work Item for Mass Production Test. */ ++ /* Event used to sync the case unloading driver and MptWorkItem ++ * is still in progress. */ ++ /* Indicate a MptWorkItem is scheduled and not yet finished. */ ++ bool bMptWorkItemInProgress; ++ /* An instance which implements function and context of MptWorkItem. */ ++ MPT_WORK_ITEM_HANDLER CurrMptAct; ++ ++ /* 1=Start, 0=Stop from UI. */ ++ u32 MptTestStart; ++ /* _TEST_MODE, defined in MPT_Req2.h */ ++ u32 MptTestItem; ++ /* Variable needed in each implementation of CurrMptAct. */ ++ u32 MptActType; /* Type of action performed in CurrMptAct. */ ++ /* The Offset of IO operation is depend of MptActType. */ ++ u32 MptIoOffset; ++ /* The Value of IO operation is depend of MptActType. */ ++ u32 MptIoValue; ++ /* The RfPath of IO operation is depend of MptActType. */ ++ u32 MptRfPath; ++ ++ enum wireless_mode MptWirelessModeToSw; /* Wireless mode to switch. */ ++ u8 MptChannelToSw; /* Channel to switch. */ ++ u8 MptInitGainToSet; /* Initial gain to set. */ ++ u32 MptBandWidth; /* bandwidth to switch. */ ++ u32 MptRateIndex; /* rate index. */ ++ /* Register value kept for Single Carrier Tx test. */ ++ u8 btMpCckTxPower; ++ /* Register value kept for Single Carrier Tx test. */ ++ u8 btMpOfdmTxPower; ++ /* For MP Tx Power index */ ++ u8 TxPwrLevel[2]; /* rf-A, rf-B */ ++ ++ /* Content of RCR Regsiter for Mass Production Test. */ ++ u32 MptRCR; ++ /* true if we only receive packets with specific pattern. */ ++ bool bMptFilterPattern; ++ /* Rx OK count, statistics used in Mass Production Test. */ ++ u32 MptRxOkCnt; ++ /* Rx CRC32 error count, statistics used in Mass Production Test. */ ++ u32 MptRxCrcErrCnt; ++ ++ bool bCckContTx; /* true if we are in CCK Continuous Tx test. */ ++ bool bOfdmContTx; /* true if we are in OFDM Continuous Tx test. */ ++ bool bStartContTx; /* true if we have start Continuous Tx test. */ ++ /* true if we are in Single Carrier Tx test. */ ++ bool bSingleCarrier; ++ /* true if we are in Carrier Suppression Tx Test. */ ++ bool bCarrierSuppression; ++ /* true if we are in Single Tone Tx test. */ ++ bool bSingleTone; ++ ++ /* ACK counter asked by K.Y.. */ ++ bool bMptEnableAckCounter; ++ u32 MptAckCounter; ++ ++ u8 APK_bound[2]; /* for APK path A/path B */ ++ bool bMptIndexEven; ++ ++ u8 backup0xc50; ++ u8 backup0xc58; ++ u8 backup0xc30; ++ u8 backup0x52_RF_A; ++ u8 backup0x52_RF_B; ++ ++ u8 h2cReqNum; ++ u8 c2hBuf[20]; ++ ++ u8 btInBuf[100]; ++ u32 mptOutLen; ++ u8 mptOutBuf[100]; ++}; ++ ++enum { ++ WRITE_REG = 1, ++ READ_REG, ++ WRITE_RF, ++ READ_RF, ++ MP_START, ++ MP_STOP, ++ MP_RATE, ++ MP_CHANNEL, ++ MP_BANDWIDTH, ++ MP_TXPOWER, ++ MP_ANT_TX, ++ MP_ANT_RX, ++ MP_CTX, ++ MP_QUERY, ++ MP_ARX, ++ MP_PSD, ++ MP_PWRTRK, ++ MP_THER, ++ MP_IOCTL, ++ EFUSE_GET, ++ EFUSE_SET, ++ MP_RESET_STATS, ++ MP_DUMP, ++ MP_PHYPARA, ++ MP_SetRFPathSwh, ++ MP_QueryDrvStats, ++ MP_SetBT, ++ CTA_TEST, ++ MP_NULL, ++}; ++ ++struct mp_priv { ++ struct adapter *papdater; ++ ++ /* Testing Flag */ ++ /* 0 for normal type packet, 1 for loopback packet (16bytes TXCMD) */ ++ u32 mode; ++ ++ u32 prev_fw_state; ++ ++ /* OID cmd handler */ ++ struct mp_wiparam workparam; ++ ++ /* Tx Section */ ++ u8 TID; ++ u32 tx_pktcount; ++ struct mp_tx tx; ++ ++ /* Rx Section */ ++ u32 rx_pktcount; ++ u32 rx_crcerrpktcount; ++ u32 rx_pktloss; ++ ++ struct recv_stat rxstat; ++ ++ /* RF/BB relative */ ++ u8 channel; ++ u8 bandwidth; ++ u8 prime_channel_offset; ++ u8 txpoweridx; ++ u8 txpoweridx_b; ++ u8 rateidx; ++ u32 preamble; ++ u32 CrystalCap; ++ ++ u16 antenna_tx; ++ u16 antenna_rx; ++ ++ u8 check_mp_pkt; ++ ++ u8 bSetTxPower; ++ ++ struct wlan_network mp_network; ++ unsigned char network_macaddr[ETH_ALEN]; ++ ++ u8 *pallocated_mp_xmitframe_buf; ++ u8 *pmp_xmtframe_buf; ++ struct __queue free_mp_xmitqueue; ++ u32 free_mp_xmitframe_cnt; ++ ++ struct mpt_context MptCtx; ++}; ++ ++struct iocmd_struct { ++ u8 cmdclass; ++ u16 value; ++ u8 index; ++}; ++ ++struct rf_reg_param { ++ u32 path; ++ u32 offset; ++ u32 value; ++}; ++ ++struct bb_reg_param { ++ u32 offset; ++ u32 value; ++}; ++/* */ ++ ++#define LOWER true ++#define RAISE false ++ ++/* Hardware Registers */ ++#define BB_REG_BASE_ADDR 0x800 ++ ++/* MP variables */ ++enum mp_mode_{ ++ MP_OFF, ++ MP_ON, ++ MP_ERR, ++ MP_CONTINUOUS_TX, ++ MP_SINGLE_CARRIER_TX, ++ MP_CARRIER_SUPPRISSION_TX, ++ MP_SINGLE_TONE_TX, ++ MP_PACKET_TX, ++ MP_PACKET_RX ++}; ++ ++extern u8 mpdatarate[NumRates]; ++ ++/* MP set force data rate base on the definition. */ ++enum mpt_rate_index { ++ /* CCK rate. */ ++ MPT_RATE_1M, /* 0 */ ++ MPT_RATE_2M, ++ MPT_RATE_55M, ++ MPT_RATE_11M, /* 3 */ ++ ++ /* OFDM rate. */ ++ MPT_RATE_6M, /* 4 */ ++ MPT_RATE_9M, ++ MPT_RATE_12M, ++ MPT_RATE_18M, ++ MPT_RATE_24M, ++ MPT_RATE_36M, ++ MPT_RATE_48M, ++ MPT_RATE_54M, /* 11 */ ++ ++ /* HT rate. */ ++ MPT_RATE_MCS0, /* 12 */ ++ MPT_RATE_MCS1, ++ MPT_RATE_MCS2, ++ MPT_RATE_MCS3, ++ MPT_RATE_MCS4, ++ MPT_RATE_MCS5, ++ MPT_RATE_MCS6, ++ MPT_RATE_MCS7, /* 19 */ ++ MPT_RATE_MCS8, ++ MPT_RATE_MCS9, ++ MPT_RATE_MCS10, ++ MPT_RATE_MCS11, ++ MPT_RATE_MCS12, ++ MPT_RATE_MCS13, ++ MPT_RATE_MCS14, ++ MPT_RATE_MCS15, /* 27 */ ++ MPT_RATE_LAST ++}; ++ ++#define MAX_TX_PWR_INDEX_N_MODE 64 /* 0x3F */ ++ ++enum power_mode { ++ POWER_LOW = 0, ++ POWER_NORMAL ++}; ++ ++#define RX_PKT_BROADCAST 1 ++#define RX_PKT_DEST_ADDR 2 ++#define RX_PKT_PHY_MATCH 3 ++ ++enum encry_ctrl_state { ++ HW_CONTROL, /* hw encryption& decryption */ ++ SW_CONTROL, /* sw encryption& decryption */ ++ HW_ENCRY_SW_DECRY, /* hw encryption & sw decryption */ ++ SW_ENCRY_HW_DECRY /* sw encryption & hw decryption */ ++}; ++ ++s32 init_mp_priv(struct adapter *padapter); ++void free_mp_priv(struct mp_priv *pmp_priv); ++s32 MPT_InitializeAdapter(struct adapter *padapter, u8 Channel); ++void MPT_DeInitAdapter(struct adapter *padapter); ++s32 mp_start_test(struct adapter *padapter); ++void mp_stop_test(struct adapter *padapter); ++ ++u32 _read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask); ++void _write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val); ++ ++u32 read_bbreg(struct adapter *padapter, u32 addr, u32 bitmask); ++void write_bbreg(struct adapter *padapter, u32 addr, u32 bitmask, u32 val); ++u32 read_rfreg(struct adapter *padapter, u8 rfpath, u32 addr); ++void write_rfreg(struct adapter *padapter, u8 rfpath, u32 addr, u32 val); ++ ++void SetChannel(struct adapter *pAdapter); ++void SetBandwidth(struct adapter *pAdapter); ++void SetTxPower(struct adapter *pAdapter); ++void SetAntennaPathPower(struct adapter *pAdapter); ++void SetDataRate(struct adapter *pAdapter); ++ ++void SetAntenna(struct adapter *pAdapter); ++ ++s32 SetThermalMeter(struct adapter *pAdapter, u8 target_ther); ++void GetThermalMeter(struct adapter *pAdapter, u8 *value); ++ ++void SetContinuousTx(struct adapter *pAdapter, u8 bStart); ++void SetSingleCarrierTx(struct adapter *pAdapter, u8 bStart); ++void SetSingleToneTx(struct adapter *pAdapter, u8 bStart); ++void SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart); ++void PhySetTxPowerLevel(struct adapter *pAdapter); ++ ++void fill_txdesc_for_mp(struct adapter *padapter, struct tx_desc *ptxdesc); ++void SetPacketTx(struct adapter *padapter); ++void SetPacketRx(struct adapter *pAdapter, u8 bStartRx); ++ ++void ResetPhyRxPktCount(struct adapter *pAdapter); ++u32 GetPhyRxPktReceived(struct adapter *pAdapter); ++u32 GetPhyRxPktCRC32Error(struct adapter *pAdapter); ++ ++s32 SetPowerTracking(struct adapter *padapter, u8 enable); ++void GetPowerTracking(struct adapter *padapter, u8 *enable); ++u32 mp_query_psd(struct adapter *pAdapter, u8 *data); ++void Hal_SetAntenna(struct adapter *pAdapter); ++void Hal_SetBandwidth(struct adapter *pAdapter); ++void Hal_SetTxPower(struct adapter *pAdapter); ++void Hal_SetCarrierSuppressionTx(struct adapter *pAdapter, u8 bStart); ++void Hal_SetSingleToneTx(struct adapter *pAdapter, u8 bStart); ++void Hal_SetSingleCarrierTx (struct adapter *pAdapter, u8 bStart); ++void Hal_SetContinuousTx (struct adapter *pAdapter, u8 bStart); ++void Hal_SetBandwidth(struct adapter *pAdapter); ++void Hal_SetDataRate(struct adapter *pAdapter); ++void Hal_SetChannel(struct adapter *pAdapter); ++void Hal_SetAntennaPathPower(struct adapter *pAdapter); ++s32 Hal_SetThermalMeter(struct adapter *pAdapter, u8 target_ther); ++s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable); ++void Hal_GetPowerTracking(struct adapter *padapter, u8 * enable); ++void Hal_GetThermalMeter(struct adapter *pAdapter, u8 *value); ++void Hal_mpt_SwitchRfSetting(struct adapter *pAdapter); ++void Hal_MPT_CCKTxPowerAdjust(struct adapter * Adapter, bool bInCH14); ++void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *pAdapter, bool beven); ++void Hal_SetCCKTxPower(struct adapter *pAdapter, u8 * TxPower); ++void Hal_SetOFDMTxPower(struct adapter *pAdapter, u8 * TxPower); ++void Hal_TriggerRFThermalMeter(struct adapter *pAdapter); ++u8 Hal_ReadRFThermalMeter(struct adapter *pAdapter); ++void Hal_SetCCKContinuousTx(struct adapter *pAdapter, u8 bStart); ++void Hal_SetOFDMContinuousTx(struct adapter *pAdapter, u8 bStart); ++void Hal_ProSetCrystalCap (struct adapter *pAdapter , u32 CrystalCapVal); ++void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv); ++void MP_PHY_SetRFPathSwitch(struct adapter *pAdapter ,bool bMain); ++ ++#endif /* _RTW_MP_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_mp_ioctl.h b/drivers/staging/r8188eu/include/rtw_mp_ioctl.h +new file mode 100644 +index 000000000000..cf99f39a582e +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_mp_ioctl.h +@@ -0,0 +1,242 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_MP_IOCTL_H_ ++#define _RTW_MP_IOCTL_H_ ++ ++#include "drv_types.h" ++#include "mp_custom_oid.h" ++#include "rtw_ioctl.h" ++#include "rtw_ioctl_rtl.h" ++#include "rtw_efuse.h" ++#include "rtw_mp.h" ++ ++struct cfg_dbg_msg_struct { ++ u32 DebugLevel; ++ u32 DebugComponent_H32; ++ u32 DebugComponent_L32; ++}; ++ ++struct mp_rw_reg { ++ u32 offset; ++ u32 width; ++ u32 value; ++}; ++ ++struct efuse_access_struct { ++ u16 start_addr; ++ u16 cnts; ++ u8 data[0]; ++}; ++ ++struct burst_rw_reg { ++ u32 offset; ++ u32 len; ++ u8 Data[256]; ++}; ++ ++struct usb_vendor_req { ++ u8 bRequest; ++ u16 wValue; ++ u16 wIndex; ++ u16 wLength; ++ u8 u8Dir;/* 0:OUT, 1:IN */ ++ u8 u8InData; ++}; ++ ++struct dr_variable_struct { ++ u8 offset; ++ u32 variable; ++}; ++ ++#define _irqlevel_changed_(a, b) ++ ++int rtl8188eu_oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv); ++ ++int rtl8188eu_oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *par_priv); ++int rtl8188eu_oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *par_priv); ++int rtl8188eu_oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *par_priv); ++int rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* rtl8188eu_oid_rtl_seg_81_87 */ ++int rtl8188eu_oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv); ++ ++int rtl8188eu_oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* rtl8188eu_oid_rtl_seg_87_11_00 */ ++int rtl8188eu_oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_wr_attrib_mem_hdl (struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv); ++/* rtl8188eu_oid_rtl_seg_87_11_20 */ ++int rtl8188eu_oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv); ++/* rtl8188eu_oid_rtl_seg_87_11_50 */ ++int rtl8188eu_oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv); ++/* rtl8188eu_oid_rtl_seg_87_11_F0 */ ++int rtl8188eu_oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv); ++ ++/* rtl8188eu_oid_rtl_seg_87_12_00 */ ++int rtl8188eu_oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *par_priv); ++int rtl8188eu_oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv); ++int rtl8188eu_oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv); ++ ++struct rwreg_param { ++ u32 offset; ++ u32 width; ++ u32 value; ++}; ++ ++struct bbreg_param { ++ u32 offset; ++ u32 phymask; ++ u32 value; ++}; ++ ++struct txpower_param { ++ u32 pwr_index; ++}; ++ ++struct datarate_param { ++ u32 rate_index; ++}; ++ ++struct rfintfs_parm { ++ u32 rfintfs; ++}; ++ ++struct mp_xmit_parm { ++ u8 enable; ++ u32 count; ++ u16 length; ++ u8 payload_type; ++ u8 da[ETH_ALEN]; ++}; ++ ++struct mp_xmit_packet { ++ u32 len; ++ u32 mem[MAX_MP_XMITBUF_SZ >> 2]; ++}; ++ ++struct psmode_param { ++ u32 ps_mode; ++ u32 smart_ps; ++}; ++ ++/* for OID_RT_PRO_READ16_EEPROM & OID_RT_PRO_WRITE16_EEPROM */ ++struct eeprom_rw_param { ++ u32 offset; ++ u16 value; ++}; ++ ++struct mp_ioctl_handler { ++ u32 paramsize; ++ s32 (*handler)(struct oid_par_priv* poid_par_priv); ++ u32 oid; ++}; ++ ++struct mp_ioctl_param{ ++ u32 subcode; ++ u32 len; ++ u8 data[0]; ++}; ++ ++#define GEN_MP_IOCTL_SUBCODE(code) _MP_IOCTL_ ## code ## _CMD_ ++ ++enum RTL871X_MP_IOCTL_SUBCODE { ++ GEN_MP_IOCTL_SUBCODE(MP_START), /*0*/ ++ GEN_MP_IOCTL_SUBCODE(MP_STOP), ++ GEN_MP_IOCTL_SUBCODE(READ_REG), ++ GEN_MP_IOCTL_SUBCODE(WRITE_REG), ++ GEN_MP_IOCTL_SUBCODE(READ_BB_REG), ++ GEN_MP_IOCTL_SUBCODE(WRITE_BB_REG), /*5*/ ++ GEN_MP_IOCTL_SUBCODE(READ_RF_REG), ++ GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG), ++ GEN_MP_IOCTL_SUBCODE(SET_CHANNEL), ++ GEN_MP_IOCTL_SUBCODE(SET_TXPOWER), ++ GEN_MP_IOCTL_SUBCODE(SET_DATARATE), /*10*/ ++ GEN_MP_IOCTL_SUBCODE(SET_BANDWIDTH), ++ GEN_MP_IOCTL_SUBCODE(SET_ANTENNA), ++ GEN_MP_IOCTL_SUBCODE(CNTU_TX), ++ GEN_MP_IOCTL_SUBCODE(SC_TX), ++ GEN_MP_IOCTL_SUBCODE(CS_TX), /*15*/ ++ GEN_MP_IOCTL_SUBCODE(ST_TX), ++ GEN_MP_IOCTL_SUBCODE(IOCTL_XMIT_PACKET), ++ GEN_MP_IOCTL_SUBCODE(SET_RX_PKT_TYPE), ++ GEN_MP_IOCTL_SUBCODE(RESET_PHY_RX_PKT_CNT), ++ GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_RECV), /*20*/ ++ GEN_MP_IOCTL_SUBCODE(GET_PHY_RX_PKT_ERROR), ++ GEN_MP_IOCTL_SUBCODE(READ16_EEPROM), ++ GEN_MP_IOCTL_SUBCODE(WRITE16_EEPROM), ++ GEN_MP_IOCTL_SUBCODE(EFUSE), ++ GEN_MP_IOCTL_SUBCODE(EFUSE_MAP), /*25*/ ++ GEN_MP_IOCTL_SUBCODE(GET_EFUSE_MAX_SIZE), ++ GEN_MP_IOCTL_SUBCODE(GET_EFUSE_CURRENT_SIZE), ++ GEN_MP_IOCTL_SUBCODE(GET_THERMAL_METER), ++ GEN_MP_IOCTL_SUBCODE(SET_PTM), ++ GEN_MP_IOCTL_SUBCODE(SET_POWER_DOWN), /*30*/ ++ GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO), ++ GEN_MP_IOCTL_SUBCODE(SET_DM_BT), /*35*/ ++ GEN_MP_IOCTL_SUBCODE(DEL_BA), /*36*/ ++ GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS), /*37*/ ++ MAX_MP_IOCTL_SUBCODE, ++}; ++ ++s32 rtl8188eu_mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv); ++ ++#define GEN_HANDLER(sz, hdl, oid) {sz, hdl, oid}, ++ ++#define EXT_MP_IOCTL_HANDLER(sz, subcode, oid) \ ++ {sz, rtl8188eu_mp_ioctl_##subcode##_hdl, oid}, ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtw_mp_phy_regdef.h b/drivers/staging/r8188eu/include/rtw_mp_phy_regdef.h +new file mode 100644 +index 000000000000..c2be770a5f5d +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_mp_phy_regdef.h +@@ -0,0 +1,1063 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++/***************************************************************************** ++ * ++ * Module: __RTW_MP_PHY_REGDEF_H_ ++ * ++ * ++ * Note: 1. Define PMAC/BB register map ++ * 2. Define RF register map ++ * 3. PMAC/BB register bit mask. ++ * 4. RF reg bit mask. ++ * 5. Other BB/RF relative definition. ++ * ++ * ++ * Export: Constants, macro, functions(API), global variables(None). ++ * ++ * Abbrev: ++ * ++ * History: ++ * Data Who Remark ++ * 08/07/2007 MHC 1. Porting from 9x series PHYCFG.h. ++ * 2. Reorganize code architecture. ++ * 09/25/2008 MH 1. Add RL6052 register definition ++ * ++ *****************************************************************************/ ++#ifndef __RTW_MP_PHY_REGDEF_H_ ++#define __RTW_MP_PHY_REGDEF_H_ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++/* */ ++/* 8192S Regsiter offset definition */ ++/* */ ++ ++/* */ ++/* 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 definition for BB/RF R/W */ ++/* */ ++ ++/* */ ++/* 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 ++ ++/* */ ++/* 2. Page2(0x200) */ ++/* */ ++/* The following two definition are only used for USB interface. */ ++/* define RF_BB_CMD_ADDR 0x02c0 RF/BB read/write command address. */ ++/* define RF_BB_CMD_DATA 0x02c4 RF/BB read/write command data. */ ++ ++/* */ ++/* 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_RFTiming1 0x810 /* Useless now */ ++#define rFPGA0_RFTiming2 0x814 ++/* define rFPGA0_XC_RFTiming 0x818 */ ++/* define rFPGA0_XD_RFTiming 0x81c */ ++ ++#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_XC_HSSIParameter1 0x830 ++#define rFPGA0_XC_HSSIParameter2 0x834 ++#define rFPGA0_XD_HSSIParameter1 0x838 ++#define rFPGA0_XD_HSSIParameter2 0x83c ++#define rFPGA0_XA_LSSIParameter 0x840 ++#define rFPGA0_XB_LSSIParameter 0x844 ++#define rFPGA0_XC_LSSIParameter 0x848 ++#define rFPGA0_XD_LSSIParameter 0x84c ++ ++#define rFPGA0_RFWakeUpParameter 0x850 /* Useless now */ ++#define rFPGA0_RFSleepUpParameter 0x854 ++ ++#define rFPGA0_XAB_SwitchControl 0x858 /* RF Channel switch */ ++#define rFPGA0_XCD_SwitchControl 0x85c ++ ++#define rFPGA0_XA_RFInterfaceOE 0x860 /* RF Channel switch */ ++#define rFPGA0_XB_RFInterfaceOE 0x864 ++#define rFPGA0_XC_RFInterfaceOE 0x868 ++#define rFPGA0_XD_RFInterfaceOE 0x86c ++ ++#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 /* Useless now */ ++#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_PSDReport 0x8b4 /* Useless now */ ++#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 rFPGA1_TxBlock 0x904 /* Useless now */ ++#define rFPGA1_DebugSelect 0x908 /* Useless now */ ++#define rFPGA1_TxInfo 0x90c /* Useless now Status report?? */ ++ ++/* */ ++/* 5. PageA(0xA00) */ ++/* */ ++/* Set Control channel to upper or lower. These settings are required only for 40MHz */ ++#define rCCK0_System 0xa00 ++ ++#define rCCK0_AFESetting 0xa04 /* Disable init gain now Select RX path by RSSI */ ++#define rCCK0_CCA 0xa08 /* Disable init gain now Init gain */ ++ ++#define rCCK0_RxAGC1 0xa0c /* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series */ ++#define rCCK0_RxAGC2 0xa10 /* AGC & DAGC */ ++ ++#define rCCK0_RxHP 0xa14 ++ ++#define rCCK0_DSPParameter1 0xa18 /* Timing recovery & Channel estimation threshold */ ++#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 */ ++#define rCCK0_TRSSIReport 0xa50 ++#define rCCK0_RxReport 0xa54 /* 0xa57 */ ++#define rCCK0_FACounterLower 0xa5c /* 0xa5b */ ++#define rCCK0_FACounterUpper 0xa58 /* 0xa5c */ ++ ++/* */ ++/* 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_RxHPParameter 0xce0 ++#define rOFDM0_TxPseudoNoiseWgt 0xce4 ++#define rOFDM0_FrameSync 0xcf0 ++#define rOFDM0_DFSReport 0xcf4 ++#define rOFDM0_TxCoeff1 0xca4 ++#define rOFDM0_TxCoeff2 0xca8 ++#define rOFDM0_TxCoeff3 0xcac ++#define rOFDM0_TxCoeff4 0xcb0 ++#define rOFDM0_TxCoeff5 0xcb4 ++#define rOFDM0_TxCoeff6 0xcb8 ++ ++/* 7. PageD(0xD00) */ ++#define rOFDM1_LSTF 0xd00 ++#define rOFDM1_TRxPathEnable 0xd04 ++ ++#define rOFDM1_CFO 0xd08 /* No setting now */ ++#define rOFDM1_CSI1 0xd10 ++#define rOFDM1_SBD 0xd14 ++#define rOFDM1_CSI2 0xd18 ++#define rOFDM1_CFOTracking 0xd2c ++#define rOFDM1_TRxMesaure1 0xd34 ++#define rOFDM1_IntfDet 0xd3c ++#define rOFDM1_PseudoNoiseStateAB 0xd50 ++#define rOFDM1_PseudoNoiseStateCD 0xd54 ++#define rOFDM1_RxPseudoNoiseWgt 0xd58 ++ ++#define rOFDM_PHYCounter1 0xda0 /* cca, parity fail */ ++#define rOFDM_PHYCounter2 0xda4 /* rate illegal, crc8 fail */ ++#define rOFDM_PHYCounter3 0xda8 /* MCS not support */ ++ ++#define rOFDM_ShortCFOAB 0xdac /* No setting now */ ++#define rOFDM_ShortCFOCD 0xdb0 ++#define rOFDM_LongCFOAB 0xdb4 ++#define rOFDM_LongCFOCD 0xdb8 ++#define rOFDM_TailCFOAB 0xdbc ++#define rOFDM_TailCFOCD 0xdc0 ++#define rOFDM_PWMeasure1 0xdc4 ++#define rOFDM_PWMeasure2 0xdc8 ++#define rOFDM_BWReport 0xdcc ++#define rOFDM_AGCReport 0xdd0 ++#define rOFDM_RxSNR 0xdd4 ++#define rOFDM_RxEVMCSI 0xdd8 ++#define rOFDM_SIGReport 0xddc ++ ++/* */ ++/* 8. PageE(0xE00) */ ++/* */ ++#define rTxAGC_Rate18_06 0xe00 ++#define rTxAGC_Rate54_24 0xe04 ++#define rTxAGC_CCK_Mcs32 0xe08 ++#define rTxAGC_Mcs03_Mcs00 0xe10 ++#define rTxAGC_Mcs07_Mcs04 0xe14 ++#define rTxAGC_Mcs11_Mcs08 0xe18 ++#define rTxAGC_Mcs15_Mcs12 0xe1c ++ ++/* Analog- control in RX_WAIT_CCA : REG: EE0 [Analog- Power & Control Register] */ ++#define rRx_Wait_CCCA 0xe70 ++#define rAnapar_Ctrl_BB 0xee0 ++ ++/* */ ++/* 7. RF Register 0x00-0x2E (RF 8256) */ ++/* RF-0222D 0x00-3F */ ++/* */ ++/* Zebra1 */ ++#define RTL92SE_FPGA_VERIFY 0 ++#define rZebra1_HSSIEnable 0x0 /* Useless now */ ++#define rZebra1_TRxEnable1 0x1 ++#define rZebra1_TRxEnable2 0x2 ++#define rZebra1_AGC 0x4 ++#define rZebra1_ChargePump 0x5 ++/* if (RTL92SE_FPGA_VERIFY == 1) */ ++#define rZebra1_Channel 0x7 /* RF channel switch */ ++/* else */ ++ ++/* endif */ ++#define rZebra1_TxGain 0x8 /* Useless now */ ++#define rZebra1_TxLPF 0x9 ++#define rZebra1_RxLPF 0xb ++#define rZebra1_RxHPFCorner 0xc ++ ++/* Zebra4 */ ++#define rGlobalCtrl 0 /* Useless now */ ++#define rRTL8256_TxLPF 19 ++#define rRTL8256_RxLPF 11 ++ ++/* RTL8258 */ ++#define rRTL8258_TxLPF 0x11 /* Useless now */ ++#define rRTL8258_RxLPF 0x13 ++#define rRTL8258_RSSILPF 0xa ++ ++/* */ ++/* RL6052 Register definition */ ++#define RF_AC 0x00 /* */ ++ ++#define RF_IQADJ_G1 0x01 /* */ ++#define RF_IQADJ_G2 0x02 /* */ ++#define RF_POW_TRSW 0x05 /* */ ++ ++#define RF_GAIN_RX 0x06 /* */ ++#define RF_GAIN_TX 0x07 /* */ ++ ++#define RF_TXM_IDAC 0x08 /* */ ++#define RF_BS_IQGEN 0x0F /* */ ++ ++#define RF_MODE1 0x10 /* */ ++#define RF_MODE2 0x11 /* */ ++ ++#define RF_RX_AGC_HP 0x12 /* */ ++#define RF_TX_AGC 0x13 /* */ ++#define RF_BIAS 0x14 /* */ ++#define RF_IPA 0x15 /* */ ++#define RF_TXBIAS 0x16 /* */ ++#define RF_POW_ABILITY 0x17 /* */ ++#define RF_MODE_AG 0x18 /* */ ++#define rRfChannel 0x18 /* RF channel and BW switch */ ++#define RF_CHNLBW 0x18 /* RF channel and BW switch */ ++#define RF_TOP 0x19 /* */ ++ ++#define RF_RX_G1 0x1A /* */ ++#define RF_RX_G2 0x1B /* */ ++ ++#define RF_RX_BB2 0x1C /* */ ++#define RF_RX_BB1 0x1D /* */ ++ ++#define RF_RCK1 0x1E /* */ ++#define RF_RCK2 0x1F /* */ ++ ++#define RF_TX_G1 0x20 /* */ ++#define RF_TX_G2 0x21 /* */ ++#define RF_TX_G3 0x22 /* */ ++ ++#define RF_TX_BB1 0x23 /* */ ++ ++#define RF_T_METER 0x24 /* */ ++ ++#define RF_SYN_G1 0x25 /* RF TX Power control */ ++#define RF_SYN_G2 0x26 /* RF TX Power control */ ++#define RF_SYN_G3 0x27 /* RF TX Power control */ ++#define RF_SYN_G4 0x28 /* RF TX Power control */ ++#define RF_SYN_G5 0x29 /* RF TX Power control */ ++#define RF_SYN_G6 0x2A /* RF TX Power control */ ++#define RF_SYN_G7 0x2B /* RF TX Power control */ ++#define RF_SYN_G8 0x2C /* RF TX Power control */ ++ ++#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 */ ++ ++/* */ ++/* 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 ++ ++#define IS_BB_REG_OFFSET_92S(_Offset) ((_Offset >= 0x800) && (_Offset <= 0xfff)) ++ ++/* 2. Page8(0x800) */ ++#define bRFMOD 0x1 /* Reg 0x800 rFPGA0_RFMOD */ ++#define bJapanMode 0x2 ++#define bCCKTxSC 0x30 ++#define bCCKEn 0x1000000 ++#define bOFDMEn 0x2000000 ++ ++#define bOFDMRxADCPhase 0x10000 /* Useless now */ ++#define bOFDMTxDACPhase 0x40000 ++#define bXATxAGC 0x3f ++ ++#define bXBTxAGC 0xf00 /* Reg 80c rFPGA0_TxGainStage */ ++#define bXCTxAGC 0xf000 ++#define bXDTxAGC 0xf0000 ++ ++#define bPAStart 0xf0000000 /* Useless now */ ++#define bTRStart 0x00f00000 ++#define bRFStart 0x0000f000 ++#define bBBStart 0x000000f0 ++#define bBBCCKStart 0x0000000f ++#define bPAEnd 0xf /* Reg0x814 */ ++#define bTREnd 0x0f000000 ++#define bRFEnd 0x000f0000 ++#define bCCAMask 0x000000f0 /* T2R */ ++#define bR2RCCAMask 0x00000f00 ++#define bHSSI_R2TDelay 0xf8000000 ++#define bHSSI_T2RDelay 0xf80000 ++#define bContTxHSSI 0x400 /* chane gain at continue Tx */ ++#define bIGFromCCK 0x200 ++#define bAGCAddress 0x3f ++#define bRxHPTx 0x7000 ++#define bRxHPT2R 0x38000 ++#define bRxHPCCKIni 0xc0000 ++#define bAGCTxCode 0xc00000 ++#define bAGCRxCode 0x300000 ++ ++#define b3WireDataLength 0x800 /* Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */ ++#define b3WireAddressLength 0x400 ++ ++#define b3WireRFPowerDown 0x1 /* Useless now */ ++/* define bHWSISelect 0x8 */ ++#define b5GPAPEPolarity 0x40000000 ++#define b2GPAPEPolarity 0x80000000 ++#define bRFSW_TxDefaultAnt 0x3 ++#define bRFSW_TxOptionAnt 0x30 ++#define bRFSW_RxDefaultAnt 0x300 ++#define bRFSW_RxOptionAnt 0x3000 ++#define bRFSI_3WireData 0x1 ++#define bRFSI_3WireClock 0x2 ++#define bRFSI_3WireLoad 0x4 ++#define bRFSI_3WireRW 0x8 ++#define bRFSI_3Wire 0xf ++ ++#define bRFSI_RFENV 0x10 /* Reg 0x870 rFPGA0_XAB_RFInterfaceSW */ ++ ++#define bRFSI_TRSW 0x20 /* Useless now */ ++#define bRFSI_TRSWB 0x40 ++#define bRFSI_ANTSW 0x100 ++#define bRFSI_ANTSWB 0x200 ++#define bRFSI_PAPE 0x400 ++#define bRFSI_PAPE5G 0x800 ++#define bBandSelect 0x1 ++#define bHTSIG2_GI 0x80 ++#define bHTSIG2_Smoothing 0x01 ++#define bHTSIG2_Sounding 0x02 ++#define bHTSIG2_Aggreaton 0x08 ++#define bHTSIG2_STBC 0x30 ++#define bHTSIG2_AdvCoding 0x40 ++#define bHTSIG2_NumOfHTLTF 0x300 ++#define bHTSIG2_CRC8 0x3fc ++#define bHTSIG1_MCS 0x7f ++#define bHTSIG1_BandWidth 0x80 ++#define bHTSIG1_HTLength 0xffff ++#define bLSIG_Rate 0xf ++#define bLSIG_Reserved 0x10 ++#define bLSIG_Length 0x1fffe ++#define bLSIG_Parity 0x20 ++#define bCCKRxPhase 0x4 ++#if (RTL92SE_FPGA_VERIFY == 1) ++#define bLSSIReadAddress 0x3f000000 /* LSSI "Read" Address ++ Reg 0x824 rFPGA0_XA_HSSIParameter2 */ ++#else ++#define bLSSIReadAddress 0x7f800000 /* T65 RF */ ++#endif ++#define bLSSIReadEdge 0x80000000 /* LSSI "Read" edge signal */ ++#if (RTL92SE_FPGA_VERIFY == 1) ++#define bLSSIReadBackData 0xfff /* Reg 0x8a0 ++ rFPGA0_XA_LSSIReadBack */ ++#else ++#define bLSSIReadBackData 0xfffff /* T65 RF */ ++#endif ++#define bLSSIReadOKFlag 0x1000 /* Useless now */ ++#define bCCKSampleRate 0x8 /* 0: 44MHz, 1:88MHz */ ++#define bRegulator0Standby 0x1 ++#define bRegulatorPLLStandby 0x2 ++#define bRegulator1Standby 0x4 ++#define bPLLPowerUp 0x8 ++#define bDPLLPowerUp 0x10 ++#define bDA10PowerUp 0x20 ++#define bAD7PowerUp 0x200 ++#define bDA6PowerUp 0x2000 ++#define bXtalPowerUp 0x4000 ++#define b40MDClkPowerUP 0x8000 ++#define bDA6DebugMode 0x20000 ++#define bDA6Swing 0x380000 ++ ++#define bADClkPhase 0x4000000 /* Reg 0x880 ++ rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */ ++ ++#define b80MClkDelay 0x18000000 /* Useless */ ++#define bAFEWatchDogEnable 0x20000000 ++ ++#define bXtalCap01 0xc0000000 /* Reg 0x884 ++ rFPGA0_AnalogParameter2 Crystal cap */ ++#define bXtalCap23 0x3 ++#define bXtalCap92x 0x0f000000 ++#define bXtalCap 0x0f000000 ++ ++#define bIntDifClkEnable 0x400 /* Useless */ ++#define bExtSigClkEnable 0x800 ++#define bBandgapMbiasPowerUp 0x10000 ++#define bAD11SHGain 0xc0000 ++#define bAD11InputRange 0x700000 ++#define bAD11OPCurrent 0x3800000 ++#define bIPathLoopback 0x4000000 ++#define bQPathLoopback 0x8000000 ++#define bAFELoopback 0x10000000 ++#define bDA10Swing 0x7e0 ++#define bDA10Reverse 0x800 ++#define bDAClkSource 0x1000 ++#define bAD7InputRange 0x6000 ++#define bAD7Gain 0x38000 ++#define bAD7OutputCMMode 0x40000 ++#define bAD7InputCMMode 0x380000 ++#define bAD7Current 0xc00000 ++#define bRegulatorAdjust 0x7000000 ++#define bAD11PowerUpAtTx 0x1 ++#define bDA10PSAtTx 0x10 ++#define bAD11PowerUpAtRx 0x100 ++#define bDA10PSAtRx 0x1000 ++#define bCCKRxAGCFormat 0x200 ++#define bPSDFFTSamplepPoint 0xc000 ++#define bPSDAverageNum 0x3000 ++#define bIQPathControl 0xc00 ++#define bPSDFreq 0x3ff ++#define bPSDAntennaPath 0x30 ++#define bPSDIQSwitch 0x40 ++#define bPSDRxTrigger 0x400000 ++#define bPSDTxTrigger 0x80000000 ++#define bPSDSineToneScale 0x7f000000 ++#define bPSDReport 0xffff ++ ++/* 3. Page9(0x900) */ ++#define bOFDMTxSC 0x30000000 /* Useless */ ++#define bCCKTxOn 0x1 ++#define bOFDMTxOn 0x2 ++#define bDebugPage 0xfff /* reset debug page and HWord, ++ * LWord */ ++#define bDebugItem 0xff /* reset debug page and LWord */ ++#define bAntL 0x10 ++#define bAntNonHT 0x100 ++#define bAntHT1 0x1000 ++#define bAntHT2 0x10000 ++#define bAntHT1S1 0x100000 ++#define bAntNonHTS1 0x1000000 ++ ++/* 4. PageA(0xA00) */ ++#define bCCKBBMode 0x3 /* Useless */ ++#define bCCKTxPowerSaving 0x80 ++#define bCCKRxPowerSaving 0x40 ++ ++#define bCCKSideBand 0x10 /* Reg 0xa00 rCCK0 20/40 sw */ ++ ++#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 init gain polar */ ++#define bCCKRxAGCSatLevel 0x1f000000 ++#define bCCKRxAGCSatCount 0xe0 ++#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */ ++#define bCCKFixedRxAGC 0x8000 ++#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 ++ ++/* 5. PageC(0xC00) */ ++#define bNumOfSTF 0x3 /* Useless */ ++#define bShift_L 0xc0 ++#define bGI_TH 0xc ++#define bRxPathA 0x1 ++#define bRxPathB 0x2 ++#define bRxPathC 0x4 ++#define bRxPathD 0x8 ++#define bTxPathA 0x1 ++#define bTxPathB 0x2 ++#define bTxPathC 0x4 ++#define bTxPathD 0x8 ++#define bTRSSIFreq 0x200 ++#define bADCBackoff 0x3000 ++#define bDFIRBackoff 0xc000 ++#define bTRSSILatchPhase 0x10000 ++#define bRxIDCOffset 0xff ++#define bRxQDCOffset 0xff00 ++#define bRxDFIRMode 0x1800000 ++#define bRxDCNFType 0xe000000 ++#define bRXIQImb_A 0x3ff ++#define bRXIQImb_B 0xfc00 ++#define bRXIQImb_C 0x3f0000 ++#define bRXIQImb_D 0xffc00000 ++#define bDC_dc_Notch 0x60000 ++#define bRxNBINotch 0x1f000000 ++#define bPD_TH 0xf ++#define bPD_TH_Opt2 0xc000 ++#define bPWED_TH 0x700 ++#define bIfMF_Win_L 0x800 ++#define bPD_Option 0x1000 ++#define bMF_Win_L 0xe000 ++#define bBW_Search_L 0x30000 ++#define bwin_enh_L 0xc0000 ++#define bBW_TH 0x700000 ++#define bED_TH2 0x3800000 ++#define bBW_option 0x4000000 ++#define bRatio_TH 0x18000000 ++#define bWindow_L 0xe0000000 ++#define bSBD_Option 0x1 ++#define bFrame_TH 0x1c ++#define bFS_Option 0x60 ++#define bDC_Slope_check 0x80 ++#define bFGuard_Counter_DC_L 0xe00 ++#define bFrame_Weight_Short 0x7000 ++#define bSub_Tune 0xe00000 ++#define bFrame_DC_Length 0xe000000 ++#define bSBD_start_offset 0x30000000 ++#define bFrame_TH_2 0x7 ++#define bFrame_GI2_TH 0x38 ++#define bGI2_Sync_en 0x40 ++#define bSarch_Short_Early 0x300 ++#define bSarch_Short_Late 0xc00 ++#define bSarch_GI2_Late 0x70000 ++#define bCFOAntSum 0x1 ++#define bCFOAcc 0x2 ++#define bCFOStartOffset 0xc ++#define bCFOLookBack 0x70 ++#define bCFOSumWeight 0x80 ++#define bDAGCEnable 0x10000 ++#define bTXIQImb_A 0x3ff ++#define bTXIQImb_B 0xfc00 ++#define bTXIQImb_C 0x3f0000 ++#define bTXIQImb_D 0xffc00000 ++#define bTxIDCOffset 0xff ++#define bTxQDCOffset 0xff00 ++#define bTxDFIRMode 0x10000 ++#define bTxPesudoNoiseOn 0x4000000 ++#define bTxPesudoNoise_A 0xff ++#define bTxPesudoNoise_B 0xff00 ++#define bTxPesudoNoise_C 0xff0000 ++#define bTxPesudoNoise_D 0xff000000 ++#define bCCADropOption 0x20000 ++#define bCCADropThres 0xfff00000 ++#define bEDCCA_H 0xf ++#define bEDCCA_L 0xf0 ++#define bLambda_ED 0x300 ++#define bRxInitialGain 0x7f ++#define bRxAntDivEn 0x80 ++#define bRxAGCAddressForLNA 0x7f00 ++#define bRxHighPowerFlow 0x8000 ++#define bRxAGCFreezeThres 0xc0000 ++#define bRxFreezeStep_AGC1 0x300000 ++#define bRxFreezeStep_AGC2 0xc00000 ++#define bRxFreezeStep_AGC3 0x3000000 ++#define bRxFreezeStep_AGC0 0xc000000 ++#define bRxRssi_Cmp_En 0x10000000 ++#define bRxQuickAGCEn 0x20000000 ++#define bRxAGCFreezeThresMode 0x40000000 ++#define bRxOverFlowCheckType 0x80000000 ++#define bRxAGCShift 0x7f ++#define bTRSW_Tri_Only 0x80 ++#define bPowerThres 0x300 ++#define bRxAGCEn 0x1 ++#define bRxAGCTogetherEn 0x2 ++#define bRxAGCMin 0x4 ++#define bRxHP_Ini 0x7 ++#define bRxHP_TRLNA 0x70 ++#define bRxHP_RSSI 0x700 ++#define bRxHP_BBP1 0x7000 ++#define bRxHP_BBP2 0x70000 ++#define bRxHP_BBP3 0x700000 ++#define bRSSI_H 0x7f0000 /* thresh for hi power */ ++#define bRSSI_Gen 0x7f000000 /* thresh for ant div */ ++#define bRxSettle_TRSW 0x7 ++#define bRxSettle_LNA 0x38 ++#define bRxSettle_RSSI 0x1c0 ++#define bRxSettle_BBP 0xe00 ++#define bRxSettle_RxHP 0x7000 ++#define bRxSettle_AntSW_RSSI 0x38000 ++#define bRxSettle_AntSW 0xc0000 ++#define bRxProcessTime_DAGC 0x300000 ++#define bRxSettle_HSSI 0x400000 ++#define bRxProcessTime_BBPPW 0x800000 ++#define bRxAntennaPowerShift 0x3000000 ++#define bRSSITableSelect 0xc000000 ++#define bRxHP_Final 0x7000000 ++#define bRxHTSettle_BBP 0x7 ++#define bRxHTSettle_HSSI 0x8 ++#define bRxHTSettle_RxHP 0x70 ++#define bRxHTSettle_BBPPW 0x80 ++#define bRxHTSettle_Idle 0x300 ++#define bRxHTSettle_Reserved 0x1c00 ++#define bRxHTRxHPEn 0x8000 ++#define bRxHTAGCFreezeThres 0x30000 ++#define bRxHTAGCTogetherEn 0x40000 ++#define bRxHTAGCMin 0x80000 ++#define bRxHTAGCEn 0x100000 ++#define bRxHTDAGCEn 0x200000 ++#define bRxHTRxHP_BBP 0x1c00000 ++#define bRxHTRxHP_Final 0xe0000000 ++#define bRxPWRatioTH 0x3 ++#define bRxPWRatioEn 0x4 ++#define bRxMFHold 0x3800 ++#define bRxPD_Delay_TH1 0x38 ++#define bRxPD_Delay_TH2 0x1c0 ++#define bRxPD_DC_COUNT_MAX 0x600 ++/* define bRxMF_Hold 0x3800 */ ++#define bRxPD_Delay_TH 0x8000 ++#define bRxProcess_Delay 0xf0000 ++#define bRxSearchrange_GI2_Early 0x700000 ++#define bRxFrame_Guard_Counter_L 0x3800000 ++#define bRxSGI_Guard_L 0xc000000 ++#define bRxSGI_Search_L 0x30000000 ++#define bRxSGI_TH 0xc0000000 ++#define bDFSCnt0 0xff ++#define bDFSCnt1 0xff00 ++#define bDFSFlag 0xf0000 ++#define bMFWeightSum 0x300000 ++#define bMinIdxTH 0x7f000000 ++#define bDAFormat 0x40000 ++#define bTxChEmuEnable 0x01000000 ++#define bTRSWIsolation_A 0x7f ++#define bTRSWIsolation_B 0x7f00 ++#define bTRSWIsolation_C 0x7f0000 ++#define bTRSWIsolation_D 0x7f000000 ++#define bExtLNAGain 0x7c00 ++ ++/* 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 ++/* define bRxPath1 0x01 */ ++/* define bRxPath2 0x02 */ ++/* define bRxPath3 0x04 */ ++/* define bRxPath4 0x08 */ ++/* define bTxPath1 0x10 */ ++/* define bTxPath2 0x20 */ ++#define bHTDetect 0x100 ++#define bCFOEn 0x10000 ++#define bCFOValue 0xfff00000 ++#define bSigTone_Re 0x3f ++#define bSigTone_Im 0x7f00 ++#define bCounter_CCA 0xffff ++#define bCounter_ParityFail 0xffff0000 ++#define bCounter_RateIllegal 0xffff ++#define bCounter_CRC8Fail 0xffff0000 ++#define bCounter_MCSNoSupport 0xffff ++#define bCounter_FastSync 0xffff ++#define bShortCFO 0xfff ++#define bShortCFOTLength 12 /* total */ ++#define bShortCFOFLength 11 /* fraction */ ++#define bLongCFO 0x7ff ++#define bLongCFOTLength 11 ++#define bLongCFOFLength 11 ++#define bTailCFO 0x1fff ++#define bTailCFOTLength 13 ++#define bTailCFOFLength 12 ++#define bmax_en_pwdB 0xffff ++#define bCC_power_dB 0xffff0000 ++#define bnoise_pwdB 0xffff ++#define bPowerMeasTLength 10 ++#define bPowerMeasFLength 3 ++#define bRx_HT_BW 0x1 ++#define bRxSC 0x6 ++#define bRx_HT 0x8 ++#define bNB_intf_det_on 0x1 ++#define bIntf_win_len_cfg 0x30 ++#define bNB_Intf_TH_cfg 0x1c0 ++#define bRFGain 0x3f ++#define bTableSel 0x40 ++#define bTRSW 0x80 ++#define bRxSNR_A 0xff ++#define bRxSNR_B 0xff00 ++#define bRxSNR_C 0xff0000 ++#define bRxSNR_D 0xff000000 ++#define bSNREVMTLength 8 ++#define bSNREVMFLength 1 ++#define bCSI1st 0xff ++#define bCSI2nd 0xff00 ++#define bRxEVM1st 0xff0000 ++#define bRxEVM2nd 0xff000000 ++#define bSIGEVM 0xff ++#define bPWDB 0xff00 ++#define bSGIEN 0x10000 ++ ++#define bSFactorQAM1 0xf /* Useless */ ++#define bSFactorQAM2 0xf0 ++#define bSFactorQAM3 0xf00 ++#define bSFactorQAM4 0xf000 ++#define bSFactorQAM5 0xf0000 ++#define bSFactorQAM6 0xf0000 ++#define bSFactorQAM7 0xf00000 ++#define bSFactorQAM8 0xf000000 ++#define bSFactorQAM9 0xf0000000 ++#define bCSIScheme 0x100000 ++ ++#define bNoiseLvlTopSet 0x3 /* Useless */ ++#define bChSmooth 0x4 ++#define bChSmoothCfg1 0x38 ++#define bChSmoothCfg2 0x1c0 ++#define bChSmoothCfg3 0xe00 ++#define bChSmoothCfg4 0x7000 ++#define bMRCMode 0x800000 ++#define bTHEVMCfg 0x7000000 ++ ++#define bLoopFitType 0x1 /* Useless */ ++#define bUpdCFO 0x40 ++#define bUpdCFOOffData 0x80 ++#define bAdvUpdCFO 0x100 ++#define bAdvTimeCtrl 0x800 ++#define bUpdClko 0x1000 ++#define bFC 0x6000 ++#define bTrackingMode 0x8000 ++#define bPhCmpEnable 0x10000 ++#define bUpdClkoLTF 0x20000 ++#define bComChCFO 0x40000 ++#define bCSIEstiMode 0x80000 ++#define bAdvUpdEqz 0x100000 ++#define bUChCfg 0x7000000 ++#define bUpdEqz 0x8000000 ++ ++#define bTxAGCRate18_06 0x7f7f7f7f /* Useless */ ++#define bTxAGCRate54_24 0x7f7f7f7f ++#define bTxAGCRateMCS32 0x7f ++#define bTxAGCRateCCK 0x7f00 ++#define bTxAGCRateMCS3_MCS0 0x7f7f7f7f ++#define bTxAGCRateMCS7_MCS4 0x7f7f7f7f ++#define bTxAGCRateMCS11_MCS8 0x7f7f7f7f ++#define bTxAGCRateMCS15_MCS12 0x7f7f7f7f ++ ++/* Rx Pseduo noise */ ++#define bRxPesudoNoiseOn 0x20000000 /* Useless */ ++#define bRxPesudoNoise_A 0xff ++#define bRxPesudoNoise_B 0xff00 ++#define bRxPesudoNoise_C 0xff0000 ++#define bRxPesudoNoise_D 0xff000000 ++#define bPesudoNoiseState_A 0xffff ++#define bPesudoNoiseState_B 0xffff0000 ++#define bPesudoNoiseState_C 0xffff ++#define bPesudoNoiseState_D 0xffff0000 ++ ++/* 7. RF Register */ ++/* Zebra1 */ ++#define bZebra1_HSSIEnable 0x8 /* Useless */ ++#define bZebra1_TRxControl 0xc00 ++#define bZebra1_TRxGainSetting 0x07f ++#define bZebra1_RxCorner 0xc00 ++#define bZebra1_TxChargePump 0x38 ++#define bZebra1_RxChargePump 0x7 ++#define bZebra1_ChannelNum 0xf80 ++#define bZebra1_TxLPFBW 0x400 ++#define bZebra1_RxLPFBW 0x600 ++ ++/* Zebra4 */ ++#define bRTL8256RegModeCtrl1 0x100 /* Useless */ ++#define bRTL8256RegModeCtrl0 0x40 ++#define bRTL8256_TxLPFBW 0x18 ++#define bRTL8256_RxLPFBW 0x600 ++ ++/* RTL8258 */ ++#define bRTL8258_TxLPFBW 0xc /* Useless */ ++#define bRTL8258_RxLPFBW 0xc00 ++#define bRTL8258_RSSILPFBW 0xc0 ++ ++/* */ ++/* Other Definition */ ++/* */ ++ ++/* byte endable for sb_write */ ++#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 bMaskH4Bits 0xf0000000 ++#define bMaskOFDM_D 0xffc00000 ++#define bMaskCCK 0x3f3f3f3f ++#define bMask12Bits 0xfff ++ ++/* for PutRFRegsetting & GetRFRegSetting BitMask */ ++#if (RTL92SE_FPGA_VERIFY == 1) ++#define bRFRegOffsetMask 0xfff ++#else ++#define bRFRegOffsetMask 0xfffff ++#endif ++#define bEnable 0x1 /* Useless */ ++#define bDisabl 0x0 ++ ++#define LeftAntenna 0x0 /* Useless */ ++#define RightAntenna 0x1 ++ ++#define tCheckTxStatus 500 /* 500ms Useless */ ++#define tUpdateRxCounter 100 /* 100ms */ ++ ++#define rateCCK 0 /* Useless */ ++#define rateOFDM 1 ++#define rateHT 2 ++ ++/* define Register-End */ ++#define bPMAC_End 0x1ff /* Useless */ ++#define bFPGAPHY0_End 0x8ff ++#define bFPGAPHY1_End 0x9ff ++#define bCCKPHY0_End 0xaff ++#define bOFDMPHY0_End 0xcff ++#define bOFDMPHY1_End 0xdff ++ ++/* define max debug item in each debug page */ ++/* define bMaxItem_FPGA_PHY0 0x9 */ ++/* define bMaxItem_FPGA_PHY1 0x3 */ ++/* define bMaxItem_PHY_11B 0x16 */ ++/* define bMaxItem_OFDM_PHY0 0x29 */ ++/* define bMaxItem_OFDM_PHY1 0x0 */ ++ ++#define bPMACControl 0x0 /* Useless */ ++#define bWMACControl 0x1 ++#define bWNICControl 0x2 ++ ++#define RCR_AAP BIT(0) /* accept all physical address */ ++#define RCR_APM BIT(1) /* accept physical match */ ++#define RCR_AM BIT(2) /* accept multicast */ ++#define RCR_AB BIT(3) /* accept broadcast */ ++#define RCR_ACRC32 BIT(5) /* accept error packet */ ++#define RCR_9356SEL BIT(6) ++#define RCR_AICV BIT(12) /* Accept ICV error packet */ ++#define RCR_RXFTH0 (BIT(13)|BIT(14)|BIT(15)) /* Rx FIFO threshold */ ++#define RCR_ADF BIT(18) /* Accept Data(frame type) frame */ ++#define RCR_ACF BIT(19) /* Accept control frame */ ++#define RCR_AMF BIT(20) /* Accept management frame */ ++#define RCR_ADD3 BIT(21) ++#define RCR_APWRMGT BIT(22) /* Accept power management packet */ ++#define RCR_CBSSID BIT(23) /* Accept BSSID match packet */ ++#define RCR_ENMARP BIT(28) /* enable mac auto reset phy */ ++#define RCR_EnCS1 BIT(29) /* enable carrier sense method 1 */ ++#define RCR_EnCS2 BIT(30) /* enable carrier sense method 2 */ ++#define RCR_OnlyErlPkt BIT(31) /* Rx Early mode is performed for ++ * packet size greater than 1536 */ ++ ++/*--------------------------Define Parameters-------------------------------*/ ++ ++#endif /* __INC_HAL8192SPHYREG_H */ +diff --git a/drivers/staging/r8188eu/include/rtw_p2p.h b/drivers/staging/r8188eu/include/rtw_p2p.h +new file mode 100644 +index 000000000000..92b9bfe3ea0b +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_p2p.h +@@ -0,0 +1,119 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_P2P_H_ ++#define __RTW_P2P_H_ ++ ++#include "drv_types.h" ++ ++u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, ++ u8 *pbuf, u8 *pssid, u8 ussidlen, ++ u8 *pdev_raddr); ++u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, ++ u8 *pbuf, u8 status_code); ++u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf); ++u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, ++ u8 *pframe, uint len); ++u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, ++ u8 *pframe, uint len, struct sta_info *psta); ++u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, ++ u8 *pframe, uint len); ++u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, ++ u8 *pframe, uint len); ++u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo, ++ u8 *pframe, uint len); ++u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe); ++u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, ++ u8 *pframe, uint len); ++u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, ++ u8 *pframe, uint len); ++u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo, ++ u8 *pframe, uint len); ++u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, ++ uint len); ++void p2p_protocol_wk_hdl(struct adapter *padapter, int intcmdtype); ++void process_p2p_ps_ie(struct adapter *padapter, u8 *ies, u32 ielength); ++void p2p_ps_wk_hdl(struct adapter *padapter, u8 p2p_ps_state); ++u8 p2p_ps_wk_cmd(struct adapter *padapter, u8 p2p_ps_state, u8 enqueue); ++void reset_global_wifidirect_info(struct adapter *padapter); ++int rtw_init_wifi_display_info(struct adapter *padapter); ++void rtw_init_wifidirect_timers(struct adapter *padapter); ++void rtw_init_wifidirect_addrs(struct adapter *padapter, u8 *dev_addr, ++ u8 *iface_addr); ++void init_wifidirect_info(struct adapter *padapter, enum P2P_ROLE role); ++int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role); ++ ++static inline void _rtw_p2p_set_state(struct wifidirect_info *wdinfo, ++ enum P2P_STATE state) ++{ ++ if (wdinfo->p2p_state != state) ++ wdinfo->p2p_state = state; ++} ++ ++static inline void _rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo, ++ enum P2P_STATE state) ++{ ++ if (wdinfo->pre_p2p_state != state) ++ wdinfo->pre_p2p_state = state; ++} ++ ++static inline void _rtw_p2p_set_role(struct wifidirect_info *wdinfo, ++ enum P2P_ROLE role) ++{ ++ if (wdinfo->role != role) ++ wdinfo->role = role; ++} ++ ++static inline int _rtw_p2p_state(struct wifidirect_info *wdinfo) ++{ ++ return wdinfo->p2p_state; ++} ++ ++static inline int _rtw_p2p_pre_state(struct wifidirect_info *wdinfo) ++{ ++ return wdinfo->pre_p2p_state; ++} ++ ++static inline int _rtw_p2p_role(struct wifidirect_info *wdinfo) ++{ ++ return wdinfo->role; ++} ++ ++static inline bool _rtw_p2p_chk_state(struct wifidirect_info *wdinfo, ++ enum P2P_STATE state) ++{ ++ return wdinfo->p2p_state == state; ++} ++ ++static inline bool _rtw_p2p_chk_role(struct wifidirect_info *wdinfo, ++ enum P2P_ROLE role) ++{ ++ return wdinfo->role == role; ++} ++ ++#define rtw_p2p_set_state(wdinfo, state) _rtw_p2p_set_state(wdinfo, state) ++#define rtw_p2p_set_pre_state(wdinfo, state) \ ++ _rtw_p2p_set_pre_state(wdinfo, state) ++#define rtw_p2p_set_role(wdinfo, role) _rtw_p2p_set_role(wdinfo, role) ++ ++#define rtw_p2p_state(wdinfo) _rtw_p2p_state(wdinfo) ++#define rtw_p2p_pre_state(wdinfo) _rtw_p2p_pre_state(wdinfo) ++#define rtw_p2p_role(wdinfo) _rtw_p2p_role(wdinfo) ++#define rtw_p2p_chk_state(wdinfo, state) _rtw_p2p_chk_state(wdinfo, state) ++#define rtw_p2p_chk_role(wdinfo, role) _rtw_p2p_chk_role(wdinfo, role) ++ ++#define rtw_p2p_findphase_ex_set(wdinfo, value) \ ++ ((wdinfo)->find_phase_state_exchange_cnt = (value)) ++ ++/* is this find phase exchange for social channel scan? */ ++#define rtw_p2p_findphase_ex_is_social(wdinfo) \ ++((wdinfo)->find_phase_state_exchange_cnt >= P2P_FINDPHASE_EX_SOCIAL_FIRST) ++ ++/* should we need find phase exchange anymore? */ ++#define rtw_p2p_findphase_ex_is_needed(wdinfo) \ ++ ((wdinfo)->find_phase_state_exchange_cnt < P2P_FINDPHASE_EX_MAX && \ ++ (wdinfo)->find_phase_state_exchange_cnt != P2P_FINDPHASE_EX_NONE) ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtw_pwrctrl.h b/drivers/staging/r8188eu/include/rtw_pwrctrl.h +new file mode 100644 +index 000000000000..543f928e8089 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_pwrctrl.h +@@ -0,0 +1,266 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#ifndef __RTW_PWRCTRL_H_ ++#define __RTW_PWRCTRL_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#define FW_PWR0 0 ++#define FW_PWR1 1 ++#define FW_PWR2 2 ++#define FW_PWR3 3 ++#define HW_PWR0 7 ++#define HW_PWR1 6 ++#define HW_PWR2 2 ++#define HW_PWR3 0 ++#define HW_PWR4 8 ++ ++#define FW_PWRMSK 0x7 ++ ++#define XMIT_ALIVE BIT(0) ++#define RECV_ALIVE BIT(1) ++#define CMD_ALIVE BIT(2) ++#define EVT_ALIVE BIT(3) ++ ++enum power_mgnt { ++ PS_MODE_ACTIVE = 0, ++ PS_MODE_MIN, ++ PS_MODE_MAX, ++ PS_MODE_DTIM, ++ PS_MODE_VOIP, ++ PS_MODE_UAPSD_WMM, ++ PS_MODE_UAPSD, ++ PS_MODE_IBSS, ++ PS_MODE_WWLAN, ++ PM_Radio_Off, ++ PM_Card_Disable, ++ PS_MODE_NUM ++}; ++ ++/* ++ BIT[2:0] = HW state ++ BIT[3] = Protocol PS state, 0: register active state, ++ 1: register sleep state ++ BIT[4] = sub-state ++*/ ++ ++#define PS_DPS BIT(0) ++#define PS_LCLK (PS_DPS) ++#define PS_RF_OFF BIT(1) ++#define PS_ALL_ON BIT(2) ++#define PS_ST_ACTIVE BIT(3) ++ ++#define PS_ISR_ENABLE BIT(4) ++#define PS_IMR_ENABLE BIT(5) ++#define PS_ACK BIT(6) ++#define PS_TOGGLE BIT(7) ++ ++#define PS_STATE_MASK (0x0F) ++#define PS_STATE_HW_MASK (0x07) ++#define PS_SEQ_MASK (0xc0) ++ ++#define PS_STATE(x) (PS_STATE_MASK & (x)) ++#define PS_STATE_HW(x) (PS_STATE_HW_MASK & (x)) ++#define PS_SEQ(x) (PS_SEQ_MASK & (x)) ++ ++#define PS_STATE_S0 (PS_DPS) ++#define PS_STATE_S1 (PS_LCLK) ++#define PS_STATE_S2 (PS_RF_OFF) ++#define PS_STATE_S3 (PS_ALL_ON) ++#define PS_STATE_S4 ((PS_ST_ACTIVE) | (PS_ALL_ON)) ++ ++#define PS_IS_RF_ON(x) ((x) & (PS_ALL_ON)) ++#define PS_IS_ACTIVE(x) ((x) & (PS_ST_ACTIVE)) ++#define CLR_PS_STATE(x) ((x) = ((x) & (0xF0))) ++ ++struct reportpwrstate_parm { ++ unsigned char mode; ++ unsigned char state; /* the CPWM value */ ++ unsigned short rsvd; ++}; ++ ++static inline void _init_pwrlock(struct semaphore *plock) ++{ ++ sema_init(plock, 1); ++} ++ ++static inline void _free_pwrlock(struct semaphore *plock) ++{ ++} ++ ++static inline void _enter_pwrlock(struct semaphore *plock) ++{ ++ _rtw_down_sema(plock); ++} ++ ++static inline void _exit_pwrlock(struct semaphore *plock) ++{ ++ up(plock); ++} ++ ++#define LPS_DELAY_TIME 1*HZ /* 1 sec */ ++ ++#define EXE_PWR_NONE 0x01 ++#define EXE_PWR_IPS 0x02 ++#define EXE_PWR_LPS 0x04 ++ ++/* RF state. */ ++enum rt_rf_power_state { ++ rf_on, /* RF is on after RFSleep or RFOff */ ++ rf_sleep, /* 802.11 Power Save mode */ ++ rf_off, /* HW/SW Radio OFF or Inactive Power Save */ ++ /* Add the new RF state above this line===== */ ++ rf_max ++}; ++ ++/* RF Off Level for IPS or HW/SW radio off */ ++#define RT_RF_OFF_LEVL_ASPM BIT(0) /* PCI ASPM */ ++#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /* PCI clock request */ ++#define RT_RF_OFF_LEVL_PCI_D3 BIT(2) /* PCI D3 mode */ ++#define RT_RF_OFF_LEVL_HALT_NIC BIT(3) /* NIC halt, re-init hw param*/ ++#define RT_RF_OFF_LEVL_FREE_FW BIT(4) /* FW free, re-download the FW*/ ++#define RT_RF_OFF_LEVL_FW_32K BIT(5) /* FW in 32k */ ++#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) /* Always enable ASPM and Clock ++ * Req in initialization. */ ++#define RT_RF_LPS_DISALBE_2R BIT(30) /* When LPS is on, disable 2R ++ * if no packet is RX or TX. */ ++#define RT_RF_LPS_LEVEL_ASPM BIT(31) /* LPS with ASPM */ ++ ++#define RT_IN_PS_LEVEL(ppsc, _PS_FLAG) \ ++ ((ppsc->cur_ps_level & _PS_FLAG) ? true : false) ++#define RT_CLEAR_PS_LEVEL(ppsc, _PS_FLAG) \ ++ (ppsc->cur_ps_level &= (~(_PS_FLAG))) ++#define RT_SET_PS_LEVEL(ppsc, _PS_FLAG) \ ++ (ppsc->cur_ps_level |= _PS_FLAG) ++ ++enum _PS_BBRegBackup_ { ++ PSBBREG_RF0 = 0, ++ PSBBREG_RF1, ++ PSBBREG_RF2, ++ PSBBREG_AFE0, ++ PSBBREG_TOTALCNT ++}; ++ ++enum { /* for ips_mode */ ++ IPS_NONE = 0, ++ IPS_NORMAL, ++ IPS_LEVEL_2, ++}; ++ ++struct pwrctrl_priv { ++ struct semaphore lock; ++ volatile u8 rpwm; /* requested power state for fw */ ++ volatile u8 cpwm; /* fw current power state. updated when ++ * 1. read from HCPWM 2. driver lowers power level */ ++ volatile u8 tog; /* toggling */ ++ volatile u8 cpwm_tog; /* toggling */ ++ ++ u8 pwr_mode; ++ u8 smart_ps; ++ u8 bcn_ant_mode; ++ ++ u32 alives; ++ struct work_struct cpwm_event; ++ u8 bpower_saving; ++ ++ u8 b_hw_radio_off; ++ u8 reg_rfoff; ++ u8 reg_pdnmode; /* powerdown mode */ ++ u32 rfoff_reason; ++ ++ /* RF OFF Level */ ++ u32 cur_ps_level; ++ u32 reg_rfps_level; ++ uint ips_enter_cnts; ++ uint ips_leave_cnts; ++ ++ u8 ips_mode; ++ u8 ips_mode_req; /* used to accept the mode setting request, ++ * will update to ipsmode later */ ++ uint bips_processing; ++ u32 ips_deny_time; /* will deny IPS when system time less than this */ ++ u8 ps_processing; /* temp used to mark whether in rtw_ps_processor */ ++ ++ u8 bLeisurePs; ++ u8 LpsIdleCount; ++ u8 power_mgnt; ++ u8 bFwCurrentInPSMode; ++ u32 DelayLPSLastTimeStamp; ++ u8 btcoex_rfon; ++ s32 pnp_current_pwr_state; ++ u8 pnp_bstop_trx; ++ ++ u8 bInternalAutoSuspend; ++ u8 bInSuspend; ++#ifdef CONFIG_BT_COEXIST ++ u8 bAutoResume; ++ u8 autopm_cnt; ++#endif ++ u8 bSupportRemoteWakeup; ++ struct timer_list pwr_state_check_timer; ++ int pwr_state_check_interval; ++ u8 pwr_state_check_cnts; ++ ++ int ps_flag; ++ ++ enum rt_rf_power_state rf_pwrstate;/* cur power state */ ++ enum rt_rf_power_state change_rfpwrstate; ++ ++ u8 wepkeymask; ++ u8 bHWPowerdown;/* if support hw power down */ ++ u8 bHWPwrPindetect; ++ u8 bkeepfwalive; ++ u8 brfoffbyhw; ++ unsigned long PS_BBRegBackup[PSBBREG_TOTALCNT]; ++}; ++ ++#define rtw_get_ips_mode_req(pwrctrlpriv) \ ++ (pwrctrlpriv)->ips_mode_req ++ ++#define rtw_ips_mode_req(pwrctrlpriv, ips_mode) \ ++ ((pwrctrlpriv)->ips_mode_req = (ips_mode)) ++ ++#define RTW_PWR_STATE_CHK_INTERVAL 2000 ++ ++#define _rtw_set_pwr_state_check_timer(pwrctrlpriv, ms) \ ++ do { \ ++ _set_timer(&(pwrctrlpriv)->pwr_state_check_timer, (ms)); \ ++ } while (0) ++ ++#define rtw_set_pwr_state_check_timer(pwrctrl) \ ++ _rtw_set_pwr_state_check_timer((pwrctrl), \ ++ (pwrctrl)->pwr_state_check_interval) ++ ++void rtw_init_pwrctrl_priv(struct adapter *adapter); ++void rtw_free_pwrctrl_priv(struct adapter *adapter); ++ ++void rtw_set_ps_mode(struct adapter *adapter, u8 ps_mode, u8 smart_ps, ++ u8 bcn_ant_mode); ++void rtw_set_rpwm(struct adapter *adapter, u8 val8); ++void LeaveAllPowerSaveMode(struct adapter *adapter); ++void ips_enter(struct adapter *padapter); ++int ips_leave(struct adapter *padapter); ++ ++void rtw_ps_processor(struct adapter *padapter); ++ ++enum rt_rf_power_state RfOnOffDetect(struct adapter *iadapter); ++ ++s32 LPS_RF_ON_check(struct adapter *adapter, u32 delay_ms); ++void LPS_Enter(struct adapter *adapter); ++void LPS_Leave(struct adapter *adapter); ++ ++u8 rtw_interface_ps_func(struct adapter *adapter, ++ enum hal_intf_ps_func efunc_id, u8 *val); ++void rtw_set_ips_deny(struct adapter *adapter, u32 ms); ++int _rtw_pwr_wakeup(struct adapter *adapter, u32 ips_defer_ms, ++ const char *caller); ++#define rtw_pwr_wakeup(adapter) \ ++ _rtw_pwr_wakeup(adapter, RTW_PWR_STATE_CHK_INTERVAL, __func__) ++#define rtw_pwr_wakeup_ex(adapter, ips_deffer_ms) \ ++ _rtw_pwr_wakeup(adapter, ips_deffer_ms, __func__) ++int rtw_pm_set_ips(struct adapter *adapter, u8 mode); ++int rtw_pm_set_lps(struct adapter *adapter, u8 mode); ++ ++#endif /* __RTL871X_PWRCTRL_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_recv.h b/drivers/staging/r8188eu/include/rtw_recv.h +new file mode 100644 +index 000000000000..d1d1ca0e56d6 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_recv.h +@@ -0,0 +1,413 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#ifndef _RTW_RECV_H_ ++#define _RTW_RECV_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#define NR_RECVFRAME 256 ++ ++#define RXFRAME_ALIGN 8 ++#define RXFRAME_ALIGN_SZ (1<signal_stat_timer, \ ++ (recvpriv)->signal_stat_sampling_interval) ++ ++struct sta_recv_priv { ++ spinlock_t lock; ++ int option; ++ struct __queue defrag_q; /* keeping the fragment frame until defrag */ ++ struct stainfo_rxcache rxcache; ++}; ++ ++struct recv_buf { ++ struct list_head list; ++ spinlock_t recvbuf_lock; ++ u32 ref_cnt; ++ struct adapter *adapter; ++ u8 *pbuf; ++ u8 *pallocated_buf; ++ u32 len; ++ u8 *phead; ++ u8 *pdata; ++ u8 *ptail; ++ u8 *pend; ++ struct urb *purb; ++ dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */ ++ u32 alloc_sz; ++ u8 irp_pending; ++ int transfer_len; ++ struct sk_buff *pskb; ++ u8 reuse; ++}; ++ ++/* ++ head -----> ++ ++ data -----> ++ ++ payload ++ ++ tail -----> ++ ++ end -----> ++ ++ len = (unsigned int )(tail - data); ++ ++*/ ++struct recv_frame { ++ struct list_head list; ++ struct sk_buff *pkt; ++ struct sk_buff *pkt_newalloc; ++ struct adapter *adapter; ++ u8 fragcnt; ++ int frame_tag; ++ struct rx_pkt_attrib attrib; ++ uint len; ++ u8 *rx_head; ++ u8 *rx_data; ++ u8 *rx_tail; ++ u8 *rx_end; ++ void *precvbuf; ++ struct sta_info *psta; ++ /* for A-MPDU Rx reordering buffer control */ ++ struct recv_reorder_ctrl *preorder_ctrl; ++}; ++ ++struct recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue); ++struct recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue); ++void rtw_init_recvframe(struct recv_frame *precvframe, ++ struct recv_priv *precvpriv); ++int rtw_free_recvframe(struct recv_frame *precvframe, ++ struct __queue *pfree_recv_queue); ++#define rtw_dequeue_recvframe(queue) rtw_alloc_recvframe(queue) ++int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue); ++int rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue); ++void rtw_free_recvframe_queue(struct __queue *pframequeue, ++ struct __queue *pfree_recv_queue); ++u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter); ++int rtw_enqueue_recvbuf_to_head(struct recv_buf *buf, struct __queue *queue); ++int rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue); ++struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue); ++ ++void rtw_reordering_ctrl_timeout_handler(void *pcontext); ++ ++static inline u8 *get_rxmem(struct recv_frame *precvframe) ++{ ++ /* always return rx_head... */ ++ if (precvframe == NULL) ++ return NULL; ++ return precvframe->rx_head; ++} ++ ++static inline u8 *get_rx_status(struct recv_frame *precvframe) ++{ ++ return get_rxmem(precvframe); ++} ++ ++static inline u8 *get_recvframe_data(struct recv_frame *precvframe) ++{ ++ /* always return rx_data */ ++ if (precvframe == NULL) ++ return NULL; ++ ++ return precvframe->rx_data; ++} ++ ++static inline u8 *recvframe_push(struct recv_frame *precvframe, int sz) ++{ ++ /* append data before rx_data */ ++ ++ /* add data to the start of recv_frame ++ * ++ * This function extends the used data area of the recv_frame at the buffer ++ * start. rx_data must be still larger than rx_head, after pushing. ++ */ ++ if (precvframe == NULL) ++ return NULL; ++ precvframe->rx_data -= sz ; ++ if (precvframe->rx_data < precvframe->rx_head) { ++ precvframe->rx_data += sz; ++ return NULL; ++ } ++ precvframe->len += sz; ++ return precvframe->rx_data; ++} ++ ++static inline u8 *recvframe_pull(struct recv_frame *precvframe, int sz) ++{ ++ /* rx_data += sz; move rx_data sz bytes hereafter */ ++ ++ /* used for extract sz bytes from rx_data, update rx_data and return ++ * the updated rx_data to the caller */ ++ ++ if (precvframe == NULL) ++ return NULL; ++ precvframe->rx_data += sz; ++ if (precvframe->rx_data > precvframe->rx_tail) { ++ precvframe->rx_data -= sz; ++ return NULL; ++ } ++ precvframe->len -= sz; ++ return precvframe->rx_data; ++} ++ ++static inline u8 *recvframe_put(struct recv_frame *precvframe, int sz) ++{ ++ /* used for append sz bytes from ptr to rx_tail, update rx_tail ++ * and return the updated rx_tail to the caller */ ++ /* after putting, rx_tail must be still larger than rx_end. */ ++ ++ if (precvframe == NULL) ++ return NULL; ++ ++ precvframe->rx_tail += sz; ++ ++ if (precvframe->rx_tail > precvframe->rx_end) { ++ precvframe->rx_tail -= sz; ++ return NULL; ++ } ++ precvframe->len += sz; ++ return precvframe->rx_tail; ++} ++ ++static inline u8 *recvframe_pull_tail(struct recv_frame *precvframe, int sz) ++{ ++ /* rmv data from rx_tail (by yitsen) */ ++ ++ /* used for extract sz bytes from rx_end, update rx_end and return ++ * the updated rx_end to the caller */ ++ /* after pulling, rx_end must be still larger than rx_data. */ ++ ++ if (precvframe == NULL) ++ return NULL; ++ precvframe->rx_tail -= sz; ++ if (precvframe->rx_tail < precvframe->rx_data) { ++ precvframe->rx_tail += sz; ++ return NULL; ++ } ++ precvframe->len -= sz; ++ return precvframe->rx_tail; ++} ++ ++static inline int get_recvframe_len(struct recv_frame *precvframe) ++{ ++ return precvframe->len; ++} ++ ++static inline s32 translate_percentage_to_dbm(u32 sig_stren_index) ++{ ++ s32 power; /* in dBm. */ ++ ++ /* Translate to dBm (x=0.5y-95). */ ++ power = (s32)((sig_stren_index + 1) >> 1); ++ power -= 95; ++ ++ return power; ++} ++ ++struct sta_info; ++ ++void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv); ++ ++void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtw_rf.h b/drivers/staging/r8188eu/include/rtw_rf.h +new file mode 100644 +index 000000000000..48129da9c93f +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_rf.h +@@ -0,0 +1,126 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_RF_H_ ++#define __RTW_RF_H_ ++ ++#include "rtw_cmd.h" ++ ++#define OFDM_PHY 1 ++#define MIXED_PHY 2 ++#define CCK_PHY 3 ++ ++#define NumRates (13) ++ ++/* slot time for 11g */ ++#define SHORT_SLOT_TIME 9 ++#define NON_SHORT_SLOT_TIME 20 ++ ++#define RTL8711_RF_MAX_SENS 6 ++#define RTL8711_RF_DEF_SENS 4 ++ ++/* We now define the following channels as the max channels in each ++ * channel plan. */ ++/* 2G, total 14 chnls */ ++/* {1,2,3,4,5,6,7,8,9,10,11,12,13,14} */ ++#define MAX_CHANNEL_NUM_2G 14 ++#define MAX_CHANNEL_NUM 14 /* 2.4 GHz only */ ++ ++#define NUM_REGULATORYS 1 ++ ++/* Country codes */ ++#define USA 0x555320 ++#define EUROPE 0x1 /* temp, should be provided later */ ++#define JAPAN 0x2 /* temp, should be provided later */ ++ ++struct regulatory_class { ++ u32 starting_freq; /* MHz, */ ++ u8 channel_set[MAX_CHANNEL_NUM]; ++ u8 channel_cck_power[MAX_CHANNEL_NUM]; /* dbm */ ++ u8 channel_ofdm_power[MAX_CHANNEL_NUM]; /* dbm */ ++ u8 txpower_limit; /* dbm */ ++ u8 channel_spacing; /* MHz */ ++ u8 modem; ++}; ++ ++enum capability { ++ cESS = 0x0001, ++ cIBSS = 0x0002, ++ cPollable = 0x0004, ++ cPollReq = 0x0008, ++ cPrivacy = 0x0010, ++ cShortPreamble = 0x0020, ++ cPBCC = 0x0040, ++ cChannelAgility = 0x0080, ++ cSpectrumMgnt = 0x0100, ++ cQos = 0x0200, /* For HCCA, use with CF-Pollable ++ * and CF-PollReq */ ++ cShortSlotTime = 0x0400, ++ cAPSD = 0x0800, ++ cRM = 0x1000, /* RRM (Radio Request Measurement) */ ++ cDSSS_OFDM = 0x2000, ++ cDelayedBA = 0x4000, ++ cImmediateBA = 0x8000, ++}; ++ ++enum _REG_PREAMBLE_MODE { ++ PREAMBLE_LONG = 1, ++ PREAMBLE_AUTO = 2, ++ PREAMBLE_SHORT = 3, ++}; ++ ++enum _RTL8712_RF_MIMO_CONFIG_ { ++ RTL8712_RFCONFIG_1T = 0x10, ++ RTL8712_RFCONFIG_2T = 0x20, ++ RTL8712_RFCONFIG_1R = 0x01, ++ RTL8712_RFCONFIG_2R = 0x02, ++ RTL8712_RFCONFIG_1T1R = 0x11, ++ RTL8712_RFCONFIG_1T2R = 0x12, ++ RTL8712_RFCONFIG_TURBO = 0x92, ++ RTL8712_RFCONFIG_2T2R = 0x22 ++}; ++ ++enum rf90_radio_path { ++ RF90_PATH_A = 0, /* Radio Path A */ ++ RF90_PATH_B = 1, /* Radio Path B */ ++ RF90_PATH_C = 2, /* Radio Path C */ ++ RF90_PATH_D = 3 /* Radio Path D */ ++}; ++ ++/* Bandwidth Offset */ ++#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0 ++#define HAL_PRIME_CHNL_OFFSET_LOWER 1 ++#define HAL_PRIME_CHNL_OFFSET_UPPER 2 ++ ++/* Represent Channel Width in HT Capabilities */ ++/* */ ++enum ht_channel_width { ++ HT_CHANNEL_WIDTH_20 = 0, ++ HT_CHANNEL_WIDTH_40 = 1, ++}; ++ ++/* */ ++/* Represent Extension Channel Offset in HT Capabilities */ ++/* This is available only in 40Mhz mode. */ ++/* */ ++enum ht_extchnl_offset { ++ HT_EXTCHNL_OFFSET_NO_EXT = 0, ++ HT_EXTCHNL_OFFSET_UPPER = 1, ++ HT_EXTCHNL_OFFSET_NO_DEF = 2, ++ HT_EXTCHNL_OFFSET_LOWER = 3, ++}; ++ ++/* 2007/11/15 MH Define different RF type. */ ++enum rt_rf_type_def { ++ RF_1T2R = 0, ++ RF_2T4R = 1, ++ RF_2T2R = 2, ++ RF_1T1R = 3, ++ RF_2T2R_GREEN = 4, ++ RF_819X_MAX_TYPE = 5, ++}; ++ ++u32 rtw_ch2freq(u32 ch); ++u32 rtw_freq2ch(u32 freq); ++ ++#endif /* _RTL8711_RF_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_security.h b/drivers/staging/r8188eu/include/rtw_security.h +new file mode 100644 +index 000000000000..ec6ecdb7bc98 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_security.h +@@ -0,0 +1,341 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __RTW_SECURITY_H_ ++#define __RTW_SECURITY_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#define _NO_PRIVACY_ 0x0 ++#define _WEP40_ 0x1 ++#define _TKIP_ 0x2 ++#define _TKIP_WTMIC_ 0x3 ++#define _AES_ 0x4 ++#define _WEP104_ 0x5 ++#define _WEP_WPA_MIXED_ 0x07 /* WEP + WPA */ ++#define _SMS4_ 0x06 ++ ++#define is_wep_enc(alg) (((alg) == _WEP40_) || ((alg) == _WEP104_)) ++ ++#define _WPA_IE_ID_ 0xdd ++#define _WPA2_IE_ID_ 0x30 ++ ++#define SHA256_MAC_LEN 32 ++#define AES_BLOCK_SIZE 16 ++#define AES_PRIV_SIZE (4 * 44) ++ ++enum { ++ ENCRYP_PROTOCOL_OPENSYS, /* open system */ ++ ENCRYP_PROTOCOL_WEP, /* WEP */ ++ ENCRYP_PROTOCOL_WPA, /* WPA */ ++ ENCRYP_PROTOCOL_WPA2, /* WPA2 */ ++ ENCRYP_PROTOCOL_WAPI, /* WAPI: Not support in this version */ ++ ENCRYP_PROTOCOL_MAX ++}; ++ ++#ifndef Ndis802_11AuthModeWPA2 ++#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1) ++#endif ++ ++#ifndef Ndis802_11AuthModeWPA2PSK ++#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2) ++#endif ++ ++union pn48 { ++ u64 val; ++ ++#ifdef __LITTLE_ENDIAN ++ struct { ++ u8 TSC0; ++ u8 TSC1; ++ u8 TSC2; ++ u8 TSC3; ++ u8 TSC4; ++ u8 TSC5; ++ u8 TSC6; ++ u8 TSC7; ++ } _byte_; ++ ++#elif defined(__BIG_ENDIAN) ++ ++ struct { ++ u8 TSC7; ++ u8 TSC6; ++ u8 TSC5; ++ u8 TSC4; ++ u8 TSC3; ++ u8 TSC2; ++ u8 TSC1; ++ u8 TSC0; ++ } _byte_; ++#endif ++}; ++ ++union Keytype { ++ u8 skey[16]; ++ u32 lkey[4]; ++}; ++ ++struct rt_pmkid_list { ++ u8 bUsed; ++ u8 Bssid[6]; ++ u8 PMKID[16]; ++ u8 SsidBuf[33]; ++ u8 *ssid_octet; ++ u16 ssid_length; ++}; ++ ++struct security_priv { ++ u32 dot11AuthAlgrthm; /* 802.11 auth, could be open, ++ * shared, 8021x and authswitch */ ++ u32 dot11PrivacyAlgrthm; /* This specify the privacy for ++ * shared auth. algorithm. */ ++ /* WEP */ ++ u32 dot11PrivacyKeyIndex; /* this is only valid for legendary ++ * wep, 0~3 for key id.(tx key index) */ ++ union Keytype dot11DefKey[4]; /* this is only valid for def. key */ ++ u32 dot11DefKeylen[4]; ++ u32 dot118021XGrpPrivacy; /* This specify the privacy algthm. ++ * used for Grp key */ ++ u32 dot118021XGrpKeyid; /* key id used for Grp Key ++ * ( tx key index) */ ++ union Keytype dot118021XGrpKey[4]; /* 802.1x Group Key, ++ * for inx0 and inx1 */ ++ union Keytype dot118021XGrptxmickey[4]; ++ union Keytype dot118021XGrprxmickey[4]; ++ union pn48 dot11Grptxpn; /* PN48 used for Grp Key xmit.*/ ++ union pn48 dot11Grprxpn; /* PN48 used for Grp Key recv.*/ ++#ifdef CONFIG_88EU_AP_MODE ++ /* extend security capabilities for AP_MODE */ ++ unsigned int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */ ++ unsigned int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */ ++ unsigned int wpa_group_cipher; ++ unsigned int wpa2_group_cipher; ++ unsigned int wpa_pairwise_cipher; ++ unsigned int wpa2_pairwise_cipher; ++#endif ++ u8 wps_ie[MAX_WPS_IE_LEN];/* added in assoc req */ ++ int wps_ie_len; ++ u8 binstallGrpkey; ++ u8 busetkipkey; ++ u8 bcheck_grpkey; ++ u8 bgrpkey_handshake; ++ s32 sw_encrypt;/* from registry_priv */ ++ s32 sw_decrypt;/* from registry_priv */ ++ s32 hw_decrypted;/* if the rx packets is hw_decrypted==false,i ++ * it means the hw has not been ready. */ ++ ++ /* keeps the auth_type & enc_status from upper layer ++ * ioctl(wpa_supplicant or wzc) */ ++ u32 ndisauthtype; /* NDIS_802_11_AUTHENTICATION_MODE */ ++ u32 ndisencryptstatus; /* NDIS_802_11_ENCRYPTION_STATUS */ ++ struct wlan_bssid_ex sec_bss; /* for joinbss (h2c buffer) usage */ ++ struct ndis_802_11_wep ndiswep; ++ u8 assoc_info[600]; ++ u8 szofcapability[256]; /* for wpa2 usage */ ++ u8 oidassociation[512]; /* for wpa/wpa2 usage */ ++ u8 authenticator_ie[256]; /* store ap security information element */ ++ u8 supplicant_ie[256]; /* store sta security information element */ ++ ++ /* for tkip countermeasure */ ++ u32 last_mic_err_time; ++ u8 btkip_countermeasure; ++ u8 btkip_wait_report; ++ u32 btkip_countermeasure_time; ++ ++ /* */ ++ /* For WPA2 Pre-Authentication. */ ++ /* */ ++ struct rt_pmkid_list PMKIDList[NUM_PMKID_CACHE]; ++ u8 PMKIDIndex; ++ u8 bWepDefaultKeyIdxSet; ++}; ++ ++#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst) \ ++do { \ ++ switch (psecuritypriv->dot11AuthAlgrthm) { \ ++ case dot11AuthAlgrthm_Open: \ ++ case dot11AuthAlgrthm_Shared: \ ++ case dot11AuthAlgrthm_Auto: \ ++ encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm; \ ++ break; \ ++ case dot11AuthAlgrthm_8021X: \ ++ if (bmcst) \ ++ encry_algo = (u8)psecuritypriv->dot118021XGrpPrivacy;\ ++ else \ ++ encry_algo = (u8)psta->dot118021XPrivacy; \ ++ break; \ ++ case dot11AuthAlgrthm_WAPI: \ ++ encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm; \ ++ break; \ ++ } \ ++} while (0) ++ ++#define SET_ICE_IV_LEN(iv_len, icv_len, encrypt) \ ++do { \ ++ switch (encrypt) { \ ++ case _WEP40_: \ ++ case _WEP104_: \ ++ iv_len = 4; \ ++ icv_len = 4; \ ++ break; \ ++ case _TKIP_: \ ++ iv_len = 8; \ ++ icv_len = 4; \ ++ break; \ ++ case _AES_: \ ++ iv_len = 8; \ ++ icv_len = 8; \ ++ break; \ ++ case _SMS4_: \ ++ iv_len = 18; \ ++ icv_len = 16; \ ++ break; \ ++ default: \ ++ iv_len = 0; \ ++ icv_len = 0; \ ++ break; \ ++ } \ ++} while (0) ++ ++#define GET_TKIP_PN(iv, dot11txpn) \ ++do { \ ++ dot11txpn._byte_.TSC0 = iv[2]; \ ++ dot11txpn._byte_.TSC1 = iv[0]; \ ++ dot11txpn._byte_.TSC2 = iv[4]; \ ++ dot11txpn._byte_.TSC3 = iv[5]; \ ++ dot11txpn._byte_.TSC4 = iv[6]; \ ++ dot11txpn._byte_.TSC5 = iv[7]; \ ++} while (0) ++ ++#define ROL32(A, n) (((A) << (n)) | (((A)>>(32-(n))) & ((1UL << (n)) - 1))) ++#define ROR32(A, n) ROL32((A), 32-(n)) ++ ++struct mic_data { ++ u32 K0, K1; /* Key */ ++ u32 L, R; /* Current state */ ++ u32 M; /* Message accumulator (single word) */ ++ u32 nBytesInM; /* # bytes in M */ ++}; ++ ++extern const u32 Te0[256]; ++extern const u32 Te1[256]; ++extern const u32 Te2[256]; ++extern const u32 Te3[256]; ++extern const u32 Te4[256]; ++extern const u32 Td0[256]; ++extern const u32 Td1[256]; ++extern const u32 Td2[256]; ++extern const u32 Td3[256]; ++extern const u32 Td4[256]; ++extern const u32 rcon[10]; ++extern const u8 Td4s[256]; ++extern const u8 rcons[10]; ++ ++#define RCON(i) (rcons[(i)] << 24) ++ ++static inline u32 rotr(u32 val, int bits) ++{ ++ return (val >> bits) | (val << (32 - bits)); ++} ++ ++#define TE0(i) Te0[((i) >> 24) & 0xff] ++#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) ++#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) ++#define TE3(i) rotr(Te0[(i) & 0xff], 24) ++#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) ++#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) ++#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) ++#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) ++#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) ++#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) ++#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) ++#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) ++#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) ++ ++#define TD0(i) Td0[((i) >> 24) & 0xff] ++#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) ++#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) ++#define TD3(i) rotr(Td0[(i) & 0xff], 24) ++#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) ++#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) ++#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) ++#define TD44(i) (Td4s[(i) & 0xff]) ++#define TD0_(i) Td0[(i) & 0xff] ++#define TD1_(i) rotr(Td0[(i) & 0xff], 8) ++#define TD2_(i) rotr(Td0[(i) & 0xff], 16) ++#define TD3_(i) rotr(Td0[(i) & 0xff], 24) ++ ++#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ ++ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) ++ ++#define PUTU32(ct, st) { \ ++(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ ++(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } ++ ++#define WPA_GET_BE32(a) ((((u32)(a)[0]) << 24) | (((u32)(a)[1]) << 16) | \ ++ (((u32)(a)[2]) << 8) | ((u32)(a)[3])) ++ ++#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_BE64(a, val) \ ++ do { \ ++ (a)[0] = (u8)(((u64)(val)) >> 56); \ ++ (a)[1] = (u8)(((u64)(val)) >> 48); \ ++ (a)[2] = (u8)(((u64)(val)) >> 40); \ ++ (a)[3] = (u8)(((u64)(val)) >> 32); \ ++ (a)[4] = (u8)(((u64)(val)) >> 24); \ ++ (a)[5] = (u8)(((u64)(val)) >> 16); \ ++ (a)[6] = (u8)(((u64)(val)) >> 8); \ ++ (a)[7] = (u8)(((u64)(val)) & 0xff); \ ++ } while (0) ++ ++/* ===== start - public domain SHA256 implementation ===== */ ++ ++/* This is based on SHA256 implementation in LibTomCrypt that was released into ++ * public domain by Tom St Denis. */ ++ ++/* Various logical functions */ ++#define RORc(x, y) \ ++ (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y)&31)) | \ ++ ((unsigned long)(x) << (unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) ++#define Ch(x, y ,z) (z ^ (x & (y ^ z))) ++#define Maj(x, y, z) (((x | y) & z) | (x & y)) ++#define S(x, n) RORc((x), (n)) ++#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) ++#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) ++#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) ++#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) ++#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) ++#ifndef MIN ++#define MIN(x, y) (((x) < (y)) ? (x) : (y)) ++#endif ++ ++void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key); ++void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b); ++void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nBytes); ++void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst); ++void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, ++ u8 *Miccode, u8 priority); ++u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe); ++u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe); ++void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe); ++u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe); ++u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe); ++void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe); ++void rtw_use_tkipkey_handler(void *FunctionContext); ++ ++#endif /* __RTL871X_SECURITY_H_ */ +diff --git a/drivers/staging/r8188eu/include/rtw_sreset.h b/drivers/staging/r8188eu/include/rtw_sreset.h +new file mode 100644 +index 000000000000..4e97997c305b +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_sreset.h +@@ -0,0 +1,34 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#ifndef _RTW_SRESET_C_ ++#define _RTW_SRESET_C_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++struct sreset_priv { ++ struct mutex silentreset_mutex; ++ u8 silent_reset_inprogress; ++ u8 wifi_error_status; ++ unsigned long last_tx_time; ++ unsigned long last_tx_complete_time; ++}; ++ ++#include "rtl8188e_hal.h" ++ ++#define WIFI_STATUS_SUCCESS 0 ++#define USB_VEN_REQ_CMD_FAIL BIT(0) ++#define USB_READ_PORT_FAIL BIT(1) ++#define USB_WRITE_PORT_FAIL BIT(2) ++#define WIFI_MAC_TXDMA_ERROR BIT(3) ++#define WIFI_TX_HANG BIT(4) ++#define WIFI_RX_HANG BIT(5) ++#define WIFI_IF_NOT_EXIST BIT(6) ++ ++void sreset_init_value(struct adapter *padapter); ++void sreset_reset_value(struct adapter *padapter); ++u8 sreset_get_wifi_status(struct adapter *padapter); ++void sreset_set_wifi_error_status(struct adapter *padapter, u32 status); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/rtw_xmit.h b/drivers/staging/r8188eu/include/rtw_xmit.h +new file mode 100644 +index 000000000000..5f6e2402e5c4 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/rtw_xmit.h +@@ -0,0 +1,367 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _RTW_XMIT_H_ ++#define _RTW_XMIT_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++#define MAX_XMITBUF_SZ (20480) /* 20k */ ++#define NR_XMITBUFF (4) ++ ++#define XMITBUF_ALIGN_SZ 4 ++ ++/* xmit extension buff defination */ ++#define MAX_XMIT_EXTBUF_SZ (1536) ++#define NR_XMIT_EXTBUFF (32) ++ ++#define MAX_NUMBLKS (1) ++ ++#define XMIT_VO_QUEUE (0) ++#define XMIT_VI_QUEUE (1) ++#define XMIT_BE_QUEUE (2) ++#define XMIT_BK_QUEUE (3) ++ ++#define VO_QUEUE_INX 0 ++#define VI_QUEUE_INX 1 ++#define BE_QUEUE_INX 2 ++#define BK_QUEUE_INX 3 ++#define BCN_QUEUE_INX 4 ++#define MGT_QUEUE_INX 5 ++#define HIGH_QUEUE_INX 6 ++#define TXCMD_QUEUE_INX 7 ++ ++#define HW_QUEUE_ENTRY 8 ++ ++#define WEP_IV(pattrib_iv, dot11txpn, keyidx)\ ++do {\ ++ pattrib_iv[0] = dot11txpn._byte_.TSC0;\ ++ pattrib_iv[1] = dot11txpn._byte_.TSC1;\ ++ pattrib_iv[2] = dot11txpn._byte_.TSC2;\ ++ pattrib_iv[3] = ((keyidx & 0x3)<<6);\ ++ dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0 : (dot11txpn.val+1);\ ++} while (0) ++ ++#define TKIP_IV(pattrib_iv, dot11txpn, keyidx)\ ++do {\ ++ pattrib_iv[0] = dot11txpn._byte_.TSC1;\ ++ pattrib_iv[1] = (dot11txpn._byte_.TSC1 | 0x20) & 0x7f;\ ++ pattrib_iv[2] = dot11txpn._byte_.TSC0;\ ++ pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);\ ++ pattrib_iv[4] = dot11txpn._byte_.TSC2;\ ++ pattrib_iv[5] = dot11txpn._byte_.TSC3;\ ++ pattrib_iv[6] = dot11txpn._byte_.TSC4;\ ++ pattrib_iv[7] = dot11txpn._byte_.TSC5;\ ++ dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : (dot11txpn.val+1);\ ++} while (0) ++ ++#define AES_IV(pattrib_iv, dot11txpn, keyidx)\ ++do { \ ++ pattrib_iv[0] = dot11txpn._byte_.TSC0; \ ++ pattrib_iv[1] = dot11txpn._byte_.TSC1; \ ++ pattrib_iv[2] = 0; \ ++ pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6); \ ++ pattrib_iv[4] = dot11txpn._byte_.TSC2; \ ++ pattrib_iv[5] = dot11txpn._byte_.TSC3; \ ++ pattrib_iv[6] = dot11txpn._byte_.TSC4; \ ++ pattrib_iv[7] = dot11txpn._byte_.TSC5; \ ++ dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : (dot11txpn.val+1);\ ++} while (0) ++ ++#define HWXMIT_ENTRY 4 ++ ++#define TXDESC_SIZE 32 ++ ++#define PACKET_OFFSET_SZ (8) ++#define TXDESC_OFFSET (TXDESC_SIZE + PACKET_OFFSET_SZ) ++ ++struct tx_desc { ++ /* DWORD 0 */ ++ __le32 txdw0; ++ __le32 txdw1; ++ __le32 txdw2; ++ __le32 txdw3; ++ __le32 txdw4; ++ __le32 txdw5; ++ __le32 txdw6; ++ __le32 txdw7; ++}; ++ ++union txdesc { ++ struct tx_desc txdesc; ++ unsigned int value[TXDESC_SIZE>>2]; ++}; ++ ++struct hw_xmit { ++ struct __queue *sta_queue; ++ int accnt; ++}; ++ ++/* reduce size */ ++struct pkt_attrib { ++ u8 type; ++ u8 subtype; ++ u8 bswenc; ++ u8 dhcp_pkt; ++ u16 ether_type; ++ u16 seqnum; ++ u16 pkt_hdrlen; /* the original 802.3 pkt header len */ ++ u16 hdrlen; /* the WLAN Header Len */ ++ u32 pktlen; /* the original 802.3 pkt raw_data len (not include ++ * ether_hdr data) */ ++ u32 last_txcmdsz; ++ u8 nr_frags; ++ u8 encrypt; /* when 0 indicate no encrypt. when non-zero, ++ * indicate the encrypt algorith */ ++ u8 iv_len; ++ u8 icv_len; ++ u8 iv[18]; ++ u8 icv[16]; ++ u8 priority; ++ u8 ack_policy; ++ u8 mac_id; ++ u8 vcs_mode; /* virtual carrier sense method */ ++ u8 dst[ETH_ALEN] __aligned(2); ++ u8 src[ETH_ALEN] __aligned(2); ++ u8 ta[ETH_ALEN] __aligned(2); ++ u8 ra[ETH_ALEN] __aligned(2); ++ u8 key_idx; ++ u8 qos_en; ++ u8 ht_en; ++ u8 raid;/* rate adpative id */ ++ u8 bwmode; ++ u8 ch_offset;/* PRIME_CHNL_OFFSET */ ++ u8 sgi;/* short GI */ ++ u8 ampdu_en;/* tx ampdu enable */ ++ u8 mdata;/* more data bit */ ++ u8 pctrl;/* per packet txdesc control enable */ ++ u8 triggered;/* for ap mode handling Power Saving sta */ ++ u8 qsel; ++ u8 eosp; ++ u8 rate; ++ u8 intel_proxim; ++ u8 retry_ctrl; ++ struct sta_info *psta; ++}; ++ ++#define WLANHDR_OFFSET 64 ++ ++#define NULL_FRAMETAG (0x0) ++#define DATA_FRAMETAG 0x01 ++#define L2_FRAMETAG 0x02 ++#define MGNT_FRAMETAG 0x03 ++#define AMSDU_FRAMETAG 0x04 ++ ++#define EII_FRAMETAG 0x05 ++#define IEEE8023_FRAMETAG 0x06 ++ ++#define MP_FRAMETAG 0x07 ++ ++#define TXAGG_FRAMETAG 0x08 ++ ++struct submit_ctx { ++ u32 submit_time; /* */ ++ u32 timeout_ms; /* <0: not synchronous, 0: wait forever, >0: up to ms waiting */ ++ int status; /* status for operation */ ++ struct completion done; ++}; ++ ++enum { ++ RTW_SCTX_SUBMITTED = -1, ++ RTW_SCTX_DONE_SUCCESS = 0, ++ RTW_SCTX_DONE_UNKNOWN, ++ RTW_SCTX_DONE_TIMEOUT, ++ RTW_SCTX_DONE_BUF_ALLOC, ++ RTW_SCTX_DONE_BUF_FREE, ++ RTW_SCTX_DONE_WRITE_PORT_ERR, ++ RTW_SCTX_DONE_TX_DESC_NA, ++ RTW_SCTX_DONE_TX_DENY, ++ RTW_SCTX_DONE_CCX_PKT_FAIL, ++ RTW_SCTX_DONE_DRV_STOP, ++ RTW_SCTX_DONE_DEV_REMOVE, ++}; ++ ++void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms); ++int rtw_sctx_wait(struct submit_ctx *sctx); ++void rtw_sctx_done_err(struct submit_ctx **sctx, int status); ++void rtw_sctx_done(struct submit_ctx **sctx); ++ ++struct xmit_buf { ++ struct list_head list; ++ struct adapter *padapter; ++ u8 *pallocated_buf; ++ u8 *pbuf; ++ void *priv_data; ++ u16 ext_tag; /* 0: Normal xmitbuf, 1: extension xmitbuf. */ ++ u16 flags; ++ u32 alloc_sz; ++ u32 len; ++ struct submit_ctx *sctx; ++ u32 ff_hwaddr; ++ struct urb *pxmit_urb[8]; ++ dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */ ++ u8 bpending[8]; ++ int last[8]; ++}; ++ ++struct xmit_frame { ++ struct list_head list; ++ struct pkt_attrib attrib; ++ struct sk_buff *pkt; ++ int frame_tag; ++ struct adapter *padapter; ++ u8 *buf_addr; ++ struct xmit_buf *pxmitbuf; ++ ++ u8 agg_num; ++ s8 pkt_offset; ++ u8 ack_report; ++}; ++ ++struct tx_servq { ++ struct list_head tx_pending; ++ struct __queue sta_pending; ++ int qcnt; ++}; ++ ++struct sta_xmit_priv { ++ spinlock_t lock; ++ int option; ++ int apsd_setting; /* When bit mask is on, the associated edca ++ * queue supports APSD. */ ++ struct tx_servq be_q; /* priority == 0,3 */ ++ struct tx_servq bk_q; /* priority == 1,2 */ ++ struct tx_servq vi_q; /* priority == 4,5 */ ++ struct tx_servq vo_q; /* priority == 6,7 */ ++ struct list_head legacy_dz; ++ struct list_head apsd; ++ u16 txseq_tid[16]; ++}; ++ ++struct hw_txqueue { ++ volatile int head; ++ volatile int tail; ++ volatile int free_sz; /* in units of 64 bytes */ ++ volatile int free_cmdsz; ++ volatile int txsz[8]; ++ uint ff_hwaddr; ++ uint cmd_hwaddr; ++ int ac_tag; ++}; ++ ++struct agg_pkt_info { ++ u16 offset; ++ u16 pkt_len; ++}; ++ ++struct xmit_priv { ++ spinlock_t lock; ++ struct semaphore xmit_sema; ++ struct semaphore terminate_xmitthread_sema; ++ struct __queue be_pending; ++ struct __queue bk_pending; ++ struct __queue vi_pending; ++ struct __queue vo_pending; ++ struct __queue bm_pending; ++ u8 *pallocated_frame_buf; ++ u8 *pxmit_frame_buf; ++ uint free_xmitframe_cnt; ++ struct __queue free_xmit_queue; ++ uint frag_len; ++ struct adapter *adapter; ++ u8 vcs_setting; ++ u8 vcs; ++ u8 vcs_type; ++ u64 tx_bytes; ++ u64 tx_pkts; ++ u64 tx_drop; ++ u64 last_tx_bytes; ++ u64 last_tx_pkts; ++ struct hw_xmit *hwxmits; ++ u8 hwxmit_entry; ++ u8 wmm_para_seq[4];/* sequence for wmm ac parameter strength ++ * from large to small. it's value is 0->vo, ++ * 1->vi, 2->be, 3->bk. */ ++ struct semaphore tx_retevt;/* all tx return event; */ ++ u8 txirp_cnt;/* */ ++ struct tasklet_struct xmit_tasklet; ++ /* per AC pending irp */ ++ int beq_cnt; ++ int bkq_cnt; ++ int viq_cnt; ++ int voq_cnt; ++ struct __queue free_xmitbuf_queue; ++ struct __queue pending_xmitbuf_queue; ++ u8 *pallocated_xmitbuf; ++ u8 *pxmitbuf; ++ uint free_xmitbuf_cnt; ++ struct __queue free_xmit_extbuf_queue; ++ u8 *pallocated_xmit_extbuf; ++ u8 *pxmit_extbuf; ++ uint free_xmit_extbuf_cnt; ++ u16 nqos_ssn; ++ int ack_tx; ++ struct mutex ack_tx_mutex; ++ struct submit_ctx ack_tx_ops; ++}; ++ ++struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv); ++s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, ++ struct xmit_buf *pxmitbuf); ++struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv); ++s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, ++ struct xmit_buf *pxmitbuf); ++void rtw_count_tx_stats(struct adapter *padapter, ++ struct xmit_frame *pxmitframe, int sz); ++void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len); ++s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, ++ struct pkt_attrib *pattrib); ++s32 rtw_put_snap(u8 *data, u16 h_proto); ++ ++struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv); ++s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, ++ struct xmit_frame *pxmitframe); ++void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, ++ struct __queue *pframequeue); ++struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, ++ struct sta_info *psta, int up, u8 *ac); ++s32 rtw_xmitframe_enqueue(struct adapter *padapter, ++ struct xmit_frame *pxmitframe); ++struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, ++ struct hw_xmit *phwxmit_i, int entry); ++ ++s32 rtw_xmit_classifier(struct adapter *padapter, ++ struct xmit_frame *pxmitframe); ++u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib); ++#define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue(&f->attrib) ++s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, ++ struct xmit_frame *pxmitframe); ++s32 _rtw_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag); ++void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv); ++s32 rtw_txframes_pending(struct adapter *padapter); ++s32 rtw_txframes_sta_ac_pending(struct adapter *padapter, ++ struct pkt_attrib *pattrib); ++void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry); ++s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter); ++void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv); ++void rtw_alloc_hwxmits(struct adapter *padapter); ++void rtw_free_hwxmits(struct adapter *padapter); ++s32 rtw_xmit(struct adapter *padapter, struct sk_buff **pkt); ++ ++#if defined(CONFIG_88EU_AP_MODE) ++int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_frame *pxmitframe); ++void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta); ++void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta); ++void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *psta); ++#endif ++ ++u8 qos_acm(u8 acm_mask, u8 priority); ++u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe); ++int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms); ++void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status); ++ ++/* include after declaring struct xmit_buf, in order to avoid warning */ ++#include "xmit_osdep.h" ++ ++#endif /* _RTL871X_XMIT_H_ */ +diff --git a/drivers/staging/r8188eu/include/sta_info.h b/drivers/staging/r8188eu/include/sta_info.h +new file mode 100644 +index 000000000000..8ff99fc6381d +--- /dev/null ++++ b/drivers/staging/r8188eu/include/sta_info.h +@@ -0,0 +1,368 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __STA_INFO_H_ ++#define __STA_INFO_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "wifi.h" ++ ++#define IBSS_START_MAC_ID 2 ++#define NUM_STA 32 ++#define NUM_ACL 16 ++ ++/* if mode ==0, then the sta is allowed once the addr is hit. */ ++/* if mode ==1, then the sta is rejected once the addr is non-hit. */ ++struct rtw_wlan_acl_node { ++ struct list_head list; ++ u8 addr[ETH_ALEN]; ++ u8 valid; ++}; ++ ++/* mode=0, disable */ ++/* mode=1, accept unless in deny list */ ++/* mode=2, deny unless in accept list */ ++struct wlan_acl_pool { ++ int mode; ++ int num; ++ struct rtw_wlan_acl_node aclnode[NUM_ACL]; ++ struct __queue acl_node_q; ++}; ++ ++struct rssi_sta { ++ s32 UndecoratedSmoothedPWDB; ++ s32 UndecoratedSmoothedCCK; ++ s32 UndecoratedSmoothedOFDM; ++ u64 PacketMap; ++ u8 ValidBit; ++}; ++ ++struct stainfo_stats { ++ u64 rx_mgnt_pkts; ++ u64 rx_beacon_pkts; ++ u64 rx_probereq_pkts; ++ u64 rx_probersp_pkts; ++ u64 rx_probersp_bm_pkts; ++ u64 rx_probersp_uo_pkts; ++ u64 rx_ctrl_pkts; ++ u64 rx_data_pkts; ++ ++ u64 last_rx_mgnt_pkts; ++ u64 last_rx_beacon_pkts; ++ u64 last_rx_probereq_pkts; ++ u64 last_rx_probersp_pkts; ++ u64 last_rx_probersp_bm_pkts; ++ u64 last_rx_probersp_uo_pkts; ++ u64 last_rx_ctrl_pkts; ++ u64 last_rx_data_pkts; ++ u64 rx_bytes; ++ u64 rx_drops; ++ u64 tx_pkts; ++ u64 tx_bytes; ++ u64 tx_drops; ++}; ++ ++struct sta_info { ++ spinlock_t lock; ++ struct list_head list; /* free_sta_queue */ ++ struct list_head hash_list; /* sta_hash */ ++ ++ struct sta_xmit_priv sta_xmitpriv; ++ struct sta_recv_priv sta_recvpriv; ++ ++ struct __queue sleep_q; ++ unsigned int sleepq_len; ++ ++ uint state; ++ uint aid; ++ uint mac_id; ++ uint qos_option; ++ u8 hwaddr[ETH_ALEN]; ++ ++ uint ieee8021x_blocked; /* 0: allowed, 1:blocked */ ++ uint dot118021XPrivacy; /* aes, tkip... */ ++ union Keytype dot11tkiptxmickey; ++ union Keytype dot11tkiprxmickey; ++ union Keytype dot118021x_UncstKey; ++ union pn48 dot11txpn; /* PN48 used for Unicast xmit. */ ++ union pn48 dot11rxpn; /* PN48 used for Unicast recv. */ ++ u8 bssrateset[16]; ++ u32 bssratelen; ++ s32 rssi; ++ s32 signal_quality; ++ ++ u8 cts2self; ++ u8 rtsen; ++ ++ u8 raid; ++ u8 init_rate; ++ u32 ra_mask; ++ u8 wireless_mode; /* NETWORK_TYPE */ ++ struct stainfo_stats sta_stats; ++ ++ /* for A-MPDU TX, ADDBA timeout check */ ++ struct timer_list addba_retry_timer; ++ ++ /* for A-MPDU Rx reordering buffer control */ ++ struct recv_reorder_ctrl recvreorder_ctrl[16]; ++ ++ /* for A-MPDU Tx */ ++ /* unsigned char ampdu_txen_bitmap; */ ++ u16 BA_starting_seqctrl[16]; ++ ++ struct ht_priv htpriv; ++ ++ /* Notes: */ ++ /* STA_Mode: */ ++ /* curr_network(mlme_priv/security_priv/qos/ht) + ++ * sta_info: (STA & AP) CAP/INFO */ ++ /* scan_q: AP CAP/INFO */ ++ ++ /* AP_Mode: */ ++ /* curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO */ ++ /* sta_info: (AP & STA) CAP/INFO */ ++ ++ struct list_head asoc_list; ++#ifdef CONFIG_88EU_AP_MODE ++ struct list_head auth_list; ++ ++ unsigned int expire_to; ++ unsigned int auth_seq; ++ unsigned int authalg; ++ unsigned char chg_txt[128]; ++ ++ u16 capability; ++ int flags; ++ ++ int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */ ++ int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */ ++ int wpa_group_cipher; ++ int wpa2_group_cipher; ++ int wpa_pairwise_cipher; ++ int wpa2_pairwise_cipher; ++ ++ u8 bpairwise_key_installed; ++ ++ u8 wpa_ie[32]; ++ ++ u8 nonerp_set; ++ u8 no_short_slot_time_set; ++ u8 no_short_preamble_set; ++ u8 no_ht_gf_set; ++ u8 no_ht_set; ++ u8 ht_20mhz_set; ++ ++ unsigned int tx_ra_bitmap; ++ u8 qos_info; ++ ++ u8 max_sp_len; ++ u8 uapsd_bk;/* BIT(0): Delivery enabled, BIT(1): Trigger enabled */ ++ u8 uapsd_be; ++ u8 uapsd_vi; ++ u8 uapsd_vo; ++ ++ u8 has_legacy_ac; ++ unsigned int sleepq_ac_len; ++#endif /* CONFIG_88EU_AP_MODE */ ++ ++#ifdef CONFIG_88EU_P2P ++ /* p2p priv data */ ++ u8 is_p2p_device; ++ u8 p2p_status_code; ++ ++ /* p2p client info */ ++ u8 dev_addr[ETH_ALEN]; ++ u8 dev_cap; ++ u16 config_methods; ++ u8 primary_dev_type[8]; ++ u8 num_of_secdev_type; ++ u8 secdev_types_list[32];/* 32/8 == 4; */ ++ u16 dev_name_len; ++ u8 dev_name[32]; ++#endif /* CONFIG_88EU_P2P */ ++ u8 under_exist_checking; ++ u8 keep_alive_trycnt; ++ ++ /* for DM */ ++ struct rssi_sta rssi_stat; ++ ++ /* ================ODM Relative Info======================= */ ++ /* Please be careful, don't declare too much structure here. ++ * It will cost memory * STA support num. */ ++ /* 2011/10/20 MH Add for ODM STA info. */ ++ /* Driver Write */ ++ u8 bValid; /* record the sta status link or not? */ ++ u8 IOTPeer; /* Enum value. HT_IOT_PEER_E */ ++ u8 rssi_level; /* for Refresh RA mask */ ++ /* ODM Write */ ++ /* 1 PHY_STATUS_INFO */ ++ u8 RSSI_Path[4]; /* */ ++ u8 RSSI_Ave; ++ u8 RXEVM[4]; ++ u8 RXSNR[4]; ++ ++ /* ================ODM Relative Info======================= */ ++ /* */ ++ ++ /* To store the sequence number of received management frame */ ++ u16 RxMgmtFrameSeqNum; ++}; ++ ++#define sta_rx_pkts(sta) \ ++ (sta->sta_stats.rx_mgnt_pkts \ ++ + sta->sta_stats.rx_ctrl_pkts \ ++ + sta->sta_stats.rx_data_pkts) ++ ++#define sta_last_rx_pkts(sta) \ ++ (sta->sta_stats.last_rx_mgnt_pkts \ ++ + sta->sta_stats.last_rx_ctrl_pkts \ ++ + sta->sta_stats.last_rx_data_pkts) ++ ++#define sta_rx_data_pkts(sta) \ ++ (sta->sta_stats.rx_data_pkts) ++ ++#define sta_last_rx_data_pkts(sta) \ ++ (sta->sta_stats.last_rx_data_pkts) ++ ++#define sta_rx_mgnt_pkts(sta) \ ++ (sta->sta_stats.rx_mgnt_pkts) ++ ++#define sta_last_rx_mgnt_pkts(sta) \ ++ (sta->sta_stats.last_rx_mgnt_pkts) ++ ++#define sta_rx_beacon_pkts(sta) \ ++ (sta->sta_stats.rx_beacon_pkts) ++ ++#define sta_last_rx_beacon_pkts(sta) \ ++ (sta->sta_stats.last_rx_beacon_pkts) ++ ++#define sta_rx_probereq_pkts(sta) \ ++ (sta->sta_stats.rx_probereq_pkts) ++ ++#define sta_last_rx_probereq_pkts(sta) \ ++ (sta->sta_stats.last_rx_probereq_pkts) ++ ++#define sta_rx_probersp_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_pkts) ++ ++#define sta_last_rx_probersp_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_pkts) ++ ++#define sta_rx_probersp_bm_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_bm_pkts) ++ ++#define sta_last_rx_probersp_bm_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_bm_pkts) ++ ++#define sta_rx_probersp_uo_pkts(sta) \ ++ (sta->sta_stats.rx_probersp_uo_pkts) ++ ++#define sta_last_rx_probersp_uo_pkts(sta) \ ++ (sta->sta_stats.last_rx_probersp_uo_pkts) ++ ++#define sta_update_last_rx_pkts(sta) \ ++do { \ ++ sta->sta_stats.last_rx_mgnt_pkts = sta->sta_stats.rx_mgnt_pkts; \ ++ sta->sta_stats.last_rx_beacon_pkts = sta->sta_stats.rx_beacon_pkts; \ ++ sta->sta_stats.last_rx_probereq_pkts = sta->sta_stats.rx_probereq_pkts; \ ++ sta->sta_stats.last_rx_probersp_pkts = sta->sta_stats.rx_probersp_pkts; \ ++ sta->sta_stats.last_rx_probersp_bm_pkts = sta->sta_stats.rx_probersp_bm_pkts; \ ++ sta->sta_stats.last_rx_probersp_uo_pkts = sta->sta_stats.rx_probersp_uo_pkts; \ ++ sta->sta_stats.last_rx_ctrl_pkts = sta->sta_stats.rx_ctrl_pkts; \ ++ sta->sta_stats.last_rx_data_pkts = sta->sta_stats.rx_data_pkts; \ ++} while (0) ++ ++#define STA_RX_PKTS_ARG(sta) \ ++ sta->sta_stats.rx_mgnt_pkts \ ++ , sta->sta_stats.rx_ctrl_pkts \ ++ , sta->sta_stats.rx_data_pkts ++ ++#define STA_LAST_RX_PKTS_ARG(sta) \ ++ sta->sta_stats.last_rx_mgnt_pkts \ ++ , sta->sta_stats.last_rx_ctrl_pkts \ ++ , sta->sta_stats.last_rx_data_pkts ++ ++#define STA_RX_PKTS_DIFF_ARG(sta) \ ++ sta->sta_stats.rx_mgnt_pkts - sta->sta_stats.last_rx_mgnt_pkts \ ++ , sta->sta_stats.rx_ctrl_pkts - sta->sta_stats.last_rx_ctrl_pkts \ ++ , sta->sta_stats.rx_data_pkts - sta->sta_stats.last_rx_data_pkts ++ ++#define STA_PKTS_FMT "(m:%llu, c:%llu, d:%llu)" ++ ++struct sta_priv { ++ u8 *pallocated_stainfo_buf; ++ u8 *pstainfo_buf; ++ struct __queue free_sta_queue; ++ ++ spinlock_t sta_hash_lock; ++ struct list_head sta_hash[NUM_STA]; ++ int asoc_sta_count; ++ struct __queue sleep_q; ++ struct __queue wakeup_q; ++ ++ struct adapter *padapter; ++ ++ spinlock_t asoc_list_lock; ++ struct list_head asoc_list; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ struct list_head auth_list; ++ spinlock_t auth_list_lock; ++ u8 asoc_list_cnt; ++ u8 auth_list_cnt; ++ ++ unsigned int auth_to; /* sec, time to expire in authenticating. */ ++ unsigned int assoc_to; /* sec, time to expire before associating. */ ++ unsigned int expire_to; /* sec , time to expire after associated. */ ++ ++ /* pointers to STA info; based on allocated AID or NULL if AID free ++ * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 ++ * and so on ++ */ ++ struct sta_info *sta_aid[NUM_STA]; ++ ++ u16 sta_dz_bitmap;/* only support 15 stations, station aid bitmap ++ * for sleeping sta. */ ++ u16 tim_bitmap; /* only support 15 stations, aid=0~15 mapping ++ * bit0~bit15 */ ++ ++ u16 max_num_sta; ++ ++ struct wlan_acl_pool acl_list; ++#endif ++ ++}; ++ ++static inline u32 wifi_mac_hash(u8 *mac) ++{ ++ u32 x; ++ ++ x = mac[0]; ++ x = (x << 2) ^ mac[1]; ++ x = (x << 2) ^ mac[2]; ++ x = (x << 2) ^ mac[3]; ++ x = (x << 2) ^ mac[4]; ++ x = (x << 2) ^ mac[5]; ++ ++ x ^= x >> 8; ++ x = x & (NUM_STA - 1); ++ return x; ++} ++ ++extern u32 _rtw_init_sta_priv(struct sta_priv *pstapriv); ++extern u32 _rtw_free_sta_priv(struct sta_priv *pstapriv); ++ ++#define stainfo_offset_valid(offset) (offset < NUM_STA && offset >= 0) ++int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta); ++struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int off); ++ ++extern struct sta_info *rtw_alloc_stainfo(struct sta_priv *stapriv, u8 *hwaddr); ++extern u32 rtw_free_stainfo(struct adapter *adapt, struct sta_info *psta); ++extern void rtw_free_all_stainfo(struct adapter *adapt); ++extern struct sta_info *rtw_get_stainfo(struct sta_priv *stapriv, u8 *hwaddr); ++extern u32 rtw_init_bcmc_stainfo(struct adapter *adapt); ++extern struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter); ++extern u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr); ++ ++#endif /* _STA_INFO_H_ */ +diff --git a/drivers/staging/r8188eu/include/usb_ops.h b/drivers/staging/r8188eu/include/usb_ops.h +new file mode 100644 +index 000000000000..c53cc54b6b87 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/usb_ops.h +@@ -0,0 +1,72 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __USB_OPS_H_ ++#define __USB_OPS_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "osdep_intf.h" ++ ++#define REALTEK_USB_VENQT_READ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) ++#define REALTEK_USB_VENQT_WRITE (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) ++#define REALTEK_USB_VENQT_CMD_REQ 0x05 ++#define REALTEK_USB_VENQT_CMD_IDX 0x00 ++ ++#define ALIGNMENT_UNIT 16 ++#define MAX_VENDOR_REQ_CMD_SIZE 254 /* 8188cu SIE Support */ ++#define MAX_USB_IO_CTL_SIZE (MAX_VENDOR_REQ_CMD_SIZE + ALIGNMENT_UNIT) ++ ++#include "usb_ops_linux.h" ++ ++void rtl8188eu_set_hw_type(struct adapter *padapter); ++#define hal_set_hw_type rtl8188eu_set_hw_type ++void rtl8188eu_set_intf_ops(struct _io_ops *pops); ++#define usb_set_intf_ops rtl8188eu_set_intf_ops ++ ++/* ++ * Increase and check if the continual_urb_error of this @param dvobjprivei ++ * is larger than MAX_CONTINUAL_URB_ERR ++ * @return true: ++ * @return false: ++ */ ++static inline int rtw_inc_and_chk_continual_urb_error(struct dvobj_priv *dvobj) ++{ ++ int ret = false; ++ int value; ++ value = atomic_inc_return(&dvobj->continual_urb_error); ++ if (value > MAX_CONTINUAL_URB_ERR) { ++ DBG_88E("[dvobj:%p][ERROR] continual_urb_error:%d > %d\n", ++ dvobj, value, MAX_CONTINUAL_URB_ERR); ++ ret = true; ++ } ++ return ret; ++} ++ ++/* ++* Set the continual_urb_error of this @param dvobjprive to 0 ++*/ ++static inline void rtw_reset_continual_urb_error(struct dvobj_priv *dvobj) ++{ ++ atomic_set(&dvobj->continual_urb_error, 0); ++} ++ ++#define USB_HIGH_SPEED_BULK_SIZE 512 ++#define USB_FULL_SPEED_BULK_SIZE 64 ++ ++static inline u8 rtw_usb_bulk_size_boundary(struct adapter *padapter, ++ int buf_len) ++{ ++ u8 rst = true; ++ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); ++ ++ if (pdvobjpriv->ishighspeed) ++ rst = (0 == (buf_len) % USB_HIGH_SPEED_BULK_SIZE) ? ++ true : false; ++ else ++ rst = (0 == (buf_len) % USB_FULL_SPEED_BULK_SIZE) ? ++ true : false; ++ return rst; ++} ++ ++#endif /* __USB_OPS_H_ */ +diff --git a/drivers/staging/r8188eu/include/usb_ops_linux.h b/drivers/staging/r8188eu/include/usb_ops_linux.h +new file mode 100644 +index 000000000000..c357a3b1560e +--- /dev/null ++++ b/drivers/staging/r8188eu/include/usb_ops_linux.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __USB_OPS_LINUX_H__ ++#define __USB_OPS_LINUX_H__ ++ ++#define VENDOR_CMD_MAX_DATA_LEN 254 ++ ++#define RTW_USB_CONTROL_MSG_TIMEOUT_TEST 10/* ms */ ++#define RTW_USB_CONTROL_MSG_TIMEOUT 500/* ms */ ++ ++#define MAX_USBCTRL_VENDORREQ_TIMES 10 ++ ++#define RTW_USB_BULKOUT_TIME 5000/* ms */ ++ ++#define _usbctrl_vendorreq_async_callback(urb, regs) \ ++ _usbctrl_vendorreq_async_callback(urb) ++#define usb_bulkout_zero_complete(purb, regs) \ ++ usb_bulkout_zero_complete(purb) ++#define usb_write_mem_complete(purb, regs) \ ++ usb_write_mem_complete(purb) ++#define usb_write_port_complete(purb, regs) \ ++ usb_write_port_complete(purb) ++#define usb_read_port_complete(purb, regs) \ ++ usb_read_port_complete(purb) ++#define usb_read_interrupt_complete(purb, regs) \ ++ usb_read_interrupt_complete(purb) ++ ++unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr); ++ ++void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem); ++void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem); ++ ++void usb_read_port_cancel(struct intf_hdl *pintfhdl); ++ ++u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem); ++void usb_write_port_cancel(struct intf_hdl *pintfhdl); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/usb_osintf.h b/drivers/staging/r8188eu/include/usb_osintf.h +new file mode 100644 +index 000000000000..d1a1f739309c +--- /dev/null ++++ b/drivers/staging/r8188eu/include/usb_osintf.h +@@ -0,0 +1,29 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __USB_OSINTF_H ++#define __USB_OSINTF_H ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++#include "usb_vendor_req.h" ++ ++extern char *rtw_initmac; ++extern int rtw_mc2u_disable; ++ ++#define USBD_HALTED(Status) ((u32)(Status) >> 30 == 3) ++ ++u8 usbvendorrequest(struct dvobj_priv *pdvobjpriv, enum bt_usb_request brequest, ++ enum rt_usb_wvalue wvalue, u8 windex, void *data, ++ u8 datalen, u8 isdirectionin); ++int pm_netdev_open(struct net_device *pnetdev, u8 bnormal); ++void netdev_br_init(struct net_device *netdev); ++void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb); ++void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr, ++ unsigned char *ipAddr); ++void nat25_db_expire(struct adapter *priv); ++int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method); ++ ++int rtw_resume_process(struct adapter *padapter); ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/usb_vendor_req.h b/drivers/staging/r8188eu/include/usb_vendor_req.h +new file mode 100644 +index 000000000000..7337b1b7419f +--- /dev/null ++++ b/drivers/staging/r8188eu/include/usb_vendor_req.h +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef _USB_VENDOR_REQUEST_H_ ++#define _USB_VENDOR_REQUEST_H_ ++ ++/* 4 Set/Get Register related wIndex/Data */ ++#define RT_USB_RESET_MASK_OFF 0 ++#define RT_USB_RESET_MASK_ON 1 ++#define RT_USB_SLEEP_MASK_OFF 0 ++#define RT_USB_SLEEP_MASK_ON 1 ++#define RT_USB_LDO_ON 1 ++#define RT_USB_LDO_OFF 0 ++ ++/* 4 Set/Get SYSCLK related wValue or Data */ ++#define RT_USB_SYSCLK_32KHZ 0 ++#define RT_USB_SYSCLK_40MHZ 1 ++#define RT_USB_SYSCLK_60MHZ 2 ++ ++enum bt_usb_request { ++ RT_USB_SET_REGISTER = 1, ++ RT_USB_SET_SYSCLK = 2, ++ RT_USB_GET_SYSCLK = 3, ++ RT_USB_GET_REGISTER = 4 ++}; ++ ++enum rt_usb_wvalue { ++ RT_USB_RESET_MASK = 1, ++ RT_USB_SLEEP_MASK = 2, ++ RT_USB_USB_HRCPWM = 3, ++ RT_USB_LDO = 4, ++ RT_USB_BOOT_TYPE = 5 ++}; ++ ++#endif +diff --git a/drivers/staging/r8188eu/include/wifi.h b/drivers/staging/r8188eu/include/wifi.h +new file mode 100644 +index 000000000000..0b3fd94cea18 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/wifi.h +@@ -0,0 +1,1029 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#ifndef _WIFI_H_ ++#define _WIFI_H_ ++ ++#include ++ ++#ifdef BIT ++/* error "BIT define occurred earlier elsewhere!\n" */ ++#undef BIT ++#endif ++#define BIT(x) (1 << (x)) ++ ++#define WLAN_ETHHDR_LEN 14 ++#define WLAN_ETHADDR_LEN 6 ++#define WLAN_IEEE_OUI_LEN 3 ++#define WLAN_ADDR_LEN 6 ++#define WLAN_CRC_LEN 4 ++#define WLAN_BSSID_LEN 6 ++#define WLAN_BSS_TS_LEN 8 ++#define WLAN_HDR_A3_LEN 24 ++#define WLAN_HDR_A4_LEN 30 ++#define WLAN_HDR_A3_QOS_LEN 26 ++#define WLAN_HDR_A4_QOS_LEN 32 ++#define WLAN_SSID_MAXLEN 32 ++#define WLAN_DATA_MAXLEN 2312 ++ ++#define WLAN_A3_PN_OFFSET 24 ++#define WLAN_A4_PN_OFFSET 30 ++ ++#define WLAN_MIN_ETHFRM_LEN 60 ++#define WLAN_MAX_ETHFRM_LEN 1514 ++#define WLAN_ETHHDR_LEN 14 ++ ++#define P80211CAPTURE_VERSION 0x80211001 ++ ++/* This value is tested by WiFi 11n Test Plan 5.2.3. */ ++/* This test verifies the WLAN NIC can update the NAV through sending ++ * the CTS with large duration. */ ++#define WiFiNavUpperUs 30000 /* 30 ms */ ++ ++enum WIFI_FRAME_TYPE { ++ WIFI_MGT_TYPE = (0), ++ WIFI_CTRL_TYPE = (BIT(2)), ++ WIFI_DATA_TYPE = (BIT(3)), ++ WIFI_QOS_DATA_TYPE = (BIT(7)|BIT(3)), /* QoS Data */ ++}; ++ ++enum WIFI_FRAME_SUBTYPE { ++ /* below is for mgt frame */ ++ WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE), ++ WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE), ++ WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE), ++ WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE), ++ WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE), ++ WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE), ++ WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE), ++ WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE), ++ WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE), ++ ++ /* below is for control frame */ ++ WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE), ++ WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE), ++ WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE), ++ WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE), ++ WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE), ++ WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) | ++ WIFI_CTRL_TYPE), ++ ++ /* below is for data frame */ ++ WIFI_DATA = (0 | WIFI_DATA_TYPE), ++ WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE), ++ WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE), ++ WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE), ++ WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE), ++ WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE), ++ WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE), ++}; ++ ++enum WIFI_REASON_CODE { ++ _RSON_RESERVED_ = 0, ++ _RSON_UNSPECIFIED_ = 1, ++ _RSON_AUTH_NO_LONGER_VALID_ = 2, ++ _RSON_DEAUTH_STA_LEAVING_ = 3, ++ _RSON_INACTIVITY_ = 4, ++ _RSON_UNABLE_HANDLE_ = 5, ++ _RSON_CLS2_ = 6, ++ _RSON_CLS3_ = 7, ++ _RSON_DISAOC_STA_LEAVING_ = 8, ++ _RSON_ASOC_NOT_AUTH_ = 9, ++ ++ /* WPA reason */ ++ _RSON_INVALID_IE_ = 13, ++ _RSON_MIC_FAILURE_ = 14, ++ _RSON_4WAY_HNDSHK_TIMEOUT_ = 15, ++ _RSON_GROUP_KEY_UPDATE_TIMEOUT_ = 16, ++ _RSON_DIFF_IE_ = 17, ++ _RSON_MLTCST_CIPHER_NOT_VALID_ = 18, ++ _RSON_UNICST_CIPHER_NOT_VALID_ = 19, ++ _RSON_AKMP_NOT_VALID_ = 20, ++ _RSON_UNSUPPORT_RSNE_VER_ = 21, ++ _RSON_INVALID_RSNE_CAP_ = 22, ++ _RSON_IEEE_802DOT1X_AUTH_FAIL_ = 23, ++ ++ /* belowing are Realtek definition */ ++ _RSON_PMK_NOT_AVAILABLE_ = 24, ++ _RSON_TDLS_TEAR_TOOFAR_ = 25, ++ _RSON_TDLS_TEAR_UN_RSN_ = 26, ++}; ++ ++/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) ++ ++#define WLAN_REASON_UNSPECIFIED 1 ++#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 ++#define WLAN_REASON_DEAUTH_LEAVING 3 ++#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 ++#define WLAN_REASON_DISASSOC_AP_BUSY 5 ++#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 ++#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 ++#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 ++#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 */ ++/* IEEE 802.11h */ ++#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10 ++#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11 ++ ++/* IEEE 802.11i ++#define WLAN_REASON_INVALID_IE 13 ++#define WLAN_REASON_MICHAEL_MIC_FAILURE 14 ++#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15 ++#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16 ++#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17 ++#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18 ++#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19 ++#define WLAN_REASON_AKMP_NOT_VALID 20 ++#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21 ++#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22 ++#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23 ++#define WLAN_REASON_CIPHER_SUITE_REJECTED 24 */ ++ ++enum WIFI_STATUS_CODE { ++ _STATS_SUCCESSFUL_ = 0, ++ _STATS_FAILURE_ = 1, ++ _STATS_CAP_FAIL_ = 10, ++ _STATS_NO_ASOC_ = 11, ++ _STATS_OTHER_ = 12, ++ _STATS_NO_SUPP_ALG_ = 13, ++ _STATS_OUT_OF_AUTH_SEQ_ = 14, ++ _STATS_CHALLENGE_FAIL_ = 15, ++ _STATS_AUTH_TIMEOUT_ = 16, ++ _STATS_UNABLE_HANDLE_STA_ = 17, ++ _STATS_RATE_FAIL_ = 18, ++}; ++ ++/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) ++#define WLAN_STATUS_SUCCESS 0 ++#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 ++#define WLAN_STATUS_CAPS_UNSUPPORTED 10 ++#define WLAN_STATUS_REASSOC_NO_ASSOC 11 ++#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 ++#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 ++#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 ++#define WLAN_STATUS_CHALLENGE_FAIL 15 ++#define WLAN_STATUS_AUTH_TIMEOUT 16 ++#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 ++#define WLAN_STATUS_ASSOC_DENIED_RATES 18 */ ++ ++/* entended */ ++/* IEEE 802.11b */ ++#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 ++#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 ++#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 ++/* IEEE 802.11h */ ++#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22 ++#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23 ++#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24 ++/* IEEE 802.11g */ ++#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 ++#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26 ++#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27 ++/* IEEE 802.11w */ ++#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30 ++#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 ++/* IEEE 802.11i */ ++#define WLAN_STATUS_INVALID_IE 40 ++#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41 ++#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42 ++#define WLAN_STATUS_AKMP_NOT_VALID 43 ++#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44 ++#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45 ++#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46 ++#define WLAN_STATUS_TS_NOT_CREATED 47 ++#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48 ++#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49 ++#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50 ++#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51 ++/* IEEE 802.11r */ ++#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52 ++#define WLAN_STATUS_INVALID_PMKID 53 ++#define WLAN_STATUS_INVALID_MDIE 54 ++#define WLAN_STATUS_INVALID_FTIE 55 ++ ++enum WIFI_REG_DOMAIN { ++ DOMAIN_FCC = 1, ++ DOMAIN_IC = 2, ++ DOMAIN_ETSI = 3, ++ DOMAIN_SPA = 4, ++ DOMAIN_FRANCE = 5, ++ DOMAIN_MKK = 6, ++ DOMAIN_ISRAEL = 7, ++ DOMAIN_MKK1 = 8, ++ DOMAIN_MKK2 = 9, ++ DOMAIN_MKK3 = 10, ++ DOMAIN_MAX ++}; ++ ++#define _TO_DS_ BIT(8) ++#define _FROM_DS_ BIT(9) ++#define _MORE_FRAG_ BIT(10) ++#define _RETRY_ BIT(11) ++#define _PWRMGT_ BIT(12) ++#define _MORE_DATA_ BIT(13) ++#define _PRIVACY_ BIT(14) ++#define _ORDER_ BIT(15) ++ ++#define SetToDs(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_TO_DS_) ++ ++#define GetToDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_TO_DS_)) != 0) ++ ++#define ClearToDs(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_TO_DS_)) ++ ++#define SetFrDs(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_FROM_DS_) ++ ++#define GetFrDs(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_FROM_DS_)) != 0) ++ ++#define ClearFrDs(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_FROM_DS_)) ++ ++#define get_tofr_ds(pframe) ((GetToDs(pframe) << 1) | GetFrDs(pframe)) ++ ++#define SetMFrag(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_FRAG_) ++ ++#define GetMFrag(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_FRAG_)) != 0) ++ ++#define ClearMFrag(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_FRAG_)) ++ ++#define SetRetry(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_RETRY_) ++ ++#define GetRetry(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_RETRY_)) != 0) ++ ++#define ClearRetry(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_RETRY_)) ++ ++#define SetPwrMgt(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_PWRMGT_) ++ ++#define GetPwrMgt(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_PWRMGT_)) != 0) ++ ++#define ClearPwrMgt(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_PWRMGT_)) ++ ++#define SetMData(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_MORE_DATA_) ++ ++#define GetMData(pbuf) (((*(__le16 *)(pbuf)) & cpu_to_le16(_MORE_DATA_)) != 0) ++ ++#define ClearMData(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_MORE_DATA_)) ++ ++#define SetPrivacy(pbuf) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(_PRIVACY_) ++ ++#define GetPrivacy(pbuf) \ ++ (((*(__le16 *)(pbuf)) & cpu_to_le16(_PRIVACY_)) != 0) ++ ++#define ClearPrivacy(pbuf) \ ++ *(__le16 *)(pbuf) &= (~cpu_to_le16(_PRIVACY_)) ++ ++#define GetOrder(pbuf) \ ++ (((*(__le16 *)(pbuf)) & cpu_to_le16(_ORDER_)) != 0) ++ ++#define GetFrameType(pbuf) \ ++ (le16_to_cpu(*(__le16 *)(pbuf)) & (BIT(3) | BIT(2))) ++ ++#define SetFrameType(pbuf, type) \ ++ do { \ ++ *(unsigned short *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \ ++ *(unsigned short *)(pbuf) |= __constant_cpu_to_le16(type); \ ++ } while (0) ++ ++#define GetFrameSubType(pbuf) (le16_to_cpu(*(__le16 *)(pbuf)) & (BIT(7) |\ ++ BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))) ++ ++#define SetFrameSubType(pbuf, type) \ ++ do { \ ++ *(__le16 *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | \ ++ BIT(5) | BIT(4) | BIT(3) | BIT(2))); \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(type); \ ++ } while (0) ++ ++#define GetSequence(pbuf) \ ++ (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 22)) >> 4) ++ ++#define GetFragNum(pbuf) \ ++ (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 22)) & 0x0f) ++ ++#define GetTupleCache(pbuf) \ ++ (cpu_to_le16(*(unsigned short *)((size_t)(pbuf) + 22))) ++ ++#define SetFragNum(pbuf, num) \ ++ do { \ ++ *(unsigned short *)((size_t)(pbuf) + 22) = \ ++ ((*(unsigned short *)((size_t)(pbuf) + 22)) & \ ++ le16_to_cpu(~(0x000f))) | \ ++ cpu_to_le16(0x0f & (num)); \ ++ } while (0) ++ ++#define SetSeqNum(pbuf, num) \ ++ do { \ ++ *(__le16 *)((size_t)(pbuf) + 22) = \ ++ ((*(__le16 *)((size_t)(pbuf) + 22)) & cpu_to_le16((unsigned short)0x000f)) | \ ++ cpu_to_le16((unsigned short)(0xfff0 & (num << 4))); \ ++ } while (0) ++ ++#define SetDuration(pbuf, dur) \ ++ *(__le16 *)((size_t)(pbuf) + 2) = cpu_to_le16(0xffff & (dur)) ++ ++#define SetPriority(pbuf, tid) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16(tid & 0xf) ++ ++#define GetPriority(pbuf) ((le16_to_cpu(*(__le16 *)(pbuf))) & 0xf) ++ ++#define SetEOSP(pbuf, eosp) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16((eosp & 1) << 4) ++ ++#define SetAckpolicy(pbuf, ack) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16((ack & 3) << 5) ++ ++#define GetAckpolicy(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 5) & 0x3) ++ ++#define GetAMsdu(pbuf) (((le16_to_cpu(*(__le16 *)pbuf)) >> 7) & 0x1) ++ ++#define SetAMsdu(pbuf, amsdu) \ ++ *(__le16 *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7) ++ ++#define GetAid(pbuf) (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + 2)) & 0x3fff) ++ ++#define GetTid(pbuf) (le16_to_cpu(*(__le16 *)((size_t)(pbuf) + \ ++ (((GetToDs(pbuf)<<1) | GetFrDs(pbuf)) == 3 ? \ ++ 30 : 24))) & 0x000f) ++ ++#define GetAddr1Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 4)) ++ ++#define GetAddr2Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 10)) ++ ++#define GetAddr3Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 16)) ++ ++#define GetAddr4Ptr(pbuf) ((unsigned char *)((size_t)(pbuf) + 24)) ++ ++static inline int IS_MCAST(unsigned char *da) ++{ ++ if ((*da) & 0x01) ++ return true; ++ else ++ return false; ++} ++ ++static inline unsigned char *get_da(unsigned char *pframe) ++{ ++ unsigned char *da; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: /* ToDs=0, FromDs=0 */ ++ da = GetAddr1Ptr(pframe); ++ break; ++ case 0x01: /* ToDs=0, FromDs=1 */ ++ da = GetAddr1Ptr(pframe); ++ break; ++ case 0x02: /* ToDs=1, FromDs=0 */ ++ da = GetAddr3Ptr(pframe); ++ break; ++ default: /* ToDs=1, FromDs=1 */ ++ da = GetAddr3Ptr(pframe); ++ break; ++ } ++ return da; ++} ++ ++static inline unsigned char *get_sa(unsigned char *pframe) ++{ ++ unsigned char *sa; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: /* ToDs=0, FromDs=0 */ ++ sa = GetAddr2Ptr(pframe); ++ break; ++ case 0x01: /* ToDs=0, FromDs=1 */ ++ sa = GetAddr3Ptr(pframe); ++ break; ++ case 0x02: /* ToDs=1, FromDs=0 */ ++ sa = GetAddr2Ptr(pframe); ++ break; ++ default: /* ToDs=1, FromDs=1 */ ++ sa = GetAddr4Ptr(pframe); ++ break; ++ } ++ return sa; ++} ++ ++static inline unsigned char *get_hdr_bssid(unsigned char *pframe) ++{ ++ unsigned char *sa; ++ unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); ++ ++ switch (to_fr_ds) { ++ case 0x00: /* ToDs=0, FromDs=0 */ ++ sa = GetAddr3Ptr(pframe); ++ break; ++ case 0x01: /* ToDs=0, FromDs=1 */ ++ sa = GetAddr2Ptr(pframe); ++ break; ++ case 0x02: /* ToDs=1, FromDs=0 */ ++ sa = GetAddr1Ptr(pframe); ++ break; ++ case 0x03: /* ToDs=1, FromDs=1 */ ++ sa = GetAddr1Ptr(pframe); ++ break; ++ default: ++ sa = NULL; /* */ ++ break; ++ } ++ return sa; ++} ++ ++static inline int IsFrameTypeCtrl(unsigned char *pframe) ++{ ++ if (WIFI_CTRL_TYPE == GetFrameType(pframe)) ++ return true; ++ else ++ return false; ++} ++/*----------------------------------------------------------------------------- ++ Below is for the security related definition ++------------------------------------------------------------------------------*/ ++#define _RESERVED_FRAME_TYPE_ 0 ++#define _SKB_FRAME_TYPE_ 2 ++#define _PRE_ALLOCMEM_ 1 ++#define _PRE_ALLOCHDR_ 3 ++#define _PRE_ALLOCLLCHDR_ 4 ++#define _PRE_ALLOCICVHDR_ 5 ++#define _PRE_ALLOCMICHDR_ 6 ++ ++#define _SIFSTIME_ \ ++ (priv->pmib->dot11BssType.net_work_type = 10) ++#define _ACKCTSLNG_ 14 /* 14 bytes long, including crclng */ ++#define _CRCLNG_ 4 ++ ++#define _ASOCREQ_IE_OFFSET_ 4 /* excluding wlan_hdr */ ++#define _ASOCRSP_IE_OFFSET_ 6 ++#define _REASOCREQ_IE_OFFSET_ 10 ++#define _REASOCRSP_IE_OFFSET_ 6 ++#define _PROBEREQ_IE_OFFSET_ 0 ++#define _PROBERSP_IE_OFFSET_ 12 ++#define _AUTH_IE_OFFSET_ 6 ++#define _DEAUTH_IE_OFFSET_ 0 ++#define _BEACON_IE_OFFSET_ 12 ++#define _PUBLIC_ACTION_IE_OFFSET_ 8 ++ ++#define _FIXED_IE_LENGTH_ _BEACON_IE_OFFSET_ ++ ++#define _SSID_IE_ 0 ++#define _SUPPORTEDRATES_IE_ 1 ++#define _DSSET_IE_ 3 ++#define _TIM_IE_ 5 ++#define _IBSS_PARA_IE_ 6 ++#define _COUNTRY_IE_ 7 ++#define _CHLGETXT_IE_ 16 ++#define _SUPPORTED_CH_IE_ 36 ++#define _CH_SWTICH_ANNOUNCE_ 37 /* Secondary Channel Offset */ ++#define _RSN_IE_2_ 48 ++#define _SSN_IE_1_ 221 ++#define _ERPINFO_IE_ 42 ++#define _EXT_SUPPORTEDRATES_IE_ 50 ++ ++#define _HT_CAPABILITY_IE_ 45 ++#define _FTIE_ 55 ++#define _TIMEOUT_ITVL_IE_ 56 ++#define _SRC_IE_ 59 ++#define _HT_EXTRA_INFO_IE_ 61 ++#define _HT_ADD_INFO_IE_ 61 /* _HT_EXTRA_INFO_IE_ */ ++#define _WAPI_IE_ 68 ++ ++#define EID_BSSCoexistence 72 /* 20/40 BSS Coexistence */ ++#define EID_BSSIntolerantChlReport 73 ++#define _RIC_Descriptor_IE_ 75 ++ ++#define _LINK_ID_IE_ 101 ++#define _CH_SWITCH_TIMING_ 104 ++#define _PTI_BUFFER_STATUS_ 106 ++#define _EXT_CAP_IE_ 127 ++#define _VENDOR_SPECIFIC_IE_ 221 ++ ++#define _RESERVED47_ 47 ++ ++/* --------------------------------------------------------------------------- ++ Below is the fixed elements... ++-----------------------------------------------------------------------------*/ ++#define _AUTH_ALGM_NUM_ 2 ++#define _AUTH_SEQ_NUM_ 2 ++#define _BEACON_ITERVAL_ 2 ++#define _CAPABILITY_ 2 ++#define _CURRENT_APADDR_ 6 ++#define _LISTEN_INTERVAL_ 2 ++#define _RSON_CODE_ 2 ++#define _ASOC_ID_ 2 ++#define _STATUS_CODE_ 2 ++#define _TIMESTAMP_ 8 ++ ++#define AUTH_ODD_TO 0 ++#define AUTH_EVEN_TO 1 ++ ++#define WLAN_ETHCONV_ENCAP 1 ++#define WLAN_ETHCONV_RFC1042 2 ++#define WLAN_ETHCONV_8021h 3 ++ ++#define cap_ESS BIT(0) ++#define cap_IBSS BIT(1) ++#define cap_CFPollable BIT(2) ++#define cap_CFRequest BIT(3) ++#define cap_Privacy BIT(4) ++#define cap_ShortPremble BIT(5) ++#define cap_PBCC BIT(6) ++#define cap_ChAgility BIT(7) ++#define cap_SpecMgmt BIT(8) ++#define cap_QoSi BIT(9) ++#define cap_ShortSlot BIT(10) ++ ++/*----------------------------------------------------------------------------- ++ Below is the definition for 802.11i / 802.1x ++------------------------------------------------------------------------------*/ ++#define _IEEE8021X_MGT_ 1 /* WPA */ ++#define _IEEE8021X_PSK_ 2 /* WPA with pre-shared key */ ++ ++/* ++#define _NO_PRIVACY_ 0 ++#define _WEP_40_PRIVACY_ 1 ++#define _TKIP_PRIVACY_ 2 ++#define _WRAP_PRIVACY_ 3 ++#define _CCMP_PRIVACY_ 4 ++#define _WEP_104_PRIVACY_ 5 ++#define _WEP_WPA_MIXED_PRIVACY_ 6 WEP + WPA ++*/ ++ ++/*----------------------------------------------------------------------------- ++ Below is the definition for WMM ++------------------------------------------------------------------------------*/ ++#define _WMM_IE_Length_ 7 /* for WMM STA */ ++#define _WMM_Para_Element_Length_ 24 ++ ++/*----------------------------------------------------------------------------- ++ Below is the definition for 802.11n ++------------------------------------------------------------------------------*/ ++ ++#define SetOrderBit(pbuf) \ ++ do { \ ++ *(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_); \ ++ } while (0) ++ ++#define GetOrderBit(pbuf) \ ++ (((*(unsigned short *)(pbuf)) & le16_to_cpu(_ORDER_)) != 0) ++ ++/** ++ * struct rtw_ieee80211_bar - HT Block Ack Request ++ * ++ * This structure refers to "HT BlockAckReq" as ++ * described in 802.11n draft section 7.2.1.7.1 ++ */ ++struct rtw_ieee80211_bar { ++ __le16 frame_control; ++ __le16 duration; ++ unsigned char ra[ETH_ALEN]; ++ unsigned char ta[ETH_ALEN]; ++ __le16 control; ++ __le16 start_seq_num; ++} __packed; ++ ++/** ++ * struct ieee80211_ht_cap - HT additional information ++ * ++ * This structure refers to "HT information element" as ++ * described in 802.11n draft section 7.3.2.53 ++ */ ++struct ieee80211_ht_addt_info { ++ unsigned char control_chan; ++ unsigned char ht_param; ++ __le16 operation_mode; ++ __le16 stbc_param; ++ unsigned char basic_set[16]; ++} __packed; ++ ++struct HT_caps_element { ++ union { ++ struct { ++ __le16 HT_caps_info; ++ unsigned char AMPDU_para; ++ unsigned char MCS_rate[16]; ++ __le16 HT_ext_caps; ++ __le16 Beamforming_caps; ++ unsigned char ASEL_caps; ++ } HT_cap_element; ++ unsigned char HT_cap[26]; ++ } u; ++} __packed; ++ ++struct HT_info_element { ++ unsigned char primary_channel; ++ unsigned char infos[5]; ++ unsigned char MCS_rate[16]; ++} __packed; ++ ++struct AC_param { ++ unsigned char ACI_AIFSN; ++ unsigned char CW; ++ __le16 TXOP_limit; ++} __packed; ++ ++struct WMM_para_element { ++ unsigned char QoS_info; ++ unsigned char reserved; ++ struct AC_param ac_param[4]; ++} __packed; ++ ++struct ADDBA_request { ++ unsigned char action_code; ++ unsigned char dialog_token; ++ __le16 BA_para_set; ++ __le16 BA_timeout_value; ++ __le16 BA_starting_seqctrl; ++} __packed; ++ ++enum ht_cap_ampdu_factor { ++ MAX_AMPDU_FACTOR_8K = 0, ++ MAX_AMPDU_FACTOR_16K = 1, ++ MAX_AMPDU_FACTOR_32K = 2, ++ MAX_AMPDU_FACTOR_64K = 3, ++}; ++ ++/* Spatial Multiplexing Power Save Modes */ ++#define WLAN_HT_CAP_SM_PS_STATIC 0 ++#define WLAN_HT_CAP_SM_PS_DYNAMIC 1 ++#define WLAN_HT_CAP_SM_PS_INVALID 2 ++#define WLAN_HT_CAP_SM_PS_DISABLED 3 ++ ++#define OP_MODE_PURE 0 ++#define OP_MODE_MAY_BE_LEGACY_STAS 1 ++#define OP_MODE_20MHZ_HT_STA_ASSOCED 2 ++#define OP_MODE_MIXED 3 ++ ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1)) ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0)) ++#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1)) ++#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2)) ++#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3)) ++#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4)) ++#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5)) ++ ++#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \ ++ ((u16) (0x0001 | 0x0002)) ++#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0 ++#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2)) ++#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3)) ++#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4)) ++ ++#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6)) ++#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7)) ++#define HT_INFO_STBC_PARAM_SECONDARY_BC ((u16) BIT(8)) ++#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9)) ++#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10)) ++#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11)) ++ ++/* ===============WPS Section=============== */ ++/* For WPSv1.0 */ ++#define WPSOUI 0x0050f204 ++/* WPS attribute ID */ ++#define WPS_ATTR_VER1 0x104A ++#define WPS_ATTR_SIMPLE_CONF_STATE 0x1044 ++#define WPS_ATTR_RESP_TYPE 0x103B ++#define WPS_ATTR_UUID_E 0x1047 ++#define WPS_ATTR_MANUFACTURER 0x1021 ++#define WPS_ATTR_MODEL_NAME 0x1023 ++#define WPS_ATTR_MODEL_NUMBER 0x1024 ++#define WPS_ATTR_SERIAL_NUMBER 0x1042 ++#define WPS_ATTR_PRIMARY_DEV_TYPE 0x1054 ++#define WPS_ATTR_SEC_DEV_TYPE_LIST 0x1055 ++#define WPS_ATTR_DEVICE_NAME 0x1011 ++#define WPS_ATTR_CONF_METHOD 0x1008 ++#define WPS_ATTR_RF_BANDS 0x103C ++#define WPS_ATTR_DEVICE_PWID 0x1012 ++#define WPS_ATTR_REQUEST_TYPE 0x103A ++#define WPS_ATTR_ASSOCIATION_STATE 0x1002 ++#define WPS_ATTR_CONFIG_ERROR 0x1009 ++#define WPS_ATTR_VENDOR_EXT 0x1049 ++#define WPS_ATTR_SELECTED_REGISTRAR 0x1041 ++ ++/* Value of WPS attribute "WPS_ATTR_DEVICE_NAME */ ++#define WPS_MAX_DEVICE_NAME_LEN 32 ++ ++/* Value of WPS Request Type Attribute */ ++#define WPS_REQ_TYPE_ENROLLEE_INFO_ONLY 0x00 ++#define WPS_REQ_TYPE_ENROLLEE_OPEN_8021X 0x01 ++#define WPS_REQ_TYPE_REGISTRAR 0x02 ++#define WPS_REQ_TYPE_WLAN_MANAGER_REGISTRAR 0x03 ++ ++/* Value of WPS Response Type Attribute */ ++#define WPS_RESPONSE_TYPE_INFO_ONLY 0x00 ++#define WPS_RESPONSE_TYPE_8021X 0x01 ++#define WPS_RESPONSE_TYPE_REGISTRAR 0x02 ++#define WPS_RESPONSE_TYPE_AP 0x03 ++ ++/* Value of WPS WiFi Simple Configuration State Attribute */ ++#define WPS_WSC_STATE_NOT_CONFIG 0x01 ++#define WPS_WSC_STATE_CONFIG 0x02 ++ ++/* Value of WPS Version Attribute */ ++#define WPS_VERSION_1 0x10 ++ ++/* Value of WPS Configuration Method Attribute */ ++#define WPS_CONFIG_METHOD_FLASH 0x0001 ++#define WPS_CONFIG_METHOD_ETHERNET 0x0002 ++#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 ++ ++/* Value of Category ID of WPS Primary Device Type Attribute */ ++#define WPS_PDT_CID_DISPLAYS 0x0007 ++#define WPS_PDT_CID_MULIT_MEDIA 0x0008 ++#define WPS_PDT_CID_RTK_WIDI WPS_PDT_CID_MULIT_MEDIA ++ ++/* Value of Sub Category ID of WPS Primary Device Type Attribute */ ++#define WPS_PDT_SCID_MEDIA_SERVER 0x0005 ++#define WPS_PDT_SCID_RTK_DMP WPS_PDT_SCID_MEDIA_SERVER ++ ++/* Value of Device Password ID */ ++#define WPS_DPID_P 0x0000 ++#define WPS_DPID_USER_SPEC 0x0001 ++#define WPS_DPID_MACHINE_SPEC 0x0002 ++#define WPS_DPID_REKEY 0x0003 ++#define WPS_DPID_PBC 0x0004 ++#define WPS_DPID_REGISTRAR_SPEC 0x0005 ++ ++/* Value of WPS RF Bands Attribute */ ++#define WPS_RF_BANDS_2_4_GHZ 0x01 ++#define WPS_RF_BANDS_5_GHZ 0x02 ++ ++/* Value of WPS Association State Attribute */ ++#define WPS_ASSOC_STATE_NOT_ASSOCIATED 0x00 ++#define WPS_ASSOC_STATE_CONNECTION_SUCCESS 0x01 ++#define WPS_ASSOC_STATE_CONFIGURATION_FAILURE 0x02 ++#define WPS_ASSOC_STATE_ASSOCIATION_FAILURE 0x03 ++#define WPS_ASSOC_STATE_IP_FAILURE 0x04 ++ ++/* =====================P2P Section===================== */ ++/* For P2P */ ++#define P2POUI 0x506F9A09 ++ ++/* P2P Attribute ID */ ++#define P2P_ATTR_STATUS 0x00 ++#define P2P_ATTR_MINOR_REASON_CODE 0x01 ++#define P2P_ATTR_CAPABILITY 0x02 ++#define P2P_ATTR_DEVICE_ID 0x03 ++#define P2P_ATTR_GO_INTENT 0x04 ++#define P2P_ATTR_CONF_TIMEOUT 0x05 ++#define P2P_ATTR_LISTEN_CH 0x06 ++#define P2P_ATTR_GROUP_BSSID 0x07 ++#define P2P_ATTR_EX_LISTEN_TIMING 0x08 ++#define P2P_ATTR_INTENTED_IF_ADDR 0x09 ++#define P2P_ATTR_MANAGEABILITY 0x0A ++#define P2P_ATTR_CH_LIST 0x0B ++#define P2P_ATTR_NOA 0x0C ++#define P2P_ATTR_DEVICE_INFO 0x0D ++#define P2P_ATTR_GROUP_INFO 0x0E ++#define P2P_ATTR_GROUP_ID 0x0F ++#define P2P_ATTR_INTERFACE 0x10 ++#define P2P_ATTR_OPERATING_CH 0x11 ++#define P2P_ATTR_INVITATION_FLAGS 0x12 ++ ++/* Value of Status Attribute */ ++#define P2P_STATUS_SUCCESS 0x00 ++#define P2P_STATUS_FAIL_INFO_UNAVAILABLE 0x01 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 0x02 ++#define P2P_STATUS_FAIL_LIMIT_REACHED 0x03 ++#define P2P_STATUS_FAIL_INVALID_PARAM 0x04 ++#define P2P_STATUS_FAIL_REQUEST_UNABLE 0x05 ++#define P2P_STATUS_FAIL_PREVOUS_PROTO_ERR 0x06 ++#define P2P_STATUS_FAIL_NO_COMMON_CH 0x07 ++#define P2P_STATUS_FAIL_UNKNOWN_P2PGROUP 0x08 ++#define P2P_STATUS_FAIL_BOTH_GOINTENT_15 0x09 ++#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVSION 0x0A ++#define P2P_STATUS_FAIL_USER_REJECT 0x0B ++ ++/* Value of Inviation Flags Attribute */ ++#define P2P_INVITATION_FLAGS_PERSISTENT BIT(0) ++ ++#define DMP_P2P_DEVCAP_SUPPORT (P2P_DEVCAP_SERVICE_DISCOVERY | \ ++ P2P_DEVCAP_CLIENT_DISCOVERABILITY | \ ++ P2P_DEVCAP_CONCURRENT_OPERATION | \ ++ P2P_DEVCAP_INVITATION_PROC) ++ ++#define DMP_P2P_GRPCAP_SUPPORT (P2P_GRPCAP_INTRABSS) ++ ++/* Value of Device Capability Bitmap */ ++#define P2P_DEVCAP_SERVICE_DISCOVERY BIT(0) ++#define P2P_DEVCAP_CLIENT_DISCOVERABILITY BIT(1) ++#define P2P_DEVCAP_CONCURRENT_OPERATION BIT(2) ++#define P2P_DEVCAP_INFRA_MANAGED BIT(3) ++#define P2P_DEVCAP_DEVICE_LIMIT BIT(4) ++#define P2P_DEVCAP_INVITATION_PROC BIT(5) ++ ++/* Value of Group Capability Bitmap */ ++#define P2P_GRPCAP_GO BIT(0) ++#define P2P_GRPCAP_PERSISTENT_GROUP BIT(1) ++#define P2P_GRPCAP_GROUP_LIMIT BIT(2) ++#define P2P_GRPCAP_INTRABSS BIT(3) ++#define P2P_GRPCAP_CROSS_CONN BIT(4) ++#define P2P_GRPCAP_PERSISTENT_RECONN BIT(5) ++#define P2P_GRPCAP_GROUP_FORMATION BIT(6) ++ ++/* P2P Public Action Frame (Management Frame) */ ++#define P2P_PUB_ACTION_ACTION 0x09 ++ ++/* P2P Public Action Frame Type */ ++#define P2P_GO_NEGO_REQ 0 ++#define P2P_GO_NEGO_RESP 1 ++#define P2P_GO_NEGO_CONF 2 ++#define P2P_INVIT_REQ 3 ++#define P2P_INVIT_RESP 4 ++#define P2P_DEVDISC_REQ 5 ++#define P2P_DEVDISC_RESP 6 ++#define P2P_PROVISION_DISC_REQ 7 ++#define P2P_PROVISION_DISC_RESP 8 ++ ++/* P2P Action Frame Type */ ++#define P2P_NOTICE_OF_ABSENCE 0 ++#define P2P_PRESENCE_REQUEST 1 ++#define P2P_PRESENCE_RESPONSE 2 ++#define P2P_GO_DISC_REQUEST 3 ++ ++#define P2P_MAX_PERSISTENT_GROUP_NUM 10 ++ ++#define P2P_PROVISIONING_SCAN_CNT 3 ++ ++#define P2P_WILDCARD_SSID_LEN 7 ++ ++/* default value, used when: (1)p2p disabed or (2)p2p enabled ++ * but only do 1 scan phase */ ++#define P2P_FINDPHASE_EX_NONE 0 ++/* used when p2p enabled and want to do 1 scan phase and ++ * P2P_FINDPHASE_EX_MAX-1 find phase */ ++#define P2P_FINDPHASE_EX_FULL 1 ++#define P2P_FINDPHASE_EX_SOCIAL_FIRST (P2P_FINDPHASE_EX_FULL+1) ++#define P2P_FINDPHASE_EX_MAX 4 ++#define P2P_FINDPHASE_EX_SOCIAL_LAST P2P_FINDPHASE_EX_MAX ++ ++/* 5 seconds timeout for sending the provision discovery request */ ++#define P2P_PROVISION_TIMEOUT 5000 ++/* 3 seconds timeout for sending the prov disc request concurrent mode */ ++#define P2P_CONCURRENT_PROVISION_TIME 3000 ++/* 5 seconds timeout for receiving the group negotiation response */ ++#define P2P_GO_NEGO_TIMEOUT 5000 ++/* 3 seconds timeout for sending the negotiation request under concurrent mode */ ++#define P2P_CONCURRENT_GO_NEGO_TIME 3000 ++/* 100ms */ ++#define P2P_TX_PRESCAN_TIMEOUT 100 ++/* 5 seconds timeout for sending the invitation request */ ++#define P2P_INVITE_TIMEOUT 5000 ++/* 3 seconds timeout for sending the invitation request under concurrent mode */ ++#define P2P_CONCURRENT_INVITE_TIME 3000 ++/* 25 seconds timeout to reset the scan channel (based on channel plan) */ ++#define P2P_RESET_SCAN_CH 25000 ++#define P2P_MAX_INTENT 15 ++ ++#define P2P_MAX_NOA_NUM 2 ++ ++/* WPS Configuration Method */ ++#define WPS_CM_NONE 0x0000 ++#define WPS_CM_LABEL 0x0004 ++#define WPS_CM_DISPLYA 0x0008 ++#define WPS_CM_EXTERNAL_NFC_TOKEN 0x0010 ++#define WPS_CM_INTEGRATED_NFC_TOKEN 0x0020 ++#define WPS_CM_NFC_INTERFACE 0x0040 ++#define WPS_CM_PUSH_BUTTON 0x0080 ++#define WPS_CM_KEYPAD 0x0100 ++#define WPS_CM_SW_PUHS_BUTTON 0x0280 ++#define WPS_CM_HW_PUHS_BUTTON 0x0480 ++#define WPS_CM_SW_DISPLAY_P 0x2008 ++#define WPS_CM_LCD_DISPLAY_P 0x4008 ++ ++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 had enabled and do nothing */ ++ P2P_STATE_IDLE = 1, ++ P2P_STATE_LISTEN = 2, /* In pure listen state */ ++ P2P_STATE_SCAN = 3, /* In scan phase */ ++ /* In the listen state of find phase */ ++ P2P_STATE_FIND_PHASE_LISTEN = 4, ++ /* In the search state of find phase */ ++ P2P_STATE_FIND_PHASE_SEARCH = 5, ++ /* In P2P provisioning discovery */ ++ P2P_STATE_TX_PROVISION_DIS_REQ = 6, ++ P2P_STATE_RX_PROVISION_DIS_RSP = 7, ++ P2P_STATE_RX_PROVISION_DIS_REQ = 8, ++ /* Doing the group owner negoitation handshake */ ++ P2P_STATE_GONEGO_ING = 9, ++ /* finish the group negoitation handshake with success */ ++ P2P_STATE_GONEGO_OK = 10, ++ /* finish the group negoitation handshake with failure */ ++ P2P_STATE_GONEGO_FAIL = 11, ++ /* receiving the P2P Inviation request and match with the profile. */ ++ P2P_STATE_RECV_INVITE_REQ_MATCH = 12, ++ /* Doing the P2P WPS */ ++ P2P_STATE_PROVISIONING_ING = 13, ++ /* Finish the P2P WPS */ ++ P2P_STATE_PROVISIONING_DONE = 14, ++ /* Transmit the P2P Invitation request */ ++ P2P_STATE_TX_INVITE_REQ = 15, ++ /* Receiving the P2P Invitation response */ ++ P2P_STATE_RX_INVITE_RESP_OK = 16, ++ /* receiving the P2P Inviation request and dismatch with the profile. */ ++ P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17, ++ /* receiving the P2P Inviation request and this wifi is GO. */ ++ P2P_STATE_RECV_INVITE_REQ_GO = 18, ++ /* receiving the P2P Inviation request to join an existing P2P Group. */ ++ P2P_STATE_RECV_INVITE_REQ_JOIN = 19, ++ /* recveing the P2P Inviation response with failure */ ++ P2P_STATE_RX_INVITE_RESP_FAIL = 20, ++ /* receiving p2p negoitation response with information is not available */ ++ P2P_STATE_RX_INFOR_NOREADY = 21, ++ /* sending p2p negoitation response with information is not available */ ++ P2P_STATE_TX_INFOR_NOREADY = 22, ++}; ++ ++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, ++}; ++ ++#define P2P_PRIVATE_IOCTL_SET_LEN 64 ++ ++enum P2P_PROTO_WK_ID { ++ P2P_FIND_PHASE_WK = 0, ++ P2P_RESTORE_STATE_WK = 1, ++ P2P_PRE_TX_PROVDISC_PROCESS_WK = 2, ++ P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3, ++ P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4, ++ P2P_AP_P2P_CH_SWITCH_PROCESS_WK =5, ++ P2P_RO_CH_WK = 6, ++}; ++ ++enum P2P_PS_STATE { ++ P2P_PS_DISABLE = 0, ++ P2P_PS_ENABLE = 1, ++ P2P_PS_SCAN = 2, ++ P2P_PS_SCAN_DONE = 3, ++ P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */ ++}; ++ ++enum P2P_PS_MODE { ++ P2P_PS_NONE = 0, ++ P2P_PS_CTWINDOW = 1, ++ P2P_PS_NOA = 2, ++ P2P_PS_MIX = 3, /* CTWindow and NoA */ ++}; ++ ++/* =====================WFD Section===================== */ ++/* For Wi-Fi Display */ ++#define WFD_ATTR_DEVICE_INFO 0x00 ++#define WFD_ATTR_ASSOC_BSSID 0x01 ++#define WFD_ATTR_COUPLED_SINK_INFO 0x06 ++#define WFD_ATTR_LOCAL_IP_ADDR 0x08 ++#define WFD_ATTR_SESSION_INFO 0x09 ++#define WFD_ATTR_ALTER_MAC 0x0a ++ ++/* For WFD Device Information Attribute */ ++#define WFD_DEVINFO_SOURCE 0x0000 ++#define WFD_DEVINFO_PSINK 0x0001 ++#define WFD_DEVINFO_SSINK 0x0002 ++#define WFD_DEVINFO_DUAL 0x0003 ++ ++#define WFD_DEVINFO_SESSION_AVAIL 0x0010 ++#define WFD_DEVINFO_WSD 0x0040 ++#define WFD_DEVINFO_PC_TDLS 0x0080 ++#define WFD_DEVINFO_HDCP_SUPPORT 0x0100 ++ ++#define IP_MCAST_MAC(mac) \ ++ ((mac[0] == 0x01) && (mac[1] == 0x00) && (mac[2] == 0x5e)) ++#define ICMPV6_MCAST_MAC(mac) \ ++ ((mac[0] == 0x33) && (mac[1] == 0x33) && (mac[2] != 0xff)) ++ ++#endif /* _WIFI_H_ */ +diff --git a/drivers/staging/r8188eu/include/wlan_bssdef.h b/drivers/staging/r8188eu/include/wlan_bssdef.h +new file mode 100644 +index 000000000000..99ca097b8edd +--- /dev/null ++++ b/drivers/staging/r8188eu/include/wlan_bssdef.h +@@ -0,0 +1,327 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __WLAN_BSSDEF_H__ ++#define __WLAN_BSSDEF_H__ ++ ++#define MAX_IE_SZ 768 ++ ++#define NDIS_802_11_LENGTH_SSID 32 ++#define NDIS_802_11_LENGTH_RATES 8 ++#define NDIS_802_11_LENGTH_RATES_EX 16 ++ ++#define NDIS_802_11_RSSI long /* in dBm */ ++ ++struct ndis_802_11_ssid { ++ u32 SsidLength; ++ u8 Ssid[32]; ++}; ++ ++enum NDIS_802_11_NETWORK_TYPE { ++ Ndis802_11FH, ++ Ndis802_11DS, ++ Ndis802_11OFDM5, ++ Ndis802_11OFDM24, ++ Ndis802_11NetworkTypeMax /* dummy upper bound */ ++}; ++ ++struct ndis_802_11_config_fh { ++ u32 Length; /* Length of structure */ ++ u32 HopPattern; /* As defined by 802.11, MSB set */ ++ u32 HopSet; /* to one if non-802.11 */ ++ u32 DwellTime; /* units are Kusec */ ++}; ++ ++/* ++ * FW will only save the channel number in DSConfig. ++ * ODI Handler will convert the channel number to freq. number. ++ */ ++struct ndis_802_11_config { ++ u32 Length; /* Length of structure */ ++ u32 BeaconPeriod; /* units are Kusec */ ++ u32 ATIMWindow; /* units are Kusec */ ++ u32 DSConfig; /* Frequency, units are kHz */ ++ struct ndis_802_11_config_fh FHConfig; ++}; ++ ++enum ndis_802_11_network_infra { ++ Ndis802_11IBSS, ++ Ndis802_11Infrastructure, ++ Ndis802_11AutoUnknown, ++ Ndis802_11InfrastructureMax, /* dummy upper bound */ ++ Ndis802_11APMode ++}; ++ ++struct ndis_802_11_fixed_ie { ++ u8 Timestamp[8]; ++ u16 BeaconInterval; ++ u16 Capabilities; ++}; ++ ++struct ndis_802_11_var_ie { ++ u8 ElementID; ++ u8 Length; ++ u8 data[1]; ++}; ++ ++/* ++ * Length is the 4 bytes multiples of the sume of ++ * [ETH_ALEN] + 2 + sizeof (struct ndis_802_11_ssid) + sizeof (u32) ++ * + sizeof (NDIS_802_11_RSSI) + sizeof (enum NDIS_802_11_NETWORK_TYPE) ++ * + sizeof (struct ndis_802_11_config) ++ * + NDIS_802_11_LENGTH_RATES_EX + IELength ++ * ++ * Except the IELength, all other fields are fixed length. ++ * Therefore, we can define a macro to represent the partial sum. */ ++ ++enum ndis_802_11_auth_mode { ++ Ndis802_11AuthModeOpen, ++ Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, ++ Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, ++ Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeWAPI, ++ Ndis802_11AuthModeMax /* Not a real mode, upper bound */ ++}; ++ ++enum ndis_802_11_wep_status { ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, ++ Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, ++ Ndis802_11Encryption3KeyAbsent, ++ Ndis802_11_EncryptionWAPI ++}; ++ ++#define NDIS_802_11_AI_REQFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2 ++#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4 ++ ++#define NDIS_802_11_AI_RESFI_CAPABILITIES 1 ++#define NDIS_802_11_AI_RESFI_STATUSCODE 2 ++#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4 ++ ++struct ndis_802_11_ai_reqfi { ++ u16 Capabilities; ++ u16 ListenInterval; ++ unsigned char CurrentAPAddress[ETH_ALEN]; ++}; ++ ++struct ndis_802_11_ai_resfi { ++ u16 Capabilities; ++ u16 StatusCode; ++ u16 AssociationId; ++}; ++ ++struct ndis_802_11_assoc_info { ++ u32 Length; ++ u16 AvailableRequestFixedIEs; ++ struct ndis_802_11_ai_reqfi RequestFixedIEs; ++ u32 RequestIELength; ++ u32 OffsetRequestIEs; ++ u16 AvailableResponseFixedIEs; ++ struct ndis_802_11_ai_resfi ResponseFixedIEs; ++ u32 ResponseIELength; ++ u32 OffsetResponseIEs; ++}; ++ ++enum ndis_802_11_reload_def { ++ Ndis802_11ReloadWEPKeys ++}; ++ ++/* Key mapping keys require a BSSID */ ++struct ndis_802_11_key { ++ u32 Length; /* Length of this structure */ ++ u32 KeyIndex; ++ u32 KeyLength; /* length of key in bytes */ ++ unsigned char BSSID[ETH_ALEN]; ++ unsigned long long KeyRSC; ++ u8 KeyMaterial[32]; /* var len depending on above field */ ++}; ++ ++struct ndis_802_11_remove_key { ++ u32 Length; /* Length */ ++ u32 KeyIndex; ++ unsigned char BSSID[ETH_ALEN]; ++}; ++ ++struct ndis_802_11_wep { ++ u32 Length; /* Length of this structure */ ++ u32 KeyIndex; /* 0 is the per-client key, ++ * 1-N are the global keys */ ++ u32 KeyLength; /* length of key in bytes */ ++ u8 KeyMaterial[16];/* variable len depending on above field */ ++}; ++ ++struct ndis_802_11_auth_req { ++ u32 Length; /* Length of structure */ ++ unsigned char Bssid[ETH_ALEN]; ++ u32 Flags; ++}; ++ ++enum ndis_802_11_status_type { ++ Ndis802_11StatusType_Authentication, ++ Ndis802_11StatusType_MediaStreamMode, ++ Ndis802_11StatusType_PMKID_CandidateList, ++ Ndis802_11StatusTypeMax /* not a real type, defined as ++ * an upper bound */ ++}; ++ ++struct ndis_802_11_status_ind { ++ enum ndis_802_11_status_type StatusType; ++}; ++ ++/* mask for authentication/integrity fields */ ++#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f ++#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01 ++#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02 ++#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06 ++#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E ++ ++/* MIC check time, 60 seconds. */ ++#define MIC_CHECK_TIME 60000000 ++ ++struct ndis_802_11_auth_evt { ++ struct ndis_802_11_status_ind Status; ++ struct ndis_802_11_auth_req Request[1]; ++}; ++ ++struct ndis_802_11_test { ++ u32 Length; ++ u32 Type; ++ union { ++ struct ndis_802_11_auth_evt AuthenticationEvent; ++ NDIS_802_11_RSSI RssiTrigger; ++ } tt; ++}; ++ ++#ifndef Ndis802_11APMode ++#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1) ++#endif ++ ++struct wlan_phy_info { ++ u8 SignalStrength;/* in percentage) */ ++ u8 SignalQuality;/* in percentage) */ ++ u8 Optimum_antenna; /* for Antenna diversity */ ++ u8 Reserved_0; ++}; ++ ++struct wlan_bcn_info { ++ /* these infor get from rtw_get_encrypt_info when ++ * * translate scan to UI */ ++ u8 encryp_protocol;/* ENCRYP_PROTOCOL_E: OPEN/WEP/WPA/WPA2/WAPI */ ++ int group_cipher; /* WPA/WPA2 group cipher */ ++ int pairwise_cipher;/* WPA/WPA2/WEP pairwise cipher */ ++ int is_8021x; ++ ++ /* bwmode 20/40 and ch_offset UP/LOW */ ++ unsigned short ht_cap_info; ++ unsigned char ht_info_infos_0; ++}; ++ ++/* temporally add #pragma pack for structure alignment issue of ++* struct wlan_bssid_ex and get_struct wlan_bssid_ex_sz() ++*/ ++struct wlan_bssid_ex { ++ u32 Length; ++ unsigned char MacAddress[ETH_ALEN]; ++ u8 Reserved[2];/* 0]: IS beacon frame */ ++ struct ndis_802_11_ssid Ssid; ++ u32 Privacy; ++ NDIS_802_11_RSSI Rssi;/* in dBM,raw data ,get from PHY) */ ++ enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; ++ struct ndis_802_11_config Configuration; ++ enum ndis_802_11_network_infra InfrastructureMode; ++ unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX]; ++ struct wlan_phy_info PhyInfo; ++ u32 IELength; ++ u8 IEs[MAX_IE_SZ]; /* timestamp, beacon interval, and ++ * capability information) */ ++} __packed; ++ ++static inline uint get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss) ++{ ++ return sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + bss->IELength; ++} ++ ++struct wlan_network { ++ struct list_head list; ++ int network_type; /* refer to ieee80211.h for WIRELESS_11B/G */ ++ int fixed; /* set fixed when not to be removed ++ * in site-surveying */ ++ unsigned long last_scanned; /* timestamp for the network */ ++ int aid; /* will only be valid when a BSS is joinned. */ ++ int join_res; ++ struct wlan_bssid_ex network; /* must be the last item */ ++ struct wlan_bcn_info BcnInfo; ++}; ++ ++enum VRTL_CARRIER_SENSE { ++ DISABLE_VCS, ++ ENABLE_VCS, ++ AUTO_VCS ++}; ++ ++enum VCS_TYPE { ++ NONE_VCS, ++ RTS_CTS, ++ CTS_TO_SELF ++}; ++ ++#define PWR_CAM 0 ++#define PWR_MINPS 1 ++#define PWR_MAXPS 2 ++#define PWR_UAPSD 3 ++#define PWR_VOIP 4 ++ ++enum UAPSD_MAX_SP { ++ NO_LIMIT, ++ TWO_MSDU, ++ FOUR_MSDU, ++ SIX_MSDU ++}; ++ ++#define NUM_PRE_AUTH_KEY 16 ++#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY ++ ++/* ++* WPA2 ++*/ ++ ++struct pmkid_candidate { ++ unsigned char BSSID[ETH_ALEN]; ++ u32 Flags; ++}; ++ ++struct ndis_802_11_pmkid_list { ++ u32 Version; /* Version of the structure */ ++ u32 NumCandidates; /* No. of pmkid candidates */ ++ struct pmkid_candidate CandidateList[1]; ++}; ++ ++struct ndis_802_11_auth_encrypt { ++ enum ndis_802_11_auth_mode AuthModeSupported; ++ enum ndis_802_11_wep_status EncryptStatusSupported; ++}; ++ ++struct ndis_802_11_cap { ++ u32 Length; ++ u32 Version; ++ u32 NoOfPMKIDs; ++ u32 NoOfAuthEncryptPairsSupported; ++ struct ndis_802_11_auth_encrypt AuthenticationEncryptionSupported[1]; ++}; ++ ++u8 key_2char2num(u8 hch, u8 lch); ++u8 key_char2num(u8 ch); ++u8 str_2char2num(u8 hch, u8 lch); ++ ++#endif /* ifndef WLAN_BSSDEF_H_ */ +diff --git a/drivers/staging/r8188eu/include/xmit_osdep.h b/drivers/staging/r8188eu/include/xmit_osdep.h +new file mode 100644 +index 000000000000..191c36361b63 +--- /dev/null ++++ b/drivers/staging/r8188eu/include/xmit_osdep.h +@@ -0,0 +1,51 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#ifndef __XMIT_OSDEP_H_ ++#define __XMIT_OSDEP_H_ ++ ++#include "osdep_service.h" ++#include "drv_types.h" ++ ++struct pkt_file { ++ struct sk_buff *pkt; ++ size_t pkt_len; /* the remainder length of the open_file */ ++ unsigned char *cur_buffer; ++ u8 *buf_start; ++ u8 *cur_addr; ++ size_t buf_len; ++}; ++ ++extern int rtw_ht_enable; ++extern int rtw_cbw40_enable; ++extern int rtw_ampdu_enable;/* for enable tx_ampdu */ ++ ++#define NR_XMITFRAME 256 ++ ++struct xmit_priv; ++struct pkt_attrib; ++struct sta_xmit_priv; ++struct xmit_frame; ++struct xmit_buf; ++ ++int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev); ++ ++void rtw_os_xmit_schedule(struct adapter *padapter); ++ ++int rtw_os_xmit_resource_alloc(struct adapter *padapter, ++ struct xmit_buf *pxmitbuf, u32 alloc_sz); ++void rtw_os_xmit_resource_free(struct adapter *padapter, ++ struct xmit_buf *pxmitbuf, u32 free_sz); ++ ++void rtw_set_tx_chksum_offload(struct sk_buff *pkt, struct pkt_attrib *pattrib); ++ ++uint rtw_remainder_len(struct pkt_file *pfile); ++void _rtw_open_pktfile(struct sk_buff *pkt, struct pkt_file *pfile); ++uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen); ++int rtw_endofpktfile(struct pkt_file *pfile); ++ ++void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt); ++void rtw_os_xmit_complete(struct adapter *padapter, ++ struct xmit_frame *pxframe); ++ ++#endif /* __XMIT_OSDEP_H_ */ +diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c +new file mode 100644 +index 000000000000..1fd375076001 +--- /dev/null ++++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c +@@ -0,0 +1,6649 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _IOCTL_LINUX_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/wlan_bssdef.h" ++#include "../include/rtw_debug.h" ++#include "../include/wifi.h" ++#include "../include/rtw_mlme.h" ++#include "../include/rtw_mlme_ext.h" ++#include "../include/rtw_ioctl.h" ++#include "../include/rtw_ioctl_set.h" ++#include "../include/rtw_mp_ioctl.h" ++#include "../include/usb_ops.h" ++#include "../include/rtl8188e_hal.h" ++ ++#include "../include/rtw_mp.h" ++#include "../include/rtw_iol.h" ++ ++#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30) ++ ++#define SCAN_ITEM_SIZE 768 ++#define MAX_CUSTOM_LEN 64 ++#define RATE_COUNT 4 ++ ++/* combo scan */ ++#define WEXT_CSCAN_AMOUNT 9 ++#define WEXT_CSCAN_BUF_LEN 360 ++#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00" ++#define WEXT_CSCAN_HEADER_SIZE 12 ++#define WEXT_CSCAN_SSID_SECTION 'S' ++#define WEXT_CSCAN_CHANNEL_SECTION 'C' ++#define WEXT_CSCAN_NPROBE_SECTION 'N' ++#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A' ++#define WEXT_CSCAN_PASV_DWELL_SECTION 'P' ++#define WEXT_CSCAN_HOME_DWELL_SECTION 'H' ++#define WEXT_CSCAN_TYPE_SECTION 'T' ++ ++static struct mp_ioctl_handler mp_ioctl_hdl[] = { ++/*0*/ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_start_test_hdl, OID_RT_PRO_START_TEST) ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_stop_test_hdl, OID_RT_PRO_STOP_TEST) ++ ++ GEN_HANDLER(sizeof(struct rwreg_param), rtl8188eu_oid_rt_pro_read_register_hdl, OID_RT_PRO_READ_REGISTER) ++ GEN_HANDLER(sizeof(struct rwreg_param), rtl8188eu_oid_rt_pro_write_register_hdl, OID_RT_PRO_WRITE_REGISTER) ++ GEN_HANDLER(sizeof(struct bb_reg_param), rtl8188eu_oid_rt_pro_read_bb_reg_hdl, OID_RT_PRO_READ_BB_REG) ++/*5*/ GEN_HANDLER(sizeof(struct bb_reg_param), rtl8188eu_oid_rt_pro_write_bb_reg_hdl, OID_RT_PRO_WRITE_BB_REG) ++ GEN_HANDLER(sizeof(struct rf_reg_param), rtl8188eu_oid_rt_pro_read_rf_reg_hdl, OID_RT_PRO_RF_READ_REGISTRY) ++ GEN_HANDLER(sizeof(struct rf_reg_param), rtl8188eu_oid_rt_pro_write_rf_reg_hdl, OID_RT_PRO_RF_WRITE_REGISTRY) ++ ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_channel_direct_call_hdl, OID_RT_PRO_SET_CHANNEL_DIRECT_CALL) ++ GEN_HANDLER(sizeof(struct txpower_param), rtl8188eu_oid_rt_pro_set_tx_power_control_hdl, OID_RT_PRO_SET_TX_POWER_CONTROL) ++/*10*/ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_data_rate_hdl, OID_RT_PRO_SET_DATA_RATE) ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_set_bandwidth_hdl, OID_RT_SET_BANDWIDTH) ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_antenna_bb_hdl, OID_RT_PRO_SET_ANTENNA_BB) ++ ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_continuous_tx_hdl, OID_RT_PRO_SET_CONTINUOUS_TX) ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_single_carrier_tx_hdl, OID_RT_PRO_SET_SINGLE_CARRIER_TX) ++/*15*/ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_carrier_suppression_tx_hdl, OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX) ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_pro_set_single_tone_tx_hdl, OID_RT_PRO_SET_SINGLE_TONE_TX) ++ ++ EXT_MP_IOCTL_HANDLER(0, xmit_packet, 0) ++ ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_set_rx_packet_type_hdl, OID_RT_SET_RX_PACKET_TYPE) ++ GEN_HANDLER(0, rtl8188eu_oid_rt_reset_phy_rx_packet_count_hdl, OID_RT_RESET_PHY_RX_PACKET_COUNT) ++/*20*/ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_phy_rx_packet_received_hdl, OID_RT_GET_PHY_RX_PACKET_RECEIVED) ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_phy_rx_packet_crc32_error_hdl, OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR) ++ ++ GEN_HANDLER(sizeof(struct eeprom_rw_param), NULL, 0) ++ GEN_HANDLER(sizeof(struct eeprom_rw_param), NULL, 0) ++ GEN_HANDLER(sizeof(struct efuse_access_struct), rtl8188eu_oid_rt_pro_efuse_hdl, OID_RT_PRO_EFUSE) ++/*25*/ GEN_HANDLER(0, rtl8188eu_oid_rt_pro_efuse_map_hdl, OID_RT_PRO_EFUSE_MAP) ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_efuse_max_size_hdl, OID_RT_GET_EFUSE_MAX_SIZE) ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_efuse_current_size_hdl, OID_RT_GET_EFUSE_CURRENT_SIZE) ++ ++ GEN_HANDLER(sizeof(u32), rtl8188eu_oid_rt_get_thermal_meter_hdl, OID_RT_PRO_GET_THERMAL_METER) ++ GEN_HANDLER(sizeof(u8), rtl8188eu_oid_rt_pro_set_power_tracking_hdl, OID_RT_PRO_SET_POWER_TRACKING) ++/*30*/ GEN_HANDLER(sizeof(u8), rtl8188eu_oid_rt_set_power_down_hdl, OID_RT_SET_POWER_DOWN) ++/*31*/ GEN_HANDLER(0, rtl8188eu_oid_rt_pro_trigger_gpio_hdl, 0) ++}; ++ ++static u32 rtw_rates[] = {1000000, 2000000, 5500000, 11000000, ++ 6000000, 9000000, 12000000, 18000000, 24000000, 36000000, ++ 48000000, 54000000}; ++ ++void indicate_wx_scan_complete_event(struct adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ ++ memset(&wrqu, 0, sizeof(union iwreq_data)); ++ wireless_send_event(padapter->pnetdev, SIOCGIWSCAN, &wrqu, NULL); ++} ++ ++void rtw_indicate_wx_assoc_event(struct adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ memset(&wrqu, 0, sizeof(union iwreq_data)); ++ ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ ++ memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN); ++ ++ DBG_88E_LEVEL(_drv_always_, "assoc success\n"); ++ wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL); ++} ++ ++void rtw_indicate_wx_disassoc_event(struct adapter *padapter) ++{ ++ union iwreq_data wrqu; ++ ++ memset(&wrqu, 0, sizeof(union iwreq_data)); ++ ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); ++ ++ DBG_88E_LEVEL(_drv_always_, "indicate disassoc\n"); ++ wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL); ++} ++ ++static char *translate_scan(struct adapter *padapter, ++ struct iw_request_info *info, ++ struct wlan_network *pnetwork, ++ char *start, char *stop) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct iw_event iwe; ++ u16 cap; ++ __le16 le_tmp; ++ u32 ht_ielen = 0; ++ char *custom; ++ char *p; ++ u16 max_rate = 0, rate, ht_cap = false; ++ u32 i = 0; ++ u8 bw_40MHz = 0, short_GI = 0; ++ u16 mcs_rate = 0; ++ u8 ss, sq; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { ++ u32 blnGotP2PIE = false; ++ ++ /* User is doing the P2P device discovery */ ++ /* The prefix of SSID should be "DIRECT-" and the IE should contains the P2P IE. */ ++ /* If not, the driver should ignore this AP and go to the next AP. */ ++ ++ /* Verifying the SSID */ ++ if (!memcmp(pnetwork->network.Ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN)) { ++ u32 p2pielen = 0; ++ ++ if (pnetwork->network.Reserved[0] == 2) {/* Probe Request */ ++ /* Verifying the P2P IE */ ++ if (rtw_get_p2p_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &p2pielen)) ++ blnGotP2PIE = true; ++ } else {/* Beacon or Probe Respones */ ++ /* Verifying the P2P IE */ ++ if (rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen)) ++ blnGotP2PIE = true; ++ } ++ } ++ ++ if (!blnGotP2PIE) ++ return start; ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ /* AP MAC address */ ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ ++ memcpy(iwe.u.ap_addr.sa_data, pnetwork->network.MacAddress, ETH_ALEN); ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); ++ ++ /* Add the ESSID */ ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.flags = 1; ++ iwe.u.data.length = min_t(u16, pnetwork->network.Ssid.SsidLength, 32); ++ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); ++ ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength - 12); ++ ++ if (p && ht_ielen > 0) { ++ struct ieee80211_ht_cap *pht_capie; ++ ++ ht_cap = true; ++ pht_capie = (struct ieee80211_ht_cap *)(p + 2); ++ memcpy(&mcs_rate, pht_capie->mcs.rx_mask, 2); ++ bw_40MHz = (le16_to_cpu(pht_capie->cap_info) & ++ IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0; ++ short_GI = (le16_to_cpu(pht_capie->cap_info) & ++ (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; ++ } ++ ++ /* Add the protocol name */ ++ iwe.cmd = SIOCGIWNAME; ++ if ((rtw_is_cckratesonly_included((u8 *)&pnetwork->network.SupportedRates))) { ++ if (ht_cap) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); ++ } else if ((rtw_is_cckrates_included((u8 *)&pnetwork->network.SupportedRates))) { ++ if (ht_cap) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg"); ++ } else { ++ if (ht_cap) ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn"); ++ else ++ snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g"); ++ } ++ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); ++ ++ /* Add mode */ ++ iwe.cmd = SIOCGIWMODE; ++ memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2); ++ ++ cap = le16_to_cpu(le_tmp); ++ ++ if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) { ++ if (cap & WLAN_CAPABILITY_BSS) ++ iwe.u.mode = IW_MODE_MASTER; ++ else ++ iwe.u.mode = IW_MODE_ADHOC; ++ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); ++ } ++ ++ if (pnetwork->network.Configuration.DSConfig < 1) ++ pnetwork->network.Configuration.DSConfig = 1; ++ ++ /* Add frequency/channel */ ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = rtw_ch2freq(pnetwork->network.Configuration.DSConfig) * 100000; ++ iwe.u.freq.e = 1; ++ iwe.u.freq.i = pnetwork->network.Configuration.DSConfig; ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); ++ ++ /* Add encryption capability */ ++ iwe.cmd = SIOCGIWENCODE; ++ if (cap & WLAN_CAPABILITY_PRIVACY) ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ else ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ iwe.u.data.length = 0; ++ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid); ++ ++ /*Add basic and extended rates */ ++ max_rate = 0; ++ custom = kzalloc(MAX_CUSTOM_LEN, GFP_ATOMIC); ++ if (!custom) ++ return start; ++ p = custom; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); ++ while (pnetwork->network.SupportedRates[i] != 0) { ++ rate = pnetwork->network.SupportedRates[i] & 0x7F; ++ if (rate > max_rate) ++ max_rate = rate; ++ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), ++ "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); ++ i++; ++ } ++ ++ if (ht_cap) { ++ if (mcs_rate & 0x8000)/* MCS15 */ ++ max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : ((short_GI) ? 144 : 130); ++ else if (mcs_rate & 0x0080)/* MCS7 */ ++ ; ++ else/* default MCS7 */ ++ max_rate = (bw_40MHz) ? ((short_GI) ? 150 : 135) : ((short_GI) ? 72 : 65); ++ ++ max_rate = max_rate * 2;/* Mbps/2; */ ++ } ++ ++ iwe.cmd = SIOCGIWRATE; ++ iwe.u.bitrate.fixed = 0; ++ iwe.u.bitrate.disabled = 0; ++ iwe.u.bitrate.value = max_rate * 500000; ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN); ++ ++ /* parsing WPA/WPA2 IE */ ++ { ++ u8 *buf; ++ u8 *wpa_ie, *rsn_ie; ++ u16 wpa_len = 0, rsn_len = 0; ++ u8 *p; ++ ++ buf = kzalloc(MAX_WPA_IE_LEN, GFP_ATOMIC); ++ if (!buf) ++ goto exit; ++ wpa_ie = kzalloc(255, GFP_ATOMIC); ++ if (!wpa_ie) { ++ kfree(buf); ++ goto exit; ++ } ++ rsn_ie = kzalloc(255, GFP_ATOMIC); ++ if (!rsn_ie) { ++ kfree(buf); ++ kfree(wpa_ie); ++ goto exit; ++ } ++ rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, rsn_ie, &rsn_len, wpa_ie, &wpa_len); ++ ++ if (wpa_len > 0) { ++ p = buf; ++ memset(buf, 0, MAX_WPA_IE_LEN); ++ p += sprintf(p, "wpa_ie ="); ++ for (i = 0; i < wpa_len; i++) ++ p += sprintf(p, "%02x", wpa_ie[i]); ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = wpa_len; ++ start = iwe_stream_add_point(info, start, stop, &iwe, wpa_ie); ++ } ++ if (rsn_len > 0) { ++ p = buf; ++ memset(buf, 0, MAX_WPA_IE_LEN); ++ p += sprintf(p, "rsn_ie ="); ++ for (i = 0; i < rsn_len; i++) ++ p += sprintf(p, "%02x", rsn_ie[i]); ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ iwe.u.data.length = strlen(buf); ++ start = iwe_stream_add_point(info, start, stop, &iwe, buf); ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = rsn_len; ++ start = iwe_stream_add_point(info, start, stop, &iwe, rsn_ie); ++ } ++ kfree(buf); ++ kfree(wpa_ie); ++ kfree(rsn_ie); ++ } ++ ++ {/* parsing WPS IE */ ++ uint cnt = 0, total_ielen; ++ u8 *wpsie_ptr = NULL; ++ uint wps_ielen = 0; ++ ++ u8 *ie_ptr = pnetwork->network.IEs + _FIXED_IE_LENGTH_; ++ total_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_; ++ ++ while (cnt < total_ielen) { ++ if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen > 2)) { ++ wpsie_ptr = &ie_ptr[cnt]; ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = (u16)wps_ielen; ++ start = iwe_stream_add_point(info, start, stop, &iwe, wpsie_ptr); ++ } ++ cnt += ie_ptr[cnt + 1] + 2; /* goto next */ ++ } ++ } ++ ++ /* Add quality statistics */ ++ iwe.cmd = IWEVQUAL; ++ iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) && ++ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network)) { ++ ss = padapter->recvpriv.signal_strength; ++ sq = padapter->recvpriv.signal_qual; ++ } else { ++ ss = pnetwork->network.PhyInfo.SignalStrength; ++ sq = pnetwork->network.PhyInfo.SignalQuality; ++ } ++ ++ iwe.u.qual.level = (u8)ss; ++ iwe.u.qual.qual = (u8)sq; /* signal quality */ ++ iwe.u.qual.noise = 0; /* noise level */ ++ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); ++exit: ++ kfree(custom); ++ return start; ++} ++ ++static int wpa_set_auth_algs(struct net_device *dev, u32 value) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ int ret = 0; ++ ++ if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) { ++ DBG_88E("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", value); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; ++ } else if (value & AUTH_ALG_SHARED_KEY) { ++ DBG_88E("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY [value:0x%x]\n", value); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; ++ } else if (value & AUTH_ALG_OPEN_SYSTEM) { ++ DBG_88E("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n"); ++ if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) { ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ } ++ } else if (value & AUTH_ALG_LEAP) { ++ DBG_88E("wpa_set_auth_algs, AUTH_ALG_LEAP\n"); ++ } else { ++ DBG_88E("wpa_set_auth_algs, error!\n"); ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len) ++{ ++ int ret = 0; ++ u32 wep_key_idx, wep_key_len, wep_total_len; ++ struct ndis_802_11_wep *pwep = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ param->u.crypt.err = 0; ++ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; ++ ++ if (param_len < (u32)((u8 *)param->u.crypt.key - (u8 *)param) + param->u.crypt.key_len) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && ++ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && ++ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { ++ if (param->u.crypt.idx >= WEP_KEYS) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } else { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (strcmp(param->u.crypt.alg, "WEP") == 0) { ++ DBG_88E("wpa_set_encryption, crypt.alg = WEP\n"); ++ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; ++ ++ wep_key_idx = param->u.crypt.idx; ++ wep_key_len = param->u.crypt.key_len; ++ ++ DBG_88E("(1)wep_key_idx =%d\n", wep_key_idx); ++ ++ if (wep_key_idx > WEP_KEYS) ++ return -EINVAL; ++ ++ if (wep_key_len > 0) { ++ wep_key_len = wep_key_len <= 5 ? 5 : 13; ++ wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); ++ pwep = kmalloc(wep_total_len, GFP_KERNEL); ++ if (!pwep) ++ goto exit; ++ ++ memset(pwep, 0, wep_total_len); ++ pwep->KeyLength = wep_key_len; ++ pwep->Length = wep_total_len; ++ if (wep_key_len == 13) { ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; ++ } ++ } else { ++ ret = -EINVAL; ++ goto exit; ++ } ++ pwep->KeyIndex = wep_key_idx; ++ pwep->KeyIndex |= 0x80000000; ++ memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength); ++ if (param->u.crypt.set_tx) { ++ DBG_88E("wep, set_tx = 1\n"); ++ if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL) ++ ret = -EOPNOTSUPP; ++ } else { ++ DBG_88E("wep, set_tx = 0\n"); ++ if (wep_key_idx >= WEP_KEYS) { ++ ret = -EOPNOTSUPP; ++ goto exit; ++ } ++ memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0], pwep->KeyMaterial, pwep->KeyLength); ++ psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength; ++ rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0); ++ } ++ goto exit; ++ } ++ ++ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */ ++ struct sta_info *psta, *pbcmc_sta; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE)) { /* sta mode */ ++ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); ++ if (!psta) { ++ ; ++ } else { ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ psta->ieee8021x_blocked = false; ++ ++ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) || ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ ++ if (param->u.crypt.set_tx == 1) { /* pairwise key */ ++ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); ++ ++ if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */ ++ memcpy(psta->dot11tkiptxmickey.skey, ¶m->u.crypt.key[16], 8); ++ memcpy(psta->dot11tkiprxmickey.skey, ¶m->u.crypt.key[24], 8); ++ padapter->securitypriv.busetkipkey = false; ++ } ++ ++ DBG_88E(" ~~~~set sta key:unicastkey\n"); ++ ++ rtw_setstakey_cmd(padapter, (unsigned char *)psta, true); ++ } else { /* group key */ ++ memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); ++ memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[16], 8); ++ memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, ¶m->u.crypt.key[24], 8); ++ padapter->securitypriv.binstallGrpkey = true; ++ DBG_88E(" ~~~~set sta key:groupkey\n"); ++ ++ padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; ++ ++ rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1); ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_DONE); ++#endif /* CONFIG_88EU_P2P */ ++ } ++ } ++ pbcmc_sta = rtw_get_bcmc_stainfo(padapter); ++ if (!pbcmc_sta) { ++ ; ++ } else { ++ /* Jeff: don't disable ieee8021x_blocked while clearing key */ ++ if (strcmp(param->u.crypt.alg, "none") != 0) ++ pbcmc_sta->ieee8021x_blocked = false; ++ ++ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) || ++ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) ++ pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; ++ } ++ } ++ } ++ ++exit: ++ ++ kfree(pwep); ++ ++ return ret; ++} ++ ++static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ielen) ++{ ++ u8 *buf = NULL; ++ int group_cipher = 0, pairwise_cipher = 0; ++ int ret = 0; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ if (ielen > MAX_WPA_IE_LEN || !pie) { ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ if (!pie) ++ return ret; ++ else ++ return -EINVAL; ++ } ++ ++ if (ielen) { ++ buf = kzalloc(ielen, GFP_KERNEL); ++ if (!buf) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ memcpy(buf, pie, ielen); ++ ++ /* dump */ ++ { ++ int i; ++ DBG_88E("\n wpa_ie(length:%d):\n", ielen); ++ for (i = 0; i < ielen; i += 8) ++ DBG_88E("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]); ++ } ++ ++ if (ielen < RSN_HEADER_LEN) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; ++ memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); ++ } ++ ++ if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; ++ memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen); ++ } ++ ++ switch (group_cipher) { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot118021XGrpPrivacy = _AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ switch (pairwise_cipher) { ++ case WPA_CIPHER_NONE: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ break; ++ case WPA_CIPHER_WEP40: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ case WPA_CIPHER_TKIP: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; ++ break; ++ case WPA_CIPHER_CCMP: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _AES_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; ++ break; ++ case WPA_CIPHER_WEP104: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ break; ++ } ++ ++ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); ++ {/* set wps_ie */ ++ u16 cnt = 0; ++ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; ++ ++ while (cnt < ielen) { ++ eid = buf[cnt]; ++ if ((eid == _VENDOR_SPECIFIC_IE_) && (!memcmp(&buf[cnt + 2], wps_oui, 4))) { ++ DBG_88E("SET WPS_IE\n"); ++ ++ padapter->securitypriv.wps_ie_len = ((buf[cnt + 1] + 2) < (MAX_WPA_IE_LEN << 2)) ? (buf[cnt + 1] + 2) : (MAX_WPA_IE_LEN << 2); ++ ++ memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len); ++ ++ set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS); ++#ifdef CONFIG_88EU_P2P ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK)) ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_ING); ++#endif /* CONFIG_88EU_P2P */ ++ cnt += buf[cnt + 1] + 2; ++ break; ++ } else { ++ cnt += buf[cnt + 1] + 2; /* goto next */ ++ } ++ } ++ } ++ } ++ ++exit: ++ kfree(buf); ++ return ret; ++} ++ ++typedef unsigned char NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; ++ ++static int rtw_wx_get_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u32 ht_ielen = 0; ++ char *p; ++ u8 ht_cap = false; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ NDIS_802_11_RATES_EX *prates = NULL; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE)) { ++ /* parsing HT_CAP_IE */ ++ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength - 12); ++ if (p && ht_ielen > 0) ++ ht_cap = true; ++ ++ prates = &pcur_bss->SupportedRates; ++ ++ if (rtw_is_cckratesonly_included((u8 *)prates)) { ++ if (ht_cap) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b"); ++ } else if (rtw_is_cckrates_included((u8 *)prates)) { ++ if (ht_cap) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bgn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bg"); ++ } else { ++ if (ht_cap) ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn"); ++ else ++ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); ++ } ++ } else { ++ snprintf(wrqu->name, IFNAMSIZ, "unassociated"); ++ } ++ ++ ++ ++ return 0; ++} ++ ++static int rtw_wx_get_freq(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ /* wrqu->freq.m = ieee80211_wlan_frequencies[pcur_bss->Configuration.DSConfig-1] * 100000; */ ++ wrqu->freq.m = rtw_ch2freq(pcur_bss->Configuration.DSConfig) * 100000; ++ wrqu->freq.e = 1; ++ wrqu->freq.i = pcur_bss->Configuration.DSConfig; ++ } else { ++ wrqu->freq.m = rtw_ch2freq(padapter->mlmeextpriv.cur_channel) * 100000; ++ wrqu->freq.e = 1; ++ wrqu->freq.i = padapter->mlmeextpriv.cur_channel; ++ } ++ ++ return 0; ++} ++ ++static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ enum ndis_802_11_network_infra networkType; ++ int ret = 0; ++ ++ ++ ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ if (!padapter->hw_init_completed) { ++ ret = -EPERM; ++ goto exit; ++ } ++ ++ switch (wrqu->mode) { ++ case IW_MODE_AUTO: ++ networkType = Ndis802_11AutoUnknown; ++ DBG_88E("set_mode = IW_MODE_AUTO\n"); ++ break; ++ case IW_MODE_ADHOC: ++ networkType = Ndis802_11IBSS; ++ DBG_88E("set_mode = IW_MODE_ADHOC\n"); ++ break; ++ case IW_MODE_MASTER: ++ networkType = Ndis802_11APMode; ++ DBG_88E("set_mode = IW_MODE_MASTER\n"); ++ break; ++ case IW_MODE_INFRA: ++ networkType = Ndis802_11Infrastructure; ++ DBG_88E("set_mode = IW_MODE_INFRA\n"); ++ break; ++ default: ++ ret = -EINVAL; ++ goto exit; ++ } ++ if (!rtw_set_802_11_infrastructure_mode(padapter, networkType)) { ++ ret = -EPERM; ++ goto exit; ++ } ++ rtw_setopmode_cmd(padapter, networkType); ++exit: ++ ++ return ret; ++} ++ ++static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) ++ wrqu->mode = IW_MODE_INFRA; ++ else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))) ++ wrqu->mode = IW_MODE_ADHOC; ++ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ wrqu->mode = IW_MODE_MASTER; ++ else ++ wrqu->mode = IW_MODE_AUTO; ++ ++ ++ ++ return 0; ++} ++ ++static int rtw_wx_set_pmkid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 j, blInserted = false; ++ int ret = false; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct iw_pmksa *pPMK = (struct iw_pmksa *)extra; ++ u8 strZeroMacAddress[ETH_ALEN] = {0x00}; ++ u8 strIssueBssid[ETH_ALEN] = {0x00}; ++ ++ memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN); ++ if (pPMK->cmd == IW_PMKSA_ADD) { ++ DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n"); ++ if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN)) ++ return ret; ++ else ++ ret = true; ++ blInserted = false; ++ ++ /* overwrite PMKID */ ++ for (j = 0; j < NUM_PMKID_CACHE; j++) { ++ if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { ++ /* BSSID is matched, the same AP => rewrite with new PMKID. */ ++ DBG_88E("[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n"); ++ memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN); ++ psecuritypriv->PMKIDList[j].bUsed = true; ++ psecuritypriv->PMKIDIndex = j + 1; ++ blInserted = true; ++ break; ++ } ++ } ++ ++ if (!blInserted) { ++ /* Find a new entry */ ++ DBG_88E("[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n", ++ psecuritypriv->PMKIDIndex); ++ ++ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN); ++ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN); ++ ++ psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true; ++ psecuritypriv->PMKIDIndex++; ++ if (psecuritypriv->PMKIDIndex == 16) ++ psecuritypriv->PMKIDIndex = 0; ++ } ++ } else if (pPMK->cmd == IW_PMKSA_REMOVE) { ++ DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n"); ++ ret = true; ++ for (j = 0; j < NUM_PMKID_CACHE; j++) { ++ if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { ++ /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ ++ memset(psecuritypriv->PMKIDList[j].Bssid, 0x00, ETH_ALEN); ++ psecuritypriv->PMKIDList[j].bUsed = false; ++ break; ++ } ++ } ++ } else if (pPMK->cmd == IW_PMKSA_FLUSH) { ++ DBG_88E("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n"); ++ memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); ++ psecuritypriv->PMKIDIndex = 0; ++ ret = true; ++ } ++ return ret; ++} ++ ++static int rtw_wx_get_sens(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ wrqu->sens.value = 0; ++ wrqu->sens.fixed = 0; /* no auto select */ ++ wrqu->sens.disabled = 1; ++ return 0; ++} ++ ++static int rtw_wx_get_range(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_range *range = (struct iw_range *)extra; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ u16 val; ++ int i; ++ ++ wrqu->data.length = sizeof(*range); ++ memset(range, 0, sizeof(*range)); ++ ++ /* Let's try to keep this struct in the same order as in ++ * linux/include/wireless.h ++ */ ++ ++ /* TODO: See what values we can set, and remove the ones we can't ++ * set, or fill them with some default data. ++ */ ++ ++ /* ~5 Mb/s real (802.11b) */ ++ range->throughput = 5 * 1000 * 1000; ++ ++ /* signal level threshold range */ ++ ++ /* percent values between 0 and 100. */ ++ range->max_qual.qual = 100; ++ range->max_qual.level = 100; ++ range->max_qual.noise = 100; ++ range->max_qual.updated = 7; /* Updated all three */ ++ ++ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ ++ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */ ++ range->avg_qual.level = 178; /* -78 dBm */ ++ range->avg_qual.noise = 0; ++ range->avg_qual.updated = 7; /* Updated all three */ ++ ++ range->num_bitrates = RATE_COUNT; ++ ++ for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) ++ range->bitrate[i] = rtw_rates[i]; ++ ++ range->min_frag = MIN_FRAG_THRESHOLD; ++ range->max_frag = MAX_FRAG_THRESHOLD; ++ ++ range->pm_capa = 0; ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 16; ++ ++ for (i = 0, val = 0; i < MAX_CHANNEL_NUM; i++) { ++ /* Include only legal frequencies for some countries */ ++ if (pmlmeext->channel_set[i].ChannelNum != 0) { ++ range->freq[val].i = pmlmeext->channel_set[i].ChannelNum; ++ range->freq[val].m = rtw_ch2freq(pmlmeext->channel_set[i].ChannelNum) * 100000; ++ range->freq[val].e = 1; ++ val++; ++ } ++ ++ if (val == IW_MAX_FREQUENCIES) ++ break; ++ } ++ ++ range->num_channels = val; ++ range->num_frequency = val; ++ ++/* The following code will proivde the security capability to network manager. */ ++/* If the driver doesn't provide this capability to network manager, */ ++/* the WPA/WPA2 routers can't be chosen in the network manager. */ ++ ++/* ++#define IW_SCAN_CAPA_NONE 0x00 ++#define IW_SCAN_CAPA_ESSID 0x01 ++#define IW_SCAN_CAPA_BSSID 0x02 ++#define IW_SCAN_CAPA_CHANNEL 0x04 ++#define IW_SCAN_CAPA_MODE 0x08 ++#define IW_SCAN_CAPA_RATE 0x10 ++#define IW_SCAN_CAPA_TYPE 0x20 ++#define IW_SCAN_CAPA_TIME 0x40 ++*/ ++ ++ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | ++ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; ++ ++ range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE | ++ IW_SCAN_CAPA_BSSID | IW_SCAN_CAPA_CHANNEL | ++ IW_SCAN_CAPA_MODE | IW_SCAN_CAPA_RATE; ++ ++ ++ return 0; ++} ++ ++/* set bssid flow */ ++/* s1. rtw_set_802_11_infrastructure_mode() */ ++/* s2. rtw_set_802_11_authentication_mode() */ ++/* s3. set_802_11_encryption_mode() */ ++/* s4. rtw_set_802_11_bssid() */ ++static int rtw_wx_set_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ uint ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct sockaddr *temp = (struct sockaddr *)awrq; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *phead; ++ u8 *dst_bssid, *src_bssid; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ enum ndis_802_11_auth_mode authmode; ++ ++ ++ ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!padapter->bup) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (temp->sa_family != ARPHRD_ETHER) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ authmode = padapter->securitypriv.ndisauthtype; ++ spin_lock_bh(&queue->lock); ++ phead = get_list_head(queue); ++ pmlmepriv->pscanned = phead->next; ++ ++ while (phead != pmlmepriv->pscanned) { ++ ++ pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list); ++ ++ pmlmepriv->pscanned = pmlmepriv->pscanned->next; ++ ++ dst_bssid = pnetwork->network.MacAddress; ++ ++ src_bssid = temp->sa_data; ++ ++ if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) { ++ if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) { ++ ret = -1; ++ spin_unlock_bh(&queue->lock); ++ goto exit; ++ } ++ ++ break; ++ } ++ } ++ spin_unlock_bh(&queue->lock); ++ ++ rtw_set_802_11_authentication_mode(padapter, authmode); ++ /* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */ ++ if (!rtw_set_802_11_bssid(padapter, temp->sa_data)) { ++ ret = -1; ++ goto exit; ++ } ++ ++exit: ++ ++ ++ ++ return ret; ++} ++ ++static int rtw_wx_get_wap(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ wrqu->ap_addr.sa_family = ARPHRD_ETHER; ++ ++ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) || ++ check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || ++ check_fwstate(pmlmepriv, WIFI_AP_STATE)) ++ memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN); ++ else ++ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); ++ ++ ++ ++ return 0; ++} ++ ++static int rtw_wx_set_mlme(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u16 reason; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_mlme *mlme = (struct iw_mlme *)extra; ++ ++ if (!mlme) ++ return -1; ++ ++ DBG_88E("%s\n", __func__); ++ ++ reason = mlme->reason_code; ++ ++ DBG_88E("%s, cmd =%d, reason =%d\n", __func__, mlme->cmd, reason); ++ ++ switch (mlme->cmd) { ++ case IW_MLME_DEAUTH: ++ if (!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ break; ++ case IW_MLME_DISASSOC: ++ if (!rtw_set_802_11_disassociate(padapter)) ++ ret = -1; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return ret; ++} ++ ++static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u8 _status = false; ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ if (padapter->registrypriv.mp_mode == 1) { ++ if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { ++ ret = -1; ++ goto exit; ++ } ++ } ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (padapter->bDriverStopped) { ++ DBG_88E("bDriverStopped =%d\n", padapter->bDriverStopped); ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!padapter->bup) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!padapter->hw_init_completed) { ++ ret = -1; ++ goto exit; ++ } ++ ++ /* When Busy Traffic, driver do not site survey. So driver return success. */ ++ /* wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout. */ ++ /* modify by thomas 2011-02-22. */ ++ if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { ++ indicate_wx_scan_complete_event(padapter); ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) { ++ indicate_wx_scan_complete_event(padapter); ++ goto exit; ++ } ++ ++/* For the DMP WiFi Display project, the driver won't to scan because */ ++/* the pmlmepriv->scan_interval is always equal to 3. */ ++/* So, the wpa_supplicant won't find out the WPS SoftAP. */ ++ ++#ifdef CONFIG_88EU_P2P ++ if (pwdinfo->p2p_state != P2P_STATE_NONE) { ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); ++ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_FULL); ++ rtw_free_network_queue(padapter, true); ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ memset(ssid, 0, sizeof(struct ndis_802_11_ssid) * RTW_SSID_SCAN_AMOUNT); ++ ++ if (wrqu->data.length == sizeof(struct iw_scan_req)) { ++ struct iw_scan_req *req = (struct iw_scan_req *)extra; ++ ++ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { ++ int len = min((int)req->essid_len, IW_ESSID_MAX_SIZE); ++ ++ memcpy(ssid[0].Ssid, req->essid, len); ++ ssid[0].SsidLength = len; ++ ++ DBG_88E("IW_SCAN_THIS_ESSID, ssid =%s, len =%d\n", req->essid, req->essid_len); ++ ++ spin_lock_bh(&pmlmepriv->lock); ++ ++ _status = rtw_sitesurvey_cmd(padapter, ssid, 1, NULL, 0); ++ ++ spin_unlock_bh(&pmlmepriv->lock); ++ } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { ++ DBG_88E("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n"); ++ } ++ } else { ++ if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE && ++ !memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) { ++ int len = wrqu->data.length - WEXT_CSCAN_HEADER_SIZE; ++ char *pos = extra + WEXT_CSCAN_HEADER_SIZE; ++ char section; ++ char sec_len; ++ int ssid_index = 0; ++ ++ while (len >= 1) { ++ section = *(pos++); ++ len -= 1; ++ ++ switch (section) { ++ case WEXT_CSCAN_SSID_SECTION: ++ if (len < 1) { ++ len = 0; ++ break; ++ } ++ sec_len = *(pos++); len -= 1; ++ if (sec_len > 0 && sec_len <= len) { ++ ssid[ssid_index].SsidLength = sec_len; ++ memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); ++ ssid_index++; ++ } ++ pos += sec_len; ++ len -= sec_len; ++ break; ++ case WEXT_CSCAN_TYPE_SECTION: ++ case WEXT_CSCAN_CHANNEL_SECTION: ++ pos += 1; ++ len -= 1; ++ break; ++ case WEXT_CSCAN_PASV_DWELL_SECTION: ++ case WEXT_CSCAN_HOME_DWELL_SECTION: ++ case WEXT_CSCAN_ACTV_DWELL_SECTION: ++ pos += 2; ++ len -= 2; ++ break; ++ default: ++ len = 0; /* stop parsing */ ++ } ++ } ++ ++ /* it has still some scan parameter to parse, we only do this now... */ ++ _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT); ++ } else { ++ _status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0); ++ } ++ } ++ ++ if (!_status) ++ ret = -1; ++ ++exit: ++ ++ return ret; ++} ++ ++static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct list_head *plist, *phead; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ char *ev = extra; ++ char *stop = ev + wrqu->data.length; ++ u32 ret = 0; ++ u32 cnt = 0; ++ u32 wait_for_surveydone; ++ int wait_status; ++#ifdef CONFIG_88EU_P2P ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++#endif /* CONFIG_88EU_P2P */ ++ ++ if (padapter->pwrctrlpriv.brfoffbyhw && padapter->bDriverStopped) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++#ifdef CONFIG_88EU_P2P ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { ++ /* P2P is enabled */ ++ wait_for_surveydone = 200; ++ } else { ++ /* P2P is disabled */ ++ wait_for_surveydone = 100; ++ } ++#else ++ { ++ wait_for_surveydone = 100; ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ wait_status = _FW_UNDER_SURVEY | _FW_UNDER_LINKING; ++ ++ while (check_fwstate(pmlmepriv, wait_status)) { ++ msleep(30); ++ cnt++; ++ if (cnt > wait_for_surveydone) ++ break; ++ } ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ if ((stop - ev) < SCAN_ITEM_SIZE) { ++ ret = -E2BIG; ++ break; ++ } ++ ++ pnetwork = container_of(plist, struct wlan_network, list); ++ ++ /* report network only if the current channel set contains the channel to which this network belongs */ ++ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0) ++ ev = translate_scan(padapter, a, pnetwork, ev, stop); ++ ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ wrqu->data.length = ev - extra; ++ wrqu->data.flags = 0; ++ ++exit: ++ ++ return ret; ++} ++ ++/* set ssid flow */ ++/* s1. rtw_set_802_11_infrastructure_mode() */ ++/* s2. set_802_11_authenticaion_mode() */ ++/* s3. set_802_11_encryption_mode() */ ++/* s4. rtw_set_802_11_ssid() */ ++static int rtw_wx_set_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct list_head *phead; ++ struct wlan_network *pnetwork = NULL; ++ enum ndis_802_11_auth_mode authmode; ++ struct ndis_802_11_ssid ndis_ssid; ++ u8 *dst_ssid, *src_ssid; ++ ++ uint ret = 0, len; ++ ++ if (_FAIL == rtw_pwr_wakeup(padapter)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (!padapter->bup) { ++ ret = -1; ++ goto exit; ++ } ++ ++ if (wrqu->essid.length > IW_ESSID_MAX_SIZE) { ++ ret = -E2BIG; ++ goto exit; ++ } ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ ret = -1; ++ goto exit; ++ } ++ ++ authmode = padapter->securitypriv.ndisauthtype; ++ DBG_88E("=>%s\n", __func__); ++ if (wrqu->essid.flags && wrqu->essid.length) { ++ len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : IW_ESSID_MAX_SIZE; ++ ++ if (wrqu->essid.length != 33) ++ DBG_88E("ssid =%s, len =%d\n", extra, wrqu->essid.length); ++ ++ memset(&ndis_ssid, 0, sizeof(struct ndis_802_11_ssid)); ++ ndis_ssid.SsidLength = len; ++ memcpy(ndis_ssid.Ssid, extra, len); ++ src_ssid = ndis_ssid.Ssid; ++ ++ spin_lock_bh(&queue->lock); ++ phead = get_list_head(queue); ++ pmlmepriv->pscanned = phead->next; ++ ++ while (phead != pmlmepriv->pscanned) { ++ pnetwork = container_of(pmlmepriv->pscanned, struct wlan_network, list); ++ ++ pmlmepriv->pscanned = pmlmepriv->pscanned->next; ++ ++ dst_ssid = pnetwork->network.Ssid.Ssid; ++ ++ if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) && ++ (pnetwork->network.Ssid.SsidLength == ndis_ssid.SsidLength)) { ++ ++ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { ++ if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) ++ continue; ++ } ++ ++ if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) { ++ ret = -1; ++ spin_unlock_bh(&queue->lock); ++ goto exit; ++ } ++ ++ break; ++ } ++ } ++ spin_unlock_bh(&queue->lock); ++ rtw_set_802_11_authentication_mode(padapter, authmode); ++ if (!rtw_set_802_11_ssid(padapter, &ndis_ssid)) { ++ ret = -1; ++ goto exit; ++ } ++ } ++ ++exit: ++ ++ DBG_88E("<=%s, ret %d\n", __func__, ret); ++ ++ ++ ++ return ret; ++} ++ ++static int rtw_wx_get_essid(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u32 len, ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; ++ ++ if ((check_fwstate(pmlmepriv, _FW_LINKED)) || ++ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) { ++ len = pcur_bss->Ssid.SsidLength; ++ memcpy(extra, pcur_bss->Ssid.Ssid, len); ++ } else { ++ len = 0; ++ *extra = 0; ++ } ++ wrqu->essid.length = len; ++ wrqu->essid.flags = 1; ++ ++ return ret; ++} ++ ++static int rtw_wx_set_rate(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int i, ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 datarates[NumRates]; ++ u32 target_rate = wrqu->bitrate.value; ++ u32 fixed = wrqu->bitrate.fixed; ++ u32 ratevalue = 0; ++ u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff}; ++ ++ if (target_rate == -1) { ++ ratevalue = 11; ++ goto set_rate; ++ } ++ target_rate = target_rate / 100000; ++ ++ switch (target_rate) { ++ case 10: ++ ratevalue = 0; ++ break; ++ case 20: ++ ratevalue = 1; ++ break; ++ case 55: ++ ratevalue = 2; ++ break; ++ case 60: ++ ratevalue = 3; ++ break; ++ case 90: ++ ratevalue = 4; ++ break; ++ case 110: ++ ratevalue = 5; ++ break; ++ case 120: ++ ratevalue = 6; ++ break; ++ case 180: ++ ratevalue = 7; ++ break; ++ case 240: ++ ratevalue = 8; ++ break; ++ case 360: ++ ratevalue = 9; ++ break; ++ case 480: ++ ratevalue = 10; ++ break; ++ case 540: ++ ratevalue = 11; ++ break; ++ default: ++ ratevalue = 11; ++ break; ++ } ++ ++set_rate: ++ ++ for (i = 0; i < NumRates; i++) { ++ if (ratevalue == mpdatarate[i]) { ++ datarates[i] = mpdatarate[i]; ++ if (fixed == 0) ++ break; ++ } else { ++ datarates[i] = 0xff; ++ } ++ } ++ ++ if (rtw_setdatarate_cmd(padapter, datarates) != _SUCCESS) ++ ret = -1; ++ ++ return ret; ++} ++ ++static int rtw_wx_get_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u16 max_rate = 0; ++ ++ max_rate = rtw_get_cur_max_rate((struct adapter *)rtw_netdev_priv(dev)); ++ ++ if (max_rate == 0) ++ return -EPERM; ++ ++ wrqu->bitrate.fixed = 0; /* no auto select */ ++ wrqu->bitrate.value = max_rate * 100000; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ ++ ++ if (wrqu->rts.disabled) { ++ padapter->registrypriv.rts_thresh = 2347; ++ } else { ++ if (wrqu->rts.value < 0 || ++ wrqu->rts.value > 2347) ++ return -EINVAL; ++ ++ padapter->registrypriv.rts_thresh = wrqu->rts.value; ++ } ++ ++ DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh); ++ ++ ++ ++ return 0; ++} ++ ++static int rtw_wx_get_rts(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ ++ ++ DBG_88E("%s, rts_thresh =%d\n", __func__, padapter->registrypriv.rts_thresh); ++ ++ wrqu->rts.value = padapter->registrypriv.rts_thresh; ++ wrqu->rts.fixed = 0; /* no auto select */ ++ /* wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); */ ++ ++ ++ ++ return 0; ++} ++ ++static int rtw_wx_set_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ ++ ++ if (wrqu->frag.disabled) { ++ padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD; ++ } else { ++ if (wrqu->frag.value < MIN_FRAG_THRESHOLD || ++ wrqu->frag.value > MAX_FRAG_THRESHOLD) ++ return -EINVAL; ++ ++ padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1; ++ } ++ ++ DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len); ++ ++ ++ ++ return 0; ++} ++ ++static int rtw_wx_get_frag(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ ++ ++ DBG_88E("%s, frag_len =%d\n", __func__, padapter->xmitpriv.frag_len); ++ ++ wrqu->frag.value = padapter->xmitpriv.frag_len; ++ wrqu->frag.fixed = 0; /* no auto select */ ++ ++ ++ ++ return 0; ++} ++ ++static int rtw_wx_get_retry(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ wrqu->retry.value = 7; ++ wrqu->retry.fixed = 0; /* no auto select */ ++ wrqu->retry.disabled = 1; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ u32 key, ret = 0; ++ u32 keyindex_provided; ++ struct ndis_802_11_wep wep; ++ enum ndis_802_11_auth_mode authmode; ++ ++ struct iw_point *erq = &wrqu->encoding; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ DBG_88E("+rtw_wx_set_enc, flags = 0x%x\n", erq->flags); ++ ++ memset(&wep, 0, sizeof(struct ndis_802_11_wep)); ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ ++ ++ ++ if (erq->flags & IW_ENCODE_DISABLED) { ++ DBG_88E("EncryptionDisabled\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype = authmode; ++ ++ goto exit; ++ } ++ ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ keyindex_provided = 1; ++ } else { ++ keyindex_provided = 0; ++ key = padapter->securitypriv.dot11PrivacyKeyIndex; ++ DBG_88E("rtw_wx_set_enc, key =%d\n", key); ++ } ++ ++ /* set authentication mode */ ++ if (erq->flags & IW_ENCODE_OPEN) { ++ DBG_88E("rtw_wx_set_enc():IW_ENCODE_OPEN\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */ ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype = authmode; ++ } else if (erq->flags & IW_ENCODE_RESTRICTED) { ++ DBG_88E("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n"); ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; ++ authmode = Ndis802_11AuthModeShared; ++ padapter->securitypriv.ndisauthtype = authmode; ++ } else { ++ DBG_88E("rtw_wx_set_enc():erq->flags = 0x%x\n", erq->flags); ++ ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */ ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ authmode = Ndis802_11AuthModeOpen; ++ padapter->securitypriv.ndisauthtype = authmode; ++ } ++ ++ wep.KeyIndex = key; ++ if (erq->length > 0) { ++ wep.KeyLength = erq->length <= 5 ? 5 : 13; ++ ++ wep.Length = wep.KeyLength + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); ++ } else { ++ wep.KeyLength = 0; ++ ++ if (keyindex_provided == 1) { ++ /* set key_id only, no given KeyMaterial(erq->length == 0). */ ++ padapter->securitypriv.dot11PrivacyKeyIndex = key; ++ ++ DBG_88E("(keyindex_provided == 1), keyid =%d, key_len =%d\n", key, padapter->securitypriv.dot11DefKeylen[key]); ++ ++ switch (padapter->securitypriv.dot11DefKeylen[key]) { ++ case 5: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; ++ break; ++ case 13: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; ++ break; ++ default: ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ break; ++ } ++ ++ goto exit; ++ } ++ } ++ ++ wep.KeyIndex |= 0x80000000; ++ ++ memcpy(wep.KeyMaterial, keybuf, wep.KeyLength); ++ ++ if (!rtw_set_802_11_add_wep(padapter, &wep)) { ++ if (rf_on == pwrpriv->rf_pwrstate) ++ ret = -EOPNOTSUPP; ++ goto exit; ++ } ++ ++exit: ++ ++ ++ ++ return ret; ++} ++ ++static int rtw_wx_get_enc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *keybuf) ++{ ++ uint key, ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_point *erq = &wrqu->encoding; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED) != true) { ++ if (!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ return 0; ++ } ++ } ++ ++ key = erq->flags & IW_ENCODE_INDEX; ++ ++ if (key) { ++ if (key > WEP_KEYS) ++ return -EINVAL; ++ key--; ++ } else { ++ key = padapter->securitypriv.dot11PrivacyKeyIndex; ++ } ++ ++ erq->flags = key + 1; ++ ++ switch (padapter->securitypriv.ndisencryptstatus) { ++ case Ndis802_11EncryptionNotSupported: ++ case Ndis802_11EncryptionDisabled: ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ break; ++ case Ndis802_11Encryption1Enabled: ++ erq->length = padapter->securitypriv.dot11DefKeylen[key]; ++ if (erq->length) { ++ memcpy(keybuf, padapter->securitypriv.dot11DefKey[key].skey, padapter->securitypriv.dot11DefKeylen[key]); ++ ++ erq->flags |= IW_ENCODE_ENABLED; ++ ++ if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen) ++ erq->flags |= IW_ENCODE_OPEN; ++ else if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeShared) ++ erq->flags |= IW_ENCODE_RESTRICTED; ++ } else { ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ } ++ break; ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ erq->length = 16; ++ erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN | IW_ENCODE_NOKEY); ++ break; ++ default: ++ erq->length = 0; ++ erq->flags |= IW_ENCODE_DISABLED; ++ break; ++ } ++ ++ ++ return ret; ++} ++ ++static int rtw_wx_get_power(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ wrqu->power.value = 0; ++ wrqu->power.fixed = 0; /* no auto select */ ++ wrqu->power.disabled = 1; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_gen_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ ret = rtw_set_wpa_ie(padapter, extra, wrqu->data.length); ++ return ret; ++} ++ ++static int rtw_wx_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_param *param = (struct iw_param *)&wrqu->param; ++ int ret = 0; ++ ++ switch (param->flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ ++ break; ++ case IW_AUTH_KEY_MGMT: ++ /* ++ * ??? does not use these parameters ++ */ ++ break; ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ if (param->value) { ++ /* wpa_supplicant is enabling the tkip countermeasure. */ ++ padapter->securitypriv.btkip_countermeasure = true; ++ } else { ++ /* wpa_supplicant is disabling the tkip countermeasure. */ ++ padapter->securitypriv.btkip_countermeasure = false; ++ } ++ break; ++ case IW_AUTH_DROP_UNENCRYPTED: ++ /* HACK: ++ * ++ * wpa_supplicant calls set_wpa_enabled when the driver ++ * is loaded and unloaded, regardless of if WPA is being ++ * used. No other calls are made which can be used to ++ * determine if encryption will be used or not prior to ++ * association being expected. If encryption is not being ++ * used, drop_unencrypted is set to false, else true -- we ++ * can use this to determine if the CAP_PRIVACY_ON bit should ++ * be set. ++ */ ++ ++ if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) ++ break;/* it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, */ ++ /* then it needn't reset it; */ ++ ++ if (param->value) { ++ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; ++ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; ++ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ } ++ ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ /* ++ * It's the starting point of a link layer connection using wpa_supplicant ++ */ ++ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { ++ LeaveAllPowerSaveMode(padapter); ++ rtw_disassoc_cmd(padapter, 500, false); ++ DBG_88E("%s...call rtw_indicate_disconnect\n ", __func__); ++ rtw_indicate_disconnect(padapter); ++ rtw_free_assoc_resources(padapter, 1); ++ } ++ ret = wpa_set_auth_algs(dev, (u32)param->value); ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ break; ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ break; ++ case IW_AUTH_PRIVACY_INVOKED: ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return ret; ++} ++ ++static int rtw_wx_set_enc_ext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ char *alg_name; ++ u32 param_len; ++ struct ieee_param *param = NULL; ++ struct iw_point *pencoding = &wrqu->encoding; ++ struct iw_encode_ext *pext = (struct iw_encode_ext *)extra; ++ int ret = 0; ++ ++ param_len = sizeof(struct ieee_param) + pext->key_len; ++ param = kzalloc(param_len, GFP_KERNEL); ++ if (!param) ++ return -ENOMEM; ++ ++ param->cmd = IEEE_CMD_SET_ENCRYPTION; ++ memset(param->sta_addr, 0xff, ETH_ALEN); ++ ++ switch (pext->alg) { ++ case IW_ENCODE_ALG_NONE: ++ /* todo: remove key */ ++ /* remove = 1; */ ++ alg_name = "none"; ++ break; ++ case IW_ENCODE_ALG_WEP: ++ alg_name = "WEP"; ++ break; ++ case IW_ENCODE_ALG_TKIP: ++ alg_name = "TKIP"; ++ break; ++ case IW_ENCODE_ALG_CCMP: ++ alg_name = "CCMP"; ++ break; ++ default: ++ return -1; ++ } ++ ++ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN); ++ ++ if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ param->u.crypt.set_tx = 1; ++ ++ /* cliW: WEP does not have group key ++ * just not checking GROUP key setting ++ */ ++ if ((pext->alg != IW_ENCODE_ALG_WEP) && ++ (pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)) ++ param->u.crypt.set_tx = 0; ++ ++ param->u.crypt.idx = (pencoding->flags & 0x00FF) - 1; ++ ++ if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) ++ memcpy(param->u.crypt.seq, pext->rx_seq, 8); ++ ++ if (pext->key_len) { ++ param->u.crypt.key_len = pext->key_len; ++ memcpy(param->u.crypt.key, pext + 1, pext->key_len); ++ } ++ ++ ret = wpa_set_encryption(dev, param, param_len); ++ ++ kfree(param); ++ return ret; ++} ++ ++static int rtw_wx_get_nick(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ if (extra) { ++ wrqu->data.length = 14; ++ wrqu->data.flags = 1; ++ memcpy(extra, "", 14); ++ } ++ ++ /* dump debug info here */ ++ return 0; ++} ++ ++static int rtw_wx_read32(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter; ++ struct iw_point *p; ++ u16 len; ++ u32 addr; ++ u32 data32; ++ u32 bytes; ++ u8 *ptmp; ++ ++ padapter = (struct adapter *)rtw_netdev_priv(dev); ++ p = &wrqu->data; ++ len = p->length; ++ ptmp = kmalloc(len, GFP_KERNEL); ++ if (!ptmp) ++ return -ENOMEM; ++ ++ if (copy_from_user(ptmp, p->pointer, len)) { ++ kfree(ptmp); ++ return -EFAULT; ++ } ++ ++ bytes = 0; ++ addr = 0; ++ sscanf(ptmp, "%d,%x", &bytes, &addr); ++ ++ switch (bytes) { ++ case 1: ++ data32 = rtw_read8(padapter, addr); ++ sprintf(extra, "0x%02X", data32); ++ break; ++ case 2: ++ data32 = rtw_read16(padapter, addr); ++ sprintf(extra, "0x%04X", data32); ++ break; ++ case 4: ++ data32 = rtw_read32(padapter, addr); ++ sprintf(extra, "0x%08X", data32); ++ break; ++ default: ++ DBG_88E(KERN_INFO "%s: usage> read [bytes],[address(hex)]\n", __func__); ++ return -EINVAL; ++ } ++ DBG_88E(KERN_INFO "%s: addr = 0x%08X data =%s\n", __func__, addr, extra); ++ ++ kfree(ptmp); ++ return 0; ++} ++ ++static int rtw_wx_write32(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ u32 addr; ++ u32 data32; ++ u32 bytes; ++ ++ bytes = 0; ++ addr = 0; ++ data32 = 0; ++ sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32); ++ ++ switch (bytes) { ++ case 1: ++ rtw_write8(padapter, addr, (u8)data32); ++ DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n", __func__, addr, (u8)data32); ++ break; ++ case 2: ++ rtw_write16(padapter, addr, (u16)data32); ++ DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n", __func__, addr, (u16)data32); ++ break; ++ case 4: ++ rtw_write32(padapter, addr, data32); ++ DBG_88E(KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n", __func__, addr, data32); ++ break; ++ default: ++ DBG_88E(KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rtw_wx_read_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u32 path, addr, data32; ++ ++ path = *(u32 *)extra; ++ addr = *((u32 *)extra + 1); ++ data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF); ++ /* ++ * IMPORTANT!! ++ * Only when wireless private ioctl is at odd order, ++ * "extra" would be copied to user space. ++ */ ++ sprintf(extra, "0x%05x", data32); ++ ++ return 0; ++} ++ ++static int rtw_wx_write_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u32 path, addr, data32; ++ ++ path = *(u32 *)extra; ++ addr = *((u32 *)extra + 1); ++ data32 = *((u32 *)extra + 2); ++ rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32); ++ ++ return 0; ++} ++ ++static int rtw_wx_priv_null(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ return -1; ++} ++ ++static int dummy(struct net_device *dev, struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ return -1; ++} ++ ++static int rtw_wx_set_channel_plan(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 channel_plan_req = (u8)(*((int *)wrqu)); ++ ++ if (_SUCCESS == rtw_set_chplan_cmd(padapter, channel_plan_req, 1)) ++ DBG_88E("%s set channel_plan = 0x%02X\n", __func__, pmlmepriv->ChannelPlan); ++ else ++ return -EPERM; ++ ++ return 0; ++} ++ ++static int rtw_wx_set_mtk_wps_probe_ie(struct net_device *dev, ++ struct iw_request_info *a, ++ union iwreq_data *wrqu, char *b) ++{ ++ return 0; ++} ++ ++static int rtw_wx_get_sensitivity(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *buf) ++{ ++ return 0; ++} ++ ++static int rtw_wx_set_mtk_wps_ie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ return 0; ++} ++ ++/* ++ * For all data larger than 16 octets, we need to use a ++ * pointer to memory allocated in user space. ++ */ ++static int rtw_drvext_hdl(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ return 0; ++} ++ ++static void rtw_dbg_mode_hdl(struct adapter *padapter, u32 id, u8 *pdata, u32 len) ++{ ++ struct mp_rw_reg *RegRWStruct; ++ struct rf_reg_param *prfreg; ++ u8 path; ++ u8 offset; ++ u32 value; ++ ++ DBG_88E("%s\n", __func__); ++ ++ switch (id) { ++ case GEN_MP_IOCTL_SUBCODE(MP_START): ++ DBG_88E("871x_driver is only for normal mode, can't enter mp mode\n"); ++ break; ++ case GEN_MP_IOCTL_SUBCODE(READ_REG): ++ RegRWStruct = (struct mp_rw_reg *)pdata; ++ switch (RegRWStruct->width) { ++ case 1: ++ RegRWStruct->value = rtw_read8(padapter, RegRWStruct->offset); ++ break; ++ case 2: ++ RegRWStruct->value = rtw_read16(padapter, RegRWStruct->offset); ++ break; ++ case 4: ++ RegRWStruct->value = rtw_read32(padapter, RegRWStruct->offset); ++ break; ++ default: ++ break; ++ } ++ ++ break; ++ case GEN_MP_IOCTL_SUBCODE(WRITE_REG): ++ RegRWStruct = (struct mp_rw_reg *)pdata; ++ switch (RegRWStruct->width) { ++ case 1: ++ rtw_write8(padapter, RegRWStruct->offset, (u8)RegRWStruct->value); ++ break; ++ case 2: ++ rtw_write16(padapter, RegRWStruct->offset, (u16)RegRWStruct->value); ++ break; ++ case 4: ++ rtw_write32(padapter, RegRWStruct->offset, (u32)RegRWStruct->value); ++ break; ++ default: ++ break; ++ } ++ ++ break; ++ case GEN_MP_IOCTL_SUBCODE(READ_RF_REG): ++ ++ prfreg = (struct rf_reg_param *)pdata; ++ ++ path = (u8)prfreg->path; ++ offset = (u8)prfreg->offset; ++ ++ value = rtw_hal_read_rfreg(padapter, path, offset, 0xffffffff); ++ ++ prfreg->value = value; ++ ++ break; ++ case GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG): ++ ++ prfreg = (struct rf_reg_param *)pdata; ++ ++ path = (u8)prfreg->path; ++ offset = (u8)prfreg->offset; ++ value = prfreg->value; ++ ++ rtw_hal_write_rfreg(padapter, path, offset, 0xffffffff, value); ++ ++ break; ++ case GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO): ++ DBG_88E("==> trigger gpio 0\n"); ++ rtw_hal_set_hwreg(padapter, HW_VAR_TRIGGER_GPIO_0, NULL); ++ break; ++ case GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS): ++ *pdata = rtw_hal_sreset_get_wifi_status(padapter); ++ break; ++ default: ++ break; ++ } ++} ++ ++static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u32 BytesRead, BytesWritten, BytesNeeded; ++ struct oid_par_priv oid_par; ++ struct mp_ioctl_handler *phandler; ++ struct mp_ioctl_param *poidparam; ++ uint status = 0; ++ u16 len; ++ u8 *pparmbuf = NULL, bset; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_point *p = &wrqu->data; ++ ++ if ((!p->length) || (!p->pointer)) { ++ ret = -EINVAL; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ pparmbuf = NULL; ++ bset = (u8)(p->flags & 0xFFFF); ++ len = p->length; ++ pparmbuf = kmalloc(len, GFP_KERNEL); ++ if (!pparmbuf) { ++ ret = -ENOMEM; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ if (copy_from_user(pparmbuf, p->pointer, len)) { ++ ret = -EFAULT; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ poidparam = (struct mp_ioctl_param *)pparmbuf; ++ ++ if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) { ++ ret = -EINVAL; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ if (padapter->registrypriv.mp_mode == 1) { ++ phandler = mp_ioctl_hdl + poidparam->subcode; ++ ++ if ((phandler->paramsize != 0) && (poidparam->len < phandler->paramsize)) { ++ ret = -EINVAL; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++ if (phandler->handler) { ++ oid_par.adapter_context = padapter; ++ oid_par.oid = phandler->oid; ++ oid_par.information_buf = poidparam->data; ++ oid_par.information_buf_len = poidparam->len; ++ oid_par.dbg = 0; ++ ++ BytesWritten = 0; ++ BytesNeeded = 0; ++ ++ if (bset) { ++ oid_par.bytes_rw = &BytesRead; ++ oid_par.bytes_needed = &BytesNeeded; ++ oid_par.type_of_oid = SET_OID; ++ } else { ++ oid_par.bytes_rw = &BytesWritten; ++ oid_par.bytes_needed = &BytesNeeded; ++ oid_par.type_of_oid = QUERY_OID; ++ } ++ ++ status = phandler->handler(&oid_par); ++ } else { ++ DBG_88E("rtw_mp_ioctl_hdl(): err!, subcode =%d, oid =%d, handler =%p\n", ++ poidparam->subcode, phandler->oid, phandler->handler); ++ ret = -EFAULT; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ } else { ++ rtw_dbg_mode_hdl(padapter, poidparam->subcode, poidparam->data, poidparam->len); ++ } ++ ++ if (bset == 0x00) {/* query info */ ++ if (copy_to_user(p->pointer, pparmbuf, len)) ++ ret = -EFAULT; ++ } ++ ++ if (status) { ++ ret = -EFAULT; ++ goto _rtw_mp_ioctl_hdl_exit; ++ } ++ ++_rtw_mp_ioctl_hdl_exit: ++ ++ kfree(pparmbuf); ++ return ret; ++} ++ ++static int rtw_get_ap_info(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u32 cnt = 0, wpa_ielen; ++ struct list_head *plist, *phead; ++ unsigned char *pbuf; ++ u8 bssid[ETH_ALEN]; ++ char data[32]; ++ struct wlan_network *pnetwork = NULL; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct iw_point *pdata = &wrqu->data; ++ ++ DBG_88E("+rtw_get_aplist_info\n"); ++ ++ if (padapter->bDriverStopped || !pdata) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ while ((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING)))) { ++ msleep(30); ++ cnt++; ++ if (cnt > 100) ++ break; ++ } ++ pdata->flags = 0; ++ if (pdata->length >= 32) { ++ if (copy_from_user(data, pdata->pointer, 32)) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } else { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ ++ if (!mac_pton(data, bssid)) { ++ DBG_88E("Invalid BSSID '%s'.\n", (u8 *)data); ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ return -EINVAL; ++ } ++ ++ if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN)) { ++ /* BSSID match, then check if supporting wpa/wpa2 */ ++ DBG_88E("BSSID:%pM\n", (bssid)); ++ ++ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12); ++ if (pbuf && (wpa_ielen > 0)) { ++ pdata->flags = 1; ++ break; ++ } ++ ++ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12); ++ if (pbuf && (wpa_ielen > 0)) { ++ pdata->flags = 2; ++ break; ++ } ++ } ++ ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (pdata->length >= 34) { ++ if (copy_to_user(pdata->pointer + 32, (u8 *)&pdata->flags, 1)) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ } ++ ++exit: ++ ++ return ret; ++} ++ ++static int rtw_set_pid(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ int *pdata = (int *)wrqu; ++ int selector; ++ ++ if (padapter->bDriverStopped || !pdata) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ selector = *pdata; ++ if (selector < 3 && selector >= 0) { ++ padapter->pid[selector] = *(pdata + 1); ++ ui_pid[selector] = *(pdata + 1); ++ DBG_88E("%s set pid[%d] =%d\n", __func__, selector, padapter->pid[selector]); ++ } else { ++ DBG_88E("%s selector %d error\n", __func__, selector); ++ } ++exit: ++ return ret; ++} ++ ++static int rtw_wps_start(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_point *pdata = &wrqu->data; ++ u32 u32wps_start = 0; ++ ++ if (!pdata) ++ return -EINVAL; ++ ret = copy_from_user((void *)&u32wps_start, pdata->pointer, 4); ++ if (ret) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (padapter->bDriverStopped) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ if (u32wps_start == 0) ++ u32wps_start = *extra; ++ ++ DBG_88E("[%s] wps_start = %d\n", __func__, u32wps_start); ++ ++ if (u32wps_start == 1) /* WPS Start */ ++ rtw_led_control(padapter, LED_CTL_START_WPS); ++ else if (u32wps_start == 2) /* WPS Stop because of wps success */ ++ rtw_led_control(padapter, LED_CTL_STOP_WPS); ++ else if (u32wps_start == 3) /* WPS Stop because of wps fail */ ++ rtw_led_control(padapter, LED_CTL_STOP_WPS_FAIL); ++ ++exit: ++ return ret; ++} ++ ++#ifdef CONFIG_88EU_P2P ++static int rtw_wext_p2p_enable(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ enum P2P_ROLE init_role = P2P_ROLE_DISABLE; ++ ++ if (*extra == '0') ++ init_role = P2P_ROLE_DISABLE; ++ else if (*extra == '1') ++ init_role = P2P_ROLE_DEVICE; ++ else if (*extra == '2') ++ init_role = P2P_ROLE_CLIENT; ++ else if (*extra == '3') ++ init_role = P2P_ROLE_GO; ++ ++ if (_FAIL == rtw_p2p_enable(padapter, init_role)) { ++ ret = -EFAULT; ++ goto exit; ++ } ++ ++ /* set channel/bandwidth */ ++ if (init_role != P2P_ROLE_DISABLE) { ++ u8 channel, ch_offset; ++ u16 bwmode; ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN)) { ++ /* Stay at the listen state and wait for discovery. */ ++ channel = pwdinfo->listen_channel; ++ pwdinfo->operating_channel = pwdinfo->listen_channel; ++ ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; ++ bwmode = HT_CHANNEL_WIDTH_20; ++ } else { ++ pwdinfo->operating_channel = pmlmeext->cur_channel; ++ ++ channel = pwdinfo->operating_channel; ++ ch_offset = pmlmeext->cur_ch_offset; ++ bwmode = pmlmeext->cur_bwmode; ++ } ++ ++ set_channel_bwmode(padapter, channel, ch_offset, bwmode); ++ } ++ ++exit: ++ return ret; ++} ++ ++static int rtw_p2p_set_go_nego_ssid(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("[%s] ssid = %s, len = %zu\n", __func__, extra, strlen(extra)); ++ memcpy(pwdinfo->nego_ssid, extra, strlen(extra)); ++ pwdinfo->nego_ssidlen = strlen(extra); ++ ++ return ret; ++} ++ ++static int rtw_p2p_set_intent(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 intent = pwdinfo->intent; ++ ++ switch (wrqu->data.length) { ++ case 1: ++ intent = extra[0] - '0'; ++ break; ++ case 2: ++ intent = str_2char2num(extra[0], extra[1]); ++ break; ++ } ++ if (intent <= 15) ++ pwdinfo->intent = intent; ++ else ++ ret = -1; ++ DBG_88E("[%s] intent = %d\n", __func__, intent); ++ return ret; ++} ++ ++static int rtw_p2p_set_listen_ch(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 listen_ch = pwdinfo->listen_channel; /* Listen channel number */ ++ ++ switch (wrqu->data.length) { ++ case 1: ++ listen_ch = extra[0] - '0'; ++ break; ++ case 2: ++ listen_ch = str_2char2num(extra[0], extra[1]); ++ break; ++ } ++ ++ if ((listen_ch == 1) || (listen_ch == 6) || (listen_ch == 11)) { ++ pwdinfo->listen_channel = listen_ch; ++ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ } else { ++ ret = -1; ++ } ++ ++ DBG_88E("[%s] listen_ch = %d\n", __func__, pwdinfo->listen_channel); ++ ++ return ret; ++} ++ ++static int rtw_p2p_set_op_ch(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++/* Commented by Albert 20110524 */ ++/* This function is used to set the operating channel if the driver will become the group owner */ ++ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 op_ch = pwdinfo->operating_channel; /* Operating channel number */ ++ ++ switch (wrqu->data.length) { ++ case 1: ++ op_ch = extra[0] - '0'; ++ break; ++ case 2: ++ op_ch = str_2char2num(extra[0], extra[1]); ++ break; ++ } ++ ++ if (op_ch > 0) ++ pwdinfo->operating_channel = op_ch; ++ else ++ ret = -1; ++ ++ DBG_88E("[%s] op_ch = %d\n", __func__, pwdinfo->operating_channel); ++ ++ return ret; ++} ++ ++static int rtw_p2p_profilefound(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ /* Comment by Albert 2010/10/13 */ ++ /* Input data format: */ ++ /* Ex: 0 */ ++ /* Ex: 1XX:XX:XX:XX:XX:XXYYSSID */ ++ /* 0 => Reflush the profile record list. */ ++ /* 1 => Add the profile list */ ++ /* XX:XX:XX:XX:XX:XX => peer's MAC Address (ex: 00:E0:4C:00:00:01) */ ++ /* YY => SSID Length */ ++ /* SSID => SSID for persistence group */ ++ ++ DBG_88E("[%s] In value = %s, len = %d\n", __func__, extra, wrqu->data.length - 1); ++ ++ /* The upper application should pass the SSID to driver by using this rtw_p2p_profilefound function. */ ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { ++ if (extra[0] == '0') { ++ /* Remove all the profile information of wifidirect_info structure. */ ++ memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM); ++ pwdinfo->profileindex = 0; ++ } else { ++ if (pwdinfo->profileindex >= P2P_MAX_PERSISTENT_GROUP_NUM) { ++ ret = -1; ++ } else { ++ int jj, kk; ++ ++ /* Add this profile information into pwdinfo->profileinfo */ ++ /* Ex: 1XX:XX:XX:XX:XX:XXYYSSID */ ++ for (jj = 0, kk = 1; jj < ETH_ALEN; jj++, kk += 3) ++ pwdinfo->profileinfo[pwdinfo->profileindex].peermac[jj] = key_2char2num(extra[kk], extra[kk + 1]); ++ ++ pwdinfo->profileinfo[pwdinfo->profileindex].ssidlen = (extra[18] - '0') * 10 + (extra[19] - '0'); ++ memcpy(pwdinfo->profileinfo[pwdinfo->profileindex].ssid, &extra[20], pwdinfo->profileinfo[pwdinfo->profileindex].ssidlen); ++ pwdinfo->profileindex++; ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++static int rtw_p2p_setDN(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1); ++ memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN); ++ memcpy(pwdinfo->device_name, extra, wrqu->data.length - 1); ++ pwdinfo->device_name_len = wrqu->data.length - 1; ++ ++ return ret; ++} ++ ++static int rtw_p2p_get_status(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ if (padapter->bShowGetP2PState) ++ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2], ++ pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]); ++ ++ /* Commented by Albert 2010/10/12 */ ++ /* Because of the output size limitation, I had removed the "Role" information. */ ++ /* About the "Role" information, we will use the new private IOCTL to get the "Role" information. */ ++ sprintf(extra, "\n\nStatus =%.2d\n", rtw_p2p_state(pwdinfo)); ++ wrqu->data.length = strlen(extra); ++ ++ return ret; ++} ++ ++/* Commented by Albert 20110520 */ ++/* This function will return the config method description */ ++/* This config method description will show us which config method the remote P2P device is intended to use */ ++/* by sending the provisioning discovery request frame. */ ++ ++static int rtw_p2p_get_req_cm(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ sprintf(extra, "\n\nCM =%s\n", pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req); ++ wrqu->data.length = strlen(extra); ++ return ret; ++} ++ ++static int rtw_p2p_get_role(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2], ++ pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]); ++ ++ sprintf(extra, "\n\nRole =%.2d\n", rtw_p2p_role(pwdinfo)); ++ wrqu->data.length = strlen(extra); ++ return ret; ++} ++ ++static int rtw_p2p_get_peer_ifaddr(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n", __func__, ++ rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->p2p_peer_interface_addr); ++ sprintf(extra, "\nMAC %pM", ++ pwdinfo->p2p_peer_interface_addr); ++ wrqu->data.length = strlen(extra); ++ return ret; ++} ++ ++static int rtw_p2p_get_peer_devaddr(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n", __func__, ++ rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->rx_prov_disc_info.peerDevAddr); ++ sprintf(extra, "\n%pM", ++ pwdinfo->rx_prov_disc_info.peerDevAddr); ++ wrqu->data.length = strlen(extra); ++ return ret; ++} ++ ++static int rtw_p2p_get_peer_devaddr_by_invitation(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("[%s] Role = %d, Status = %d, peer addr = %pM\n", ++ __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), ++ pwdinfo->p2p_peer_device_addr); ++ sprintf(extra, "\nMAC %pM", ++ pwdinfo->p2p_peer_device_addr); ++ wrqu->data.length = strlen(extra); ++ return ret; ++} ++ ++static int rtw_p2p_get_groupid(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ sprintf(extra, "\n%.2X:%.2X:%.2X:%.2X:%.2X:%.2X %s", ++ pwdinfo->groupid_info.go_device_addr[0], pwdinfo->groupid_info.go_device_addr[1], ++ pwdinfo->groupid_info.go_device_addr[2], pwdinfo->groupid_info.go_device_addr[3], ++ pwdinfo->groupid_info.go_device_addr[4], pwdinfo->groupid_info.go_device_addr[5], ++ pwdinfo->groupid_info.ssid); ++ wrqu->data.length = strlen(extra); ++ return ret; ++} ++ ++static int rtw_p2p_get_op_ch(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++ ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("[%s] Op_ch = %02x\n", __func__, pwdinfo->operating_channel); ++ ++ sprintf(extra, "\n\nOp_ch =%.2d\n", pwdinfo->operating_channel); ++ wrqu->data.length = strlen(extra); ++ return ret; ++} ++ ++static int rtw_p2p_get_wps_configmethod(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = {0x00}; ++ int jj, kk; ++ u8 peerMACStr[17] = {0x00}; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u16 attr_content = 0; ++ uint attr_contentlen = 0; ++ /* 6 is the string "wpsCM =", 17 is the MAC addr, we have to clear it at wrqu->data.pointer */ ++ u8 attr_content_str[6 + 17] = {0x00}; ++ ++ /* Commented by Albert 20110727 */ ++ /* The input data is the MAC address which the application wants to know its WPS config method. */ ++ /* After knowing its WPS config method, the application can decide the config method for provisioning discovery. */ ++ /* Format: iwpriv wlanx p2p_get_wpsCM 00:E0:4C:00:00:05 */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, (char *)extra); ++ if (copy_from_user(peerMACStr, wrqu->data.pointer + 6, 17)) ++ return -EFAULT; ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]); ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) { ++ u8 *wpsie; ++ uint wpsie_len = 0; ++ __be16 be_tmp; ++ ++ /* The mac address is matched. */ ++ wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &wpsie_len); ++ if (wpsie) { ++ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_CONF_METHOD, (u8 *)&be_tmp, &attr_contentlen); ++ if (attr_contentlen) { ++ attr_content = be16_to_cpu(be_tmp); ++ sprintf(attr_content_str, "\n\nM =%.4d", attr_content); ++ blnMatch = 1; ++ } ++ } ++ break; ++ } ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (!blnMatch) ++ sprintf(attr_content_str, "\n\nM = 0000"); ++ ++ if (copy_to_user(wrqu->data.pointer, attr_content_str, 6 + 17)) ++ return -EFAULT; ++ return ret; ++} ++ ++static int rtw_p2p_get_go_device_address(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = {0x00}; ++ int jj, kk; ++ u8 peerMACStr[17] = {0x00}; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ u8 attr_content[100] = {0x00}; ++ ++ u8 go_devadd_str[100 + 10] = {0x00}; ++ /* +10 is for the str "go_devadd =", we have to clear it at wrqu->data.pointer */ ++ ++ /* Commented by Albert 20121209 */ ++ /* The input data is the GO's interface address which the application wants to know its device address. */ ++ /* Format: iwpriv wlanx p2p_get2 go_devadd = 00:E0:4C:00:00:05 */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, (char *)extra); ++ if (copy_from_user(peerMACStr, wrqu->data.pointer + 10, 17)) ++ return -EFAULT; ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]); ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) { ++ /* Commented by Albert 2011/05/18 */ ++ /* Match the device address located in the P2P IE */ ++ /* This is for the case that the P2P device address is not the same as the P2P interface address. */ ++ ++ p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen); ++ if (p2pie) { ++ while (p2pie) { ++ /* The P2P Device ID attribute is included in the Beacon frame. */ ++ /* The P2P Device Info attribute is included in the probe response frame. */ ++ ++ memset(attr_content, 0x00, 100); ++ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) { ++ /* Handle the P2P Device ID attribute of Beacon first */ ++ blnMatch = 1; ++ break; ++ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) { ++ /* Handle the P2P Device Info attribute of probe response */ ++ blnMatch = 1; ++ break; ++ } ++ ++ /* Get the next P2P IE */ ++ p2pie = rtw_get_p2p_ie(p2pie + p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen); ++ } ++ } ++ } ++ ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (!blnMatch) ++ sprintf(go_devadd_str, "\n\ndev_add = NULL"); ++ else ++ sprintf(go_devadd_str, "\ndev_add =%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ++ attr_content[0], attr_content[1], attr_content[2], attr_content[3], attr_content[4], attr_content[5]); ++ ++ if (copy_to_user(wrqu->data.pointer, go_devadd_str, 10 + 17)) ++ return -EFAULT; ++ return ret; ++} ++ ++static int rtw_p2p_get_device_type(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = {0x00}; ++ int jj, kk; ++ u8 peerMACStr[17] = {0x00}; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u8 dev_type[8] = {0x00}; ++ uint dev_type_len = 0; ++ u8 dev_type_str[17 + 9] = {0x00}; /* +9 is for the str "dev_type =", we have to clear it at wrqu->data.pointer */ ++ ++ /* Commented by Albert 20121209 */ ++ /* The input data is the MAC address which the application wants to know its device type. */ ++ /* Such user interface could know the device type. */ ++ /* Format: iwpriv wlanx p2p_get2 dev_type = 00:E0:4C:00:00:05 */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, (char *)extra); ++ if (copy_from_user(peerMACStr, wrqu->data.pointer + 9, 17)) ++ return -EFAULT; ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]); ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) { ++ u8 *wpsie; ++ uint wpsie_len = 0; ++ ++ /* The mac address is matched. */ ++ ++ wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12], ++ pnetwork->network.IELength - 12, ++ NULL, &wpsie_len); ++ if (wpsie) { ++ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_PRIMARY_DEV_TYPE, dev_type, &dev_type_len); ++ if (dev_type_len) { ++ u16 type = 0; ++ __be16 be_tmp; ++ ++ memcpy(&be_tmp, dev_type, 2); ++ type = be16_to_cpu(be_tmp); ++ sprintf(dev_type_str, "\n\nN =%.2d", type); ++ blnMatch = 1; ++ } ++ } ++ break; ++ } ++ ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (!blnMatch) ++ sprintf(dev_type_str, "\n\nN = 00"); ++ ++ if (copy_to_user(wrqu->data.pointer, dev_type_str, 9 + 17)) { ++ return -EFAULT; ++ } ++ ++ return ret; ++} ++ ++static int rtw_p2p_get_device_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = {0x00}; ++ int jj, kk; ++ u8 peerMACStr[17] = {0x00}; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u8 dev_name[WPS_MAX_DEVICE_NAME_LEN] = {0x00}; ++ uint dev_len = 0; ++ u8 dev_name_str[WPS_MAX_DEVICE_NAME_LEN + 5] = {0x00}; /* +5 is for the str "devN =", we have to clear it at wrqu->data.pointer */ ++ ++ /* Commented by Albert 20121225 */ ++ /* The input data is the MAC address which the application wants to know its device name. */ ++ /* Such user interface could show peer device's device name instead of ssid. */ ++ /* Format: iwpriv wlanx p2p_get2 devN = 00:E0:4C:00:00:05 */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, (char *)extra); ++ if (copy_from_user(peerMACStr, wrqu->data.pointer + 5, 17)) ++ return -EFAULT; ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]); ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) { ++ u8 *wpsie; ++ uint wpsie_len = 0; ++ ++ /* The mac address is matched. */ ++ wpsie = rtw_get_wps_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &wpsie_len); ++ if (wpsie) { ++ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_DEVICE_NAME, dev_name, &dev_len); ++ if (dev_len) { ++ sprintf(dev_name_str, "\n\nN =%s", dev_name); ++ blnMatch = 1; ++ } ++ } ++ break; ++ } ++ ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (!blnMatch) ++ sprintf(dev_name_str, "\n\nN = 0000"); ++ ++ if (copy_to_user(wrqu->data.pointer, dev_name_str, 5 + ((dev_len > 17) ? dev_len : 17))) ++ return -EFAULT; ++ return ret; ++} ++ ++static int rtw_p2p_get_invitation_procedure(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ u8 peerMAC[ETH_ALEN] = {0x00}; ++ int jj, kk; ++ u8 peerMACStr[17] = {0x00}; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ u8 blnMatch = 0; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ u8 attr_content[2] = {0x00}; ++ ++ u8 inv_proc_str[17 + 8] = {0x00}; ++ /* +8 is for the str "InvProc =", we have to clear it at wrqu->data.pointer */ ++ ++ /* Commented by Ouden 20121226 */ ++ /* The application wants to know P2P initiation procedure is supported or not. */ ++ /* Format: iwpriv wlanx p2p_get2 InvProc = 00:E0:4C:00:00:05 */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, (char *)extra); ++ if (copy_from_user(peerMACStr, wrqu->data.pointer + 8, 17)) ++ return -EFAULT; ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ peerMAC[jj] = key_2char2num(peerMACStr[kk], peerMACStr[kk + 1]); ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) { ++ /* Commented by Albert 20121226 */ ++ /* Match the device address located in the P2P IE */ ++ /* This is for the case that the P2P device address is not the same as the P2P interface address. */ ++ ++ p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen); ++ if (p2pie) { ++ while (p2pie) { ++ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_CAPABILITY, attr_content, &attr_contentlen)) { ++ /* Handle the P2P capability attribute */ ++ blnMatch = 1; ++ break; ++ } ++ ++ /* Get the next P2P IE */ ++ p2pie = rtw_get_p2p_ie(p2pie + p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen); ++ } ++ } ++ } ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (!blnMatch) { ++ sprintf(inv_proc_str, "\nIP =-1"); ++ } else { ++ if (attr_content[0] & 0x20) ++ sprintf(inv_proc_str, "\nIP = 1"); ++ else ++ sprintf(inv_proc_str, "\nIP = 0"); ++ } ++ if (copy_to_user(wrqu->data.pointer, inv_proc_str, 8 + 17)) ++ return -EFAULT; ++ return ret; ++} ++ ++static int rtw_p2p_connect(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 peerMAC[ETH_ALEN] = {0x00}; ++ int jj, kk; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ uint uintPeerChannel = 0; ++ ++ /* Commented by Albert 20110304 */ ++ /* The input data contains two informations. */ ++ /* 1. First information is the MAC address which wants to formate with */ ++ /* 2. Second information is the WPS PINCode or "pbc" string for push button method */ ++ /* Format: 00:E0:4C:00:00:05 */ ++ /* Format: 00:E0:4C:00:00:05 */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, extra); ++ ++ if (pwdinfo->p2p_state == P2P_STATE_NONE) { ++ DBG_88E("[%s] WiFi Direct is disable!\n", __func__); ++ return ret; ++ } ++ ++ if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) ++ return -1; ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]); ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (uintPeerChannel) { ++ memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info)); ++ memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); ++ ++ pwdinfo->nego_req_info.peer_channel_num[0] = uintPeerChannel; ++ memcpy(pwdinfo->nego_req_info.peerDevAddr, pnetwork->network.MacAddress, ETH_ALEN); ++ pwdinfo->nego_req_info.benable = true; ++ ++ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); ++ if (rtw_p2p_state(pwdinfo) != P2P_STATE_GONEGO_OK) { ++ /* Restore to the listen state if the current p2p state is not nego OK */ ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); ++ } ++ ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING); ++ ++ DBG_88E("[%s] Start PreTx Procedure!\n", __func__); ++ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); ++ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_GO_NEGO_TIMEOUT); ++ } else { ++ DBG_88E("[%s] Not Found in Scanning Queue~\n", __func__); ++ ret = -1; ++ } ++ return ret; ++} ++ ++static int rtw_p2p_invite_req(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ int jj, kk; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ uint uintPeerChannel = 0; ++ u8 attr_content[50] = {0x00}; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ struct tx_invite_req_info *pinvite_req_info = &pwdinfo->invitereq_info; ++ ++ /* The input data contains two informations. */ ++ /* 1. First information is the P2P device address which you want to send to. */ ++ /* 2. Second information is the group id which combines with GO's mac address, space and GO's ssid. */ ++ /* Command line sample: iwpriv wlan0 p2p_set invite ="00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy" */ ++ /* Format: 00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, extra); ++ ++ if (wrqu->data.length <= 37) { ++ DBG_88E("[%s] Wrong format!\n", __func__); ++ return ret; ++ } ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { ++ DBG_88E("[%s] WiFi Direct is disable!\n", __func__); ++ return ret; ++ } else { ++ /* Reset the content of struct tx_invite_req_info */ ++ pinvite_req_info->benable = false; ++ memset(pinvite_req_info->go_bssid, 0x00, ETH_ALEN); ++ memset(pinvite_req_info->go_ssid, 0x00, WLAN_SSID_MAXLEN); ++ pinvite_req_info->ssidlen = 0x00; ++ pinvite_req_info->operating_ch = pwdinfo->operating_channel; ++ memset(pinvite_req_info->peer_macaddr, 0x00, ETH_ALEN); ++ pinvite_req_info->token = 3; ++ } ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ pinvite_req_info->peer_macaddr[jj] = key_2char2num(extra[kk], extra[kk + 1]); ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ pnetwork = container_of(plist, struct wlan_network, list); ++ ++ /* Commented by Albert 2011/05/18 */ ++ /* Match the device address located in the P2P IE */ ++ /* This is for the case that the P2P device address is not the same as the P2P interface address. */ ++ ++ p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen); ++ if (p2pie) { ++ /* The P2P Device ID attribute is included in the Beacon frame. */ ++ /* The P2P Device Info attribute is included in the probe response frame. */ ++ ++ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) { ++ /* Handle the P2P Device ID attribute of Beacon first */ ++ if (!memcmp(attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN)) { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) { ++ /* Handle the P2P Device Info attribute of probe response */ ++ if (!memcmp(attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN)) { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++ } ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (uintPeerChannel) { ++ /* Store the GO's bssid */ ++ for (jj = 0, kk = 18; jj < ETH_ALEN; jj++, kk += 3) ++ pinvite_req_info->go_bssid[jj] = key_2char2num(extra[kk], extra[kk + 1]); ++ ++ /* Store the GO's ssid */ ++ pinvite_req_info->ssidlen = wrqu->data.length - 36; ++ memcpy(pinvite_req_info->go_ssid, &extra[36], (u32)pinvite_req_info->ssidlen); ++ pinvite_req_info->benable = true; ++ pinvite_req_info->peer_ch = uintPeerChannel; ++ ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INVITE_REQ); ++ ++ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ ++ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); ++ ++ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_INVITE_TIMEOUT); ++ } else { ++ DBG_88E("[%s] NOT Found in the Scanning Queue!\n", __func__); ++ } ++ return ret; ++} ++ ++static int rtw_p2p_set_persistent(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ /* The input data is 0 or 1 */ ++ /* 0: disable persistent group functionality */ ++ /* 1: enable persistent group founctionality */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, extra); ++ ++ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { ++ DBG_88E("[%s] WiFi Direct is disable!\n", __func__); ++ return ret; ++ } else { ++ if (extra[0] == '0') /* Disable the persistent group function. */ ++ pwdinfo->persistent_supported = false; ++ else if (extra[0] == '1') /* Enable the persistent group function. */ ++ pwdinfo->persistent_supported = true; ++ else ++ pwdinfo->persistent_supported = false; ++ } ++ pr_info("[%s] persistent_supported = %d\n", __func__, pwdinfo->persistent_supported); ++ return ret; ++} ++ ++static int rtw_p2p_prov_disc(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ u8 peerMAC[ETH_ALEN] = {0x00}; ++ int jj, kk; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct list_head *plist, *phead; ++ struct __queue *queue = &pmlmepriv->scanned_queue; ++ struct wlan_network *pnetwork = NULL; ++ uint uintPeerChannel = 0; ++ u8 attr_content[100] = {0x00}; ++ u8 *p2pie; ++ uint p2pielen = 0, attr_contentlen = 0; ++ ++ /* The input data contains two informations. */ ++ /* 1. First information is the MAC address which wants to issue the provisioning discovery request frame. */ ++ /* 2. Second information is the WPS configuration method which wants to discovery */ ++ /* Format: 00:E0:4C:00:00:05_display */ ++ /* Format: 00:E0:4C:00:00:05_keypad */ ++ /* Format: 00:E0:4C:00:00:05_pbc */ ++ /* Format: 00:E0:4C:00:00:05_label */ ++ ++ DBG_88E("[%s] data = %s\n", __func__, extra); ++ ++ if (pwdinfo->p2p_state == P2P_STATE_NONE) { ++ DBG_88E("[%s] WiFi Direct is disable!\n", __func__); ++ return ret; ++ } else { ++ /* Reset the content of struct tx_provdisc_req_info excluded the wps_config_method_request. */ ++ memset(pwdinfo->tx_prov_disc_info.peerDevAddr, 0x00, ETH_ALEN); ++ memset(pwdinfo->tx_prov_disc_info.peerIFAddr, 0x00, ETH_ALEN); ++ memset(&pwdinfo->tx_prov_disc_info.ssid, 0x00, sizeof(struct ndis_802_11_ssid)); ++ pwdinfo->tx_prov_disc_info.peer_channel_num[0] = 0; ++ pwdinfo->tx_prov_disc_info.peer_channel_num[1] = 0; ++ pwdinfo->tx_prov_disc_info.benable = false; ++ } ++ ++ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) ++ peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]); ++ ++ if (!memcmp(&extra[18], "display", 7)) { ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_DISPLYA; ++ } else if (!memcmp(&extra[18], "keypad", 7)) { ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_KEYPAD; ++ } else if (!memcmp(&extra[18], "pbc", 3)) { ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON; ++ } else if (!memcmp(&extra[18], "label", 5)) { ++ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_LABEL; ++ } else { ++ DBG_88E("[%s] Unknown WPS config methodn", __func__); ++ return ret; ++ } ++ ++ spin_lock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ phead = get_list_head(queue); ++ plist = phead->next; ++ ++ while (phead != plist) { ++ if (uintPeerChannel != 0) ++ break; ++ ++ pnetwork = container_of(plist, struct wlan_network, list); ++ ++ /* Commented by Albert 2011/05/18 */ ++ /* Match the device address located in the P2P IE */ ++ /* This is for the case that the P2P device address is not the same as the P2P interface address. */ ++ ++ p2pie = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen); ++ if (p2pie) { ++ while (p2pie) { ++ /* The P2P Device ID attribute is included in the Beacon frame. */ ++ /* The P2P Device Info attribute is included in the probe response frame. */ ++ ++ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) { ++ /* Handle the P2P Device ID attribute of Beacon first */ ++ if (!memcmp(attr_content, peerMAC, ETH_ALEN)) { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) { ++ /* Handle the P2P Device Info attribute of probe response */ ++ if (!memcmp(attr_content, peerMAC, ETH_ALEN)) { ++ uintPeerChannel = pnetwork->network.Configuration.DSConfig; ++ break; ++ } ++ } ++ ++ /* Get the next P2P IE */ ++ p2pie = rtw_get_p2p_ie(p2pie + p2pielen, pnetwork->network.IELength - 12 - (p2pie - &pnetwork->network.IEs[12] + p2pielen), NULL, &p2pielen); ++ } ++ } ++ ++ plist = plist->next; ++ } ++ ++ spin_unlock_bh(&pmlmepriv->scanned_queue.lock); ++ ++ if (uintPeerChannel) { ++ DBG_88E("[%s] peer channel: %d!\n", __func__, uintPeerChannel); ++ memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, pnetwork->network.MacAddress, ETH_ALEN); ++ memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, peerMAC, ETH_ALEN); ++ pwdinfo->tx_prov_disc_info.peer_channel_num[0] = (u16)uintPeerChannel; ++ pwdinfo->tx_prov_disc_info.benable = true; ++ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ); ++ ++ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { ++ memcpy(&pwdinfo->tx_prov_disc_info.ssid, &pnetwork->network.Ssid, sizeof(struct ndis_802_11_ssid)); ++ } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { ++ memcpy(pwdinfo->tx_prov_disc_info.ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN); ++ pwdinfo->tx_prov_disc_info.ssid.SsidLength = P2P_WILDCARD_SSID_LEN; ++ } ++ ++ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); ++ ++ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); ++ ++ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT); ++ } else { ++ DBG_88E("[%s] NOT Found in the Scanning Queue!\n", __func__); ++ } ++ return ret; ++} ++ ++/* This function is used to inform the driver the user had specified the pin code value or pbc */ ++/* to application. */ ++ ++static int rtw_p2p_got_wpsinfo(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ ++ DBG_88E("[%s] data = %s\n", __func__, extra); ++ /* Added by Albert 20110328 */ ++ /* if the input data is P2P_NO_WPSINFO -> reset the wpsinfo */ ++ /* if the input data is P2P_GOT_WPSINFO_PEER_DISPLAY_PIN -> the utility just input the PIN code got from the peer P2P device. */ ++ /* if the input data is P2P_GOT_WPSINFO_SELF_DISPLAY_PIN -> the utility just got the PIN code from itself. */ ++ /* if the input data is P2P_GOT_WPSINFO_PBC -> the utility just determine to use the PBC */ ++ ++ if (*extra == '0') ++ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; ++ else if (*extra == '1') ++ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PEER_DISPLAY_PIN; ++ else if (*extra == '2') ++ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_SELF_DISPLAY_PIN; ++ else if (*extra == '3') ++ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PBC; ++ else ++ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; ++ return ret; ++} ++ ++#endif /* CONFIG_88EU_P2P */ ++ ++static int rtw_p2p_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_88EU_P2P ++ DBG_88E("[%s] extra = %s\n", __func__, extra); ++ if (!memcmp(extra, "enable =", 7)) { ++ rtw_wext_p2p_enable(dev, info, wrqu, &extra[7]); ++ } else if (!memcmp(extra, "setDN =", 6)) { ++ wrqu->data.length -= 6; ++ rtw_p2p_setDN(dev, info, wrqu, &extra[6]); ++ } else if (!memcmp(extra, "profilefound =", 13)) { ++ wrqu->data.length -= 13; ++ rtw_p2p_profilefound(dev, info, wrqu, &extra[13]); ++ } else if (!memcmp(extra, "prov_disc =", 10)) { ++ wrqu->data.length -= 10; ++ rtw_p2p_prov_disc(dev, info, wrqu, &extra[10]); ++ } else if (!memcmp(extra, "nego =", 5)) { ++ wrqu->data.length -= 5; ++ rtw_p2p_connect(dev, info, wrqu, &extra[5]); ++ } else if (!memcmp(extra, "intent =", 7)) { ++ /* Commented by Albert 2011/03/23 */ ++ /* The wrqu->data.length will include the null character */ ++ /* So, we will decrease 7 + 1 */ ++ wrqu->data.length -= 8; ++ rtw_p2p_set_intent(dev, info, wrqu, &extra[7]); ++ } else if (!memcmp(extra, "ssid =", 5)) { ++ wrqu->data.length -= 5; ++ rtw_p2p_set_go_nego_ssid(dev, info, wrqu, &extra[5]); ++ } else if (!memcmp(extra, "got_wpsinfo =", 12)) { ++ wrqu->data.length -= 12; ++ rtw_p2p_got_wpsinfo(dev, info, wrqu, &extra[12]); ++ } else if (!memcmp(extra, "listen_ch =", 10)) { ++ /* Commented by Albert 2011/05/24 */ ++ /* The wrqu->data.length will include the null character */ ++ /* So, we will decrease (10 + 1) */ ++ wrqu->data.length -= 11; ++ rtw_p2p_set_listen_ch(dev, info, wrqu, &extra[10]); ++ } else if (!memcmp(extra, "op_ch =", 6)) { ++ /* Commented by Albert 2011/05/24 */ ++ /* The wrqu->data.length will include the null character */ ++ /* So, we will decrease (6 + 1) */ ++ wrqu->data.length -= 7; ++ rtw_p2p_set_op_ch(dev, info, wrqu, &extra[6]); ++ } else if (!memcmp(extra, "invite =", 7)) { ++ wrqu->data.length -= 8; ++ rtw_p2p_invite_req(dev, info, wrqu, &extra[7]); ++ } else if (!memcmp(extra, "persistent =", 11)) { ++ wrqu->data.length -= 11; ++ rtw_p2p_set_persistent(dev, info, wrqu, &extra[11]); ++ } ++#endif /* CONFIG_88EU_P2P */ ++ ++ return ret; ++} ++ ++static int rtw_p2p_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_88EU_P2P ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ if (padapter->bShowGetP2PState) ++ DBG_88E("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer); ++ if (!memcmp(wrqu->data.pointer, "status", 6)) { ++ rtw_p2p_get_status(dev, info, wrqu, extra); ++ } else if (!memcmp(wrqu->data.pointer, "role", 4)) { ++ rtw_p2p_get_role(dev, info, wrqu, extra); ++ } else if (!memcmp(wrqu->data.pointer, "peer_ifa", 8)) { ++ rtw_p2p_get_peer_ifaddr(dev, info, wrqu, extra); ++ } else if (!memcmp(wrqu->data.pointer, "req_cm", 6)) { ++ rtw_p2p_get_req_cm(dev, info, wrqu, extra); ++ } else if (!memcmp(wrqu->data.pointer, "peer_deva", 9)) { ++ /* Get the P2P device address when receiving the provision discovery request frame. */ ++ rtw_p2p_get_peer_devaddr(dev, info, wrqu, extra); ++ } else if (!memcmp(wrqu->data.pointer, "group_id", 8)) { ++ rtw_p2p_get_groupid(dev, info, wrqu, extra); ++ } else if (!memcmp(wrqu->data.pointer, "peer_deva_inv", 9)) { ++ /* Get the P2P device address when receiving the P2P Invitation request frame. */ ++ rtw_p2p_get_peer_devaddr_by_invitation(dev, info, wrqu, extra); ++ } else if (!memcmp(wrqu->data.pointer, "op_ch", 5)) { ++ rtw_p2p_get_op_ch(dev, info, wrqu, extra); ++ } ++#endif /* CONFIG_88EU_P2P */ ++ return ret; ++} ++ ++static int rtw_p2p_get2(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ ++#ifdef CONFIG_88EU_P2P ++ DBG_88E("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer); ++ if (!memcmp(extra, "wpsCM =", 6)) { ++ wrqu->data.length -= 6; ++ rtw_p2p_get_wps_configmethod(dev, info, wrqu, &extra[6]); ++ } else if (!memcmp(extra, "devN =", 5)) { ++ wrqu->data.length -= 5; ++ rtw_p2p_get_device_name(dev, info, wrqu, &extra[5]); ++ } else if (!memcmp(extra, "dev_type =", 9)) { ++ wrqu->data.length -= 9; ++ rtw_p2p_get_device_type(dev, info, wrqu, &extra[9]); ++ } else if (!memcmp(extra, "go_devadd =", 10)) { ++ wrqu->data.length -= 10; ++ rtw_p2p_get_go_device_address(dev, info, wrqu, &extra[10]); ++ } else if (!memcmp(extra, "InvProc =", 8)) { ++ wrqu->data.length -= 8; ++ rtw_p2p_get_invitation_procedure(dev, info, wrqu, &extra[8]); ++ } ++ ++#endif /* CONFIG_88EU_P2P */ ++ ++ return ret; ++} ++ ++static int rtw_cta_test_start(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ DBG_88E("%s %s\n", __func__, extra); ++ if (!strcmp(extra, "1")) ++ padapter->in_cta_test = 1; ++ else ++ padapter->in_cta_test = 0; ++ ++ if (padapter->in_cta_test) { ++ u32 v = rtw_read32(padapter, REG_RCR); ++ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);/* RCR_ADF */ ++ rtw_write32(padapter, REG_RCR, v); ++ DBG_88E("enable RCR_ADF\n"); ++ } else { ++ u32 v = rtw_read32(padapter, REG_RCR); ++ v |= RCR_CBSSID_DATA | RCR_CBSSID_BCN;/* RCR_ADF */ ++ rtw_write32(padapter, REG_RCR, v); ++ DBG_88E("disable RCR_ADF\n"); ++ } ++ return ret; ++} ++ ++static int rtw_rereg_nd_name(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ struct rereg_nd_name_data *rereg_priv = &padapter->rereg_nd_name_priv; ++ char new_ifname[IFNAMSIZ]; ++ ++ if (rereg_priv->old_ifname[0] == 0) { ++ char *reg_ifname; ++ reg_ifname = padapter->registrypriv.if2name; ++ ++ strncpy(rereg_priv->old_ifname, reg_ifname, IFNAMSIZ); ++ rereg_priv->old_ifname[IFNAMSIZ - 1] = 0; ++ } ++ ++ if (wrqu->data.length > IFNAMSIZ) ++ return -EFAULT; ++ ++ if (copy_from_user(new_ifname, wrqu->data.pointer, IFNAMSIZ)) ++ return -EFAULT; ++ ++ if (0 == strcmp(rereg_priv->old_ifname, new_ifname)) ++ return ret; ++ ++ DBG_88E("%s new_ifname:%s\n", __func__, new_ifname); ++ ret = rtw_change_ifname(padapter, new_ifname); ++ if (0 != ret) ++ goto exit; ++ ++ if (!memcmp(rereg_priv->old_ifname, "disable%d", 9)) { ++ padapter->ledpriv.bRegUseLed = rereg_priv->old_bRegUseLed; ++ rtw_hal_sw_led_init(padapter); ++ rtw_ips_mode_req(&padapter->pwrctrlpriv, rereg_priv->old_ips_mode); ++ } ++ ++ strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ); ++ rereg_priv->old_ifname[IFNAMSIZ - 1] = 0; ++ ++ if (!memcmp(new_ifname, "disable%d", 9)) { ++ DBG_88E("%s disable\n", __func__); ++ /* free network queue for Android's timming issue */ ++ rtw_free_network_queue(padapter, true); ++ ++ /* close led */ ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ rereg_priv->old_bRegUseLed = padapter->ledpriv.bRegUseLed; ++ padapter->ledpriv.bRegUseLed = false; ++ rtw_hal_sw_led_deinit(padapter); ++ ++ /* the interface is being "disabled", we can do deeper IPS */ ++ rereg_priv->old_ips_mode = rtw_get_ips_mode_req(&padapter->pwrctrlpriv); ++ rtw_ips_mode_req(&padapter->pwrctrlpriv, IPS_NORMAL); ++ } ++exit: ++ return ret; ++} ++ ++static void mac_reg_dump(struct adapter *padapter) ++{ ++ int i, j = 1; ++ pr_info("\n ======= MAC REG =======\n"); ++ for (i = 0x0; i < 0x300; i += 4) { ++ if (j % 4 == 1) ++ pr_info("0x%02x", i); ++ pr_info(" 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ pr_info("\n"); ++ } ++ for (i = 0x400; i < 0x800; i += 4) { ++ if (j % 4 == 1) ++ pr_info("0x%02x", i); ++ pr_info(" 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ pr_info("\n"); ++ } ++} ++ ++static void bb_reg_dump(struct adapter *padapter) ++{ ++ int i, j = 1; ++ pr_info("\n ======= BB REG =======\n"); ++ for (i = 0x800; i < 0x1000; i += 4) { ++ if (j % 4 == 1) ++ pr_info("0x%02x", i); ++ ++ pr_info(" 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ pr_info("\n"); ++ } ++} ++ ++static void rf_reg_dump(struct adapter *padapter) ++{ ++ int i, j = 1, path; ++ u32 value; ++ u8 rf_type, path_nums = 0; ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ pr_info("\n ======= RF REG =======\n"); ++ if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) ++ path_nums = 1; ++ else ++ path_nums = 2; ++ ++ for (path = 0; path < path_nums; path++) { ++ pr_info("\nRF_Path(%x)\n", path); ++ for (i = 0; i < 0x100; i++) { ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if (j % 4 == 1) ++ pr_info("0x%02x ", i); ++ pr_info(" 0x%08x ", value); ++ if ((j++) % 4 == 0) ++ pr_info("\n"); ++ } ++ } ++} ++ ++static int rtw_dbg_port(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ u8 major_cmd, minor_cmd; ++ u16 arg; ++ s32 extra_arg; ++ u32 *pdata, val32; ++ struct sta_info *psta; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ struct wlan_network *cur_network = &pmlmepriv->cur_network; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ pdata = (u32 *)&wrqu->data; ++ ++ val32 = *pdata; ++ arg = (u16)(val32 & 0x0000ffff); ++ major_cmd = (u8)(val32 >> 24); ++ minor_cmd = (u8)((val32 >> 16) & 0x00ff); ++ ++ extra_arg = *(pdata + 1); ++ ++ switch (major_cmd) { ++ case 0x70:/* read_reg */ ++ switch (minor_cmd) { ++ case 1: ++ DBG_88E("rtw_read8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg)); ++ break; ++ case 2: ++ DBG_88E("rtw_read16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg)); ++ break; ++ case 4: ++ DBG_88E("rtw_read32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg)); ++ break; ++ } ++ break; ++ case 0x71:/* write_reg */ ++ switch (minor_cmd) { ++ case 1: ++ rtw_write8(padapter, arg, extra_arg); ++ DBG_88E("rtw_write8(0x%x) = 0x%02x\n", arg, rtw_read8(padapter, arg)); ++ break; ++ case 2: ++ rtw_write16(padapter, arg, extra_arg); ++ DBG_88E("rtw_write16(0x%x) = 0x%04x\n", arg, rtw_read16(padapter, arg)); ++ break; ++ case 4: ++ rtw_write32(padapter, arg, extra_arg); ++ DBG_88E("rtw_write32(0x%x) = 0x%08x\n", arg, rtw_read32(padapter, arg)); ++ break; ++ } ++ break; ++ case 0x72:/* read_bb */ ++ DBG_88E("read_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff)); ++ break; ++ case 0x73:/* write_bb */ ++ rtw_hal_write_bbreg(padapter, arg, 0xffffffff, extra_arg); ++ DBG_88E("write_bbreg(0x%x) = 0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff)); ++ break; ++ case 0x74:/* read_rf */ ++ DBG_88E("read RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff)); ++ break; ++ case 0x75:/* write_rf */ ++ rtw_hal_write_rfreg(padapter, minor_cmd, arg, 0xffffffff, extra_arg); ++ DBG_88E("write RF_reg path(0x%02x), offset(0x%x), value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff)); ++ break; ++ ++ case 0x76: ++ switch (minor_cmd) { ++ case 0x00: /* normal mode, */ ++ padapter->recvpriv.is_signal_dbg = 0; ++ break; ++ case 0x01: /* dbg mode */ ++ padapter->recvpriv.is_signal_dbg = 1; ++ extra_arg = extra_arg > 100 ? 100 : extra_arg; ++ extra_arg = extra_arg < 0 ? 0 : extra_arg; ++ padapter->recvpriv.signal_strength_dbg = extra_arg; ++ break; ++ } ++ break; ++ case 0x78: /* IOL test */ ++ switch (minor_cmd) { ++ case 0x04: /* LLT table initialization test */ ++ { ++ u8 page_boundary = 0xf9; ++ struct xmit_frame *xmit_frame; ++ ++ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter); ++ if (!xmit_frame) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ rtw_IOL_append_LLT_cmd(xmit_frame, page_boundary); ++ ++ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 500, 0)) ++ ret = -EPERM; ++ } ++ break; ++ case 0x05: /* blink LED test */ ++ { ++ u16 reg = 0x4c; ++ u32 blink_num = 50; ++ u32 blink_delay_ms = 200; ++ int i; ++ struct xmit_frame *xmit_frame; ++ ++ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter); ++ if (!xmit_frame) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ for (i = 0; i < blink_num; i++) { ++ rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x00, 0xff); ++ rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms); ++ rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x08, 0xff); ++ rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms); ++ } ++ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, (blink_delay_ms * blink_num * 2) + 200, 0)) ++ ret = -EPERM; ++ } ++ break; ++ ++ case 0x06: /* continuous write byte test */ ++ { ++ u16 reg = arg; ++ u16 start_value = 0; ++ u32 write_num = extra_arg; ++ int i; ++ u8 final; ++ struct xmit_frame *xmit_frame; ++ ++ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter); ++ if (!xmit_frame) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ for (i = 0; i < write_num; i++) ++ rtw_IOL_append_WB_cmd(xmit_frame, reg, i + start_value, 0xFF); ++ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0)) ++ ret = -EPERM; ++ ++ final = rtw_read8(padapter, reg); ++ if (start_value + write_num - 1 == final) ++ DBG_88E("continuous IOL_CMD_WB_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final); ++ else ++ DBG_88E("continuous IOL_CMD_WB_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final); ++ } ++ break; ++ ++ case 0x07: /* continuous write word test */ ++ { ++ u16 reg = arg; ++ u16 start_value = 200; ++ u32 write_num = extra_arg; ++ ++ int i; ++ u16 final; ++ struct xmit_frame *xmit_frame; ++ ++ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter); ++ if (!xmit_frame) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ for (i = 0; i < write_num; i++) ++ rtw_IOL_append_WW_cmd(xmit_frame, reg, i + start_value, 0xFFFF); ++ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0)) ++ ret = -EPERM; ++ ++ final = rtw_read16(padapter, reg); ++ if (start_value + write_num - 1 == final) ++ DBG_88E("continuous IOL_CMD_WW_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final); ++ else ++ DBG_88E("continuous IOL_CMD_WW_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final); ++ } ++ break; ++ case 0x08: /* continuous write dword test */ ++ { ++ u16 reg = arg; ++ u32 start_value = 0x110000c7; ++ u32 write_num = extra_arg; ++ ++ int i; ++ u32 final; ++ struct xmit_frame *xmit_frame; ++ ++ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter); ++ if (!xmit_frame) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ for (i = 0; i < write_num; i++) ++ rtw_IOL_append_WD_cmd(xmit_frame, reg, i + start_value, 0xFFFFFFFF); ++ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0)) ++ ret = -EPERM; ++ ++ final = rtw_read32(padapter, reg); ++ if (start_value + write_num - 1 == final) ++ DBG_88E("continuous IOL_CMD_WD_REG to 0x%x %u times Success, start:%u, final:%u\n", ++ reg, write_num, start_value, final); ++ else ++ DBG_88E("continuous IOL_CMD_WD_REG to 0x%x %u times Fail, start:%u, final:%u\n", ++ reg, write_num, start_value, final); ++ } ++ break; ++ } ++ break; ++ case 0x79: ++ { ++ /* ++ * dbg 0x79000000 [value], set RESP_TXAGC to + value, value:0~15 ++ * dbg 0x79010000 [value], set RESP_TXAGC to - value, value:0~15 ++ */ ++ u8 value = extra_arg & 0x0f; ++ u8 sign = minor_cmd; ++ u16 write_value = 0; ++ ++ DBG_88E("%s set RESP_TXAGC to %s %u\n", __func__, sign ? "minus" : "plus", value); ++ ++ if (sign) ++ value = value | 0x10; ++ ++ write_value = value | (value << 5); ++ rtw_write16(padapter, 0x6d9, write_value); ++ } ++ break; ++ case 0x7a: ++ receive_disconnect(padapter, pmlmeinfo->network.MacAddress ++ , WLAN_REASON_EXPIRATION_CHK); ++ break; ++ case 0x7F: ++ switch (minor_cmd) { ++ case 0x0: ++ DBG_88E("fwstate = 0x%x\n", get_fwstate(pmlmepriv)); ++ break; ++ case 0x01: ++ DBG_88E("auth_alg = 0x%x, enc_alg = 0x%x, auth_type = 0x%x, enc_type = 0x%x\n", ++ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm, ++ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus); ++ break; ++ case 0x02: ++ DBG_88E("pmlmeinfo->state = 0x%x\n", pmlmeinfo->state); ++ break; ++ case 0x03: ++ DBG_88E("qos_option =%d\n", pmlmepriv->qospriv.qos_option); ++ DBG_88E("ht_option =%d\n", pmlmepriv->htpriv.ht_option); ++ break; ++ case 0x04: ++ DBG_88E("cur_ch =%d\n", pmlmeext->cur_channel); ++ DBG_88E("cur_bw =%d\n", pmlmeext->cur_bwmode); ++ DBG_88E("cur_ch_off =%d\n", pmlmeext->cur_ch_offset); ++ break; ++ case 0x05: ++ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); ++ if (psta) { ++ int i; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ DBG_88E("SSID =%s\n", cur_network->network.Ssid.Ssid); ++ DBG_88E("sta's macaddr: %pM\n", psta->hwaddr); ++ DBG_88E("cur_channel =%d, cur_bwmode =%d, cur_ch_offset =%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); ++ DBG_88E("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); ++ DBG_88E("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++ DBG_88E("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ DBG_88E("bwmode =%d, ch_offset =%d, sgi =%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); ++ DBG_88E("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ DBG_88E("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++ for (i = 0; i < 16; i++) { ++ preorder_ctrl = &psta->recvreorder_ctrl[i]; ++ if (preorder_ctrl->enable) ++ DBG_88E("tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq); ++ } ++ } else { ++ DBG_88E("can't get sta's macaddr, cur_network's macaddr:%pM\n", (cur_network->network.MacAddress)); ++ } ++ break; ++ case 0x06: ++ { ++ u32 ODMFlag; ++ rtw_hal_get_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag)); ++ DBG_88E("(B)DMFlag = 0x%x, arg = 0x%x\n", ODMFlag, arg); ++ ODMFlag = (u32)(0x0f & arg); ++ DBG_88E("(A)DMFlag = 0x%x\n", ODMFlag); ++ rtw_hal_set_hwreg(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag)); ++ } ++ break; ++ case 0x07: ++ DBG_88E("bSurpriseRemoved =%d, bDriverStopped =%d\n", ++ padapter->bSurpriseRemoved, padapter->bDriverStopped); ++ break; ++ case 0x08: ++ { ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ DBG_88E("free_xmitbuf_cnt =%d, free_xmitframe_cnt =%d, free_xmit_extbuf_cnt =%d\n", ++ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmit_extbuf_cnt); ++ DBG_88E("rx_urb_pending_cn =%d\n", precvpriv->rx_pending_cnt); ++ } ++ break; ++ case 0x09: ++ { ++ int i, j; ++ struct list_head *plist, *phead; ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++#ifdef CONFIG_88EU_AP_MODE ++ DBG_88E("sta_dz_bitmap = 0x%x, tim_bitmap = 0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); ++#endif ++ spin_lock_bh(&pstapriv->sta_hash_lock); ++ ++ for (i = 0; i < NUM_STA; i++) { ++ phead = &pstapriv->sta_hash[i]; ++ plist = phead->next; ++ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, hash_list); ++ ++ plist = plist->next; ++ ++ if (extra_arg == psta->aid) { ++ DBG_88E("sta's macaddr:%pM\n", (psta->hwaddr)); ++ DBG_88E("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); ++ DBG_88E("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); ++ DBG_88E("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); ++ DBG_88E("bwmode =%d, ch_offset =%d, sgi =%d\n", psta->htpriv.bwmode, psta->htpriv.ch_offset, psta->htpriv.sgi); ++ DBG_88E("ampdu_enable = %d\n", psta->htpriv.ampdu_enable); ++ DBG_88E("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ DBG_88E("capability = 0x%x\n", psta->capability); ++ DBG_88E("flags = 0x%x\n", psta->flags); ++ DBG_88E("wpa_psk = 0x%x\n", psta->wpa_psk); ++ DBG_88E("wpa2_group_cipher = 0x%x\n", psta->wpa2_group_cipher); ++ DBG_88E("wpa2_pairwise_cipher = 0x%x\n", psta->wpa2_pairwise_cipher); ++ DBG_88E("qos_info = 0x%x\n", psta->qos_info); ++#endif ++ DBG_88E("dot118021XPrivacy = 0x%x\n", psta->dot118021XPrivacy); ++ ++ for (j = 0; j < 16; j++) { ++ preorder_ctrl = &psta->recvreorder_ctrl[j]; ++ if (preorder_ctrl->enable) ++ DBG_88E("tid =%d, indicate_seq =%d\n", j, preorder_ctrl->indicate_seq); ++ } ++ } ++ } ++ } ++ spin_unlock_bh(&pstapriv->sta_hash_lock); ++ } ++ break; ++ case 0x0c:/* dump rx/tx packet */ ++ if (arg == 0) { ++ DBG_88E("dump rx packet (%d)\n", extra_arg); ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_RXPKT, &(extra_arg)); ++ } else if (arg == 1) { ++ DBG_88E("dump tx packet (%d)\n", extra_arg); ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(extra_arg)); ++ } ++ break; ++ case 0x0f: ++ if (extra_arg == 0) { ++ DBG_88E("###### silent reset test.......#####\n"); ++ rtw_hal_sreset_reset(padapter); ++ } ++ break; ++ case 0x15: ++ { ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ DBG_88E("==>silent resete cnts:%d\n", pwrpriv->ips_enter_cnts); ++ } ++ break; ++ case 0x10:/* driver version display */ ++ DBG_88E("rtw driver version =%s\n", DRIVERVERSION); ++ break; ++ case 0x11: ++ DBG_88E("turn %s Rx RSSI display function\n", (extra_arg == 1) ? "on" : "off"); ++ padapter->bRxRSSIDisplay = extra_arg; ++ break; ++ case 0x12: /* set rx_stbc */ ++ { ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */ ++ /* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */ ++ if (pregpriv && ++ (extra_arg == 0 || ++ extra_arg == 1 || ++ extra_arg == 2 || ++ extra_arg == 3)) { ++ pregpriv->rx_stbc = extra_arg; ++ DBG_88E("set rx_stbc =%d\n", pregpriv->rx_stbc); ++ } else { ++ DBG_88E("get rx_stbc =%d\n", pregpriv->rx_stbc); ++ } ++ } ++ break; ++ case 0x13: /* set ampdu_enable */ ++ { ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ /* 0: disable, 0x1:enable (but wifi_spec should be 0), 0x2: force enable (don't care wifi_spec) */ ++ if (pregpriv && extra_arg >= 0 && extra_arg < 3) { ++ pregpriv->ampdu_enable = extra_arg; ++ DBG_88E("set ampdu_enable =%d\n", pregpriv->ampdu_enable); ++ } else { ++ DBG_88E("get ampdu_enable =%d\n", pregpriv->ampdu_enable); ++ } ++ } ++ break; ++ case 0x14: /* get wifi_spec */ ++ { ++ struct registry_priv *pregpriv = &padapter->registrypriv; ++ DBG_88E("get wifi_spec =%d\n", pregpriv->wifi_spec); ++ } ++ break; ++ case 0x23: ++ DBG_88E("turn %s the bNotifyChannelChange Variable\n", (extra_arg == 1) ? "on" : "off"); ++ padapter->bNotifyChannelChange = extra_arg; ++ break; ++ case 0x24: ++#ifdef CONFIG_88EU_P2P ++ DBG_88E("turn %s the bShowGetP2PState Variable\n", (extra_arg == 1) ? "on" : "off"); ++ padapter->bShowGetP2PState = extra_arg; ++#endif /* CONFIG_88EU_P2P */ ++ break; ++ case 0xaa: ++ if (extra_arg > 0x13) ++ extra_arg = 0xFF; ++ DBG_88E("chang data rate to :0x%02x\n", extra_arg); ++ padapter->fix_rate = extra_arg; ++ break; ++ case 0xdd:/* registers dump, 0 for mac reg, 1 for bb reg, 2 for rf reg */ ++ if (extra_arg == 0) ++ mac_reg_dump(padapter); ++ else if (extra_arg == 1) ++ bb_reg_dump(padapter); ++ else if (extra_arg == 2) ++ rf_reg_dump(padapter); ++ break; ++ case 0xee:/* turn on/off dynamic funcs */ ++ { ++ u32 odm_flag; ++ ++ if (0xf == extra_arg) { ++ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag); ++ DBG_88E(" === DMFlag(0x%08x) ===\n", odm_flag); ++ DBG_88E("extra_arg = 0 - disable all dynamic func\n"); ++ DBG_88E("extra_arg = 1 - disable DIG- BIT(0)\n"); ++ DBG_88E("extra_arg = 2 - disable High power - BIT(1)\n"); ++ DBG_88E("extra_arg = 3 - disable tx power tracking - BIT(2)\n"); ++ DBG_88E("extra_arg = 4 - disable BT coexistence - BIT(3)\n"); ++ DBG_88E("extra_arg = 5 - disable antenna diversity - BIT(4)\n"); ++ DBG_88E("extra_arg = 6 - enable all dynamic func\n"); ++ } else { ++ /* extra_arg = 0 - disable all dynamic func ++ extra_arg = 1 - disable DIG ++ extra_arg = 2 - disable tx power tracking ++ extra_arg = 3 - turn on all dynamic func ++ */ ++ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &(extra_arg)); ++ rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag); ++ DBG_88E(" === DMFlag(0x%08x) ===\n", odm_flag); ++ } ++ } ++ break; ++ ++ case 0xfd: ++ rtw_write8(padapter, 0xc50, arg); ++ DBG_88E("wr(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50)); ++ rtw_write8(padapter, 0xc58, arg); ++ DBG_88E("wr(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58)); ++ break; ++ case 0xfe: ++ DBG_88E("rd(0xc50) = 0x%x\n", rtw_read8(padapter, 0xc50)); ++ DBG_88E("rd(0xc58) = 0x%x\n", rtw_read8(padapter, 0xc58)); ++ break; ++ case 0xff: ++ DBG_88E("dbg(0x210) = 0x%x\n", rtw_read32(padapter, 0x210)); ++ DBG_88E("dbg(0x608) = 0x%x\n", rtw_read32(padapter, 0x608)); ++ DBG_88E("dbg(0x280) = 0x%x\n", rtw_read32(padapter, 0x280)); ++ DBG_88E("dbg(0x284) = 0x%x\n", rtw_read32(padapter, 0x284)); ++ DBG_88E("dbg(0x288) = 0x%x\n", rtw_read32(padapter, 0x288)); ++ ++ DBG_88E("dbg(0x664) = 0x%x\n", rtw_read32(padapter, 0x664)); ++ ++ DBG_88E("\n"); ++ ++ DBG_88E("dbg(0x430) = 0x%x\n", rtw_read32(padapter, 0x430)); ++ DBG_88E("dbg(0x438) = 0x%x\n", rtw_read32(padapter, 0x438)); ++ ++ DBG_88E("dbg(0x440) = 0x%x\n", rtw_read32(padapter, 0x440)); ++ ++ DBG_88E("dbg(0x458) = 0x%x\n", rtw_read32(padapter, 0x458)); ++ ++ DBG_88E("dbg(0x484) = 0x%x\n", rtw_read32(padapter, 0x484)); ++ DBG_88E("dbg(0x488) = 0x%x\n", rtw_read32(padapter, 0x488)); ++ ++ DBG_88E("dbg(0x444) = 0x%x\n", rtw_read32(padapter, 0x444)); ++ DBG_88E("dbg(0x448) = 0x%x\n", rtw_read32(padapter, 0x448)); ++ DBG_88E("dbg(0x44c) = 0x%x\n", rtw_read32(padapter, 0x44c)); ++ DBG_88E("dbg(0x450) = 0x%x\n", rtw_read32(padapter, 0x450)); ++ break; ++ } ++ break; ++ default: ++ DBG_88E("error dbg cmd!\n"); ++ break; ++ } ++ return ret; ++} ++ ++static int rtw_wx_set_priv(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *awrq, ++ char *extra) ++{ ++ int ret = 0; ++ int len = 0; ++ char *ext; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_point *dwrq = (struct iw_point *)awrq; ++ ++ if (dwrq->length == 0) ++ return -EFAULT; ++ ++ len = dwrq->length; ++ ext = vmalloc(len); ++ if (!ext) ++ return -ENOMEM; ++ ++ if (copy_from_user(ext, dwrq->pointer, len)) { ++ vfree(ext); ++ return -EFAULT; ++ } ++ ++ /* added for wps2.0 @20110524 */ ++ if (dwrq->flags == 0x8766 && len > 8) { ++ u32 cp_sz; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ u8 *probereq_wpsie = ext; ++ int probereq_wpsie_len = len; ++ u8 wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; ++ ++ if ((_VENDOR_SPECIFIC_IE_ == probereq_wpsie[0]) && ++ (!memcmp(&probereq_wpsie[2], wps_oui, 4))) { ++ cp_sz = probereq_wpsie_len > MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN : probereq_wpsie_len; ++ ++ pmlmepriv->wps_probe_req_ie_len = 0; ++ kfree(pmlmepriv->wps_probe_req_ie); ++ pmlmepriv->wps_probe_req_ie = NULL; ++ ++ pmlmepriv->wps_probe_req_ie = kmalloc(cp_sz, GFP_KERNEL); ++ if (!pmlmepriv->wps_probe_req_ie) { ++ ret = -EINVAL; ++ goto FREE_EXT; ++ } ++ memcpy(pmlmepriv->wps_probe_req_ie, probereq_wpsie, cp_sz); ++ pmlmepriv->wps_probe_req_ie_len = cp_sz; ++ } ++ goto FREE_EXT; ++ } ++ ++ if (len >= WEXT_CSCAN_HEADER_SIZE && ++ !memcmp(ext, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) { ++ ret = rtw_wx_set_scan(dev, info, awrq, ext); ++ goto FREE_EXT; ++ } ++ ++FREE_EXT: ++ ++ vfree(ext); ++ ++ return ret; ++} ++ ++static int rtw_pm_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int ret = 0; ++ unsigned mode = 0; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ ++ DBG_88E("[%s] extra = %s\n", __func__, extra); ++ ++ if (!memcmp(extra, "lps =", 4)) { ++ sscanf(extra + 4, "%u", &mode); ++ ret = rtw_pm_set_lps(padapter, mode); ++ } else if (!memcmp(extra, "ips =", 4)) { ++ sscanf(extra + 4, "%u", &mode); ++ ret = rtw_pm_set_ips(padapter, mode); ++ } else { ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int rtw_mp_efuse_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ struct hal_data_8188e *haldata = GET_HAL_DATA(padapter); ++ struct efuse_hal *pEfuseHal; ++ struct iw_point *wrqu; ++ ++ u8 *PROMContent = pEEPROM->efuse_eeprom_data; ++ u8 ips_mode = 0, lps_mode = 0; ++ struct pwrctrl_priv *pwrctrlpriv; ++ u8 *data = NULL; ++ u8 *rawdata = NULL; ++ char *pch, *ptmp, *token, *tmp[3] = {NULL, NULL, NULL}; ++ u16 i = 0, j = 0, mapLen = 0, addr = 0, cnts = 0; ++ u16 max_available_size = 0, raw_cursize = 0, raw_maxsize = 0; ++ int err; ++ u8 org_fw_iol = padapter->registrypriv.fw_iol;/* 0:Disable, 1:enable, 2:by usb speed */ ++ ++ wrqu = (struct iw_point *)wdata; ++ pwrctrlpriv = &padapter->pwrctrlpriv; ++ pEfuseHal = &haldata->EfuseHal; ++ ++ err = 0; ++ data = kzalloc(EFUSE_BT_MAX_MAP_LEN, GFP_KERNEL); ++ if (!data) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ rawdata = kzalloc(EFUSE_BT_MAX_MAP_LEN, GFP_KERNEL); ++ if (!rawdata) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ if (copy_from_user(extra, wrqu->pointer, wrqu->length)) { ++ err = -EFAULT; ++ goto exit; ++ } ++ lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */ ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ ips_mode = pwrctrlpriv->ips_mode;/* keep org value */ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ ++ pch = extra; ++ DBG_88E("%s: in =%s\n", __func__, extra); ++ ++ i = 0; ++ /* mac 16 "00e04c871200" rmap, 00, 2 */ ++ while ((token = strsep(&pch, ",")) != NULL) { ++ if (i > 2) ++ break; ++ tmp[i] = token; ++ i++; ++ } ++ padapter->registrypriv.fw_iol = 0;/* 0:Disable, 1:enable, 2:by usb speed */ ++ ++ if (strcmp(tmp[0], "status") == 0) { ++ sprintf(extra, "Load File efuse =%s, Load File MAC =%s", (pEEPROM->bloadfile_fail_flag ? "FAIL" : "OK"), (pEEPROM->bloadmac_fail_flag ? "FAIL" : "OK")); ++ ++ goto exit; ++ } else if (strcmp(tmp[0], "filemap") == 0) { ++ mapLen = EFUSE_MAP_SIZE; ++ ++ sprintf(extra, "\n"); ++ for (i = 0; i < EFUSE_MAP_SIZE; i += 16) { ++ sprintf(extra + strlen(extra), "0x%02x\t", i); ++ for (j = 0; j < 8; j++) ++ sprintf(extra + strlen(extra), "%02X ", PROMContent[i + j]); ++ sprintf(extra + strlen(extra), "\t"); ++ for (; j < 16; j++) ++ sprintf(extra + strlen(extra), "%02X ", PROMContent[i + j]); ++ sprintf(extra + strlen(extra), "\n"); ++ } ++ } else if (strcmp(tmp[0], "realmap") == 0) { ++ mapLen = EFUSE_MAP_SIZE; ++ if (rtw_efuse_map_read(padapter, 0, mapLen, pEfuseHal->fakeEfuseInitMap) == _FAIL) { ++ DBG_88E("%s: read realmap Fail!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ sprintf(extra, "\n"); ++ for (i = 0; i < EFUSE_MAP_SIZE; i += 16) { ++ sprintf(extra + strlen(extra), "0x%02x\t", i); ++ for (j = 0; j < 8; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeEfuseInitMap[i + j]); ++ sprintf(extra + strlen(extra), "\t"); ++ for (; j < 16; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeEfuseInitMap[i + j]); ++ sprintf(extra + strlen(extra), "\n"); ++ } ++ } else if (strcmp(tmp[0], "rmap") == 0) { ++ if (!tmp[1] || !tmp[2]) { ++ DBG_88E("%s: rmap Fail!! Parameters error!\n", __func__); ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ /* rmap addr cnts */ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ DBG_88E("%s: addr =%x\n", __func__, addr); ++ ++ cnts = simple_strtoul(tmp[2], &ptmp, 10); ++ if (cnts == 0) { ++ DBG_88E("%s: rmap Fail!! cnts error!\n", __func__); ++ err = -EINVAL; ++ goto exit; ++ } ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if ((addr + cnts) > max_available_size) { ++ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts); ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_map_read error!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ *extra = 0; ++ for (i = 0; i < cnts; i++) ++ sprintf(extra + strlen(extra), "0x%02X ", data[i]); ++ } else if (strcmp(tmp[0], "realraw") == 0) { ++ addr = 0; ++ mapLen = EFUSE_MAX_SIZE; ++ if (rtw_efuse_access(padapter, false, addr, mapLen, rawdata) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_access Fail!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ sprintf(extra, "\n"); ++ for (i = 0; i < mapLen; i++) { ++ sprintf(extra + strlen(extra), "%02X", rawdata[i]); ++ ++ if ((i & 0xF) == 0xF) ++ sprintf(extra + strlen(extra), "\n"); ++ else if ((i & 0x7) == 0x7) ++ sprintf(extra + strlen(extra), "\t"); ++ else ++ sprintf(extra + strlen(extra), " "); ++ } ++ } else if (strcmp(tmp[0], "mac") == 0) { ++ cnts = 6; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if ((addr + cnts) > max_available_size) { ++ DBG_88E("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __func__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_map_read error!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ *extra = 0; ++ for (i = 0; i < cnts; i++) { ++ sprintf(extra + strlen(extra), "%02X", data[i]); ++ if (i != (cnts - 1)) ++ sprintf(extra + strlen(extra), ":"); ++ } ++ } else if (strcmp(tmp[0], "vidpid") == 0) { ++ cnts = 4; ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if ((addr + cnts) > max_available_size) { ++ DBG_88E("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __func__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ if (rtw_efuse_map_read(padapter, addr, cnts, data) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_access error!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ *extra = 0; ++ for (i = 0; i < cnts; i++) { ++ sprintf(extra + strlen(extra), "0x%02X", data[i]); ++ if (i != (cnts - 1)) ++ sprintf(extra + strlen(extra), ","); ++ } ++ } else if (strcmp(tmp[0], "ableraw") == 0) { ++ efuse_GetCurrentSize(padapter, &raw_cursize); ++ raw_maxsize = efuse_GetMaxSize(padapter); ++ sprintf(extra, "[available raw size] = %d bytes", raw_maxsize - raw_cursize); ++ } else if (strcmp(tmp[0], "btfmap") == 0) { ++ mapLen = EFUSE_BT_MAX_MAP_LEN; ++ if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) { ++ DBG_88E("%s: rtw_BT_efuse_map_read Fail!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ sprintf(extra, "\n"); ++ for (i = 0; i < 512; i += 16) { ++ /* set 512 because the iwpriv's extra size have limit 0x7FF */ ++ sprintf(extra + strlen(extra), "0x%03x\t", i); ++ for (j = 0; j < 8; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->BTEfuseInitMap[i + j]); ++ sprintf(extra + strlen(extra), "\t"); ++ for (; j < 16; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->BTEfuseInitMap[i + j]); ++ sprintf(extra + strlen(extra), "\n"); ++ } ++ } else if (strcmp(tmp[0], "btbmap") == 0) { ++ mapLen = EFUSE_BT_MAX_MAP_LEN; ++ if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) { ++ DBG_88E("%s: rtw_BT_efuse_map_read Fail!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ sprintf(extra, "\n"); ++ for (i = 512; i < 1024; i += 16) { ++ sprintf(extra + strlen(extra), "0x%03x\t", i); ++ for (j = 0; j < 8; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->BTEfuseInitMap[i + j]); ++ sprintf(extra + strlen(extra), "\t"); ++ for (; j < 16; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->BTEfuseInitMap[i + j]); ++ sprintf(extra + strlen(extra), "\n"); ++ } ++ } else if (strcmp(tmp[0], "btrmap") == 0) { ++ if (!tmp[1] || !tmp[2]) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ /* rmap addr cnts */ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ DBG_88E("%s: addr = 0x%X\n", __func__, addr); ++ ++ cnts = simple_strtoul(tmp[2], &ptmp, 10); ++ if (cnts == 0) { ++ DBG_88E("%s: btrmap Fail!! cnts error!\n", __func__); ++ err = -EINVAL; ++ goto exit; ++ } ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if ((addr + cnts) > max_available_size) { ++ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_BT_efuse_map_read(padapter, addr, cnts, data) == _FAIL) { ++ DBG_88E("%s: rtw_BT_efuse_map_read error!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ *extra = 0; ++ for (i = 0; i < cnts; i++) ++ sprintf(extra + strlen(extra), " 0x%02X ", data[i]); ++ } else if (strcmp(tmp[0], "btffake") == 0) { ++ sprintf(extra, "\n"); ++ for (i = 0; i < 512; i += 16) { ++ sprintf(extra + strlen(extra), "0x%03x\t", i); ++ for (j = 0; j < 8; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]); ++ sprintf(extra + strlen(extra), "\t"); ++ for (; j < 16; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]); ++ sprintf(extra + strlen(extra), "\n"); ++ } ++ } else if (strcmp(tmp[0], "btbfake") == 0) { ++ sprintf(extra, "\n"); ++ for (i = 512; i < 1024; i += 16) { ++ sprintf(extra + strlen(extra), "0x%03x\t", i); ++ for (j = 0; j < 8; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]); ++ sprintf(extra + strlen(extra), "\t"); ++ for (; j < 16; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]); ++ sprintf(extra + strlen(extra), "\n"); ++ } ++ } else if (strcmp(tmp[0], "wlrfkmap") == 0) { ++ sprintf(extra, "\n"); ++ for (i = 0; i < EFUSE_MAP_SIZE; i += 16) { ++ sprintf(extra + strlen(extra), "0x%02x\t", i); ++ for (j = 0; j < 8; j++) ++ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeEfuseModifiedMap[i + j]); ++ sprintf(extra + strlen(extra), "\t"); ++ for (; j < 16; j++) ++ sprintf(extra + strlen(extra), " %02X", pEfuseHal->fakeEfuseModifiedMap[i + j]); ++ sprintf(extra + strlen(extra), "\n"); ++ } ++ } else { ++ sprintf(extra, "Command not found!"); ++ } ++ ++exit: ++ kfree(data); ++ kfree(rawdata); ++ if (!err) ++ wrqu->length = strlen(extra); ++ ++ rtw_pm_set_ips(padapter, ips_mode); ++ rtw_pm_set_lps(padapter, lps_mode); ++ padapter->registrypriv.fw_iol = org_fw_iol;/* 0:Disable, 1:enable, 2:by usb speed */ ++ return err; ++} ++ ++static int rtw_mp_efuse_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ struct adapter *padapter; ++ struct pwrctrl_priv *pwrctrlpriv; ++ struct hal_data_8188e *haldata; ++ struct efuse_hal *pEfuseHal; ++ ++ u8 ips_mode = 0, lps_mode = 0; ++ u32 i, jj, kk; ++ u8 *setdata = NULL; ++ u8 *ShadowMapBT = NULL; ++ u8 *ShadowMapWiFi = NULL; ++ u8 *setrawdata = NULL; ++ char *pch, *ptmp, *token, *tmp[3] = {NULL, NULL, NULL}; ++ u16 addr = 0, cnts = 0, max_available_size = 0; ++ int err; ++ ++ padapter = rtw_netdev_priv(dev); ++ pwrctrlpriv = &padapter->pwrctrlpriv; ++ haldata = GET_HAL_DATA(padapter); ++ pEfuseHal = &haldata->EfuseHal; ++ err = 0; ++ setdata = kzalloc(1024, GFP_KERNEL); ++ if (!setdata) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ShadowMapBT = kmalloc(EFUSE_BT_MAX_MAP_LEN, GFP_KERNEL); ++ if (!ShadowMapBT) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ShadowMapWiFi = kmalloc(EFUSE_MAP_SIZE, GFP_KERNEL); ++ if (!ShadowMapWiFi) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ setrawdata = kmalloc(EFUSE_MAX_SIZE, GFP_KERNEL); ++ if (!setrawdata) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */ ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ ips_mode = pwrctrlpriv->ips_mode;/* keep org value */ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ ++ pch = extra; ++ DBG_88E("%s: in =%s\n", __func__, extra); ++ ++ i = 0; ++ while ((token = strsep(&pch, ",")) != NULL) { ++ if (i > 2) ++ break; ++ tmp[i] = token; ++ i++; ++ } ++ ++ /* tmp[0],[1],[2] */ ++ /* wmap, addr, 00e04c871200 */ ++ if (strcmp(tmp[0], "wmap") == 0) { ++ if (!tmp[1] || !tmp[2]) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts % 2) { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_88E("%s: addr = 0x%X\n", __func__, addr); ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ DBG_88E("%s: map data =%s\n", __func__, tmp[2]); ++ ++ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) ++ setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]); ++ /* Change to check TYPE_EFUSE_MAP_LEN, because 8188E raw 256, logic map over 256. */ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_size, false); ++ if ((addr + cnts) > max_available_size) { ++ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } else if (strcmp(tmp[0], "wraw") == 0) { ++ if (!tmp[1] || !tmp[2]) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts % 2) { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_88E("%s: addr = 0x%X\n", __func__, addr); ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ DBG_88E("%s: raw data =%s\n", __func__, tmp[2]); ++ ++ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) ++ setrawdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]); ++ ++ if (rtw_efuse_access(padapter, true, addr, cnts, setrawdata) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_access error!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } else if (strcmp(tmp[0], "mac") == 0) { ++ if (!tmp[1]) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ /* mac, 00e04c871200 */ ++ addr = EEPROM_MAC_ADDR_88EU; ++ cnts = strlen(tmp[1]); ++ if (cnts % 2) { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) { ++ err = -EINVAL; ++ goto exit; ++ } ++ if (cnts > 6) { ++ DBG_88E("%s: error data for mac addr =\"%s\"\n", __func__, tmp[1]); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ DBG_88E("%s: addr = 0x%X\n", __func__, addr); ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ DBG_88E("%s: MAC address =%s\n", __func__, tmp[1]); ++ ++ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) ++ setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]); ++ /* Change to check TYPE_EFUSE_MAP_LEN, because 8188E raw 256, logic map over 256. */ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_size, false); ++ if ((addr + cnts) > max_available_size) { ++ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } else if (strcmp(tmp[0], "vidpid") == 0) { ++ if (!tmp[1]) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ /* pidvid, da0b7881 */ ++ addr = EEPROM_VID_88EE; ++ cnts = strlen(tmp[1]); ++ if (cnts % 2) { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_88E("%s: addr = 0x%X\n", __func__, addr); ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ DBG_88E("%s: VID/PID =%s\n", __func__, tmp[1]); ++ ++ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) ++ setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if ((addr + cnts) > max_available_size) { ++ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_map_write error!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } else if (strcmp(tmp[0], "btwmap") == 0) { ++ if (!tmp[1] || !tmp[2]) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts % 2) { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_88E("%s: addr = 0x%X\n", __func__, addr); ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ DBG_88E("%s: BT data =%s\n", __func__, tmp[2]); ++ ++ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) ++ setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if ((addr + cnts) > max_available_size) { ++ DBG_88E("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts); ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_BT_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) { ++ DBG_88E("%s: rtw_BT_efuse_map_write error!!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } else if (strcmp(tmp[0], "btwfake") == 0) { ++ if (!tmp[1] || !tmp[2]) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts % 2) { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_88E("%s: addr = 0x%X\n", __func__, addr); ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ DBG_88E("%s: BT tmp data =%s\n", __func__, tmp[2]); ++ ++ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) ++ pEfuseHal->fakeBTEfuseModifiedMap[addr + jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]); ++ } else if (strcmp(tmp[0], "btdumpfake") == 0) { ++ if (rtw_BT_efuse_map_read(padapter, 0, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _SUCCESS) { ++ DBG_88E("%s: BT read all map success\n", __func__); ++ } else { ++ DBG_88E("%s: BT read all map Fail!\n", __func__); ++ err = -EFAULT; ++ } ++ } else if (strcmp(tmp[0], "wldumpfake") == 0) { ++ if (rtw_efuse_map_read(padapter, 0, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeEfuseModifiedMap) == _SUCCESS) { ++ DBG_88E("%s: BT read all map success\n", __func__); ++ } else { ++ DBG_88E("%s: BT read all map Fail\n", __func__); ++ err = -EFAULT; ++ } ++ } else if (strcmp(tmp[0], "btfk2map") == 0) { ++ memcpy(pEfuseHal->BTEfuseModifiedMap, pEfuseHal->fakeBTEfuseModifiedMap, EFUSE_BT_MAX_MAP_LEN); ++ ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if (max_available_size < 1) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_BT_efuse_map_write(padapter, 0x00, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _FAIL) { ++ DBG_88E("%s: rtw_BT_efuse_map_write error!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } else if (strcmp(tmp[0], "wlfk2map") == 0) { ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if (max_available_size < 1) { ++ err = -EFAULT; ++ goto exit; ++ } ++ ++ if (rtw_efuse_map_write(padapter, 0x00, EFUSE_MAX_MAP_LEN, pEfuseHal->fakeEfuseModifiedMap) == _FAIL) { ++ DBG_88E("%s: rtw_efuse_map_write error!\n", __func__); ++ err = -EFAULT; ++ goto exit; ++ } ++ } else if (strcmp(tmp[0], "wlwfake") == 0) { ++ if (!tmp[1] || !tmp[2]) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ addr = simple_strtoul(tmp[1], &ptmp, 16); ++ addr &= 0xFFF; ++ ++ cnts = strlen(tmp[2]); ++ if (cnts % 2) { ++ err = -EINVAL; ++ goto exit; ++ } ++ cnts /= 2; ++ if (cnts == 0) { ++ err = -EINVAL; ++ goto exit; ++ } ++ ++ DBG_88E("%s: addr = 0x%X\n", __func__, addr); ++ DBG_88E("%s: cnts =%d\n", __func__, cnts); ++ DBG_88E("%s: map tmp data =%s\n", __func__, tmp[2]); ++ ++ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2) ++ pEfuseHal->fakeEfuseModifiedMap[addr + jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]); ++ } ++ ++exit: ++ kfree(setdata); ++ kfree(ShadowMapBT); ++ kfree(ShadowMapWiFi); ++ kfree(setrawdata); ++ ++ rtw_pm_set_ips(padapter, ips_mode); ++ rtw_pm_set_lps(padapter, lps_mode); ++ ++ return err; ++} ++ ++/* ++ * Input Format: %s,%d,%d ++ * %s is width, could be ++ * "b" for 1 byte ++ * "w" for WORD (2 bytes) ++ * "dw" for DWORD (4 bytes) ++ * 1st %d is address(offset) ++ * 2st %d is data to write ++ */ ++static int rtw_mp_write_reg(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ char *pch, *pnext, *ptmp; ++ char *width_str; ++ char width; ++ u32 addr, data; ++ int ret; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ pch = extra; ++ pnext = strpbrk(pch, ",.-"); ++ if (!pnext) ++ return -EINVAL; ++ *pnext = 0; ++ width_str = pch; ++ ++ pch = pnext + 1; ++ pnext = strpbrk(pch, ",.-"); ++ if (!pnext) ++ return -EINVAL; ++ *pnext = 0; ++ addr = simple_strtoul(pch, &ptmp, 16); ++ if (addr > 0x3FFF) ++ return -EINVAL; ++ ++ pch = pnext + 1; ++ if ((pch - extra) >= wrqu->length) ++ return -EINVAL; ++ data = simple_strtoul(pch, &ptmp, 16); ++ ++ ret = 0; ++ width = width_str[0]; ++ switch (width) { ++ case 'b': ++ /* 1 byte */ ++ if (data > 0xFF) { ++ ret = -EINVAL; ++ break; ++ } ++ rtw_write8(padapter, addr, data); ++ break; ++ case 'w': ++ /* 2 bytes */ ++ if (data > 0xFFFF) { ++ ret = -EINVAL; ++ break; ++ } ++ rtw_write16(padapter, addr, data); ++ break; ++ case 'd': ++ /* 4 bytes */ ++ rtw_write32(padapter, addr, data); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Input Format: %s,%d ++ * %s is width, could be ++ * "b" for 1 byte ++ * "w" for WORD (2 bytes) ++ * "dw" for DWORD (4 bytes) ++ * %d is address(offset) ++ * ++ * Return: ++ * %d for data readed ++ */ ++static int rtw_mp_read_reg(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ char *pch, *pnext, *ptmp; ++ char *width_str; ++ char width; ++ char data[20], tmp[20]; ++ u32 addr; ++ u32 ret, i = 0, j = 0, strtout = 0; ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ memset(data, 0, 20); ++ memset(tmp, 0, 20); ++ memset(extra, 0, wrqu->length); ++ ++ pch = input; ++ pnext = strpbrk(pch, ",.-"); ++ if (!pnext) { ++ kfree(input); ++ return -EINVAL; ++ } ++ *pnext = 0; ++ width_str = pch; ++ ++ pch = pnext + 1; ++ if ((pch - input) >= wrqu->length) { ++ kfree(input); ++ return -EINVAL; ++ } ++ kfree(input); ++ addr = simple_strtoul(pch, &ptmp, 16); ++ if (addr > 0x3FFF) ++ return -EINVAL; ++ ++ ret = 0; ++ width = width_str[0]; ++ switch (width) { ++ case 'b': ++ /* 1 byte */ ++ sprintf(extra, "%d\n", rtw_read8(padapter, addr)); ++ wrqu->length = strlen(extra); ++ break; ++ case 'w': ++ /* 2 bytes */ ++ sprintf(data, "%04x\n", rtw_read16(padapter, addr)); ++ for (i = 0; i <= strlen(data); i++) { ++ if (i % 2 == 0) { ++ tmp[j] = ' '; ++ j++; ++ } ++ if (data[i] != '\0') ++ tmp[j] = data[i]; ++ j++; ++ } ++ pch = tmp; ++ DBG_88E("pch =%s", pch); ++ ++ while (*pch != '\0') { ++ pnext = strpbrk(pch, " "); ++ if (!pnext) ++ break; ++ ++ pnext++; ++ if (*pnext != '\0') { ++ strtout = simple_strtoul(pnext, &ptmp, 16); ++ sprintf(extra + strlen(extra), " %d", strtout); ++ } else { ++ break; ++ } ++ pch = pnext; ++ } ++ wrqu->length = 6; ++ break; ++ case 'd': ++ /* 4 bytes */ ++ sprintf(data, "%08x", rtw_read32(padapter, addr)); ++ /* add read data format blank */ ++ for (i = 0; i <= strlen(data); i++) { ++ if (i % 2 == 0) { ++ tmp[j] = ' '; ++ j++; ++ } ++ if (data[i] != '\0') ++ tmp[j] = data[i]; ++ ++ j++; ++ } ++ pch = tmp; ++ DBG_88E("pch =%s", pch); ++ ++ while (*pch != '\0') { ++ pnext = strpbrk(pch, " "); ++ if (!pnext) ++ break; ++ pnext++; ++ if (*pnext != '\0') { ++ strtout = simple_strtoul(pnext, &ptmp, 16); ++ sprintf(extra + strlen(extra), " %d", strtout); ++ } else { ++ break; ++ } ++ pch = pnext; ++ } ++ wrqu->length = strlen(extra); ++ break; ++ default: ++ wrqu->length = 0; ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Input Format: %d,%x,%x ++ * %d is RF path, should be smaller than RF_PATH_MAX ++ * 1st %x is address(offset) ++ * 2st %x is data to write ++ */ ++ static int rtw_mp_write_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 path, addr, data; ++ int ret; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ ret = sscanf(extra, "%d,%x,%x", &path, &addr, &data); ++ if (ret < 3) ++ return -EINVAL; ++ ++ if (path >= RF_PATH_MAX) ++ return -EINVAL; ++ if (addr > 0xFF) ++ return -EINVAL; ++ if (data > 0xFFFFF) ++ return -EINVAL; ++ ++ memset(extra, 0, wrqu->length); ++ ++ write_rfreg(padapter, path, addr, data); ++ ++ sprintf(extra, "write_rf completed\n"); ++ wrqu->length = strlen(extra); ++ ++ return 0; ++} ++ ++/* ++ * Input Format: %d,%x ++ * %d is RF path, should be smaller than RF_PATH_MAX ++ * %x is address(offset) ++ * ++ * Return: ++ * %d for data readed ++ */ ++static int rtw_mp_read_rf(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ char *pch, *pnext, *ptmp; ++ char data[20], tmp[20]; ++ u32 path, addr; ++ u32 ret, i = 0, j = 0, strtou = 0; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ ret = sscanf(input, "%d,%x", &path, &addr); ++ kfree(input); ++ if (ret < 2) ++ return -EINVAL; ++ ++ if (path >= RF_PATH_MAX) ++ return -EINVAL; ++ if (addr > 0xFF) ++ return -EINVAL; ++ ++ memset(extra, 0, wrqu->length); ++ ++ sprintf(data, "%08x", read_rfreg(padapter, path, addr)); ++ /* add read data format blank */ ++ for (i = 0; i <= strlen(data); i++) { ++ if (i % 2 == 0) { ++ tmp[j] = ' '; ++ j++; ++ } ++ tmp[j] = data[i]; ++ j++; ++ } ++ pch = tmp; ++ DBG_88E("pch =%s", pch); ++ ++ while (*pch != '\0') { ++ pnext = strpbrk(pch, " "); ++ pnext++; ++ if (*pnext != '\0') { ++ strtou = simple_strtoul(pnext, &ptmp, 16); ++ sprintf(extra + strlen(extra), " %d", strtou); ++ } else { ++ break; ++ } ++ pch = pnext; ++ } ++ wrqu->length = strlen(extra); ++ return 0; ++} ++ ++static int rtw_mp_start(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (padapter->registrypriv.mp_mode == 0) { ++ padapter->registrypriv.mp_mode = 1; ++ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ LeaveAllPowerSaveMode(padapter); ++ ++ MPT_InitializeAdapter(padapter, 1); ++ } ++ if (padapter->registrypriv.mp_mode == 0) ++ return -EPERM; ++ if (padapter->mppriv.mode == MP_OFF) { ++ if (mp_start_test(padapter) == _FAIL) ++ return -EPERM; ++ padapter->mppriv.mode = MP_ON; ++ } ++ return 0; ++} ++ ++static int rtw_mp_stop(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (padapter->registrypriv.mp_mode == 1) { ++ MPT_DeInitAdapter(padapter); ++ padapter->registrypriv.mp_mode = 0; ++ } ++ ++ if (padapter->mppriv.mode != MP_OFF) { ++ mp_stop_test(padapter); ++ padapter->mppriv.mode = MP_OFF; ++ } ++ ++ return 0; ++} ++ ++extern int wifirate2_ratetbl_inx(unsigned char rate); ++ ++static int rtw_mp_rate(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 rate = MPT_RATE_1M; ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ rate = rtw_atoi(input); ++ sprintf(extra, "Set data rate to %d", rate); ++ kfree(input); ++ if (rate <= 0x7f) ++ rate = wifirate2_ratetbl_inx((u8)rate); ++ else ++ rate = (rate - 0x80 + MPT_RATE_MCS0); ++ ++ if (rate >= MPT_RATE_LAST) ++ return -EINVAL; ++ ++ padapter->mppriv.rateidx = rate; ++ Hal_SetDataRate(padapter); ++ ++ wrqu->length = strlen(extra) + 1; ++ return 0; ++} ++ ++static int rtw_mp_channel(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ u32 channel = 1; ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ channel = rtw_atoi(input); ++ sprintf(extra, "Change channel %d to channel %d", padapter->mppriv.channel, channel); ++ ++ padapter->mppriv.channel = channel; ++ Hal_SetChannel(padapter); ++ ++ wrqu->length = strlen(extra) + 1; ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_bandwidth(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 bandwidth = 0, sg = 0; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ sscanf(extra, "40M =%d, shortGI =%d", &bandwidth, &sg); ++ ++ if (bandwidth != HT_CHANNEL_WIDTH_40) ++ bandwidth = HT_CHANNEL_WIDTH_20; ++ ++ padapter->mppriv.bandwidth = (u8)bandwidth; ++ padapter->mppriv.preamble = sg; ++ ++ SetBandwidth(padapter); ++ ++ return 0; ++} ++ ++static int rtw_mp_txpower(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 idx_a = 0, idx_b = 0; ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ sscanf(input, "patha =%d, pathb =%d", &idx_a, &idx_b); ++ ++ sprintf(extra, "Set power level path_A:%d path_B:%d", idx_a, idx_b); ++ padapter->mppriv.txpoweridx = (u8)idx_a; ++ padapter->mppriv.txpoweridx_b = (u8)idx_b; ++ padapter->mppriv.bSetTxPower = 1; ++ Hal_SetAntennaPathPower(padapter); ++ ++ wrqu->length = strlen(extra) + 1; ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_ant_tx(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 i; ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ u16 antenna = 0; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ ++ sprintf(extra, "switch Tx antenna to %s", input); ++ ++ for (i = 0; i < strlen(input); i++) { ++ switch (input[i]) { ++ case 'a': ++ antenna |= ANTENNA_A; ++ break; ++ case 'b': ++ antenna |= ANTENNA_B; ++ break; ++ } ++ } ++ padapter->mppriv.antenna_tx = antenna; ++ ++ Hal_SetAntenna(padapter); ++ ++ wrqu->length = strlen(extra) + 1; ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_ant_rx(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 i; ++ u16 antenna = 0; ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ memset(extra, 0, wrqu->length); ++ ++ sprintf(extra, "switch Rx antenna to %s", input); ++ ++ for (i = 0; i < strlen(input); i++) { ++ switch (input[i]) { ++ case 'a': ++ antenna |= ANTENNA_A; ++ break; ++ case 'b': ++ antenna |= ANTENNA_B; ++ break; ++ } ++ } ++ ++ padapter->mppriv.antenna_rx = antenna; ++ Hal_SetAntenna(padapter); ++ wrqu->length = strlen(extra); ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_ctx(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 pkTx = 1, countPkTx = 1, cotuTx = 1, CarrSprTx = 1, scTx = 1, sgleTx = 1, stop = 1; ++ u32 bStartTest = 1; ++ u32 count = 0; ++ struct mp_priv *pmp_priv; ++ struct pkt_attrib *pattrib; ++ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ pmp_priv = &padapter->mppriv; ++ ++ if (copy_from_user(extra, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ DBG_88E("%s: in =%s\n", __func__, extra); ++ ++ countPkTx = strncmp(extra, "count =", 5); /* strncmp true is 0 */ ++ cotuTx = strncmp(extra, "background", 20); ++ CarrSprTx = strncmp(extra, "background, cs", 20); ++ scTx = strncmp(extra, "background, sc", 20); ++ sgleTx = strncmp(extra, "background, stone", 20); ++ pkTx = strncmp(extra, "background, pkt", 20); ++ stop = strncmp(extra, "stop", 4); ++ sscanf(extra, "count =%d, pkt", &count); ++ ++ memset(extra, '\0', sizeof(*extra)); ++ ++ if (stop == 0) { ++ bStartTest = 0; /* To set Stop */ ++ pmp_priv->tx.stop = 1; ++ sprintf(extra, "Stop continuous Tx"); ++ } else { ++ bStartTest = 1; ++ if (pmp_priv->mode != MP_ON) { ++ if (pmp_priv->tx.stop != 1) { ++ DBG_88E("%s: MP_MODE != ON %d\n", __func__, pmp_priv->mode); ++ return -EFAULT; ++ } ++ } ++ } ++ ++ if (pkTx == 0 || countPkTx == 0) ++ pmp_priv->mode = MP_PACKET_TX; ++ if (sgleTx == 0) ++ pmp_priv->mode = MP_SINGLE_TONE_TX; ++ if (cotuTx == 0) ++ pmp_priv->mode = MP_CONTINUOUS_TX; ++ if (CarrSprTx == 0) ++ pmp_priv->mode = MP_CARRIER_SUPPRISSION_TX; ++ if (scTx == 0) ++ pmp_priv->mode = MP_SINGLE_CARRIER_TX; ++ ++ switch (pmp_priv->mode) { ++ case MP_PACKET_TX: ++ if (bStartTest == 0) { ++ pmp_priv->tx.stop = 1; ++ pmp_priv->mode = MP_ON; ++ sprintf(extra, "Stop continuous Tx"); ++ } else if (pmp_priv->tx.stop == 1) { ++ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500 count =%u,\n", count); ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = count; ++ pmp_priv->tx.payload = 2; ++ pattrib = &pmp_priv->tx.attrib; ++ pattrib->pktlen = 1500; ++ memset(pattrib->dst, 0xFF, ETH_ALEN); ++ SetPacketTx(padapter); ++ } else { ++ return -EFAULT; ++ } ++ wrqu->length = strlen(extra); ++ return 0; ++ case MP_SINGLE_TONE_TX: ++ if (bStartTest != 0) ++ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes."); ++ Hal_SetSingleToneTx(padapter, (u8)bStartTest); ++ break; ++ case MP_CONTINUOUS_TX: ++ if (bStartTest != 0) ++ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes."); ++ Hal_SetContinuousTx(padapter, (u8)bStartTest); ++ break; ++ case MP_CARRIER_SUPPRISSION_TX: ++ if (bStartTest != 0) { ++ if (pmp_priv->rateidx <= MPT_RATE_11M) { ++ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes."); ++ Hal_SetCarrierSuppressionTx(padapter, (u8)bStartTest); ++ } else { ++ sprintf(extra, "Specify carrier suppression but not CCK rate"); ++ } ++ } ++ break; ++ case MP_SINGLE_CARRIER_TX: ++ if (bStartTest != 0) ++ sprintf(extra, "Start continuous DA = ffffffffffff len = 1500\n infinite = yes."); ++ Hal_SetSingleCarrierTx(padapter, (u8)bStartTest); ++ break; ++ default: ++ sprintf(extra, "Error! Continuous-Tx is not on-going."); ++ return -EFAULT; ++ } ++ ++ if (bStartTest == 1 && pmp_priv->mode != MP_ON) { ++ struct mp_priv *pmp_priv = &padapter->mppriv; ++ if (pmp_priv->tx.stop == 0) { ++ pmp_priv->tx.stop = 1; ++ msleep(5); ++ } ++ pmp_priv->tx.stop = 0; ++ pmp_priv->tx.count = 1; ++ SetPacketTx(padapter); ++ } else { ++ pmp_priv->mode = MP_ON; ++ } ++ ++ wrqu->length = strlen(extra); ++ return 0; ++} ++ ++static int rtw_mp_arx(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 bStartRx = 0, bStopRx = 0, bQueryPhy; ++ u32 cckok = 0, cckcrc = 0, ofdmok = 0, ofdmcrc = 0, htok = 0, htcrc = 0, OFDM_FA = 0, CCK_FA = 0; ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (!input) ++ return -ENOMEM; ++ ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ DBG_88E("%s: %s\n", __func__, input); ++ ++ bStartRx = (strncmp(input, "start", 5) == 0) ? 1 : 0; /* strncmp true is 0 */ ++ bStopRx = (strncmp(input, "stop", 5) == 0) ? 1 : 0; /* strncmp true is 0 */ ++ bQueryPhy = (strncmp(input, "phy", 3) == 0) ? 1 : 0; /* strncmp true is 0 */ ++ ++ if (bStartRx) { ++ sprintf(extra, "start"); ++ SetPacketRx(padapter, bStartRx); ++ } else if (bStopRx) { ++ SetPacketRx(padapter, 0); ++ sprintf(extra, "Received packet OK:%d CRC error:%d", padapter->mppriv.rx_pktcount, padapter->mppriv.rx_crcerrpktcount); ++ } else if (bQueryPhy) { ++ /* ++ OFDM FA ++ RegCF0[15:0] ++ RegCF2[31:16] ++ RegDA0[31:16] ++ RegDA4[15:0] ++ RegDA4[31:16] ++ RegDA8[15:0] ++ CCK FA ++ (RegA5B<<8) | RegA5C ++ */ ++ cckok = read_bbreg(padapter, 0xf88, 0xffffffff); ++ cckcrc = read_bbreg(padapter, 0xf84, 0xffffffff); ++ ofdmok = read_bbreg(padapter, 0xf94, 0x0000FFFF); ++ ofdmcrc = read_bbreg(padapter, 0xf94, 0xFFFF0000); ++ htok = read_bbreg(padapter, 0xf90, 0x0000FFFF); ++ htcrc = read_bbreg(padapter, 0xf90, 0xFFFF0000); ++ ++ OFDM_FA = read_bbreg(padapter, 0xcf0, 0x0000FFFF); ++ OFDM_FA = read_bbreg(padapter, 0xcf2, 0xFFFF0000); ++ OFDM_FA = read_bbreg(padapter, 0xda0, 0xFFFF0000); ++ OFDM_FA = read_bbreg(padapter, 0xda4, 0x0000FFFF); ++ OFDM_FA = read_bbreg(padapter, 0xda4, 0xFFFF0000); ++ OFDM_FA = read_bbreg(padapter, 0xda8, 0x0000FFFF); ++ CCK_FA = (rtw_read8(padapter, 0xa5b) << 8) | (rtw_read8(padapter, 0xa5c)); ++ ++ sprintf(extra, "Phy Received packet OK:%d CRC error:%d FA Counter: %d", cckok + ofdmok + htok, cckcrc + ofdmcrc + htcrc, OFDM_FA + CCK_FA); ++ } ++ wrqu->length = strlen(extra) + 1; ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_trx_query(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 txok, txfail, rxok, rxfail; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ txok = padapter->mppriv.tx.sended; ++ txfail = 0; ++ rxok = padapter->mppriv.rx_pktcount; ++ rxfail = padapter->mppriv.rx_crcerrpktcount; ++ ++ memset(extra, '\0', 128); ++ ++ sprintf(extra, "Tx OK:%d, Tx Fail:%d, Rx OK:%d, CRC error:%d ", txok, txfail, rxok, rxfail); ++ ++ wrqu->length = strlen(extra) + 1; ++ ++ return 0; ++} ++ ++static int rtw_mp_pwrtrk(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 enable; ++ u32 thermal; ++ s32 ret; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ memset(extra, 0, wrqu->length); ++ ++ enable = 1; ++ if (wrqu->length > 1) {/* not empty string */ ++ if (strncmp(input, "stop", 4) == 0) { ++ enable = 0; ++ sprintf(extra, "mp tx power tracking stop"); ++ } else if (sscanf(input, "ther =%d", &thermal)) { ++ ret = Hal_SetThermalMeter(padapter, (u8)thermal); ++ if (ret == _FAIL) ++ return -EPERM; ++ sprintf(extra, "mp tx power tracking start, target value =%d ok ", thermal); ++ } else { ++ kfree(input); ++ return -EINVAL; ++ } ++ } ++ ++ kfree(input); ++ ret = Hal_SetPowerTracking(padapter, enable); ++ if (ret == _FAIL) ++ return -EPERM; ++ ++ wrqu->length = strlen(extra); ++ return 0; ++} ++ ++static int rtw_mp_psd(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ ++ strcpy(extra, input); ++ ++ wrqu->length = mp_query_psd(padapter, extra); ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_thermal(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u8 val; ++ u16 bwrite = 1; ++ u16 addr = EEPROM_THERMAL_METER_88E; ++ ++ u16 cnt = 1; ++ u16 max_available_size = 0; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (copy_from_user(extra, wrqu->pointer, wrqu->length)) ++ return -EFAULT; ++ ++ bwrite = strncmp(extra, "write", 6); /* strncmp true is 0 */ ++ ++ Hal_GetThermalMeter(padapter, &val); ++ ++ if (bwrite == 0) { ++ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); ++ if (2 > max_available_size) { ++ DBG_88E("no available efuse!\n"); ++ return -EFAULT; ++ } ++ if (rtw_efuse_map_write(padapter, addr, cnt, &val) == _FAIL) { ++ DBG_88E("rtw_efuse_map_write error\n"); ++ return -EFAULT; ++ } else { ++ sprintf(extra, " efuse write ok :%d", val); ++ } ++ } else { ++ sprintf(extra, "%d", val); ++ } ++ wrqu->length = strlen(extra); ++ ++ return 0; ++} ++ ++static int rtw_mp_reset_stats(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ struct mp_priv *pmp_priv; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ pmp_priv = &padapter->mppriv; ++ ++ pmp_priv->tx.sended = 0; ++ pmp_priv->tx_pktcount = 0; ++ pmp_priv->rx_pktcount = 0; ++ pmp_priv->rx_crcerrpktcount = 0; ++ ++ /* reset phy counter */ ++ write_bbreg(padapter, 0xf14, BIT(16), 0x1); ++ msleep(10); ++ write_bbreg(padapter, 0xf14, BIT(16), 0x0); ++ ++ return 0; ++} ++ ++static int rtw_mp_dump(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ u32 value; ++ u8 rf_type, path_nums = 0; ++ u32 i, j = 1, path; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (strncmp(extra, "all", 4) == 0) { ++ DBG_88E("\n ======= MAC REG =======\n"); ++ for (i = 0x0; i < 0x300; i += 4) { ++ if (j % 4 == 1) ++ DBG_88E("0x%02x", i); ++ DBG_88E(" 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ DBG_88E("\n"); ++ } ++ for (i = 0x400; i < 0x1000; i += 4) { ++ if (j % 4 == 1) ++ DBG_88E("0x%02x", i); ++ DBG_88E(" 0x%08x ", rtw_read32(padapter, i)); ++ if ((j++) % 4 == 0) ++ DBG_88E("\n"); ++ } ++ ++ j = 1; ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ ++ DBG_88E("\n ======= RF REG =======\n"); ++ if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) ++ path_nums = 1; ++ else ++ path_nums = 2; ++ ++ for (path = 0; path < path_nums; path++) { ++ for (i = 0; i < 0x34; i++) { ++ value = rtw_hal_read_rfreg(padapter, path, i, 0xffffffff); ++ if (j % 4 == 1) ++ DBG_88E("0x%02x ", i); ++ DBG_88E(" 0x%08x ", value); ++ if ((j++) % 4 == 0) ++ DBG_88E("\n"); ++ } ++ } ++ } ++ return 0; ++} ++ ++static int rtw_mp_phypara(struct net_device *dev, ++ struct iw_request_info *info, ++ struct iw_point *wrqu, char *extra) ++{ ++ char *input = kmalloc(wrqu->length, GFP_KERNEL); ++ u32 valxcap; ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->pointer, wrqu->length)) { ++ kfree(input); ++ return -EFAULT; ++ } ++ ++ DBG_88E("%s:iwpriv in =%s\n", __func__, input); ++ ++ sscanf(input, "xcap =%d", &valxcap); ++ ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_SetRFPath(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ char *input = kmalloc(wrqu->data.length, GFP_KERNEL); ++ u8 bMain = 1, bTurnoff = 1; ++ ++ if (!input) ++ return -ENOMEM; ++ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length)) ++ return -EFAULT; ++ DBG_88E("%s:iwpriv in =%s\n", __func__, input); ++ ++ bMain = strncmp(input, "1", 2); /* strncmp true is 0 */ ++ bTurnoff = strncmp(input, "0", 3); /* strncmp true is 0 */ ++ ++ if (bMain == 0) { ++ MP_PHY_SetRFPathSwitch(padapter, true); ++ DBG_88E("%s:PHY_SetRFPathSwitch = true\n", __func__); ++ } else if (bTurnoff == 0) { ++ MP_PHY_SetRFPathSwitch(padapter, false); ++ DBG_88E("%s:PHY_SetRFPathSwitch = false\n", __func__); ++ } ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_QueryDrv(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ char *input = kmalloc(wrqu->data.length, GFP_KERNEL); ++ u8 qAutoLoad = 1; ++ struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); ++ ++ if (!input) ++ return -ENOMEM; ++ ++ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length)) ++ return -EFAULT; ++ DBG_88E("%s:iwpriv in =%s\n", __func__, input); ++ ++ qAutoLoad = strncmp(input, "autoload", 8); /* strncmp true is 0 */ ++ ++ if (qAutoLoad == 0) { ++ DBG_88E("%s:qAutoLoad\n", __func__); ++ ++ if (pEEPROM->bautoload_fail_flag) ++ sprintf(extra, "fail"); ++ else ++ sprintf(extra, "ok"); ++ } ++ wrqu->data.length = strlen(extra) + 1; ++ kfree(input); ++ return 0; ++} ++ ++static int rtw_mp_set(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ struct iw_point *wrqu = (struct iw_point *)wdata; ++ u32 subcmd = wrqu->flags; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (!padapter) ++ return -ENETDOWN; ++ ++ if (!extra) { ++ wrqu->length = 0; ++ return -EIO; ++ } ++ ++ switch (subcmd) { ++ case MP_START: ++ DBG_88E("set case mp_start\n"); ++ rtw_mp_start(dev, info, wrqu, extra); ++ break; ++ case MP_STOP: ++ DBG_88E("set case mp_stop\n"); ++ rtw_mp_stop(dev, info, wrqu, extra); ++ break; ++ case MP_BANDWIDTH: ++ DBG_88E("set case mp_bandwidth\n"); ++ rtw_mp_bandwidth(dev, info, wrqu, extra); ++ break; ++ case MP_RESET_STATS: ++ DBG_88E("set case MP_RESET_STATS\n"); ++ rtw_mp_reset_stats(dev, info, wrqu, extra); ++ break; ++ case MP_SetRFPathSwh: ++ DBG_88E("set MP_SetRFPathSwitch\n"); ++ rtw_mp_SetRFPath(dev, info, wdata, extra); ++ break; ++ case CTA_TEST: ++ DBG_88E("set CTA_TEST\n"); ++ rtw_cta_test_start(dev, info, wdata, extra); ++ break; ++ } ++ ++ return 0; ++} ++ ++static int rtw_mp_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wdata, char *extra) ++{ ++ struct iw_point *wrqu = (struct iw_point *)wdata; ++ u32 subcmd = wrqu->flags; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ ++ if (!padapter) ++ return -ENETDOWN; ++ if (!extra) { ++ wrqu->length = 0; ++ return -EIO; ++ } ++ ++ switch (subcmd) { ++ case WRITE_REG: ++ rtw_mp_write_reg(dev, info, wrqu, extra); ++ break; ++ case WRITE_RF: ++ rtw_mp_write_rf(dev, info, wrqu, extra); ++ break; ++ case MP_PHYPARA: ++ DBG_88E("mp_get MP_PHYPARA\n"); ++ rtw_mp_phypara(dev, info, wrqu, extra); ++ break; ++ case MP_CHANNEL: ++ DBG_88E("set case mp_channel\n"); ++ rtw_mp_channel(dev, info, wrqu, extra); ++ break; ++ case READ_REG: ++ DBG_88E("mp_get READ_REG\n"); ++ rtw_mp_read_reg(dev, info, wrqu, extra); ++ break; ++ case READ_RF: ++ DBG_88E("mp_get READ_RF\n"); ++ rtw_mp_read_rf(dev, info, wrqu, extra); ++ break; ++ case MP_RATE: ++ DBG_88E("set case mp_rate\n"); ++ rtw_mp_rate(dev, info, wrqu, extra); ++ break; ++ case MP_TXPOWER: ++ DBG_88E("set case MP_TXPOWER\n"); ++ rtw_mp_txpower(dev, info, wrqu, extra); ++ break; ++ case MP_ANT_TX: ++ DBG_88E("set case MP_ANT_TX\n"); ++ rtw_mp_ant_tx(dev, info, wrqu, extra); ++ break; ++ case MP_ANT_RX: ++ DBG_88E("set case MP_ANT_RX\n"); ++ rtw_mp_ant_rx(dev, info, wrqu, extra); ++ break; ++ case MP_QUERY: ++ rtw_mp_trx_query(dev, info, wrqu, extra); ++ break; ++ case MP_CTX: ++ DBG_88E("set case MP_CTX\n"); ++ rtw_mp_ctx(dev, info, wrqu, extra); ++ break; ++ case MP_ARX: ++ DBG_88E("set case MP_ARX\n"); ++ rtw_mp_arx(dev, info, wrqu, extra); ++ break; ++ case EFUSE_GET: ++ DBG_88E("efuse get EFUSE_GET\n"); ++ rtw_mp_efuse_get(dev, info, wdata, extra); ++ break; ++ case MP_DUMP: ++ DBG_88E("set case MP_DUMP\n"); ++ rtw_mp_dump(dev, info, wrqu, extra); ++ break; ++ case MP_PSD: ++ DBG_88E("set case MP_PSD\n"); ++ rtw_mp_psd(dev, info, wrqu, extra); ++ break; ++ case MP_THER: ++ DBG_88E("set case MP_THER\n"); ++ rtw_mp_thermal(dev, info, wrqu, extra); ++ break; ++ case MP_QueryDrvStats: ++ DBG_88E("mp_get MP_QueryDrvStats\n"); ++ rtw_mp_QueryDrv(dev, info, wdata, extra); ++ break; ++ case MP_PWRTRK: ++ DBG_88E("set case MP_PWRTRK\n"); ++ rtw_mp_pwrtrk(dev, info, wrqu, extra); ++ break; ++ case EFUSE_SET: ++ DBG_88E("set case efuse set\n"); ++ rtw_mp_efuse_set(dev, info, wdata, extra); ++ break; ++ } ++ ++ msleep(10); /* delay 5ms for sending pkt before exit adb shell operation */ ++ return 0; ++} ++ ++static int rtw_tdls(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ return 0; ++} ++ ++static int rtw_tdls_get(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ return 0; ++} ++ ++static int rtw_test( ++ struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ u32 len; ++ u8 *pbuf, *pch; ++ char *ptmp; ++ u8 *delim = ","; ++ ++ DBG_88E("+%s\n", __func__); ++ len = wrqu->data.length; ++ ++ pbuf = kzalloc(len, GFP_KERNEL); ++ if (!pbuf) { ++ DBG_88E("%s: no memory!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(pbuf, wrqu->data.pointer, len)) { ++ kfree(pbuf); ++ DBG_88E("%s: copy from user fail!\n", __func__); ++ return -EFAULT; ++ } ++ DBG_88E("%s: string =\"%s\"\n", __func__, pbuf); ++ ++ ptmp = (char *)pbuf; ++ pch = strsep(&ptmp, delim); ++ if (!pch || strlen(pch) == 0) { ++ kfree(pbuf); ++ DBG_88E("%s: parameter error(level 1)!\n", __func__); ++ return -EFAULT; ++ } ++ kfree(pbuf); ++ return 0; ++} ++ ++static iw_handler rtw_handlers[] = { ++ IW_HANDLER(SIOCGIWNAME, rtw_wx_get_name), ++ IW_HANDLER(SIOCSIWNWID, dummy), ++ IW_HANDLER(SIOCGIWNWID, dummy), ++ IW_HANDLER(SIOCGIWFREQ, rtw_wx_get_freq), ++ IW_HANDLER(SIOCSIWMODE, rtw_wx_set_mode), ++ IW_HANDLER(SIOCGIWMODE, rtw_wx_get_mode), ++ IW_HANDLER(SIOCSIWSENS, dummy), ++ IW_HANDLER(SIOCGIWSENS, rtw_wx_get_sens), ++ IW_HANDLER(SIOCGIWRANGE, rtw_wx_get_range), ++ IW_HANDLER(SIOCSIWPRIV, rtw_wx_set_priv), ++ IW_HANDLER(SIOCSIWSPY, dummy), ++ IW_HANDLER(SIOCGIWSPY, dummy), ++ IW_HANDLER(SIOCSIWAP, rtw_wx_set_wap), ++ IW_HANDLER(SIOCGIWAP, rtw_wx_get_wap), ++ IW_HANDLER(SIOCSIWMLME, rtw_wx_set_mlme), ++ IW_HANDLER(SIOCGIWAPLIST, dummy), ++ IW_HANDLER(SIOCSIWSCAN, rtw_wx_set_scan), ++ IW_HANDLER(SIOCGIWSCAN, rtw_wx_get_scan), ++ IW_HANDLER(SIOCSIWESSID, rtw_wx_set_essid), ++ IW_HANDLER(SIOCGIWESSID, rtw_wx_get_essid), ++ IW_HANDLER(SIOCSIWNICKN, dummy), ++ IW_HANDLER(SIOCGIWNICKN, rtw_wx_get_nick), ++ IW_HANDLER(SIOCSIWRATE, rtw_wx_set_rate), ++ IW_HANDLER(SIOCGIWRATE, rtw_wx_get_rate), ++ IW_HANDLER(SIOCSIWRTS, rtw_wx_set_rts), ++ IW_HANDLER(SIOCGIWRTS, rtw_wx_get_rts), ++ IW_HANDLER(SIOCSIWFRAG, rtw_wx_set_frag), ++ IW_HANDLER(SIOCGIWFRAG, rtw_wx_get_frag), ++ IW_HANDLER(SIOCSIWTXPOW, dummy), ++ IW_HANDLER(SIOCGIWTXPOW, dummy), ++ IW_HANDLER(SIOCSIWRETRY, dummy), ++ IW_HANDLER(SIOCGIWRETRY, rtw_wx_get_retry), ++ IW_HANDLER(SIOCSIWENCODE, rtw_wx_set_enc), ++ IW_HANDLER(SIOCGIWENCODE, rtw_wx_get_enc), ++ IW_HANDLER(SIOCSIWPOWER, dummy), ++ IW_HANDLER(SIOCGIWPOWER, rtw_wx_get_power), ++ IW_HANDLER(SIOCSIWGENIE, rtw_wx_set_gen_ie), ++ IW_HANDLER(SIOCSIWAUTH, rtw_wx_set_auth), ++ IW_HANDLER(SIOCSIWENCODEEXT, rtw_wx_set_enc_ext), ++ IW_HANDLER(SIOCSIWPMKSA, rtw_wx_set_pmkid), ++}; ++ ++static const struct iw_priv_args rtw_private_args[] = { ++ { ++ SIOCIWFIRSTPRIV + 0x0, ++ IW_PRIV_TYPE_CHAR | 0x7FF, 0, "write" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x1, ++ IW_PRIV_TYPE_CHAR | 0x7FF, ++ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "read" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x4, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x5, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setpid" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x6, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x7, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "get_sensitivity" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x8, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_prob_req_ie" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x9, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_assoc_req_ie" ++ }, ++ ++ { ++ SIOCIWFIRSTPRIV + 0xA, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "channel_plan" ++ }, ++ ++ { ++ SIOCIWFIRSTPRIV + 0xB, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "dbg" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xC, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "rfw" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0xD, ++ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "rfr" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x10, ++ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, 0, "p2p_set" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x11, ++ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | P2P_PRIVATE_IOCTL_SET_LEN, "p2p_get" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x12, ++ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IFNAMSIZ, "p2p_get2" ++ }, ++ {SIOCIWFIRSTPRIV + 0x13, IW_PRIV_TYPE_CHAR | 128, 0, "NULL"}, ++ { ++ SIOCIWFIRSTPRIV + 0x14, ++ IW_PRIV_TYPE_CHAR | 64, 0, "tdls" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x15, ++ IW_PRIV_TYPE_CHAR | P2P_PRIVATE_IOCTL_SET_LEN, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | P2P_PRIVATE_IOCTL_SET_LEN, "tdls_get" ++ }, ++ { ++ SIOCIWFIRSTPRIV + 0x16, ++ IW_PRIV_TYPE_CHAR | 64, 0, "pm_set" ++ }, ++ ++ {SIOCIWFIRSTPRIV + 0x18, IW_PRIV_TYPE_CHAR | IFNAMSIZ, 0, "rereg_nd_name"}, ++ ++ {SIOCIWFIRSTPRIV + 0x1A, IW_PRIV_TYPE_CHAR | 1024, 0, "efuse_set"}, ++ {SIOCIWFIRSTPRIV + 0x1B, IW_PRIV_TYPE_CHAR | 128, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"}, ++ {SIOCIWFIRSTPRIV + 0x1D, IW_PRIV_TYPE_CHAR | 40, IW_PRIV_TYPE_CHAR | 0x7FF, "test" ++ }, ++ ++ {SIOCIWFIRSTPRIV + 0x0E, IW_PRIV_TYPE_CHAR | 1024, 0, ""}, /* set */ ++ {SIOCIWFIRSTPRIV + 0x0F, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, ""},/* get */ ++/* --- sub-ioctls definitions --- */ ++ ++ {MP_START, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_start"}, /* set */ ++ {MP_PHYPARA, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_phypara"},/* get */ ++ {MP_STOP, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_stop"}, /* set */ ++ {MP_CHANNEL, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_channel"},/* get */ ++ {MP_BANDWIDTH, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_bandwidth"}, /* set */ ++ {MP_RATE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate"},/* get */ ++ {MP_RESET_STATS, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_reset_stats"}, ++ {MP_QUERY, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_query"}, /* get */ ++ {READ_REG, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_reg"}, ++ {MP_RATE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate"}, ++ {READ_RF, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_rf"}, ++ {MP_PSD, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_psd"}, ++ {MP_DUMP, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_dump"}, ++ {MP_TXPOWER, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_txpower"}, ++ {MP_ANT_TX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_tx"}, ++ {MP_ANT_RX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_rx"}, ++ {WRITE_REG, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_reg"}, ++ {WRITE_RF, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_rf"}, ++ {MP_CTX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ctx"}, ++ {MP_ARX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_arx"}, ++ {MP_THER, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ther"}, ++ {EFUSE_SET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_set"}, ++ {EFUSE_GET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"}, ++ {MP_PWRTRK, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_pwrtrk"}, ++ {MP_QueryDrvStats, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_drvquery"}, ++ {MP_IOCTL, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_ioctl"}, /* mp_ioctl */ ++ {MP_SetRFPathSwh, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_setrfpath"}, ++ {CTA_TEST, IW_PRIV_TYPE_CHAR | 1024, 0, "cta_test"}, ++}; ++ ++static iw_handler rtw_private_handler[] = { ++rtw_wx_write32, /* 0x00 */ ++rtw_wx_read32, /* 0x01 */ ++rtw_drvext_hdl, /* 0x02 */ ++rtw_mp_ioctl_hdl, /* 0x03 */ ++ ++/* for MM DTV platform */ ++ rtw_get_ap_info, /* 0x04 */ ++ ++ rtw_set_pid, /* 0x05 */ ++ rtw_wps_start, /* 0x06 */ ++ ++ rtw_wx_get_sensitivity, /* 0x07 */ ++ rtw_wx_set_mtk_wps_probe_ie, /* 0x08 */ ++ rtw_wx_set_mtk_wps_ie, /* 0x09 */ ++ ++/* Set Channel depend on the country code */ ++ rtw_wx_set_channel_plan, /* 0x0A */ ++ ++ rtw_dbg_port, /* 0x0B */ ++ rtw_wx_write_rf, /* 0x0C */ ++ rtw_wx_read_rf, /* 0x0D */ ++ ++ rtw_mp_set, /* 0x0E */ ++ rtw_mp_get, /* 0x0F */ ++ rtw_p2p_set, /* 0x10 */ ++ rtw_p2p_get, /* 0x11 */ ++ rtw_p2p_get2, /* 0x12 */ ++ ++ NULL, /* 0x13 */ ++ rtw_tdls, /* 0x14 */ ++ rtw_tdls_get, /* 0x15 */ ++ ++ rtw_pm_set, /* 0x16 */ ++ rtw_wx_priv_null, /* 0x17 */ ++ rtw_rereg_nd_name, /* 0x18 */ ++ rtw_wx_priv_null, /* 0x19 */ ++ ++ rtw_mp_efuse_set, /* 0x1A */ ++ rtw_mp_efuse_get, /* 0x1B */ ++ NULL, /* 0x1C is reserved for hostapd */ ++ rtw_test, /* 0x1D */ ++}; ++ ++static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); ++ struct iw_statistics *piwstats = &padapter->iwstats; ++ int tmp_noise = 0; ++ int tmp; ++ ++ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { ++ piwstats->qual.qual = 0; ++ piwstats->qual.level = 0; ++ piwstats->qual.noise = 0; ++ } else { ++ tmp_noise = padapter->recvpriv.noise; ++ ++ piwstats->qual.level = padapter->signal_strength; ++ tmp = 219 + 3 * padapter->signal_strength; ++ tmp = min(100, tmp); ++ tmp = max(0, tmp); ++ piwstats->qual.qual = tmp; ++ piwstats->qual.noise = tmp_noise; ++ } ++ piwstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; ++ return &padapter->iwstats; ++} ++ ++struct iw_handler_def rtw_handlers_def = { ++ .standard = rtw_handlers, ++ .num_standard = sizeof(rtw_handlers) / sizeof(iw_handler), ++ .private = rtw_private_handler, ++ .private_args = (struct iw_priv_args *)rtw_private_args, ++ .num_private = sizeof(rtw_private_handler) / sizeof(iw_handler), ++ .num_private_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args), ++ .get_wireless_stats = rtw_get_wireless_stats, ++}; +diff --git a/drivers/staging/r8188eu/os_dep/mlme_linux.c b/drivers/staging/r8188eu/os_dep/mlme_linux.c +new file mode 100644 +index 000000000000..e3ee9dc7ab90 +--- /dev/null ++++ b/drivers/staging/r8188eu/os_dep/mlme_linux.c +@@ -0,0 +1,216 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. i*/ ++ ++#define _MLME_OSDEP_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/mlme_osdep.h" ++ ++void rtw_join_timeout_handler (struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, mlmepriv.assoc_timer); ++ ++ _rtw_join_timeout_handler(adapter); ++} ++ ++void _rtw_scan_timeout_handler (struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, mlmepriv.scan_to_timer); ++ ++ rtw_scan_timeout_handler(adapter); ++} ++ ++static void _dynamic_check_timer_handlder(struct timer_list *t) ++{ ++ struct adapter *adapter = from_timer(adapter, t, mlmepriv.dynamic_chk_timer); ++ ++ if (adapter->registrypriv.mp_mode == 1) ++ return; ++ rtw_dynamic_check_timer_handlder(adapter); ++ _set_timer(&adapter->mlmepriv.dynamic_chk_timer, 2000); ++} ++ ++void rtw_init_mlme_timer(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ timer_setup(&pmlmepriv->assoc_timer, rtw_join_timeout_handler, 0); ++ timer_setup(&pmlmepriv->scan_to_timer, _rtw_scan_timeout_handler, 0); ++ timer_setup(&pmlmepriv->dynamic_chk_timer, _dynamic_check_timer_handlder, 0); ++} ++ ++void rtw_os_indicate_connect(struct adapter *adapter) ++{ ++ ++ rtw_indicate_wx_assoc_event(adapter); ++ netif_carrier_on(adapter->pnetdev); ++ if (adapter->pid[2] != 0) ++ rtw_signal_process(adapter->pid[2], SIGALRM); ++ ++} ++ ++void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted) ++{ ++ indicate_wx_scan_complete_event(padapter); ++} ++ ++static struct rt_pmkid_list backup_pmkid[NUM_PMKID_CACHE]; ++ ++void rtw_reset_securitypriv(struct adapter *adapter) ++{ ++ u8 backup_index = 0; ++ u8 backup_counter = 0x00; ++ u32 backup_time = 0; ++ ++ if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { ++ /* 802.1x */ ++ /* We have to backup the PMK information for WiFi PMK Caching test item. */ ++ /* Backup the btkip_countermeasure information. */ ++ /* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */ ++ memset(&backup_pmkid[0], 0x00, sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); ++ memcpy(&backup_pmkid[0], &adapter->securitypriv.PMKIDList[0], sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); ++ backup_index = adapter->securitypriv.PMKIDIndex; ++ backup_counter = adapter->securitypriv.btkip_countermeasure; ++ backup_time = adapter->securitypriv.btkip_countermeasure_time; ++ memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv)); ++ ++ /* Restore the PMK information to securitypriv structure for the following connection. */ ++ memcpy(&adapter->securitypriv.PMKIDList[0], ++ &backup_pmkid[0], ++ sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE); ++ adapter->securitypriv.PMKIDIndex = backup_index; ++ adapter->securitypriv.btkip_countermeasure = backup_counter; ++ adapter->securitypriv.btkip_countermeasure_time = backup_time; ++ adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; ++ adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; ++ } else { ++ /* reset values in securitypriv */ ++ struct security_priv *psec_priv = &adapter->securitypriv; ++ ++ psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psec_priv->dot11PrivacyKeyIndex = 0; ++ psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psec_priv->dot118021XGrpKeyid = 1; ++ psec_priv->ndisauthtype = Ndis802_11AuthModeOpen; ++ psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled; ++ } ++} ++ ++void rtw_os_indicate_disconnect(struct adapter *adapter) ++{ ++ ++ netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */ ++ rtw_indicate_wx_disassoc_event(adapter); ++ rtw_reset_securitypriv(adapter); ++} ++ ++void rtw_report_sec_ie(struct adapter *adapter, u8 authmode, u8 *sec_ie) ++{ ++ uint len; ++ u8 *buff, *p, i; ++ union iwreq_data wrqu; ++ ++ buff = NULL; ++ if (authmode == _WPA_IE_ID_) { ++ buff = kzalloc(IW_CUSTOM_MAX, GFP_KERNEL); ++ if (!buff) ++ return; ++ p = buff; ++ p += sprintf(p, "ASSOCINFO(ReqIEs ="); ++ len = sec_ie[1] + 2; ++ len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX; ++ for (i = 0; i < len; i++) ++ p += sprintf(p, "%02x", sec_ie[i]); ++ p += sprintf(p, ")"); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = p - buff; ++ wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? ++ wrqu.data.length : IW_CUSTOM_MAX; ++ wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff); ++ kfree(buff); ++ } ++} ++ ++static void _survey_timer_hdl(struct timer_list *t) ++{ ++ struct adapter *padapter = from_timer(padapter, t, mlmeextpriv.survey_timer); ++ ++ survey_timer_hdl(padapter); ++} ++ ++static void _link_timer_hdl(struct timer_list *t) ++{ ++ struct adapter *padapter = from_timer(padapter, t, mlmeextpriv.link_timer); ++ link_timer_hdl(padapter); ++} ++ ++static void _addba_timer_hdl(struct timer_list *t) ++{ ++ struct sta_info *psta = from_timer(psta, t, addba_retry_timer); ++ addba_timer_hdl(psta); ++} ++ ++void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta) ++{ ++ timer_setup(&psta->addba_retry_timer, _addba_timer_hdl, 0); ++} ++ ++void init_mlme_ext_timer(struct adapter *padapter) ++{ ++ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; ++ ++ timer_setup(&pmlmeext->survey_timer, _survey_timer_hdl, 0); ++ timer_setup(&pmlmeext->link_timer, _link_timer_hdl, 0); ++} ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++void rtw_indicate_sta_assoc_event(struct adapter *padapter, struct sta_info *psta) ++{ ++ union iwreq_data wrqu; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if (!psta) ++ return; ++ ++ if (psta->aid > NUM_STA) ++ return; ++ ++ if (pstapriv->sta_aid[psta->aid - 1] != psta) ++ return; ++ ++ wrqu.addr.sa_family = ARPHRD_ETHER; ++ ++ memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); ++ ++ DBG_88E("+rtw_indicate_sta_assoc_event\n"); ++ ++ wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL); ++} ++ ++void rtw_indicate_sta_disassoc_event(struct adapter *padapter, struct sta_info *psta) ++{ ++ union iwreq_data wrqu; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ ++ if (!psta) ++ return; ++ ++ if (psta->aid > NUM_STA) ++ return; ++ ++ if (pstapriv->sta_aid[psta->aid - 1] != psta) ++ return; ++ ++ wrqu.addr.sa_family = ARPHRD_ETHER; ++ ++ memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN); ++ ++ DBG_88E("+rtw_indicate_sta_disassoc_event\n"); ++ ++ wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL); ++} ++ ++#endif +diff --git a/drivers/staging/r8188eu/os_dep/os_intfs.c b/drivers/staging/r8188eu/os_dep/os_intfs.c +new file mode 100644 +index 000000000000..8d0158f4a45d +--- /dev/null ++++ b/drivers/staging/r8188eu/os_dep/os_intfs.c +@@ -0,0 +1,1199 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _OS_INTFS_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/xmit_osdep.h" ++#include "../include/recv_osdep.h" ++#include "../include/hal_intf.h" ++#include "../include/rtw_ioctl.h" ++ ++#include "../include/usb_osintf.h" ++#include "../include/rtw_br_ext.h" ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); ++MODULE_AUTHOR("Realtek Semiconductor Corp."); ++MODULE_VERSION(DRIVERVERSION); ++ ++#define CONFIG_BR_EXT_BRNAME "br0" ++#define RTW_NOTCH_FILTER 0 /* 0:Disable, 1:Enable, */ ++ ++/* module param defaults */ ++static int rtw_chip_version = 0x00; ++static int rtw_rfintfs = HWPI; ++static int rtw_lbkmode;/* RTL8712_AIR_TRX; */ ++static int rtw_network_mode = Ndis802_11IBSS;/* Ndis802_11Infrastructure; infra, ad-hoc, auto */ ++static int rtw_channel = 1;/* ad-hoc support requirement */ ++static int rtw_wireless_mode = WIRELESS_11BG_24N; ++static int rtw_vrtl_carrier_sense = AUTO_VCS; ++static int rtw_vcs_type = RTS_CTS;/* */ ++static int rtw_rts_thresh = 2347;/* */ ++static int rtw_frag_thresh = 2346;/* */ ++static int rtw_preamble = PREAMBLE_LONG;/* long, short, auto */ ++static int rtw_scan_mode = 1;/* active, passive */ ++static int rtw_adhoc_tx_pwr = 1; ++static int rtw_soft_ap; ++static int rtw_power_mgnt = 1; ++static int rtw_ips_mode = IPS_NORMAL; ++ ++static int rtw_smart_ps = 2; ++ ++module_param(rtw_ips_mode, int, 0644); ++MODULE_PARM_DESC(rtw_ips_mode, "The default IPS mode"); ++ ++static int rtw_debug = 1; ++static int rtw_radio_enable = 1; ++static int rtw_long_retry_lmt = 7; ++static int rtw_short_retry_lmt = 7; ++static int rtw_busy_thresh = 40; ++static int rtw_ack_policy = NORMAL_ACK; ++ ++static int rtw_mp_mode; ++ ++static int rtw_software_encrypt; ++static int rtw_software_decrypt; ++ ++static int rtw_acm_method;/* 0:By SW 1:By HW. */ ++ ++static int rtw_wmm_enable = 1;/* default is set to enable the wmm. */ ++static int rtw_uapsd_enable; ++static int rtw_uapsd_max_sp = NO_LIMIT; ++static int rtw_uapsd_acbk_en; ++static int rtw_uapsd_acbe_en; ++static int rtw_uapsd_acvi_en; ++static int rtw_uapsd_acvo_en; ++ ++static int rtw_led_enable = 1; ++ ++int rtw_ht_enable = 1; ++int rtw_cbw40_enable = 3; /* 0 :disable, bit(0): enable 2.4g, bit(1): enable 5g */ ++int rtw_ampdu_enable = 1;/* for enable tx_ampdu */ ++static int rtw_rx_stbc = 1;/* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */ ++static int rtw_ampdu_amsdu;/* 0: disabled, 1:enabled, 2:auto */ ++ ++static int rtw_lowrate_two_xmit = 1;/* Use 2 path Tx to transmit MCS0~7 and legacy mode */ ++ ++static int rtw_rf_config = RF_819X_MAX_TYPE; /* auto */ ++static int rtw_low_power; ++static int rtw_wifi_spec; ++static int rtw_channel_plan = RT_CHANNEL_DOMAIN_MAX; ++static int rtw_AcceptAddbaReq = true;/* 0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */ ++ ++static int rtw_antdiv_cfg = 2; /* 0:OFF , 1:ON, 2:decide by Efuse config */ ++static int rtw_antdiv_type; /* 0:decide by efuse 1: for 88EE, 1Tx and 1RxCG are diversity.(2 Ant with SPDT), 2: for 88EE, 1Tx and 2Rx are diversity.(2 Ant, Tx and RxCG are both on aux port, RxCS is on main port), 3: for 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */ ++ ++static int rtw_enusbss;/* 0:disable, 1:enable */ ++ ++static int rtw_hwpdn_mode = 2;/* 0:disable, 1:enable, 2: by EFUSE config */ ++ ++static int rtw_hwpwrp_detect; /* HW power ping detect 0:disable , 1:enable */ ++ ++static int rtw_hw_wps_pbc = 1; ++ ++int rtw_mc2u_disable; ++ ++static int rtw_80211d; ++ ++static char *ifname = "wlan%d"; ++module_param(ifname, charp, 0644); ++MODULE_PARM_DESC(ifname, "The default name to allocate for first interface"); ++ ++static char *if2name = "wlan%d"; ++module_param(if2name, charp, 0644); ++MODULE_PARM_DESC(if2name, "The default name to allocate for second interface"); ++ ++char *rtw_initmac; /* temp mac address if users want to use instead of the mac address in Efuse */ ++ ++module_param(rtw_initmac, charp, 0644); ++module_param(rtw_channel_plan, int, 0644); ++module_param(rtw_chip_version, int, 0644); ++module_param(rtw_rfintfs, int, 0644); ++module_param(rtw_lbkmode, int, 0644); ++module_param(rtw_network_mode, int, 0644); ++module_param(rtw_channel, int, 0644); ++module_param(rtw_mp_mode, int, 0644); ++module_param(rtw_wmm_enable, int, 0644); ++module_param(rtw_vrtl_carrier_sense, int, 0644); ++module_param(rtw_vcs_type, int, 0644); ++module_param(rtw_busy_thresh, int, 0644); ++module_param(rtw_led_enable, int, 0644); ++module_param(rtw_ht_enable, int, 0644); ++module_param(rtw_cbw40_enable, int, 0644); ++module_param(rtw_ampdu_enable, int, 0644); ++module_param(rtw_rx_stbc, int, 0644); ++module_param(rtw_ampdu_amsdu, int, 0644); ++module_param(rtw_lowrate_two_xmit, int, 0644); ++module_param(rtw_rf_config, int, 0644); ++module_param(rtw_power_mgnt, int, 0644); ++module_param(rtw_smart_ps, int, 0644); ++module_param(rtw_low_power, int, 0644); ++module_param(rtw_wifi_spec, int, 0644); ++module_param(rtw_antdiv_cfg, int, 0644); ++module_param(rtw_antdiv_type, int, 0644); ++module_param(rtw_enusbss, int, 0644); ++module_param(rtw_hwpdn_mode, int, 0644); ++module_param(rtw_hwpwrp_detect, int, 0644); ++module_param(rtw_hw_wps_pbc, int, 0644); ++ ++static uint rtw_max_roaming_times = 2; ++module_param(rtw_max_roaming_times, uint, 0644); ++MODULE_PARM_DESC(rtw_max_roaming_times, "The max roaming times to try"); ++ ++static int rtw_fw_iol = 1;/* 0:Disable, 1:enable, 2:by usb speed */ ++module_param(rtw_fw_iol, int, 0644); ++MODULE_PARM_DESC(rtw_fw_iol, "FW IOL"); ++ ++module_param(rtw_mc2u_disable, int, 0644); ++ ++module_param(rtw_80211d, int, 0644); ++MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism"); ++ ++static uint rtw_notch_filter = RTW_NOTCH_FILTER; ++module_param(rtw_notch_filter, uint, 0644); ++MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P"); ++module_param_named(debug, rtw_debug, int, 0444); ++MODULE_PARM_DESC(debug, "Set debug level (1-9) (default 1)"); ++ ++/* dummy routines */ ++void rtw_proc_remove_one(struct net_device *dev) ++{ ++} ++ ++void rtw_proc_init_one(struct net_device *dev) ++{ ++} ++ ++#if 0 /* TODO: Convert these to /sys */ ++void rtw_proc_init_one(struct net_device *dev) ++{ ++ struct proc_dir_entry *dir_dev = NULL; ++ struct proc_dir_entry *entry = NULL; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ u8 rf_type; ++ ++ if (!rtw_proc) { ++ memcpy(rtw_proc_name, DRV_NAME, sizeof(DRV_NAME)); ++ ++ rtw_proc = create_proc_entry(rtw_proc_name, S_IFDIR, init_net.proc_net); ++ if (!rtw_proc) { ++ DBG_88E(KERN_ERR "Unable to create rtw_proc directory\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("ver_info", S_IFREG | S_IRUGO, rtw_proc, proc_get_drv_version, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ } ++ ++ if (!padapter->dir_dev) { ++ padapter->dir_dev = create_proc_entry(dev->name, ++ S_IFDIR | S_IRUGO | S_IXUGO, ++ rtw_proc); ++ dir_dev = padapter->dir_dev; ++ if (!dir_dev) { ++ if (rtw_proc_cnt == 0) { ++ if (rtw_proc) { ++ remove_proc_entry(rtw_proc_name, init_net.proc_net); ++ rtw_proc = NULL; ++ } ++ } ++ ++ pr_info("Unable to create dir_dev directory\n"); ++ return; ++ } ++ } else { ++ return; ++ } ++ ++ rtw_proc_cnt++; ++ ++ entry = create_proc_read_entry("write_reg", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_write_reg, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_write_reg; ++ ++ entry = create_proc_read_entry("read_reg", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_read_reg, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_read_reg; ++ ++ entry = create_proc_read_entry("fwstate", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_fwstate, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("sec_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_sec_info, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("mlmext_state", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_mlmext_state, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("qos_option", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_qos_option, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("ht_option", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_ht_option, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rf_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_info, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("ap_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_ap_info, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("adapter_state", S_IFREG | S_IRUGO, ++ dir_dev, proc_getstruct adapter_state, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("trx_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_trx_info, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("mac_reg_dump1", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_mac_reg_dump1, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("mac_reg_dump2", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_mac_reg_dump2, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("mac_reg_dump3", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_mac_reg_dump3, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("bb_reg_dump1", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_bb_reg_dump1, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("bb_reg_dump2", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_bb_reg_dump2, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("bb_reg_dump3", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_bb_reg_dump3, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rf_reg_dump1", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_reg_dump1, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rf_reg_dump2", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_reg_dump2, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) { ++ entry = create_proc_read_entry("rf_reg_dump3", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_reg_dump3, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rf_reg_dump4", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rf_reg_dump4, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ } ++ ++#ifdef CONFIG_88EU_AP_MODE ++ ++ entry = create_proc_read_entry("all_sta_info", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_all_sta_info, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++#endif ++ ++ entry = create_proc_read_entry("best_channel", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_best_channel, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ ++ entry = create_proc_read_entry("rx_signal", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rx_signal, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_rx_signal; ++ entry = create_proc_read_entry("ht_enable", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_ht_enable, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_ht_enable; ++ ++ entry = create_proc_read_entry("cbw40_enable", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_cbw40_enable, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_cbw40_enable; ++ ++ entry = create_proc_read_entry("ampdu_enable", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_ampdu_enable, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_ampdu_enable; ++ ++ entry = create_proc_read_entry("rx_stbc", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rx_stbc, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_rx_stbc; ++ ++ entry = create_proc_read_entry("path_rssi", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_two_path_rssi, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry = create_proc_read_entry("rssi_disp", S_IFREG | S_IRUGO, ++ dir_dev, proc_get_rssi_disp, dev); ++ if (!entry) { ++ pr_info("Unable to create_proc_read_entry!\n"); ++ return; ++ } ++ entry->write_proc = proc_set_rssi_disp; ++} ++ ++void rtw_proc_remove_one(struct net_device *dev) ++{ ++ struct proc_dir_entry *dir_dev = NULL; ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ u8 rf_type; ++ ++ dir_dev = padapter->dir_dev; ++ padapter->dir_dev = NULL; ++ ++ if (dir_dev) { ++ remove_proc_entry("write_reg", dir_dev); ++ remove_proc_entry("read_reg", dir_dev); ++ remove_proc_entry("fwstate", dir_dev); ++ remove_proc_entry("sec_info", dir_dev); ++ remove_proc_entry("mlmext_state", dir_dev); ++ remove_proc_entry("qos_option", dir_dev); ++ remove_proc_entry("ht_option", dir_dev); ++ remove_proc_entry("rf_info", dir_dev); ++ remove_proc_entry("ap_info", dir_dev); ++ remove_proc_entry("adapter_state", dir_dev); ++ remove_proc_entry("trx_info", dir_dev); ++ remove_proc_entry("mac_reg_dump1", dir_dev); ++ remove_proc_entry("mac_reg_dump2", dir_dev); ++ remove_proc_entry("mac_reg_dump3", dir_dev); ++ remove_proc_entry("bb_reg_dump1", dir_dev); ++ remove_proc_entry("bb_reg_dump2", dir_dev); ++ remove_proc_entry("bb_reg_dump3", dir_dev); ++ remove_proc_entry("rf_reg_dump1", dir_dev); ++ remove_proc_entry("rf_reg_dump2", dir_dev); ++ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); ++ if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) { ++ remove_proc_entry("rf_reg_dump3", dir_dev); ++ remove_proc_entry("rf_reg_dump4", dir_dev); ++ } ++#ifdef CONFIG_88EU_AP_MODE ++ remove_proc_entry("all_sta_info", dir_dev); ++#endif ++ ++ remove_proc_entry("best_channel", dir_dev); ++ remove_proc_entry("rx_signal", dir_dev); ++ remove_proc_entry("cbw40_enable", dir_dev); ++ remove_proc_entry("ht_enable", dir_dev); ++ remove_proc_entry("ampdu_enable", dir_dev); ++ remove_proc_entry("rx_stbc", dir_dev); ++ remove_proc_entry("path_rssi", dir_dev); ++ remove_proc_entry("rssi_disp", dir_dev); ++ remove_proc_entry(dev->name, rtw_proc); ++ dir_dev = NULL; ++ } else { ++ return; ++ } ++ rtw_proc_cnt--; ++ ++ if (rtw_proc_cnt == 0) { ++ if (rtw_proc) { ++ remove_proc_entry("ver_info", rtw_proc); ++ ++ remove_proc_entry(rtw_proc_name, init_net.proc_net); ++ rtw_proc = NULL; ++ } ++ } ++} ++#endif ++ ++static uint loadparam(struct adapter *padapter, struct net_device *pnetdev) ++{ ++ struct registry_priv *registry_par = &padapter->registrypriv; ++ ++ GlobalDebugLevel = rtw_debug; ++ registry_par->chip_version = (u8)rtw_chip_version; ++ registry_par->rfintfs = (u8)rtw_rfintfs; ++ registry_par->lbkmode = (u8)rtw_lbkmode; ++ registry_par->network_mode = (u8)rtw_network_mode; ++ ++ memcpy(registry_par->ssid.Ssid, "ANY", 3); ++ registry_par->ssid.SsidLength = 3; ++ ++ registry_par->channel = (u8)rtw_channel; ++ registry_par->wireless_mode = (u8)rtw_wireless_mode; ++ registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense; ++ registry_par->vcs_type = (u8)rtw_vcs_type; ++ registry_par->rts_thresh = (u16)rtw_rts_thresh; ++ registry_par->frag_thresh = (u16)rtw_frag_thresh; ++ registry_par->preamble = (u8)rtw_preamble; ++ registry_par->scan_mode = (u8)rtw_scan_mode; ++ registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr; ++ registry_par->soft_ap = (u8)rtw_soft_ap; ++ registry_par->smart_ps = (u8)rtw_smart_ps; ++ registry_par->power_mgnt = (u8)rtw_power_mgnt; ++ registry_par->ips_mode = (u8)rtw_ips_mode; ++ registry_par->radio_enable = (u8)rtw_radio_enable; ++ registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt; ++ registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt; ++ registry_par->busy_thresh = (u16)rtw_busy_thresh; ++ registry_par->ack_policy = (u8)rtw_ack_policy; ++ registry_par->mp_mode = (u8)rtw_mp_mode; ++ registry_par->software_encrypt = (u8)rtw_software_encrypt; ++ registry_par->software_decrypt = (u8)rtw_software_decrypt; ++ registry_par->acm_method = (u8)rtw_acm_method; ++ ++ /* UAPSD */ ++ registry_par->wmm_enable = (u8)rtw_wmm_enable; ++ registry_par->uapsd_enable = (u8)rtw_uapsd_enable; ++ registry_par->uapsd_max_sp = (u8)rtw_uapsd_max_sp; ++ registry_par->uapsd_acbk_en = (u8)rtw_uapsd_acbk_en; ++ registry_par->uapsd_acbe_en = (u8)rtw_uapsd_acbe_en; ++ registry_par->uapsd_acvi_en = (u8)rtw_uapsd_acvi_en; ++ registry_par->uapsd_acvo_en = (u8)rtw_uapsd_acvo_en; ++ ++ registry_par->led_enable = (u8)rtw_led_enable; ++ ++ registry_par->ht_enable = (u8)rtw_ht_enable; ++ registry_par->cbw40_enable = (u8)rtw_cbw40_enable; ++ registry_par->ampdu_enable = (u8)rtw_ampdu_enable; ++ registry_par->rx_stbc = (u8)rtw_rx_stbc; ++ registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu; ++ registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit; ++ registry_par->rf_config = (u8)rtw_rf_config; ++ registry_par->low_power = (u8)rtw_low_power; ++ registry_par->wifi_spec = (u8)rtw_wifi_spec; ++ registry_par->channel_plan = (u8)rtw_channel_plan; ++ registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq; ++ registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg; ++ registry_par->antdiv_type = (u8)rtw_antdiv_type; ++ registry_par->hwpdn_mode = (u8)rtw_hwpdn_mode;/* 0:disable, 1:enable, 2:by EFUSE config */ ++ registry_par->hwpwrp_detect = (u8)rtw_hwpwrp_detect;/* 0:disable, 1:enable */ ++ registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc; ++ ++ registry_par->max_roaming_times = (u8)rtw_max_roaming_times; ++ ++ registry_par->fw_iol = rtw_fw_iol; ++ ++ registry_par->enable80211d = (u8)rtw_80211d; ++ snprintf(registry_par->ifname, 16, "%s", ifname); ++ snprintf(registry_par->if2name, 16, "%s", if2name); ++ registry_par->notch_filter = (u8)rtw_notch_filter; ++ ++ return _SUCCESS; ++} ++ ++static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct sockaddr *addr = p; ++ ++ if (!padapter->bup) ++ memcpy(padapter->eeprompriv.mac_addr, addr->sa_data, ETH_ALEN); ++ ++ return 0; ++} ++ ++static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ padapter->stats.tx_packets = pxmitpriv->tx_pkts;/* pxmitpriv->tx_pkts++; */ ++ padapter->stats.rx_packets = precvpriv->rx_pkts;/* precvpriv->rx_pkts++; */ ++ padapter->stats.tx_dropped = pxmitpriv->tx_drop; ++ padapter->stats.rx_dropped = precvpriv->rx_drop; ++ padapter->stats.tx_bytes = pxmitpriv->tx_bytes; ++ padapter->stats.rx_bytes = precvpriv->rx_bytes; ++ return &padapter->stats; ++} ++ ++/* ++ * AC to queue mapping ++ * ++ * AC_VO -> queue 0 ++ * AC_VI -> queue 1 ++ * AC_BE -> queue 2 ++ * AC_BK -> queue 3 ++ */ ++static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; ++ ++/* Given a data frame determine the 802.1p/1d tag to use. */ ++static unsigned int rtw_classify8021d(struct sk_buff *skb) ++{ ++ unsigned int dscp; ++ ++ /* skb->priority values from 256->263 are magic values to ++ * directly indicate a specific 802.1d priority. This is used ++ * to allow 802.1d priority to be passed directly in from VLAN ++ * tags, etc. ++ */ ++ if (skb->priority >= 256 && skb->priority <= 263) ++ return skb->priority - 256; ++ ++ switch (skb->protocol) { ++ case htons(ETH_P_IP): ++ dscp = ip_hdr(skb)->tos & 0xfc; ++ break; ++ default: ++ return 0; ++ } ++ ++ return dscp >> 5; ++} ++ ++static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev) ++{ ++ struct adapter *padapter = rtw_netdev_priv(dev); ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ skb->priority = rtw_classify8021d(skb); ++ ++ if (pmlmepriv->acm_mask != 0) ++ skb->priority = qos_acm(pmlmepriv->acm_mask, skb->priority); ++ ++ return rtw_1d_to_queue[skb->priority]; ++} ++ ++u16 rtw_recv_select_queue(struct sk_buff *skb) ++{ ++ struct iphdr *piphdr; ++ unsigned int dscp; ++ __be16 eth_type; ++ u32 priority; ++ u8 *pdata = skb->data; ++ ++ memcpy(ð_type, pdata + (ETH_ALEN << 1), 2); ++ ++ switch (eth_type) { ++ case htons(ETH_P_IP): ++ piphdr = (struct iphdr *)(pdata + ETH_HLEN); ++ dscp = piphdr->tos & 0xfc; ++ priority = dscp >> 5; ++ break; ++ default: ++ priority = 0; ++ } ++ ++ return rtw_1d_to_queue[priority]; ++} ++ ++static const struct net_device_ops rtw_netdev_ops = { ++ .ndo_open = netdev_open, ++ .ndo_stop = netdev_close, ++ .ndo_start_xmit = rtw_xmit_entry, ++ .ndo_select_queue = rtw_select_queue, ++ .ndo_set_mac_address = rtw_net_set_mac_address, ++ .ndo_get_stats = rtw_net_get_stats, ++}; ++ ++int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname) ++{ ++ int err; ++ ++ err = dev_alloc_name(pnetdev, ifname); ++ if (err < 0) ++ return err; ++ ++ netif_carrier_off(pnetdev); ++ return 0; ++} ++ ++static const struct device_type wlan_type = { ++ .name = "wlan", ++}; ++ ++struct net_device *rtw_init_netdev(struct adapter *old_padapter) ++{ ++ struct adapter *padapter; ++ struct net_device *pnetdev; ++ ++ if (old_padapter) ++ pnetdev = rtw_alloc_etherdev_with_old_priv(sizeof(struct adapter), (void *)old_padapter); ++ else ++ pnetdev = rtw_alloc_etherdev(sizeof(struct adapter)); ++ ++ if (!pnetdev) ++ return NULL; ++ ++ pnetdev->dev.type = &wlan_type; ++ padapter = rtw_netdev_priv(pnetdev); ++ padapter->pnetdev = pnetdev; ++ DBG_88E("register rtw_netdev_ops to netdev_ops\n"); ++ pnetdev->netdev_ops = &rtw_netdev_ops; ++ pnetdev->watchdog_timeo = HZ * 3; /* 3 second timeout */ ++ pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def; ++ ++ /* step 2. */ ++ loadparam(padapter, pnetdev); ++ ++ return pnetdev; ++} ++ ++u32 rtw_start_drv_threads(struct adapter *padapter) ++{ ++ u32 _status = _SUCCESS; ++ ++ padapter->cmdThread = kthread_run(rtw_cmd_thread, padapter, "RTW_CMD_THREAD"); ++ if (IS_ERR(padapter->cmdThread)) ++ _status = _FAIL; ++ else ++ _rtw_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); /* wait for cmd_thread to run */ ++ ++ rtw_hal_start_thread(padapter); ++ return _status; ++} ++ ++void rtw_stop_drv_threads(struct adapter *padapter) ++{ ++ /* Below is to termindate rtw_cmd_thread & event_thread... */ ++ up(&padapter->cmdpriv.cmd_queue_sema); ++ if (padapter->cmdThread) ++ _rtw_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); ++ ++ rtw_hal_stop_thread(padapter); ++} ++ ++static u8 rtw_init_default_value(struct adapter *padapter) ++{ ++ struct registry_priv *pregistrypriv = &padapter->registrypriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ ++ /* xmit_priv */ ++ pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; ++ pxmitpriv->vcs = pregistrypriv->vcs_type; ++ pxmitpriv->vcs_type = pregistrypriv->vcs_type; ++ pxmitpriv->frag_len = pregistrypriv->frag_thresh; ++ ++ /* mlme_priv */ ++ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ ++ pmlmepriv->scan_mode = SCAN_ACTIVE; ++ ++ /* ht_priv */ ++ pmlmepriv->htpriv.ampdu_enable = false;/* set to disabled */ ++ ++ /* security_priv */ ++ psecuritypriv->binstallGrpkey = _FAIL; ++ psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt; ++ psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt; ++ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ ++ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; ++ psecuritypriv->dot11PrivacyKeyIndex = 0; ++ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; ++ psecuritypriv->dot118021XGrpKeyid = 1; ++ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen; ++ psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled; ++ ++ /* registry_priv */ ++ rtw_init_registrypriv_dev_network(padapter); ++ rtw_update_registrypriv_dev_network(padapter); ++ ++ /* hal_priv */ ++ rtw_hal_def_value_init(padapter); ++ ++ /* misc. */ ++ padapter->bReadPortCancel = false; ++ padapter->bWritePortCancel = false; ++ padapter->bRxRSSIDisplay = 0; ++ padapter->bNotifyChannelChange = 0; ++#ifdef CONFIG_88EU_P2P ++ padapter->bShowGetP2PState = 1; ++#endif ++ return _SUCCESS; ++} ++ ++u8 rtw_reset_drv_sw(struct adapter *padapter) ++{ ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; ++ ++ /* hal_priv */ ++ rtw_hal_def_value_init(padapter); ++ padapter->bReadPortCancel = false; ++ padapter->bWritePortCancel = false; ++ padapter->bRxRSSIDisplay = 0; ++ pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */ ++ ++ padapter->xmitpriv.tx_pkts = 0; ++ padapter->recvpriv.rx_pkts = 0; ++ ++ pmlmepriv->LinkDetectInfo.bBusyTraffic = false; ++ ++ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING); ++ ++ rtw_hal_sreset_reset_value(padapter); ++ pwrctrlpriv->pwr_state_check_cnts = 0; ++ ++ /* mlmeextpriv */ ++ padapter->mlmeextpriv.sitesurvey_res.state = SCAN_DISABLE; ++ ++ rtw_set_signal_stat_timer(&padapter->recvpriv); ++ ++ return _SUCCESS; ++} ++ ++u8 rtw_init_drv_sw(struct adapter *padapter) ++{ ++ u8 ret8 = _SUCCESS; ++ ++ if ((rtw_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) { ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ padapter->cmdpriv.padapter = padapter; ++ ++ if ((rtw_init_evt_priv(&padapter->evtpriv)) == _FAIL) { ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ if (rtw_init_mlme_priv(padapter) == _FAIL) { ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++#ifdef CONFIG_88EU_P2P ++ rtw_init_wifidirect_timers(padapter); ++ init_wifidirect_info(padapter, P2P_ROLE_DISABLE); ++ reset_global_wifidirect_info(padapter); ++#endif /* CONFIG_88EU_P2P */ ++ ++ if (init_mlme_ext_priv(padapter) == _FAIL) { ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ if (_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) { ++ DBG_88E("Can't _rtw_init_xmit_priv\n"); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ if (_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) { ++ DBG_88E("Can't _rtw_init_recv_priv\n"); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ if (_rtw_init_sta_priv(&padapter->stapriv) == _FAIL) { ++ DBG_88E("Can't _rtw_init_sta_priv\n"); ++ ret8 = _FAIL; ++ goto exit; ++ } ++ ++ padapter->stapriv.padapter = padapter; ++ ++ rtw_init_bcmc_stainfo(padapter); ++ ++ rtw_init_pwrctrl_priv(padapter); ++ ++ if (init_mp_priv(padapter) == _FAIL) ++ DBG_88E("%s: initialize MP private data Fail!\n", __func__); ++ ++ ret8 = rtw_init_default_value(padapter); ++ ++ rtw_hal_dm_init(padapter); ++ rtw_hal_sw_led_init(padapter); ++ ++ rtw_hal_sreset_init(padapter); ++ ++ spin_lock_init(&padapter->br_ext_lock); ++ ++exit: ++ return ret8; ++} ++ ++void rtw_cancel_all_timer(struct adapter *padapter) ++{ ++ _cancel_timer_ex(&padapter->mlmepriv.assoc_timer); ++ ++ _cancel_timer_ex(&padapter->mlmepriv.scan_to_timer); ++ ++ _cancel_timer_ex(&padapter->mlmepriv.dynamic_chk_timer); ++ ++ /* cancel sw led timer */ ++ rtw_hal_sw_led_deinit(padapter); ++ ++ _cancel_timer_ex(&padapter->pwrctrlpriv.pwr_state_check_timer); ++ ++ _cancel_timer_ex(&padapter->recvpriv.signal_stat_timer); ++ /* cancel dm timer */ ++ rtw_hal_dm_deinit(padapter); ++} ++ ++u8 rtw_free_drv_sw(struct adapter *padapter) ++{ ++ /* we can call rtw_p2p_enable here, but: */ ++ /* 1. rtw_p2p_enable may have IO operation */ ++ /* 2. rtw_p2p_enable is bundled with wext interface */ ++ #ifdef CONFIG_88EU_P2P ++ { ++ struct wifidirect_info *pwdinfo = &padapter->wdinfo; ++ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { ++ _cancel_timer_ex(&pwdinfo->find_phase_timer); ++ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); ++ _cancel_timer_ex(&pwdinfo->pre_tx_scan_timer); ++ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); ++ } ++ } ++ #endif ++ ++ free_mlme_ext_priv(&padapter->mlmeextpriv); ++ ++ rtw_free_cmd_priv(&padapter->cmdpriv); ++ ++ rtw_free_evt_priv(&padapter->evtpriv); ++ ++ rtw_free_mlme_priv(&padapter->mlmepriv); ++ _rtw_free_xmit_priv(&padapter->xmitpriv); ++ ++ _rtw_free_sta_priv(&padapter->stapriv); /* will free bcmc_stainfo here */ ++ ++ _rtw_free_recv_priv(&padapter->recvpriv); ++ ++ rtw_free_pwrctrl_priv(padapter); ++ ++ rtw_hal_free_data(padapter); ++ ++ /* free the old_pnetdev */ ++ if (padapter->rereg_nd_name_priv.old_pnetdev) { ++ free_netdev(padapter->rereg_nd_name_priv.old_pnetdev); ++ padapter->rereg_nd_name_priv.old_pnetdev = NULL; ++ } ++ ++ /* clear pbuddystruct adapter to avoid access wrong pointer. */ ++ if (padapter->pbuddy_adapter) ++ padapter->pbuddy_adapter->pbuddy_adapter = NULL; ++ ++ return _SUCCESS; ++} ++ ++void netdev_br_init(struct net_device *netdev) ++{ ++ struct adapter *adapter = (struct adapter *)rtw_netdev_priv(netdev); ++ ++ rcu_read_lock(); ++ ++ if (rcu_dereference(adapter->pnetdev->rx_handler_data)) { ++ struct net_device *br_netdev; ++ struct net *devnet = NULL; ++ ++ devnet = dev_net(netdev); ++ br_netdev = dev_get_by_name(devnet, CONFIG_BR_EXT_BRNAME); ++ if (br_netdev) { ++ memcpy(adapter->br_mac, br_netdev->dev_addr, ETH_ALEN); ++ dev_put(br_netdev); ++ } else { ++ pr_info("%s()-%d: dev_get_by_name(%s) failed!", ++ __func__, __LINE__, CONFIG_BR_EXT_BRNAME); ++ } ++ } ++ adapter->ethBrExtInfo.addPPPoETag = 1; ++ ++ rcu_read_unlock(); ++} ++ ++int _netdev_open(struct net_device *pnetdev) ++{ ++ uint status; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv; ++ ++ DBG_88E("+88eu_drv - drv_open, bup =%d\n", padapter->bup); ++ ++ if (pwrctrlpriv->ps_flag) { ++ padapter->net_closed = false; ++ goto netdev_open_normal_process; ++ } ++ ++ if (!padapter->bup) { ++ padapter->bDriverStopped = false; ++ padapter->bSurpriseRemoved = false; ++ padapter->bCardDisableWOHSM = false; ++ ++ status = rtw_hal_init(padapter); ++ if (status == _FAIL) ++ goto netdev_open_error; ++ ++ pr_info("MAC Address = %pM\n", pnetdev->dev_addr); ++ ++ status = rtw_start_drv_threads(padapter); ++ if (status == _FAIL) { ++ pr_info("Initialize driver software resource Failed!\n"); ++ goto netdev_open_error; ++ } ++ ++ if (init_hw_mlme_ext(padapter) == _FAIL) { ++ pr_info("can't init mlme_ext_priv\n"); ++ goto netdev_open_error; ++ } ++ if (padapter->intf_start) ++ padapter->intf_start(padapter); ++ rtw_proc_init_one(pnetdev); ++ ++ rtw_led_control(padapter, LED_CTL_NO_LINK); ++ ++ padapter->bup = true; ++ } ++ padapter->net_closed = false; ++ ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 2000); ++ ++ padapter->pwrctrlpriv.bips_processing = false; ++ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); ++ ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_start_queue(pnetdev); ++ else ++ rtw_netif_wake_queue(pnetdev); ++ ++ netdev_br_init(pnetdev); ++ ++netdev_open_normal_process: ++ DBG_88E("-88eu_drv - drv_open, bup =%d\n", padapter->bup); ++ return 0; ++ ++netdev_open_error: ++ padapter->bup = false; ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ DBG_88E("-88eu_drv - drv_open fail, bup =%d\n", padapter->bup); ++ return -1; ++} ++ ++int netdev_open(struct net_device *pnetdev) ++{ ++ int ret; ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ ++ _enter_critical_mutex(padapter->hw_init_mutex, NULL); ++ ret = _netdev_open(pnetdev); ++ _exit_critical_mutex(padapter->hw_init_mutex, NULL); ++ return ret; ++} ++ ++static int ips_netdrv_open(struct adapter *padapter) ++{ ++ int status = _SUCCESS; ++ padapter->net_closed = false; ++ DBG_88E("===> %s.........\n", __func__); ++ ++ padapter->bDriverStopped = false; ++ padapter->bSurpriseRemoved = false; ++ padapter->bCardDisableWOHSM = false; ++ ++ status = rtw_hal_init(padapter); ++ if (status == _FAIL) ++ goto netdev_open_error; ++ ++ if (padapter->intf_start) ++ padapter->intf_start(padapter); ++ ++ rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv); ++ _set_timer(&padapter->mlmepriv.dynamic_chk_timer, 5000); ++ ++ return _SUCCESS; ++ ++netdev_open_error: ++ DBG_88E("-ips_netdrv_open - drv_open failure, bup =%d\n", padapter->bup); ++ ++ return _FAIL; ++} ++ ++int rtw_ips_pwr_up(struct adapter *padapter) ++{ ++ int result; ++ u32 start_time = jiffies; ++ DBG_88E("===> rtw_ips_pwr_up..............\n"); ++ rtw_reset_drv_sw(padapter); ++ ++ result = ips_netdrv_open(padapter); ++ ++ rtw_led_control(padapter, LED_CTL_NO_LINK); ++ ++ DBG_88E("<=== rtw_ips_pwr_up.............. in %dms\n", rtw_get_passing_time_ms(start_time)); ++ return result; ++} ++ ++void rtw_ips_pwr_down(struct adapter *padapter) ++{ ++ u32 start_time = jiffies; ++ DBG_88E("===> rtw_ips_pwr_down...................\n"); ++ ++ padapter->bCardDisableWOHSM = true; ++ padapter->net_closed = true; ++ ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ ++ rtw_ips_dev_unload(padapter); ++ padapter->bCardDisableWOHSM = false; ++ DBG_88E("<=== rtw_ips_pwr_down..................... in %dms\n", rtw_get_passing_time_ms(start_time)); ++} ++ ++void rtw_ips_dev_unload(struct adapter *padapter) ++{ ++ DBG_88E("====> %s...\n", __func__); ++ ++ rtw_hal_set_hwreg(padapter, HW_VAR_FIFO_CLEARN_UP, NULL); ++ ++ if (padapter->intf_stop) ++ padapter->intf_stop(padapter); ++ ++ /* s5. */ ++ if (!padapter->bSurpriseRemoved) ++ rtw_hal_deinit(padapter); ++} ++ ++int pm_netdev_open(struct net_device *pnetdev, u8 bnormal) ++{ ++ int status; ++ ++ if (bnormal) ++ status = netdev_open(pnetdev); ++ else ++ status = (_SUCCESS == ips_netdrv_open((struct adapter *)rtw_netdev_priv(pnetdev))) ? (0) : (-1); ++ return status; ++} ++ ++int netdev_close(struct net_device *pnetdev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); ++ ++ if (padapter->pwrctrlpriv.bInternalAutoSuspend) { ++ if (padapter->pwrctrlpriv.rf_pwrstate == rf_off) ++ padapter->pwrctrlpriv.ps_flag = true; ++ } ++ padapter->net_closed = true; ++ ++ if (padapter->pwrctrlpriv.rf_pwrstate == rf_on) { ++ DBG_88E("(2)88eu_drv - drv_close, bup =%d, hw_init_completed =%d\n", ++ padapter->bup, padapter->hw_init_completed); ++ ++ /* s1. */ ++ if (pnetdev) { ++ if (!rtw_netif_queue_stopped(pnetdev)) ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ /* s2. */ ++ LeaveAllPowerSaveMode(padapter); ++ rtw_disassoc_cmd(padapter, 500, false); ++ /* s2-2. indicate disconnect to os */ ++ rtw_indicate_disconnect(padapter); ++ /* s2-3. */ ++ rtw_free_assoc_resources(padapter, 1); ++ /* s2-4. */ ++ rtw_free_network_queue(padapter, true); ++ /* Close LED */ ++ rtw_led_control(padapter, LED_CTL_POWER_OFF); ++ } ++ ++ nat25_db_cleanup(padapter); ++ ++#ifdef CONFIG_88EU_P2P ++ rtw_p2p_enable(padapter, P2P_ROLE_DISABLE); ++#endif /* CONFIG_88EU_P2P */ ++ ++ kfree(dvobj->firmware.szFwBuffer); ++ dvobj->firmware.szFwBuffer = NULL; ++ ++ DBG_88E("-88eu_drv - drv_close, bup =%d\n", padapter->bup); ++ return 0; ++} +diff --git a/drivers/staging/r8188eu/os_dep/osdep_service.c b/drivers/staging/r8188eu/os_dep/osdep_service.c +new file mode 100644 +index 000000000000..95ac6086370b +--- /dev/null ++++ b/drivers/staging/r8188eu/os_dep/osdep_service.c +@@ -0,0 +1,343 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _OSDEP_SERVICE_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/rtw_ioctl_set.h" ++ ++/* ++* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE ++* @return: one of RTW_STATUS_CODE ++*/ ++inline int RTW_STATUS_CODE(int error_code) ++{ ++ if (error_code >= 0) ++ return _SUCCESS; ++ return _FAIL; ++} ++ ++u32 rtw_atoi(u8 *s) ++{ ++ int num = 0, flag = 0; ++ int i; ++ for (i = 0; i <= strlen(s); i++) { ++ if (s[i] >= '0' && s[i] <= '9') ++ num = num * 10 + s[i] - '0'; ++ else if (s[0] == '-' && i == 0) ++ flag = 1; ++ else ++ break; ++ } ++ if (flag == 1) ++ num = num * -1; ++ return num; ++} ++ ++void *rtw_malloc2d(int h, int w, int size) ++{ ++ int j; ++ ++ void **a = kzalloc(h * sizeof(void *) + h * w * size, GFP_KERNEL); ++ if (!a) ++ return NULL; ++ ++ for (j = 0; j < h; j++) ++ a[j] = ((char *)(a + h)) + j * w * size; ++ ++ return a; ++} ++ ++/* ++For the following list_xxx operations, ++caller must guarantee the atomic context. ++Otherwise, there will be racing condition. ++*/ ++/* ++Caller must check if the list is empty before calling rtw_list_delete ++*/ ++ ++u32 _rtw_down_sema(struct semaphore *sema) ++{ ++ if (down_interruptible(sema)) ++ return _FAIL; ++ else ++ return _SUCCESS; ++} ++ ++void _rtw_mutex_init(struct mutex *pmutex) ++{ ++ mutex_init(pmutex); ++} ++ ++void _rtw_mutex_free(struct mutex *pmutex) ++{ ++ mutex_destroy(pmutex); ++} ++ ++void _rtw_init_queue(struct __queue *pqueue) ++{ ++ INIT_LIST_HEAD(&pqueue->queue); ++ spin_lock_init(&pqueue->lock); ++} ++ ++inline u32 rtw_systime_to_ms(u32 systime) ++{ ++ return systime * 1000 / HZ; ++} ++ ++inline u32 rtw_ms_to_systime(u32 ms) ++{ ++ return ms * HZ / 1000; ++} ++ ++/* the input parameter start use the same unit as jiffies */ ++inline s32 rtw_get_passing_time_ms(u32 start) ++{ ++ return rtw_systime_to_ms(jiffies - start); ++} ++ ++void rtw_usleep_os(int us) ++{ ++ if (1 < (us / 1000)) ++ msleep(1); ++ else ++ msleep((us / 1000) + 1); ++} ++ ++#define RTW_SUSPEND_LOCK_NAME "rtw_wifi" ++ ++static const struct device_type wlan_type = { ++ .name = "wlan", ++}; ++ ++struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, ++ void *old_priv) ++{ ++ struct net_device *pnetdev; ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); ++ if (!pnetdev) ++ goto RETURN; ++ ++ pnetdev->dev.type = &wlan_type; ++ pnpi = netdev_priv(pnetdev); ++ pnpi->priv = old_priv; ++ pnpi->sizeof_priv = sizeof_priv; ++ ++RETURN: ++ return pnetdev; ++} ++ ++struct net_device *rtw_alloc_etherdev(int sizeof_priv) ++{ ++ struct net_device *pnetdev; ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4); ++ if (!pnetdev) ++ goto RETURN; ++ ++ pnpi = netdev_priv(pnetdev); ++ ++ pnpi->priv = vzalloc(sizeof_priv); ++ if (!pnpi->priv) { ++ free_netdev(pnetdev); ++ pnetdev = NULL; ++ goto RETURN; ++ } ++ ++ pnpi->sizeof_priv = sizeof_priv; ++RETURN: ++ return pnetdev; ++} ++ ++void rtw_free_netdev(struct net_device *netdev) ++{ ++ struct rtw_netdev_priv_indicator *pnpi; ++ ++ if (!netdev) ++ goto RETURN; ++ ++ pnpi = netdev_priv(netdev); ++ ++ if (!pnpi->priv) ++ goto RETURN; ++ ++ vfree(pnpi->priv); ++ free_netdev(netdev); ++ ++RETURN: ++ return; ++} ++ ++int rtw_change_ifname(struct adapter *padapter, const char *ifname) ++{ ++ struct net_device *pnetdev; ++ struct net_device *cur_pnetdev; ++ struct rereg_nd_name_data *rereg_priv; ++ int ret; ++ ++ if (!padapter) ++ goto error; ++ ++ cur_pnetdev = padapter->pnetdev; ++ rereg_priv = &padapter->rereg_nd_name_priv; ++ ++ /* free the old_pnetdev */ ++ if (rereg_priv->old_pnetdev) { ++ free_netdev(rereg_priv->old_pnetdev); ++ rereg_priv->old_pnetdev = NULL; ++ } ++ ++ if (!rtnl_is_locked()) ++ unregister_netdev(cur_pnetdev); ++ else ++ unregister_netdevice(cur_pnetdev); ++ ++ rtw_proc_remove_one(cur_pnetdev); ++ ++ rereg_priv->old_pnetdev = cur_pnetdev; ++ ++ pnetdev = rtw_init_netdev(padapter); ++ if (!pnetdev) { ++ ret = -1; ++ goto error; ++ } ++ ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(adapter_to_dvobj(padapter))); ++ ++ rtw_init_netdev_name(pnetdev, ifname); ++ ++ memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ ++ if (!rtnl_is_locked()) ++ ret = register_netdev(pnetdev); ++ else ++ ret = register_netdevice(pnetdev); ++ if (ret != 0) ++ goto error; ++ ++ rtw_proc_init_one(pnetdev); ++ return 0; ++error: ++ return -1; ++} ++ ++void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len) ++{ ++ u32 dup_len = 0; ++ u8 *ori = NULL; ++ u8 *dup = NULL; ++ ++ if (!buf || !buf_len) ++ return; ++ ++ if (!src || !src_len) ++ goto keep_ori; ++ ++ /* duplicate src */ ++ dup = kmalloc(src_len, GFP_ATOMIC); ++ if (dup) { ++ dup_len = src_len; ++ memcpy(dup, src, dup_len); ++ } ++ ++keep_ori: ++ ori = *buf; ++ ++ /* replace buf with dup */ ++ *buf_len = 0; ++ *buf = dup; ++ *buf_len = dup_len; ++ ++ /* free ori */ ++ kfree(ori); ++} ++ ++/** ++ * rtw_cbuf_full - test if cbuf is full ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Returns: true if cbuf is full ++ */ ++inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf) ++{ ++ return (cbuf->write == cbuf->read - 1) ? true : false; ++} ++ ++/** ++ * rtw_cbuf_empty - test if cbuf is empty ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Returns: true if cbuf is empty ++ */ ++inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf) ++{ ++ return (cbuf->write == cbuf->read) ? true : false; ++} ++ ++/** ++ * rtw_cbuf_push - push a pointer into cbuf ++ * @cbuf: pointer of struct rtw_cbuf ++ * @buf: pointer to push in ++ * ++ * Lock free operation, be careful of the use scheme ++ * Returns: true push success ++ */ ++bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf) ++{ ++ if (rtw_cbuf_full(cbuf)) ++ return _FAIL; ++ ++ if (0) ++ DBG_88E("%s on %u\n", __func__, cbuf->write); ++ cbuf->bufs[cbuf->write] = buf; ++ cbuf->write = (cbuf->write + 1) % cbuf->size; ++ ++ return _SUCCESS; ++} ++ ++/** ++ * rtw_cbuf_pop - pop a pointer from cbuf ++ * @cbuf: pointer of struct rtw_cbuf ++ * ++ * Lock free operation, be careful of the use scheme ++ * Returns: pointer popped out ++ */ ++void *rtw_cbuf_pop(struct rtw_cbuf *cbuf) ++{ ++ void *buf; ++ if (rtw_cbuf_empty(cbuf)) ++ return NULL; ++ ++ if (0) ++ DBG_88E("%s on %u\n", __func__, cbuf->read); ++ buf = cbuf->bufs[cbuf->read]; ++ cbuf->read = (cbuf->read + 1) % cbuf->size; ++ ++ return buf; ++} ++ ++/** ++ * rtw_cbuf_alloc - allocate a rtw_cbuf with given size and do initialization ++ * @size: size of pointer ++ * ++ * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure ++ */ ++struct rtw_cbuf *rtw_cbuf_alloc(u32 size) ++{ ++ struct rtw_cbuf *cbuf; ++ ++ cbuf = kmalloc(sizeof(*cbuf) + sizeof(void *) * size, GFP_KERNEL); ++ ++ if (cbuf) { ++ cbuf->write = 0; ++ cbuf->read = 0; ++ cbuf->size = size; ++ } ++ return cbuf; ++} +diff --git a/drivers/staging/r8188eu/os_dep/recv_linux.c b/drivers/staging/r8188eu/os_dep/recv_linux.c +new file mode 100644 +index 000000000000..917a63e3e94c +--- /dev/null ++++ b/drivers/staging/r8188eu/os_dep/recv_linux.c +@@ -0,0 +1,214 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _RECV_OSDEP_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++ ++#include "../include/wifi.h" ++#include "../include/recv_osdep.h" ++ ++#include "../include/osdep_intf.h" ++#include "../include/usb_ops.h" ++ ++/* init os related resource in struct recv_priv */ ++int rtw_os_recv_resource_init(struct recv_priv *precvpriv, ++ struct adapter *padapter) ++{ ++ return _SUCCESS; ++} ++ ++/* alloc os related resource in struct recv_frame */ ++int rtw_os_recv_resource_alloc(struct adapter *padapter, ++ struct recv_frame *precvframe) ++{ ++ precvframe->pkt_newalloc = NULL; ++ precvframe->pkt = NULL; ++ return _SUCCESS; ++} ++ ++/* free os related resource in struct recv_frame */ ++void rtw_os_recv_resource_free(struct recv_priv *precvpriv) ++{ ++} ++ ++/* alloc os related resource in struct recv_buf */ ++int rtw_os_recvbuf_resource_alloc(struct adapter *padapter, ++ struct recv_buf *precvbuf) ++{ ++ int res = _SUCCESS; ++ ++ precvbuf->irp_pending = false; ++ precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); ++ if (!precvbuf->purb) ++ res = _FAIL; ++ precvbuf->pskb = NULL; ++ precvbuf->reuse = false; ++ precvbuf->pallocated_buf = NULL; ++ precvbuf->pbuf = NULL; ++ precvbuf->pdata = NULL; ++ precvbuf->phead = NULL; ++ precvbuf->ptail = NULL; ++ precvbuf->pend = NULL; ++ precvbuf->transfer_len = 0; ++ precvbuf->len = 0; ++ return res; ++} ++ ++/* free os related resource in struct recv_buf */ ++int rtw_os_recvbuf_resource_free(struct adapter *padapter, ++ struct recv_buf *precvbuf) ++{ ++ usb_free_urb(precvbuf->purb); ++ return _SUCCESS; ++} ++ ++void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) ++{ ++ union iwreq_data wrqu; ++ struct iw_michaelmicfailure ev; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct security_priv *psecuritypriv = &padapter->securitypriv; ++ u32 cur_time = 0; ++ ++ if (psecuritypriv->last_mic_err_time == 0) { ++ psecuritypriv->last_mic_err_time = jiffies; ++ } else { ++ cur_time = jiffies; ++ ++ if (cur_time - psecuritypriv->last_mic_err_time < 60 * HZ) { ++ psecuritypriv->btkip_countermeasure = true; ++ psecuritypriv->last_mic_err_time = 0; ++ psecuritypriv->btkip_countermeasure_time = cur_time; ++ } else { ++ psecuritypriv->last_mic_err_time = jiffies; ++ } ++ } ++ ++ memset(&ev, 0x00, sizeof(ev)); ++ if (bgroup) ++ ev.flags |= IW_MICFAILURE_GROUP; ++ else ++ ev.flags |= IW_MICFAILURE_PAIRWISE; ++ ++ ev.src_addr.sa_family = ARPHRD_ETHER; ++ memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN); ++ memset(&wrqu, 0x00, sizeof(wrqu)); ++ wrqu.data.length = sizeof(ev); ++ wireless_send_event(padapter->pnetdev, IWEVMICHAELMICFAILURE, ++ &wrqu, (char *)&ev); ++} ++ ++void rtw_hostapd_mlme_rx(struct adapter *padapter, ++ struct recv_frame *precv_frame) ++{ ++} ++ ++int rtw_recv_indicatepkt(struct adapter *padapter, ++ struct recv_frame *precv_frame) ++{ ++ struct recv_priv *precvpriv; ++ struct __queue *pfree_recv_queue; ++ struct sk_buff *skb; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ precvpriv = &padapter->recvpriv; ++ pfree_recv_queue = &precvpriv->free_recv_queue; ++ ++ skb = precv_frame->pkt; ++ if (!skb) ++ goto _recv_indicatepkt_drop; ++ ++ skb->data = precv_frame->rx_data; ++ ++ skb_set_tail_pointer(skb, precv_frame->len); ++ ++ skb->len = precv_frame->len; ++ ++ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { ++ struct sk_buff *pskb2 = NULL; ++ struct sta_info *psta = NULL; ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct rx_pkt_attrib *pattrib = &precv_frame->attrib; ++ bool bmcast = is_multicast_ether_addr(pattrib->dst); ++ ++ if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ++ ETH_ALEN)) { ++ if (bmcast) { ++ psta = rtw_get_bcmc_stainfo(padapter); ++ pskb2 = skb_clone(skb, GFP_ATOMIC); ++ } else { ++ psta = rtw_get_stainfo(pstapriv, pattrib->dst); ++ } ++ ++ if (psta) { ++ struct net_device *pnetdev; ++ ++ pnetdev = (struct net_device *)padapter->pnetdev; ++ skb->dev = pnetdev; ++ skb_set_queue_mapping(skb, rtw_recv_select_queue(skb)); ++ ++ rtw_xmit_entry(skb, pnetdev); ++ ++ if (bmcast) ++ skb = pskb2; ++ else ++ goto _recv_indicatepkt_end; ++ } ++ } ++ } ++ ++ rcu_read_lock(); ++ rcu_dereference(padapter->pnetdev->rx_handler_data); ++ rcu_read_unlock(); ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ skb->dev = padapter->pnetdev; ++ skb->protocol = eth_type_trans(skb, padapter->pnetdev); ++ ++ netif_rx(skb); ++ ++_recv_indicatepkt_end: ++ ++ /* pointers to NULL before rtw_free_recvframe() */ ++ precv_frame->pkt = NULL; ++ ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ ++ return _SUCCESS; ++ ++_recv_indicatepkt_drop: ++ ++ /* enqueue back to free_recv_queue */ ++ rtw_free_recvframe(precv_frame, pfree_recv_queue); ++ ++ return _FAIL; ++} ++ ++void rtw_os_read_port(struct adapter *padapter, struct recv_buf *precvbuf) ++{ ++ struct recv_priv *precvpriv = &padapter->recvpriv; ++ ++ precvbuf->ref_cnt--; ++ /* free skb in recv_buf */ ++ dev_kfree_skb_any(precvbuf->pskb); ++ precvbuf->pskb = NULL; ++ precvbuf->reuse = false; ++ if (!precvbuf->irp_pending) ++ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, ++ (unsigned char *)precvbuf); ++} ++ ++static void _rtw_reordering_ctrl_timeout_handler(struct timer_list *t) ++{ ++ struct recv_reorder_ctrl *preorder_ctrl; ++ ++ preorder_ctrl = from_timer(preorder_ctrl, t, reordering_ctrl_timer); ++ rtw_reordering_ctrl_timeout_handler(preorder_ctrl); ++} ++ ++void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl) ++{ ++ timer_setup(&preorder_ctrl->reordering_ctrl_timer, _rtw_reordering_ctrl_timeout_handler, 0); ++} +diff --git a/drivers/staging/r8188eu/os_dep/usb_intf.c b/drivers/staging/r8188eu/os_dep/usb_intf.c +new file mode 100644 +index 000000000000..bb85ab77fd26 +--- /dev/null ++++ b/drivers/staging/r8188eu/os_dep/usb_intf.c +@@ -0,0 +1,781 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2011 Realtek Corporation. */ ++ ++#define _HCI_INTF_C_ ++ ++#include ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/recv_osdep.h" ++#include "../include/xmit_osdep.h" ++#include "../include/hal_intf.h" ++#include "../include/osdep_intf.h" ++#include "../include/usb_vendor_req.h" ++#include "../include/usb_ops.h" ++#include "../include/usb_osintf.h" ++#include "../include/rtw_ioctl.h" ++ ++int ui_pid[3] = {0, 0, 0}; ++ ++static int rtw_suspend(struct usb_interface *intf, pm_message_t message); ++static int rtw_resume(struct usb_interface *intf); ++ ++static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid); ++static void rtw_dev_remove(struct usb_interface *pusb_intf); ++ ++#define USB_VENDER_ID_REALTEK 0x0bda ++ ++/* DID_USB_v916_20130116 */ ++static struct usb_device_id rtw_usb_id_tbl[] = { ++ /*=== Realtek demoboard ===*/ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8179)}, /* 8188EUS */ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */ ++ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xf179)}, /* 8188FU */ ++ /*=== Customer ID ===*/ ++ /****** 8188EUS ********/ ++ {USB_DEVICE(0x07B8, 0x8179)}, /* Abocom - Abocom */ ++ {USB_DEVICE(0x0DF6, 0x0076)}, /* Sitecom N150 v2 */ ++ {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ ++ {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ ++ {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ ++ {USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */ ++ {USB_DEVICE(0x056E, 0x4008)}, /* Elecom WDC-150SU2M */ ++ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */ ++ {USB_DEVICE(0x2357, 0x0111)}, /* TP-Link TL-WN727N v5.21 */ ++ {USB_DEVICE(0x2C4E, 0x0102)}, /* MERCUSYS MW150US v2 */ ++ {USB_DEVICE(0x0B05, 0x18F0)}, /* ASUS USB-N10 Nano B1 */ ++ {USB_DEVICE(0x7392, 0xb811)}, /* Edimax EW-7811Un V2 */ ++ {} /* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(usb, rtw_usb_id_tbl); ++ ++static struct specific_device_id specific_device_id_tbl[] = { ++ {} /* empty table for now */ ++}; ++ ++struct rtw_usb_drv { ++ struct usb_driver usbdrv; ++ int drv_registered; ++ struct mutex hw_init_mutex; ++}; ++ ++static struct rtw_usb_drv rtl8188e_usb_drv = { ++ .usbdrv.name = "r8188eu", ++ .usbdrv.probe = rtw_drv_init, ++ .usbdrv.disconnect = rtw_dev_remove, ++ .usbdrv.id_table = rtw_usb_id_tbl, ++ .usbdrv.suspend = rtw_suspend, ++ .usbdrv.resume = rtw_resume, ++ .usbdrv.reset_resume = rtw_resume, ++}; ++ ++static struct rtw_usb_drv *usb_drv = &rtl8188e_usb_drv; ++ ++static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) ++{ ++ return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN; ++} ++ ++static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) ++{ ++ return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; ++} ++ ++static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) ++{ ++ return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT; ++} ++ ++static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) ++{ ++ return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK; ++} ++ ++static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) ++{ ++ return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd); ++} ++ ++static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) ++{ ++ return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd); ++} ++ ++static inline int usb_endpoint_is_int(const struct usb_endpoint_descriptor *epd) ++{ ++ return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd); ++} ++ ++static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) ++{ ++ return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ++} ++ ++static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj) ++{ ++ u8 rst = _SUCCESS; ++ ++ _rtw_mutex_init(&dvobj->usb_vendor_req_mutex); ++ ++ dvobj->usb_alloc_vendor_req_buf = kzalloc(MAX_USB_IO_CTL_SIZE, GFP_KERNEL); ++ if (!dvobj->usb_alloc_vendor_req_buf) { ++ DBG_88E("alloc usb_vendor_req_buf failed... /n"); ++ rst = _FAIL; ++ goto exit; ++ } ++ dvobj->usb_vendor_req_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(dvobj->usb_alloc_vendor_req_buf), ALIGNMENT_UNIT); ++exit: ++ return rst; ++} ++ ++static void rtw_deinit_intf_priv(struct dvobj_priv *dvobj) ++{ ++ kfree(dvobj->usb_alloc_vendor_req_buf); ++ _rtw_mutex_free(&dvobj->usb_vendor_req_mutex); ++} ++ ++static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) ++{ ++ int i; ++ int status = _FAIL; ++ struct dvobj_priv *pdvobjpriv; ++ struct usb_host_config *phost_conf; ++ struct usb_config_descriptor *pconf_desc; ++ struct usb_host_interface *phost_iface; ++ struct usb_interface_descriptor *piface_desc; ++ struct usb_endpoint_descriptor *pendp_desc; ++ struct usb_device *pusbd; ++ ++ pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL); ++ if (!pdvobjpriv) ++ goto exit; ++ ++ pdvobjpriv->pusbintf = usb_intf; ++ pusbd = interface_to_usbdev(usb_intf); ++ pdvobjpriv->pusbdev = pusbd; ++ usb_set_intfdata(usb_intf, pdvobjpriv); ++ ++ pdvobjpriv->RtNumInPipes = 0; ++ pdvobjpriv->RtNumOutPipes = 0; ++ ++ phost_conf = pusbd->actconfig; ++ pconf_desc = &phost_conf->desc; ++ ++ phost_iface = &usb_intf->altsetting[0]; ++ piface_desc = &phost_iface->desc; ++ ++ pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces; ++ pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber; ++ pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; ++ ++ for (i = 0; i < pdvobjpriv->nr_endpoint; i++) { ++ int ep_num; ++ pendp_desc = &phost_iface->endpoint[i].desc; ++ ++ ep_num = usb_endpoint_num(pendp_desc); ++ ++ if (usb_endpoint_is_bulk_in(pendp_desc)) { ++ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = ep_num; ++ pdvobjpriv->RtNumInPipes++; ++ } else if (usb_endpoint_is_int_in(pendp_desc)) { ++ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = ep_num; ++ pdvobjpriv->RtNumInPipes++; ++ } else if (usb_endpoint_is_bulk_out(pendp_desc)) { ++ pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = ++ ep_num; ++ pdvobjpriv->RtNumOutPipes++; ++ } ++ pdvobjpriv->ep_num[i] = ep_num; ++ } ++ ++ if (pusbd->speed == USB_SPEED_HIGH) { ++ pdvobjpriv->ishighspeed = true; ++ DBG_88E("USB_SPEED_HIGH\n"); ++ } else { ++ pdvobjpriv->ishighspeed = false; ++ DBG_88E("NON USB_SPEED_HIGH\n"); ++ } ++ ++ if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) ++ goto free_dvobj; ++ ++ /* 3 misc */ ++ sema_init(&pdvobjpriv->usb_suspend_sema, 0); ++ rtw_reset_continual_urb_error(pdvobjpriv); ++ ++ usb_get_dev(pusbd); ++ ++ status = _SUCCESS; ++ ++free_dvobj: ++ if (status != _SUCCESS && pdvobjpriv) { ++ usb_set_intfdata(usb_intf, NULL); ++ kfree(pdvobjpriv); ++ pdvobjpriv = NULL; ++ } ++exit: ++ return pdvobjpriv; ++} ++ ++static void usb_dvobj_deinit(struct usb_interface *usb_intf) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf); ++ ++ usb_set_intfdata(usb_intf, NULL); ++ if (dvobj) { ++ /* Modify condition for 92DU DMDP 2010.11.18, by Thomas */ ++ if ((dvobj->NumInterfaces != 2 && ++ dvobj->NumInterfaces != 3) || ++ (dvobj->InterfaceNumber == 1)) { ++ if (interface_to_usbdev(usb_intf)->state != ++ USB_STATE_NOTATTACHED) { ++ /* If we didn't unplug usb dongle and ++ * remove/insert module, driver fails ++ * on sitesurvey for the first time when ++ * device is up . Reset usb port for sitesurvey ++ * fail issue. */ ++ DBG_88E("usb attached..., try to reset usb device\n"); ++ usb_reset_device(interface_to_usbdev(usb_intf)); ++ } ++ } ++ rtw_deinit_intf_priv(dvobj); ++ kfree(dvobj); ++ } ++ ++ usb_put_dev(interface_to_usbdev(usb_intf)); ++ ++} ++ ++static void chip_by_usb_id(struct adapter *padapter) ++{ ++ padapter->chip_type = NULL_CHIP_TYPE; ++ hal_set_hw_type(padapter); ++} ++ ++static void usb_intf_start(struct adapter *padapter) ++{ ++ rtw_hal_inirp_init(padapter); ++} ++ ++static void usb_intf_stop(struct adapter *padapter) ++{ ++ /* cancel in irp */ ++ rtw_hal_inirp_deinit(padapter); ++ ++ /* cancel out irp */ ++ rtw_write_port_cancel(padapter); ++ ++ /* todo:cancel other irps */ ++} ++ ++static void rtw_dev_unload(struct adapter *padapter) ++{ ++ if (padapter->bup) { ++ DBG_88E("===> rtw_dev_unload\n"); ++ padapter->bDriverStopped = true; ++ if (padapter->xmitpriv.ack_tx) ++ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); ++ /* s3. */ ++ if (padapter->intf_stop) ++ padapter->intf_stop(padapter); ++ /* s4. */ ++ if (!padapter->pwrctrlpriv.bInternalAutoSuspend) ++ rtw_stop_drv_threads(padapter); ++ ++ /* s5. */ ++ if (!padapter->bSurpriseRemoved) { ++ rtw_hal_deinit(padapter); ++ padapter->bSurpriseRemoved = true; ++ } ++ ++ padapter->bup = false; ++ } ++ ++ DBG_88E("<=== rtw_dev_unload\n"); ++} ++ ++static void process_spec_devid(const struct usb_device_id *pdid) ++{ ++ u16 vid, pid; ++ u32 flags; ++ int i; ++ int num = sizeof(specific_device_id_tbl) / ++ sizeof(struct specific_device_id); ++ ++ for (i = 0; i < num; i++) { ++ vid = specific_device_id_tbl[i].idVendor; ++ pid = specific_device_id_tbl[i].idProduct; ++ flags = specific_device_id_tbl[i].flags; ++ ++ if ((pdid->idVendor == vid) && (pdid->idProduct == pid) && ++ (flags & SPEC_DEV_ID_DISABLE_HT)) { ++ rtw_ht_enable = 0; ++ rtw_cbw40_enable = 0; ++ rtw_ampdu_enable = 0; ++ } ++ } ++} ++ ++int rtw_hw_suspend(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++ ++ if (!padapter) ++ goto error_exit; ++ if ((!padapter->bup) || (padapter->bDriverStopped) || ++ (padapter->bSurpriseRemoved)) { ++ DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", ++ padapter->bup, padapter->bDriverStopped, ++ padapter->bSurpriseRemoved); ++ goto error_exit; ++ } ++ ++ LeaveAllPowerSaveMode(padapter); ++ ++ DBG_88E("==> rtw_hw_suspend\n"); ++ _enter_pwrlock(&pwrpriv->lock); ++ pwrpriv->bips_processing = true; ++ /* s1. */ ++ if (pnetdev) { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ /* s2. */ ++ rtw_disassoc_cmd(padapter, 500, false); ++ ++ /* s2-2. indicate disconnect to os */ ++ { ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) { ++ _clr_fwstate_(pmlmepriv, _FW_LINKED); ++ ++ rtw_led_control(padapter, LED_CTL_NO_LINK); ++ ++ rtw_os_indicate_disconnect(padapter); ++ ++ /* donnot enqueue cmd */ ++ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 0); ++ } ++ } ++ /* s2-3. */ ++ rtw_free_assoc_resources(padapter, 1); ++ ++ /* s2-4. */ ++ rtw_free_network_queue(padapter, true); ++ rtw_ips_dev_unload(padapter); ++ pwrpriv->rf_pwrstate = rf_off; ++ pwrpriv->bips_processing = false; ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ return 0; ++ ++error_exit: ++ DBG_88E("%s, failed\n", __func__); ++ return -1; ++} ++ ++int rtw_hw_resume(struct adapter *padapter) ++{ ++ struct pwrctrl_priv *pwrpriv; ++ struct net_device *pnetdev = padapter->pnetdev; ++ ++ if (!padapter) ++ goto error_exit; ++ pwrpriv = &padapter->pwrctrlpriv; ++ DBG_88E("==> rtw_hw_resume\n"); ++ _enter_pwrlock(&pwrpriv->lock); ++ pwrpriv->bips_processing = true; ++ rtw_reset_drv_sw(padapter); ++ ++ if (pm_netdev_open(pnetdev, false) != 0) { ++ _exit_pwrlock(&pwrpriv->lock); ++ goto error_exit; ++ } ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ ++ if (!netif_queue_stopped(pnetdev)) ++ netif_start_queue(pnetdev); ++ else ++ netif_wake_queue(pnetdev); ++ ++ pwrpriv->bkeepfwalive = false; ++ pwrpriv->brfoffbyhw = false; ++ ++ pwrpriv->rf_pwrstate = rf_on; ++ pwrpriv->bips_processing = false; ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ return 0; ++error_exit: ++ DBG_88E("%s, Open net dev failed\n", __func__); ++ return -1; ++} ++ ++static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); ++ struct adapter *padapter = dvobj->if1; ++ struct net_device *pnetdev = padapter->pnetdev; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ ++ int ret = 0; ++ u32 start_time = jiffies; ++ ++ ++ DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid); ++ ++ if ((!padapter->bup) || (padapter->bDriverStopped) || ++ (padapter->bSurpriseRemoved)) { ++ DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", ++ padapter->bup, padapter->bDriverStopped, ++ padapter->bSurpriseRemoved); ++ goto exit; ++ } ++ ++ pwrpriv->bInSuspend = true; ++ rtw_cancel_all_timer(padapter); ++ LeaveAllPowerSaveMode(padapter); ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ /* s1. */ ++ if (pnetdev) { ++ netif_carrier_off(pnetdev); ++ rtw_netif_stop_queue(pnetdev); ++ } ++ ++ /* s2. */ ++ rtw_disassoc_cmd(padapter, 0, false); ++ ++ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && ++ check_fwstate(pmlmepriv, _FW_LINKED)) { ++ DBG_88E("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n", ++ __func__, __LINE__, ++ pmlmepriv->cur_network.network.Ssid.Ssid, ++ pmlmepriv->cur_network.network.MacAddress, ++ pmlmepriv->cur_network.network.Ssid.SsidLength, ++ pmlmepriv->assoc_ssid.SsidLength); ++ ++ pmlmepriv->to_roaming = 1; ++ } ++ /* s2-2. indicate disconnect to os */ ++ rtw_indicate_disconnect(padapter); ++ /* s2-3. */ ++ rtw_free_assoc_resources(padapter, 1); ++ /* s2-4. */ ++ rtw_free_network_queue(padapter, true); ++ ++ rtw_dev_unload(padapter); ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) ++ rtw_indicate_scan_done(padapter, 1); ++ ++ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) ++ rtw_indicate_disconnect(padapter); ++ ++exit: ++ DBG_88E("<=== %s return %d.............. in %dms\n", __func__ ++ , ret, rtw_get_passing_time_ms(start_time)); ++ ++ return ret; ++} ++ ++static int rtw_resume(struct usb_interface *pusb_intf) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); ++ struct adapter *padapter = dvobj->if1; ++ struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; ++ int ret = 0; ++ ++ if (pwrpriv->bInternalAutoSuspend) ++ ret = rtw_resume_process(padapter); ++ else ++ ret = rtw_resume_process(padapter); ++ return ret; ++} ++ ++int rtw_resume_process(struct adapter *padapter) ++{ ++ struct net_device *pnetdev; ++ struct pwrctrl_priv *pwrpriv = NULL; ++ int ret = -1; ++ u32 start_time = jiffies; ++ ++ DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid); ++ ++ if (padapter) { ++ pnetdev = padapter->pnetdev; ++ pwrpriv = &padapter->pwrctrlpriv; ++ } else { ++ goto exit; ++ } ++ ++ _enter_pwrlock(&pwrpriv->lock); ++ rtw_reset_drv_sw(padapter); ++ if (pwrpriv) ++ pwrpriv->bkeepfwalive = false; ++ ++ DBG_88E("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive); ++ if (pm_netdev_open(pnetdev, true) != 0) ++ goto exit; ++ ++ netif_device_attach(pnetdev); ++ netif_carrier_on(pnetdev); ++ ++ _exit_pwrlock(&pwrpriv->lock); ++ ++ if (padapter->pid[1] != 0) { ++ DBG_88E("pid[1]:%d\n", padapter->pid[1]); ++ rtw_signal_process(padapter->pid[1], SIGUSR2); ++ } ++ ++ rtw_roaming(padapter, NULL); ++ ++ ret = 0; ++exit: ++ if (pwrpriv) ++ pwrpriv->bInSuspend = false; ++ DBG_88E("<=== %s return %d.............. in %dms\n", __func__, ++ ret, rtw_get_passing_time_ms(start_time)); ++ ++ ++ return ret; ++} ++ ++/* ++ * drv_init() - a device potentially for us ++ * ++ * notes: drv_init() is called when the bus driver has located ++ * a card for us to support. ++ * We accept the new device by returning 0. ++ */ ++ ++static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, ++ struct usb_interface *pusb_intf) ++{ ++ struct adapter *padapter = NULL; ++ struct net_device *pnetdev = NULL; ++ int status = _FAIL; ++ ++ padapter = vzalloc(sizeof(*padapter)); ++ if (!padapter) ++ goto exit; ++ padapter->dvobj = dvobj; ++ dvobj->if1 = padapter; ++ ++ padapter->bDriverStopped = true; ++ ++ padapter->hw_init_mutex = &usb_drv->hw_init_mutex; ++ ++ /* step 1-1., decide the chip_type via vid/pid */ ++ padapter->interface_type = RTW_USB; ++ chip_by_usb_id(padapter); ++ ++ if (rtw_handle_dualmac(padapter, 1) != _SUCCESS) ++ goto free_adapter; ++ ++ pnetdev = rtw_init_netdev(padapter); ++ if (!pnetdev) ++ goto handle_dualmac; ++ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj)); ++ padapter = rtw_netdev_priv(pnetdev); ++ ++ /* step 2. hook HalFunc, allocate HalData */ ++ rtl8188eu_set_hal_ops(padapter); ++ ++ padapter->intf_start = &usb_intf_start; ++ padapter->intf_stop = &usb_intf_stop; ++ ++ /* step init_io_priv */ ++ rtw_init_io_priv(padapter, usb_set_intf_ops); ++ ++ /* step read_chip_version */ ++ rtw_hal_read_chip_version(padapter); ++ ++ /* step usb endpoint mapping */ ++ rtw_hal_chip_configure(padapter); ++ ++ /* step read efuse/eeprom data and get mac_addr */ ++ rtw_hal_read_chip_info(padapter); ++ ++ /* step 5. */ ++ if (rtw_init_drv_sw(padapter) == _FAIL) ++ goto free_hal_data; ++ ++#ifdef CONFIG_PM ++ if (padapter->pwrctrlpriv.bSupportRemoteWakeup) { ++ dvobj->pusbdev->do_remote_wakeup = 1; ++ pusb_intf->needs_remote_wakeup = 1; ++ device_init_wakeup(&pusb_intf->dev, 1); ++ DBG_88E("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n", ++ device_may_wakeup(&pusb_intf->dev)); ++ } ++#endif ++ ++ /* 2012-07-11 Move here to prevent the 8723AS-VAU BT auto ++ * suspend influence */ ++ if (usb_autopm_get_interface(pusb_intf) < 0) ++ DBG_88E("can't get autopm:\n"); ++ ++ /* alloc dev name after read efuse. */ ++ rtw_init_netdev_name(pnetdev, padapter->registrypriv.ifname); ++ rtw_macaddr_cfg(padapter->eeprompriv.mac_addr); ++#ifdef CONFIG_88EU_P2P ++ rtw_init_wifidirect_addrs(padapter, padapter->eeprompriv.mac_addr, ++ padapter->eeprompriv.mac_addr); ++#endif ++ memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN); ++ DBG_88E("MAC Address from pnetdev->dev_addr = %pM\n", ++ pnetdev->dev_addr); ++ ++ /* step 6. Tell the network stack we exist */ ++ if (register_netdev(pnetdev) != 0) ++ goto free_hal_data; ++ ++ DBG_88E("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" ++ , padapter->bDriverStopped ++ , padapter->bSurpriseRemoved ++ , padapter->bup ++ , padapter->hw_init_completed ++ ); ++ ++ status = _SUCCESS; ++ ++free_hal_data: ++ if (status != _SUCCESS) ++ kfree(padapter->HalData); ++handle_dualmac: ++ if (status != _SUCCESS) ++ rtw_handle_dualmac(padapter, 0); ++free_adapter: ++ if (status != _SUCCESS) { ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++ else if (padapter) ++ vfree(padapter); ++ padapter = NULL; ++ } ++exit: ++ return padapter; ++} ++ ++static void rtw_usb_if1_deinit(struct adapter *if1) ++{ ++ struct net_device *pnetdev = if1->pnetdev; ++ struct mlme_priv *pmlmepriv = &if1->mlmepriv; ++ ++ if (check_fwstate(pmlmepriv, _FW_LINKED)) ++ rtw_disassoc_cmd(if1, 0, false); ++ ++#ifdef CONFIG_88EU_AP_MODE ++ free_mlme_ap_info(if1); ++#endif ++ ++ if (if1->DriverState != DRIVER_DISAPPEAR) { ++ if (pnetdev) { ++ /* will call netdev_close() */ ++ unregister_netdev(pnetdev); ++ rtw_proc_remove_one(pnetdev); ++ } ++ } ++ rtw_cancel_all_timer(if1); ++ ++ rtw_dev_unload(if1); ++ DBG_88E("+r871xu_dev_remove, hw_init_completed=%d\n", ++ if1->hw_init_completed); ++ rtw_handle_dualmac(if1, 0); ++ rtw_free_drv_sw(if1); ++ if (pnetdev) ++ rtw_free_netdev(pnetdev); ++} ++ ++static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid) ++{ ++ struct adapter *if1 = NULL; ++ struct dvobj_priv *dvobj; ++ ++ /* step 0. */ ++ process_spec_devid(pdid); ++ ++ /* Initialize dvobj_priv */ ++ dvobj = usb_dvobj_init(pusb_intf); ++ if (!dvobj) ++ goto err; ++ ++ if1 = rtw_usb_if1_init(dvobj, pusb_intf); ++ if (!if1) { ++ DBG_88E("rtw_init_primarystruct adapter Failed!\n"); ++ goto free_dvobj; ++ } ++ ++ if (ui_pid[1] != 0) { ++ DBG_88E("ui_pid[1]:%d\n", ui_pid[1]); ++ rtw_signal_process(ui_pid[1], SIGUSR2); ++ } ++ ++ return 0; ++ ++free_dvobj: ++ usb_dvobj_deinit(pusb_intf); ++err: ++ return -ENODEV; ++} ++ ++/* ++ * dev_remove() - our device is being removed ++*/ ++/* rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() => how to recognize both */ ++static void rtw_dev_remove(struct usb_interface *pusb_intf) ++{ ++ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); ++ struct adapter *padapter = dvobj->if1; ++ ++ DBG_88E("+rtw_dev_remove\n"); ++ ++ if (usb_drv->drv_registered) ++ padapter->bSurpriseRemoved = true; ++ ++ rtw_pm_set_ips(padapter, IPS_NONE); ++ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); ++ ++ LeaveAllPowerSaveMode(padapter); ++ ++ rtw_usb_if1_deinit(padapter); ++ ++ usb_dvobj_deinit(pusb_intf); ++ ++ DBG_88E("-r871xu_dev_remove, done\n"); ++} ++ ++static int __init rtw_drv_entry(void) ++{ ++ DBG_88E(DRV_NAME " driver version=%s\n", DRIVERVERSION); ++ ++ _rtw_mutex_init(&usb_drv->hw_init_mutex); ++ ++ usb_drv->drv_registered = true; ++ return usb_register(&usb_drv->usbdrv); ++} ++ ++static void __exit rtw_drv_halt(void) ++{ ++ DBG_88E("+rtw_drv_halt\n"); ++ ++ usb_drv->drv_registered = false; ++ usb_deregister(&usb_drv->usbdrv); ++ ++ _rtw_mutex_free(&usb_drv->hw_init_mutex); ++ DBG_88E("-rtw_drv_halt\n"); ++} ++ ++module_init(rtw_drv_entry); ++module_exit(rtw_drv_halt); +diff --git a/drivers/staging/r8188eu/os_dep/usb_ops_linux.c b/drivers/staging/r8188eu/os_dep/usb_ops_linux.c +new file mode 100644 +index 000000000000..62dd4a131534 +--- /dev/null ++++ b/drivers/staging/r8188eu/os_dep/usb_ops_linux.c +@@ -0,0 +1,253 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _USB_OPS_LINUX_C_ ++ ++#include "../include/drv_types.h" ++#include "../include/usb_ops_linux.h" ++#include "../include/rtw_sreset.h" ++ ++unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) ++{ ++ unsigned int pipe = 0, ep_num = 0; ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ ++ if (addr == RECV_BULK_IN_ADDR) { ++ pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]); ++ } else if (addr == RECV_INT_IN_ADDR) { ++ pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]); ++ } else if (addr < HW_QUEUE_ENTRY) { ++ ep_num = pdvobj->Queue2Pipe[addr]; ++ pipe = usb_sndbulkpipe(pusbd, ep_num); ++ } ++ ++ return pipe; ++} ++ ++struct zero_bulkout_context { ++ void *pbuf; ++ void *purb; ++ void *pirp; ++ void *padapter; ++}; ++ ++void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem) ++{ ++} ++ ++void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) ++{ ++} ++ ++void usb_read_port_cancel(struct intf_hdl *pintfhdl) ++{ ++ int i; ++ struct recv_buf *precvbuf; ++ struct adapter *padapter = pintfhdl->padapter; ++ precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf; ++ ++ DBG_88E("%s\n", __func__); ++ ++ padapter->bReadPortCancel = true; ++ ++ for (i = 0; i < NR_RECVBUFF; i++) { ++ precvbuf->reuse = true; ++ if (precvbuf->purb) ++ usb_kill_urb(precvbuf->purb); ++ precvbuf++; ++ } ++} ++ ++static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) ++{ ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; ++ struct adapter *padapter = pxmitbuf->padapter; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct hal_data_8188e *haldata; ++ ++ switch (pxmitbuf->flags) { ++ case VO_QUEUE_INX: ++ pxmitpriv->voq_cnt--; ++ break; ++ case VI_QUEUE_INX: ++ pxmitpriv->viq_cnt--; ++ break; ++ case BE_QUEUE_INX: ++ pxmitpriv->beq_cnt--; ++ break; ++ case BK_QUEUE_INX: ++ pxmitpriv->bkq_cnt--; ++ break; ++ case HIGH_QUEUE_INX: ++#ifdef CONFIG_88EU_AP_MODE ++ rtw_chk_hi_queue_cmd(padapter); ++#endif ++ break; ++ default: ++ break; ++ } ++ ++ if (padapter->bSurpriseRemoved || padapter->bDriverStopped || ++ padapter->bWritePortCancel) { ++ DBG_88E("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n", ++ __func__, padapter->bDriverStopped, ++ padapter->bSurpriseRemoved, padapter->bReadPortCancel, ++ pxmitbuf->ext_tag); ++ ++ goto check_completion; ++ } ++ ++ if (purb->status) { ++ DBG_88E("###=> urb_write_port_complete status(%d)\n", purb->status); ++ if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) { ++ sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); ++ } else if (purb->status == -EINPROGRESS) { ++ goto check_completion; ++ } else if (purb->status == -ENOENT) { ++ DBG_88E("%s: -ENOENT\n", __func__); ++ goto check_completion; ++ } else if (purb->status == -ECONNRESET) { ++ DBG_88E("%s: -ECONNRESET\n", __func__); ++ goto check_completion; ++ } else if (purb->status == -ESHUTDOWN) { ++ padapter->bDriverStopped = true; ++ goto check_completion; ++ } else { ++ padapter->bSurpriseRemoved = true; ++ DBG_88E("bSurpriseRemoved = true\n"); ++ ++ goto check_completion; ++ } ++ } ++ ++ haldata = GET_HAL_DATA(padapter); ++ haldata->srestpriv.last_tx_complete_time = jiffies; ++ ++check_completion: ++ rtw_sctx_done_err(&pxmitbuf->sctx, ++ purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : ++ RTW_SCTX_DONE_SUCCESS); ++ ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++ ++} ++ ++u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) ++{ ++ unsigned long irqL; ++ unsigned int pipe; ++ int status; ++ u32 ret = _FAIL; ++ struct urb *purb = NULL; ++ struct adapter *padapter = (struct adapter *)pintfhdl->padapter; ++ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem; ++ struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; ++ struct usb_device *pusbd = pdvobj->pusbdev; ++ ++ if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) || ++ (padapter->pwrctrlpriv.pnp_bstop_trx)) { ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); ++ goto exit; ++ } ++ ++ spin_lock_irqsave(&pxmitpriv->lock, irqL); ++ ++ switch (addr) { ++ case VO_QUEUE_INX: ++ pxmitpriv->voq_cnt++; ++ pxmitbuf->flags = VO_QUEUE_INX; ++ break; ++ case VI_QUEUE_INX: ++ pxmitpriv->viq_cnt++; ++ pxmitbuf->flags = VI_QUEUE_INX; ++ break; ++ case BE_QUEUE_INX: ++ pxmitpriv->beq_cnt++; ++ pxmitbuf->flags = BE_QUEUE_INX; ++ break; ++ case BK_QUEUE_INX: ++ pxmitpriv->bkq_cnt++; ++ pxmitbuf->flags = BK_QUEUE_INX; ++ break; ++ case HIGH_QUEUE_INX: ++ pxmitbuf->flags = HIGH_QUEUE_INX; ++ break; ++ default: ++ pxmitbuf->flags = MGT_QUEUE_INX; ++ break; ++ } ++ ++ spin_unlock_irqrestore(&pxmitpriv->lock, irqL); ++ ++ purb = pxmitbuf->pxmit_urb[0]; ++ ++ /* translate DMA FIFO addr to pipehandle */ ++ pipe = ffaddr2pipehdl(pdvobj, addr); ++ ++ usb_fill_bulk_urb(purb, pusbd, pipe, ++ pxmitframe->buf_addr, /* pxmitbuf->pbuf */ ++ cnt, ++ usb_write_port_complete, ++ pxmitbuf);/* context is pxmitbuf */ ++ ++ status = usb_submit_urb(purb, GFP_ATOMIC); ++ if (!status) { ++ struct hal_data_8188e *haldata = GET_HAL_DATA(padapter); ++ ++ haldata->srestpriv.last_tx_time = jiffies; ++ } else { ++ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); ++ DBG_88E("usb_write_port, status =%d\n", status); ++ ++ switch (status) { ++ case -ENODEV: ++ padapter->bDriverStopped = true; ++ break; ++ default: ++ break; ++ } ++ goto exit; ++ } ++ ++ ret = _SUCCESS; ++ ++/* We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */ ++ ++exit: ++ if (ret != _SUCCESS) ++ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); ++ ++ return ret; ++} ++ ++void usb_write_port_cancel(struct intf_hdl *pintfhdl) ++{ ++ int i, j; ++ struct adapter *padapter = pintfhdl->padapter; ++ struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf; ++ ++ DBG_88E("%s\n", __func__); ++ ++ padapter->bWritePortCancel = true; ++ ++ for (i = 0; i < NR_XMITBUFF; i++) { ++ for (j = 0; j < 8; j++) { ++ if (pxmitbuf->pxmit_urb[j]) ++ usb_kill_urb(pxmitbuf->pxmit_urb[j]); ++ } ++ pxmitbuf++; ++ } ++ ++ pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf; ++ for (i = 0; i < NR_XMIT_EXTBUFF; i++) { ++ for (j = 0; j < 8; j++) { ++ if (pxmitbuf->pxmit_urb[j]) ++ usb_kill_urb(pxmitbuf->pxmit_urb[j]); ++ } ++ pxmitbuf++; ++ } ++} +diff --git a/drivers/staging/r8188eu/os_dep/xmit_linux.c b/drivers/staging/r8188eu/os_dep/xmit_linux.c +new file mode 100644 +index 000000000000..565ac5be7db3 +--- /dev/null ++++ b/drivers/staging/r8188eu/os_dep/xmit_linux.c +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright(c) 2007 - 2012 Realtek Corporation. */ ++ ++#define _XMIT_OSDEP_C_ ++ ++#include "../include/osdep_service.h" ++#include "../include/drv_types.h" ++#include "../include/wifi.h" ++#include "../include/mlme_osdep.h" ++#include "../include/xmit_osdep.h" ++#include "../include/osdep_intf.h" ++#include "../include/usb_osintf.h" ++ ++uint rtw_remainder_len(struct pkt_file *pfile) ++{ ++ return pfile->buf_len - ((size_t)(pfile->cur_addr) - ++ (size_t)(pfile->buf_start)); ++} ++ ++void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile) ++{ ++ ++ if (!pktptr) { ++ pr_err("8188eu: pktptr is NULL\n"); ++ return; ++ } ++ if (!pfile) { ++ pr_err("8188eu: pfile is NULL\n"); ++ return; ++ } ++ pfile->pkt = pktptr; ++ pfile->cur_addr = pktptr->data; ++ pfile->buf_start = pktptr->data; ++ pfile->pkt_len = pktptr->len; ++ pfile->buf_len = pktptr->len; ++ ++ pfile->cur_buffer = pfile->buf_start; ++ ++} ++ ++uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) ++{ ++ uint len = 0; ++ ++ len = rtw_remainder_len(pfile); ++ len = (rlen > len) ? len : rlen; ++ ++ if (rmem) ++ skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, rmem, len); ++ ++ pfile->cur_addr += len; ++ pfile->pkt_len -= len; ++ ++ return len; ++} ++ ++int rtw_endofpktfile(struct pkt_file *pfile) ++{ ++ ++ if (pfile->pkt_len == 0) { ++ ++ return true; ++ } ++ ++ return false; ++} ++ ++void rtw_set_tx_chksum_offload(struct sk_buff *pkt, struct pkt_attrib *pattrib) ++{ ++} ++ ++int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz) ++{ ++ int i; ++ ++ pxmitbuf->pallocated_buf = kzalloc(alloc_sz, GFP_KERNEL); ++ if (!pxmitbuf->pallocated_buf) ++ return _FAIL; ++ ++ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); ++ pxmitbuf->dma_transfer_addr = 0; ++ ++ for (i = 0; i < 8; i++) { ++ pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); ++ if (!pxmitbuf->pxmit_urb[i]) { ++ DBG_88E("pxmitbuf->pxmit_urb[i]==NULL"); ++ return _FAIL; ++ } ++ } ++ return _SUCCESS; ++} ++ ++void rtw_os_xmit_resource_free(struct adapter *padapter, ++ struct xmit_buf *pxmitbuf, u32 free_sz) ++{ ++ int i; ++ ++ for (i = 0; i < 8; i++) ++ usb_free_urb(pxmitbuf->pxmit_urb[i]); ++ ++ kfree(pxmitbuf->pallocated_buf); ++} ++ ++#define WMM_XMIT_THRESHOLD (NR_XMITFRAME * 2 / 5) ++ ++void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt) ++{ ++ u16 queue; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ ++ queue = skb_get_queue_mapping(pkt); ++ if (padapter->registrypriv.wifi_spec) { ++ if (__netif_subqueue_stopped(padapter->pnetdev, queue) && ++ (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) ++ netif_wake_subqueue(padapter->pnetdev, queue); ++ } else { ++ if (__netif_subqueue_stopped(padapter->pnetdev, queue)) ++ netif_wake_subqueue(padapter->pnetdev, queue); ++ } ++ ++ dev_kfree_skb_any(pkt); ++} ++ ++void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe) ++{ ++ if (pxframe->pkt) ++ rtw_os_pkt_complete(padapter, pxframe->pkt); ++ pxframe->pkt = NULL; ++} ++ ++void rtw_os_xmit_schedule(struct adapter *padapter) ++{ ++ struct xmit_priv *pxmitpriv; ++ ++ if (!padapter) ++ return; ++ ++ pxmitpriv = &padapter->xmitpriv; ++ ++ spin_lock_bh(&pxmitpriv->lock); ++ ++ if (rtw_txframes_pending(padapter)) ++ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); ++ ++ spin_unlock_bh(&pxmitpriv->lock); ++} ++ ++static void rtw_check_xmit_resource(struct adapter *padapter, struct sk_buff *pkt) ++{ ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ u16 queue; ++ ++ queue = skb_get_queue_mapping(pkt); ++ if (padapter->registrypriv.wifi_spec) { ++ /* No free space for Tx, tx_worker is too slow */ ++ if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD) ++ netif_stop_subqueue(padapter->pnetdev, queue); ++ } else { ++ if (pxmitpriv->free_xmitframe_cnt <= 4) { ++ if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue))) ++ netif_stop_subqueue(padapter->pnetdev, queue); ++ } ++ } ++} ++ ++static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) ++{ ++ struct sta_priv *pstapriv = &padapter->stapriv; ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct list_head *phead, *plist; ++ struct sk_buff *newskb; ++ struct sta_info *psta = NULL; ++ s32 res; ++ ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ phead = &pstapriv->asoc_list; ++ plist = phead->next; ++ ++ /* free sta asoc_queue */ ++ while (phead != plist) { ++ psta = container_of(plist, struct sta_info, asoc_list); ++ ++ plist = plist->next; ++ ++ /* avoid come from STA1 and send back STA1 */ ++ if (!memcmp(psta->hwaddr, &skb->data[6], 6)) ++ continue; ++ ++ newskb = skb_copy(skb, GFP_ATOMIC); ++ ++ if (newskb) { ++ memcpy(newskb->data, psta->hwaddr, 6); ++ res = rtw_xmit(padapter, &newskb); ++ if (res < 0) { ++ DBG_88E("%s()-%d: rtw_xmit() return error!\n", __func__, __LINE__); ++ pxmitpriv->tx_drop++; ++ dev_kfree_skb_any(newskb); ++ } else { ++ pxmitpriv->tx_pkts++; ++ } ++ } else { ++ DBG_88E("%s-%d: skb_copy() failed!\n", __func__, __LINE__); ++ pxmitpriv->tx_drop++; ++ ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ return false; /* Caller shall tx this multicast frame via normal way. */ ++ } ++ } ++ ++ spin_unlock_bh(&pstapriv->asoc_list_lock); ++ dev_kfree_skb_any(skb); ++ return true; ++} ++ ++int rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev) ++{ ++ struct adapter *padapter = (struct adapter *)rtw_netdev_priv(pnetdev); ++ struct xmit_priv *pxmitpriv = &padapter->xmitpriv; ++ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; ++ s32 res = 0; ++ ++ if (!rtw_if_up(padapter)) ++ goto drop_packet; ++ ++ rtw_check_xmit_resource(padapter, pkt); ++ ++ if (!rtw_mc2u_disable && check_fwstate(pmlmepriv, WIFI_AP_STATE) && ++ (IP_MCAST_MAC(pkt->data) || ICMPV6_MCAST_MAC(pkt->data)) && ++ (padapter->registrypriv.wifi_spec == 0)) { ++ if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME / 4)) { ++ res = rtw_mlcst2unicst(padapter, pkt); ++ if (res) ++ goto exit; ++ } ++ } ++ ++ res = rtw_xmit(padapter, &pkt); ++ if (res < 0) ++ goto drop_packet; ++ ++ pxmitpriv->tx_pkts++; ++ goto exit; ++ ++drop_packet: ++ pxmitpriv->tx_drop++; ++ dev_kfree_skb_any(pkt); ++ ++exit: ++ ++ return 0; ++} diff --git a/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-20231117.patch b/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-20231117.patch new file mode 100644 index 0000000000..0ebc0c6aca --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-20231117.patch @@ -0,0 +1,1720 @@ +From 8bb11a9489a5af4f23949f0109bf40d65d787095 Mon Sep 17 00:00:00 2001 +From: kimocoder +Date: Tue, 6 Jun 2023 17:50:45 +0200 +Subject: [PATCH 01/13] Revert "Some cleanup of unused chips" + +This reverts commit b3227c731ec957b706f8eb2ebcf42ba1c2f0d610. +--- + drivers/staging/rtl8812au/hal/hal_com.c | 280 ++++++++++++++++++ + drivers/staging/rtl8812au/hal/hal_intf.c | 18 ++ + drivers/staging/rtl8812au/hal/hal_mp.c | 27 ++ + .../hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c | 18 +- + .../hal/phydm/rtl8814a/halphyrf_8814a_ap.c | 28 +- + .../rtl8812au/hal/rtl8814a/usb/usb_halinit.c | 30 +- + .../staging/rtl8812au/include/gspi_osintf.h | 7 + + .../staging/rtl8812au/include/rtl8812a_recv.h | 4 + + .../staging/rtl8812au/include/rtl8814a_recv.h | 4 + + drivers/staging/rtl8812au/include/rtw_cmd.h | 9 +- + drivers/staging/rtl8812au/include/rtw_debug.h | 4 + + drivers/staging/rtl8812au/include/rtw_recv.h | 36 ++- + drivers/staging/rtl8812au/include/rtw_xmit.h | 5 + + .../staging/rtl8812au/include/sdio_osintf.h | 7 + + .../staging/rtl8812au/os_dep/osdep_service.c | 31 ++ + 15 files changed, 478 insertions(+), 30 deletions(-) + +diff --git a/drivers/staging/rtl8812au/hal/hal_com.c b/drivers/staging/rtl8812au/hal/hal_com.c +index 3b7d7dc52..b3b1e16c8 100644 +--- a/drivers/staging/rtl8812au/hal/hal_com.c ++++ b/drivers/staging/rtl8812au/hal/hal_com.c +@@ -4330,6 +4330,28 @@ s32 rtw_hal_set_FwMediaStatusRpt_cmd(_adapter *adapter, bool opmode, bool miraca + if (ret != _SUCCESS) + goto exit; + ++#if defined(CONFIG_RTL8188E) ++ if (rtw_get_chip_type(adapter) == RTL8188E) { ++ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); ++ ++ /* 8188E FW doesn't set macid no link, driver does it by self */ ++ if (opmode) ++ rtw_hal_set_hwreg(adapter, HW_VAR_MACID_LINK, &macid); ++ else ++ rtw_hal_set_hwreg(adapter, HW_VAR_MACID_NOLINK, &macid); ++ ++ /* for 8188E RA */ ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ if (hal_data->fw_ractrl == _FALSE) { ++ u8 max_macid; ++ ++ max_macid = rtw_search_max_mac_id(adapter); ++ rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, &max_macid); ++ } ++#endif ++ } ++#endif ++ + #if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + /* TODO: this should move to IOT issue area */ + if (rtw_get_chip_type(adapter) == RTL8812 +@@ -4734,6 +4756,21 @@ static void rtw_hal_force_enable_rxdma(_adapter *adapter) + rtw_write32(adapter, REG_RXPKT_NUM, + (rtw_read32(adapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN))); + } ++#if defined(CONFIG_RTL8188E) ++static void rtw_hal_disable_tx_report(_adapter *adapter) ++{ ++ rtw_write8(adapter, REG_TX_RPT_CTRL, ++ ((rtw_read8(adapter, REG_TX_RPT_CTRL) & ~BIT(1))) & ~BIT(5)); ++ RTW_INFO("disable TXRPT:0x%02x\n", rtw_read8(adapter, REG_TX_RPT_CTRL)); ++} ++ ++static void rtw_hal_enable_tx_report(_adapter *adapter) ++{ ++ rtw_write8(adapter, REG_TX_RPT_CTRL, ++ ((rtw_read8(adapter, REG_TX_RPT_CTRL) | BIT(1))) | BIT(5)); ++ RTW_INFO("enable TX_RPT:0x%02x\n", rtw_read8(adapter, REG_TX_RPT_CTRL)); ++} ++#endif + static void rtw_hal_release_rx_dma(_adapter *adapter) + { + u32 val32 = 0; +@@ -5819,6 +5856,10 @@ static void rtw_hal_ap_wow_enable(_adapter *padapter) + issue_beacon(padapter, 0); + + rtw_msleep_os(2); ++ #if defined(CONFIG_RTL8188E) ++ if (IS_HARDWARE_TYPE_8188E(padapter)) ++ rtw_hal_disable_tx_report(padapter); ++ #endif + /* RX DMA stop */ + res = rtw_hal_pause_rx_dma(padapter); + if (res == _FAIL) +@@ -5879,6 +5920,11 @@ static void rtw_hal_ap_wow_disable(_adapter *padapter) + } + #endif /*DBG_CHECK_FW_PS_STATE*/ + ++ #if defined(CONFIG_RTL8188E) ++ if (IS_HARDWARE_TYPE_8188E(padapter)) ++ rtw_hal_enable_tx_report(padapter); ++ #endif ++ + rtw_hal_force_enable_rxdma(padapter); + + rtw_hal_fw_dl(padapter, _FALSE); +@@ -9558,6 +9604,10 @@ static void rtw_hal_wow_enable(_adapter *adapter) + (u8 *)&media_status_rpt); + + /* RX DMA stop */ ++ #if defined(CONFIG_RTL8188E) ++ if (IS_HARDWARE_TYPE_8188E(adapter)) ++ rtw_hal_disable_tx_report(adapter); ++ #endif + + res = rtw_hal_pause_rx_dma(adapter); + if (res == _FAIL) +@@ -9746,6 +9796,11 @@ static void rtw_hal_wow_disable(_adapter *adapter) + #endif + rtw_hal_release_rx_dma(adapter); + ++ #if defined(CONFIG_RTL8188E) ++ if (IS_HARDWARE_TYPE_8188E(adapter)) ++ rtw_hal_enable_tx_report(adapter); ++ #endif ++ + if ((pwrctl->wowlan_wake_reason != RX_DISASSOC) && + (pwrctl->wowlan_wake_reason != RX_DEAUTH) && + (pwrctl->wowlan_wake_reason != FW_DECISION_DISCONNECT)) { +@@ -12549,6 +12604,61 @@ int hal_efuse_macaddr_offset(_adapter *adapter) + interface_type = rtw_get_intf_type(adapter); + + switch (rtw_get_chip_type(adapter)) { ++#ifdef CONFIG_RTL8723B ++ case RTL8723B: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8723BU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8723BS; ++ else if (interface_type == RTW_PCIE) ++ addr_offset = EEPROM_MAC_ADDR_8723BE; ++ break; ++#endif ++#ifdef CONFIG_RTL8703B ++ case RTL8703B: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8703BU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8703BS; ++ break; ++#endif ++#ifdef CONFIG_RTL8723D ++ case RTL8723D: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8723DU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8723DS; ++ else if (interface_type == RTW_PCIE) ++ addr_offset = EEPROM_MAC_ADDR_8723DE; ++ break; ++#endif ++ ++#ifdef CONFIG_RTL8188E ++ case RTL8188E: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_88EU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_88ES; ++ else if (interface_type == RTW_PCIE) ++ addr_offset = EEPROM_MAC_ADDR_88EE; ++ break; ++#endif ++#ifdef CONFIG_RTL8188F ++ case RTL8188F: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8188FU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8188FS; ++ break; ++#endif ++#ifdef CONFIG_RTL8188GTV ++ case RTL8188GTV: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8188GTVU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8188GTVS; ++ break; ++#endif + #ifdef CONFIG_RTL8812A + case RTL8812: + if (interface_type == RTW_USB) +@@ -12567,6 +12677,16 @@ int hal_efuse_macaddr_offset(_adapter *adapter) + addr_offset = EEPROM_MAC_ADDR_8821AE; + break; + #endif ++#ifdef CONFIG_RTL8192E ++ case RTL8192E: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8192EU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8192ES; ++ else if (interface_type == RTW_PCIE) ++ addr_offset = EEPROM_MAC_ADDR_8192EE; ++ break; ++#endif + #ifdef CONFIG_RTL8814A + case RTL8814A: + if (interface_type == RTW_USB) +@@ -12576,6 +12696,46 @@ int hal_efuse_macaddr_offset(_adapter *adapter) + break; + #endif + ++#ifdef CONFIG_RTL8822B ++ case RTL8822B: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8822BU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8822BS; ++ else if (interface_type == RTW_PCIE) ++ addr_offset = EEPROM_MAC_ADDR_8822BE; ++ break; ++#endif /* CONFIG_RTL8822B */ ++ ++#ifdef CONFIG_RTL8821C ++ case RTL8821C: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8821CU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8821CS; ++ else if (interface_type == RTW_PCIE) ++ addr_offset = EEPROM_MAC_ADDR_8821CE; ++ break; ++#endif /* CONFIG_RTL8821C */ ++ ++#ifdef CONFIG_RTL8710B ++ case RTL8710B: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8710B; ++ break; ++#endif ++ ++#ifdef CONFIG_RTL8192F ++ case RTL8192F: ++ if (interface_type == RTW_USB) ++ addr_offset = EEPROM_MAC_ADDR_8192FU; ++ else if (interface_type == RTW_SDIO) ++ addr_offset = EEPROM_MAC_ADDR_8192FS; ++ else if (interface_type == RTW_PCIE) ++ addr_offset = EEPROM_MAC_ADDR_8192FE; ++ break; ++#endif /* CONFIG_RTL8192F */ ++ + } + + if (addr_offset == -1) { +@@ -12793,6 +12953,32 @@ void rtw_bb_rf_gain_offset(_adapter *padapter) + } else + RTW_INFO("Using the default RF gain.\n"); + ++#elif defined(CONFIG_RTL8188E) ++ if (value & BIT4 && (registry_par->RegPwrTrimEnable == 1)) { ++ RTW_INFO("8188ES Offset RF Gain.\n"); ++ RTW_INFO("8188ES Offset RF Gain. EEPROMRFGainVal=0x%x\n", ++ pHalData->EEPROMRFGainVal); ++ ++ if (pHalData->EEPROMRFGainVal != 0xff) { ++ res = rtw_hal_read_rfreg(padapter, RF_PATH_A, ++ REG_RF_BB_GAIN_OFFSET, 0xffffffff); ++ ++ RTW_INFO("Offset RF Gain. reg 0x55=0x%x\n", res); ++ res &= 0xfff87fff; ++ ++ res |= (pHalData->EEPROMRFGainVal & 0x0f) << 15; ++ RTW_INFO("Offset RF Gain. res=0x%x\n", res); ++ ++ rtw_hal_write_rfreg(padapter, RF_PATH_A, ++ REG_RF_BB_GAIN_OFFSET, ++ RF_GAIN_OFFSET_MASK, res); ++ } else { ++ RTW_INFO("Offset RF Gain. EEPROMRFGainVal=0x%x == 0xff, didn't run Kfree\n", ++ pHalData->EEPROMRFGainVal); ++ } ++ } else ++ RTW_INFO("Using the default RF gain.\n"); ++#else + /* TODO: call this when channel switch */ + if (kfree_data->flag & KFREE_FLAG_ON) + rtw_rf_apply_tx_gain_offset(padapter, 6); /* input ch6 to select BB_GAIN_2G */ +@@ -13524,8 +13710,14 @@ u8 rtw_get_current_tx_sgi(_adapter *padapter, struct sta_info *psta) + return curr_tx_sgi; + + if (padapter->fix_rate == 0xff) { ++#if defined(CONFIG_RTL8188E) ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ curr_tx_sgi = hal_data->odmpriv.ra_info[psta->cmn.mac_id].rate_sgi; ++#endif /* (RATE_ADAPTIVE_SUPPORT == 1)*/ ++#else + ra_info = &psta->cmn.ra_info; + curr_tx_sgi = ((ra_info->curr_tx_rate) & 0x80) >> 7; ++#endif + } else { + curr_tx_sgi = ((padapter->fix_rate) & 0x80) >> 7; + } +@@ -13543,8 +13735,14 @@ u8 rtw_get_current_tx_rate(_adapter *padapter, struct sta_info *psta) + return rate_id; + + if (padapter->fix_rate == 0xff) { ++#if defined(CONFIG_RTL8188E) ++#if (RATE_ADAPTIVE_SUPPORT == 1) ++ rate_id = hal_data->odmpriv.ra_info[psta->cmn.mac_id].decision_rate; ++#endif /* (RATE_ADAPTIVE_SUPPORT == 1)*/ ++#else + ra_info = &psta->cmn.ra_info; + rate_id = ra_info->curr_tx_rate & 0x7f; ++#endif + } else { + rate_id = padapter->fix_rate & 0x7f; + } +@@ -13628,6 +13826,14 @@ void hal_set_crystal_cap(_adapter *adapter, u8 crystal_cap) + crystal_cap = crystal_cap & 0x3F; + + switch (rtw_get_chip_type(adapter)) { ++#if defined(CONFIG_RTL8188E) || defined(CONFIG_RTL8188F) || defined(CONFIG_RTL8188GTV) ++ case RTL8188E: ++ case RTL8188F: ++ case RTL8188GTV: ++ /* write 0x24[16:11] = 0x24[22:17] = CrystalCap */ ++ phy_set_bb_reg(adapter, REG_AFE_XTAL_CTRL, 0x007FF800, (crystal_cap | (crystal_cap << 6))); ++ break; ++#endif + #if defined(CONFIG_RTL8812A) + case RTL8812: + /* write 0x2C[30:25] = 0x2C[24:19] = CrystalCap */ +@@ -13651,6 +13857,25 @@ void hal_set_crystal_cap(_adapter *adapter, u8 crystal_cap) + /* write 0x2C[26:21] = 0x2C[20:15] = CrystalCap*/ + phy_set_bb_reg(adapter, REG_MAC_PHY_CTRL, 0x07FF8000, (crystal_cap | (crystal_cap << 6))); + break; ++#endif ++#if defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) || defined(CONFIG_RTL8192F) ++ ++ case RTL8822B: ++ case RTL8821C: ++ case RTL8192F: ++ /* write 0x28[6:1] = 0x24[30:25] = CrystalCap */ ++ crystal_cap = crystal_cap & 0x3F; ++ phy_set_bb_reg(adapter, REG_AFE_XTAL_CTRL, 0x7E000000, crystal_cap); ++ phy_set_bb_reg(adapter, REG_AFE_PLL_CTRL, 0x7E, crystal_cap); ++ break; ++#endif ++#if defined(CONFIG_RTL8710B) ++ case RTL8710B: ++ /*Change by ylb 20160728, Becase 0x2C[23:12] is removed to syson 0x60[29:18] */ ++ /* 0x2C[23:18] = 0x2C[29:24] = CrystalCap //Xo:[29:24], Xi:[23:18]*/ ++ crystal_cap = crystal_cap & 0x3F; ++ hal_set_syson_reg(adapter, REG_SYS_XTAL_CTRL0, 0x3FFC0000, (crystal_cap | (crystal_cap << 6))); ++ break; + #endif + default: + rtw_warn_on(1); +@@ -13665,6 +13890,36 @@ int hal_spec_init(_adapter *adapter) + interface_type = rtw_get_intf_type(adapter); + + switch (rtw_get_chip_type(adapter)) { ++#ifdef CONFIG_RTL8723B ++ case RTL8723B: ++ init_hal_spec_8723b(adapter); ++ break; ++#endif ++#ifdef CONFIG_RTL8703B ++ case RTL8703B: ++ init_hal_spec_8703b(adapter); ++ break; ++#endif ++#ifdef CONFIG_RTL8723D ++ case RTL8723D: ++ init_hal_spec_8723d(adapter); ++ break; ++#endif ++#ifdef CONFIG_RTL8188E ++ case RTL8188E: ++ init_hal_spec_8188e(adapter); ++ break; ++#endif ++#ifdef CONFIG_RTL8188F ++ case RTL8188F: ++ init_hal_spec_8188f(adapter); ++ break; ++#endif ++#ifdef CONFIG_RTL8188GTV ++ case RTL8188GTV: ++ init_hal_spec_8188gtv(adapter); ++ break; ++#endif + #ifdef CONFIG_RTL8812A + case RTL8812: + init_hal_spec_8812a(adapter); +@@ -13675,11 +13930,36 @@ int hal_spec_init(_adapter *adapter) + init_hal_spec_8821a(adapter); + break; + #endif ++#ifdef CONFIG_RTL8192E ++ case RTL8192E: ++ init_hal_spec_8192e(adapter); ++ break; ++#endif + #ifdef CONFIG_RTL8814A + case RTL8814A: + init_hal_spec_8814a(adapter); + break; + #endif ++#ifdef CONFIG_RTL8822B ++ case RTL8822B: ++ rtl8822b_init_hal_spec(adapter); ++ break; ++#endif ++#ifdef CONFIG_RTL8821C ++ case RTL8821C: ++ init_hal_spec_rtl8821c(adapter); ++ break; ++#endif ++#ifdef CONFIG_RTL8710B ++ case RTL8710B: ++ init_hal_spec_8710b(adapter); ++ break; ++#endif ++#ifdef CONFIG_RTL8192F ++ case RTL8192F: ++ init_hal_spec_8192f(adapter); ++ break; ++#endif + + default: + RTW_ERR("%s: unknown chip_type:%u\n" +diff --git a/drivers/staging/rtl8812au/hal/hal_intf.c b/drivers/staging/rtl8812au/hal/hal_intf.c +index b20ef6322..66a2954c5 100644 +--- a/drivers/staging/rtl8812au/hal/hal_intf.c ++++ b/drivers/staging/rtl8812au/hal/hal_intf.c +@@ -20,9 +20,20 @@ + + const u32 _chip_type_to_odm_ic_type[] = { + 0, ++ ODM_RTL8188E, ++ ODM_RTL8192E, + ODM_RTL8812, + ODM_RTL8821, ++ ODM_RTL8723B, + ODM_RTL8814A, ++ ODM_RTL8703B, ++ ODM_RTL8188F, ++ ODM_RTL8188F, ++ ODM_RTL8822B, ++ ODM_RTL8723D, ++ ODM_RTL8821C, ++ ODM_RTL8710B, ++ ODM_RTL8192F, + 0, + }; + +@@ -1402,6 +1413,7 @@ bool rtw_hal_rfkill_poll(_adapter *adapter, u8 *valid) + u8 rtw_hal_ops_check(_adapter *padapter) + { + u8 ret = _SUCCESS; ++#if 1 + /*** initialize section ***/ + if (NULL == padapter->hal_func.read_chip_version) { + rtw_hal_error_msg("read_chip_version"); +@@ -1591,6 +1603,12 @@ u8 rtw_hal_ops_check(_adapter *padapter) + rtw_hal_error_msg("hal_mac_c2h_handler"); + ret = _FAIL; + } ++#elif !defined(CONFIG_RTL8188E) ++ if (NULL == padapter->hal_func.c2h_handler) { ++ rtw_hal_error_msg("c2h_handler"); ++ ret = _FAIL; ++ } ++#endif + + #if defined(CONFIG_LPS) || defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) + if (NULL == padapter->hal_func.fill_fake_txdesc) { +diff --git a/drivers/staging/rtl8812au/hal/hal_mp.c b/drivers/staging/rtl8812au/hal/hal_mp.c +index 5dfaf91fe..7960556f2 100644 +--- a/drivers/staging/rtl8812au/hal/hal_mp.c ++++ b/drivers/staging/rtl8812au/hal/hal_mp.c +@@ -21,12 +21,39 @@ + #ifdef RTW_HALMAC + #include /* struct HAL_DATA_TYPE, RF register definition and etc. */ + #else /* !RTW_HALMAC */ ++ #ifdef CONFIG_RTL8188E ++ #include ++ #endif ++ #ifdef CONFIG_RTL8723B ++ #include ++ #endif ++ #ifdef CONFIG_RTL8192E ++ #include ++ #endif + #if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8812A) + #include + #endif + #if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + #include + #endif ++ #ifdef CONFIG_RTL8703B ++ #include ++ #endif ++ #ifdef CONFIG_RTL8723D ++ #include ++ #endif ++ #ifdef CONFIG_RTL8710B ++ #include ++ #endif ++ #ifdef CONFIG_RTL8188F ++ #include ++ #endif ++ #ifdef CONFIG_RTL8188GTV ++ #include ++ #endif ++ #ifdef CONFIG_RTL8192F ++ #include ++ #endif + #endif /* !RTW_HALMAC */ + + +diff --git a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c +index 5bfb27041..6c93e5f6f 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c ++++ b/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c +@@ -1202,6 +1202,16 @@ VOID + IN BOOLEAN is2T + ) + { ++#if (RT_PLATFORM == PLATFORM_WINDOWS) ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++#endif ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++#endif ++#endif + + u4Byte tmpReg, tmpReg2, index, i; + u1Byte path, pathbound = PATH_NUM; +@@ -1216,12 +1226,12 @@ VOID + rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN }; + +- u4Byte BB_backup[DP_BB_REG_NUM]; ++ u4Byte BB_backup[DP_BB_REG_NUM]; + u4Byte BB_REG[DP_BB_REG_NUM] = { +- rOFDM0_TRxPathEnable, rFPGA0_RFMOD, ++ rOFDM0_TRxPathEnable, rFPGA0_RFMOD, + rOFDM0_TRMuxPar, rFPGA0_XCD_RFInterfaceSW, +- rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, +- rFPGA0_XB_RFInterfaceOE}; ++ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, ++ rFPGA0_XB_RFInterfaceOE}; + u4Byte BB_settings[DP_BB_REG_NUM] = { + 0x00a05430, 0x02040000, 0x000800e4, 0x22208000, + 0x0, 0x0, 0x0}; +diff --git a/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c b/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c +index 81ea9a614..adf2cd9c6 100644 +--- a/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c ++++ b/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c +@@ -1201,29 +1201,39 @@ VOID + IN BOOLEAN is2T + ) + { ++#if (RT_PLATFORM == PLATFORM_WINDOWS) ++#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); ++#if (DM_ODM_SUPPORT_TYPE == ODM_CE) ++ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; ++#endif ++#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) ++ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; ++#endif ++#endif + + u32 tmpReg, tmpReg2, index, i; + u8 path, pathbound = PATH_NUM; + u32 AFE_backup[IQK_ADDA_REG_NUM]; +- u32 AFE_REG[IQK_ADDA_REG_NUM] = { +- rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ u32 AFE_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, + rRx_Wait_CCA, rTx_CCK_RFON, +- rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, +- rTx_To_Tx, rRx_CCK, ++ rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, +- rRx_TO_Rx, rStandby, ++ rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN }; + +- u32 BB_backup[DP_BB_REG_NUM]; ++ u32 BB_backup[DP_BB_REG_NUM]; + u32 BB_REG[DP_BB_REG_NUM] = { +- rOFDM0_TRxPathEnable, rFPGA0_RFMOD, ++ rOFDM0_TRxPathEnable, rFPGA0_RFMOD, + rOFDM0_TRMuxPar, rFPGA0_XCD_RFInterfaceSW, + rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, +- rFPGA0_XB_RFInterfaceOE}; ++ rFPGA0_XB_RFInterfaceOE}; + u32 BB_settings[DP_BB_REG_NUM] = { + 0x00a05430, 0x02040000, 0x000800e4, 0x22208000, +- 0x0, 0x0, 0x0}; ++ 0x0, 0x0, 0x0}; + + u32 RF_backup[DP_PATH_NUM][DP_RF_REG_NUM]; + u32 RF_REG[DP_RF_REG_NUM] = { +diff --git a/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c b/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c +index b2427fe25..5c0bf0d03 100644 +--- a/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c ++++ b/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c +@@ -1585,9 +1585,9 @@ HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM); + // Reset USB mode switch setting + rtw_write8(Adapter, REG_SDIO_CTRL_8814A, 0x0); + rtw_write8(Adapter, REG_ACLK_MON, 0x0); +- ++ + //RT_TRACE(COMP_INIT, DBG_TRACE, ("InitializeAdapter8188EUsb() <====\n")); +- ++ + HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK); + // 2010/08/26 MH Merge from 8192CE. + if(pwrctrlpriv->rf_pwrstate == rf_on) +@@ -2048,19 +2048,19 @@ InitAdapterVariablesByPROM_8814AU( + hal_ReadTxPowerInfo8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadBoardType8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_Read_TRX_antenna_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); +- ++ + // + // Read Bluetooth co-exist and initialize + // + hal_EfuseParseBTCoexistInfo8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); +- ++ + hal_ReadChannelPlan8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_EfuseParseXtal_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadThermalMeter_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadRemoteWakeup_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadAntennaDiversity8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadRFEType_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); +- ++ + ReadLEDSetting_8814AU(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + + hal_ReadUsbModeSwitch_8814AU(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); +@@ -2074,7 +2074,7 @@ InitAdapterVariablesByPROM_8814AU( + static void hal_ReadPROMContent_8814A( + IN PADAPTER Adapter + ) +-{ ++{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + u8 eeValue; + +@@ -2097,7 +2097,7 @@ ReadAdapterInfo8814AU( + ) + { + Hal_InitEfuseVars_8814A(Adapter); +- ++ + /* Read all content in Efuse/EEPROM. */ + hal_ReadPROMContent_8814A(Adapter); + +@@ -2118,17 +2118,17 @@ void UpdateInterruptMask8814AU(PADAPTER padapter,u8 bHIMR0 ,u32 AddMSR, u32 Remo + himr = &(pHalData->IntrMask[0]); + else + himr = &(pHalData->IntrMask[1]); +- ++ + if (AddMSR) + *himr |= AddMSR; + + if (RemoveMSR) + *himr &= (~RemoveMSR); + +- if(bHIMR0) ++ if(bHIMR0) + rtw_write32(padapter, REG_HIMR0_8814A, *himr); + else +- rtw_write32(padapter, REG_HIMR1_8814A, *himr); ++ rtw_write32(padapter, REG_HIMR1_8814A, *himr); + + } + +@@ -2223,7 +2223,7 @@ u8 SetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val) + + void GetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val) + { +- HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + switch(variable) + { +@@ -2340,7 +2340,7 @@ static void rtl8814au_init_default_value(_adapter * padapter) + } + + static u8 rtl8814au_ps_func(PADAPTER Adapter,HAL_INTF_PS_FUNC efunc_id, u8 *val) +-{ ++{ + u8 bResult = _TRUE; + switch(efunc_id){ + +@@ -2365,7 +2365,7 @@ void rtl8814au_set_hal_ops(_adapter * padapter) + + pHalFunc->hal_power_on = _InitPowerOn_8814AU; + pHalFunc->hal_power_off = hal_carddisable_8814; +- ++ + pHalFunc->hal_init = &rtl8814au_hal_init; + pHalFunc->hal_deinit = &rtl8814au_hal_deinit; + +@@ -2384,11 +2384,11 @@ void rtl8814au_set_hal_ops(_adapter * padapter) + // pHalFunc->InitSwLeds = NULL; + // pHalFunc->DeInitSwLeds = NULL; + #endif//CONFIG_RTW_LED +- ++ + pHalFunc->init_default_value = &rtl8814au_init_default_value; + pHalFunc->intf_chip_configure = &rtl8814au_interface_configure; + pHalFunc->read_adapter_info = &ReadAdapterInfo8814AU; +- ++ + pHalFunc->set_hw_reg_handler = &SetHwReg8814AU; + pHalFunc->GetHwRegHandler = &GetHwReg8814AU; + pHalFunc->get_hal_def_var_handler = &GetHalDefVar8814AUsb; +diff --git a/drivers/staging/rtl8812au/include/gspi_osintf.h b/drivers/staging/rtl8812au/include/gspi_osintf.h +index 2bff22ffd..6393f779d 100644 +--- a/drivers/staging/rtl8812au/include/gspi_osintf.h ++++ b/drivers/staging/rtl8812au/include/gspi_osintf.h +@@ -15,4 +15,11 @@ + #ifndef __SDIO_OSINTF_H__ + #define __SDIO_OSINTF_H__ + ++ ++#ifdef PLATFORM_OS_CE ++ extern NDIS_STATUS ce_sd_get_dev_hdl(PADAPTER padapter); ++ SD_API_STATUS ce_sd_int_callback(SD_DEVICE_HANDLE hDevice, PADAPTER padapter); ++ extern void sd_setup_irs(PADAPTER padapter); ++#endif ++ + #endif +diff --git a/drivers/staging/rtl8812au/include/rtl8812a_recv.h b/drivers/staging/rtl8812au/include/rtl8812a_recv.h +index 07b824550..bf1d4b651 100644 +--- a/drivers/staging/rtl8812au/include/rtl8812a_recv.h ++++ b/drivers/staging/rtl8812au/include/rtl8812a_recv.h +@@ -18,6 +18,9 @@ + #if defined(CONFIG_USB_HCI) + + #ifndef MAX_RECVBUF_SZ ++ #ifdef PLATFORM_OS_CE ++ #define MAX_RECVBUF_SZ (8192+1024) /* 8K+1k */ ++ #else + #ifndef CONFIG_MINIMAL_MEMORY_USAGE + #ifdef CONFIG_PREALLOC_RX_SKB_BUFFER + #define MAX_RECVBUF_SZ (rtw_rtkm_get_buff_size()) /*depend rtkm*/ +@@ -36,6 +39,7 @@ + #else + #define MAX_RECVBUF_SZ (4000) /* about 4K */ + #endif ++ #endif + #endif /* !MAX_RECVBUF_SZ */ + + #elif defined(CONFIG_PCI_HCI) +diff --git a/drivers/staging/rtl8812au/include/rtl8814a_recv.h b/drivers/staging/rtl8812au/include/rtl8814a_recv.h +index f723c0a10..c6792d8a5 100644 +--- a/drivers/staging/rtl8812au/include/rtl8814a_recv.h ++++ b/drivers/staging/rtl8812au/include/rtl8814a_recv.h +@@ -18,6 +18,9 @@ + #if defined(CONFIG_USB_HCI) + + #ifndef MAX_RECVBUF_SZ ++ #ifdef PLATFORM_OS_CE ++ #define MAX_RECVBUF_SZ (8192+1024) /* 8K+1k */ ++ #else + #ifndef CONFIG_MINIMAL_MEMORY_USAGE + #ifdef CONFIG_PLATFORM_MSTAR + #define MAX_RECVBUF_SZ (8192) /* 8K */ +@@ -32,6 +35,7 @@ + #else + #define MAX_RECVBUF_SZ (4000) /* about 4K */ + #endif ++ #endif + #endif /* !MAX_RECVBUF_SZ */ + + #elif defined(CONFIG_PCI_HCI) +diff --git a/drivers/staging/rtl8812au/include/rtw_cmd.h b/drivers/staging/rtl8812au/include/rtw_cmd.h +index 0f549a65a..4df67602f 100644 +--- a/drivers/staging/rtl8812au/include/rtw_cmd.h ++++ b/drivers/staging/rtl8812au/include/rtw_cmd.h +@@ -26,7 +26,11 @@ + #define MAX_RSPSZ 512 + #define MAX_EVTSZ 1024 + +-#define CMDBUFF_ALIGN_SZ 512 ++#ifdef PLATFORM_OS_CE ++ #define CMDBUFF_ALIGN_SZ 4 ++#else ++ #define CMDBUFF_ALIGN_SZ 512 ++#endif + + struct cmd_obj { + _adapter *padapter; +@@ -110,6 +114,9 @@ struct evt_priv { + #if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + u8 *c2h_mem; + u8 *allocated_c2h_mem; ++#ifdef PLATFORM_OS_XP ++ PMDL pc2h_mdl; ++#endif + #endif + + }; +diff --git a/drivers/staging/rtl8812au/include/rtw_debug.h b/drivers/staging/rtl8812au/include/rtw_debug.h +index 93f9e6e3c..e3562ca4a 100644 +--- a/drivers/staging/rtl8812au/include/rtw_debug.h ++++ b/drivers/staging/rtl8812au/include/rtw_debug.h +@@ -28,6 +28,10 @@ enum { + + #define DRIVER_PREFIX "RTW: " + ++#ifdef PLATFORM_OS_CE ++extern void rtl871x_cedbg(const char *fmt, ...); ++#endif ++ + #define RTW_PRINT(x, ...) do {} while (0) + #define RTW_ERR(x, ...) do {} while (0) + #define RTW_WARN(x,...) do {} while (0) +diff --git a/drivers/staging/rtl8812au/include/rtw_recv.h b/drivers/staging/rtl8812au/include/rtw_recv.h +index ee0ec77cb..d6422a1d2 100644 +--- a/drivers/staging/rtl8812au/include/rtw_recv.h ++++ b/drivers/staging/rtl8812au/include/rtw_recv.h +@@ -19,6 +19,19 @@ + #define RTW_RX_MSDU_ACT_INDICATE BIT0 + #define RTW_RX_MSDU_ACT_FORWARD BIT1 + ++#ifdef PLATFORM_OS_XP ++ #ifdef CONFIG_SDIO_HCI ++ #define NR_RECVBUFF 1024/* 512 */ /* 128 */ ++ #else ++ #define NR_RECVBUFF (16) ++ #endif ++#elif defined(PLATFORM_OS_CE) ++ #ifdef CONFIG_SDIO_HCI ++ #define NR_RECVBUFF (128) ++ #else ++ #define NR_RECVBUFF (4) ++ #endif ++#else /* PLATFORM_LINUX /PLATFORM_BSD */ + + #include + +@@ -42,6 +55,7 @@ + #ifdef CONFIG_RTW_NAPI + #define RTL_NAPI_WEIGHT (32) + #endif ++#endif + + #if defined(CONFIG_RTL8821C) && defined(CONFIG_SDIO_HCI) && defined(CONFIG_RECV_THREAD_MODE) + #ifdef NR_RECVBUFF +@@ -340,6 +354,17 @@ struct recv_priv { + + _adapter *adapter; + ++#ifdef PLATFORM_WINDOWS ++ _nic_hdl RxPktPoolHdl; ++ _nic_hdl RxBufPoolHdl; ++ ++#ifdef PLATFORM_OS_XP ++ PMDL pbytecnt_mdl; ++#endif ++ uint counter; /* record the number that up-layer will return to drv; only when counter==0 can we release recv_priv */ ++ NDIS_EVENT recv_resource_evt ; ++#endif ++ + + u32 is_any_non_be_pkts; + +@@ -508,11 +533,20 @@ struct recv_buf { + + #ifdef CONFIG_USB_HCI + +-#if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) ++#if defined(PLATFORM_OS_XP) || defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) + PURB purb; + dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */ + u32 alloc_sz; + #endif ++ ++#ifdef PLATFORM_OS_XP ++ PIRP pirp; ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ USB_TRANSFER usb_transfer_read_port; ++#endif ++ + u8 irp_pending; + int transfer_len; + +diff --git a/drivers/staging/rtl8812au/include/rtw_xmit.h b/drivers/staging/rtl8812au/include/rtw_xmit.h +index 69ec205f4..660a29ae2 100644 +--- a/drivers/staging/rtl8812au/include/rtw_xmit.h ++++ b/drivers/staging/rtl8812au/include/rtw_xmit.h +@@ -60,6 +60,10 @@ + #endif + #define NR_XMITBUFF (128) + #endif ++ ++#ifdef PLATFORM_OS_CE ++ #define XMITBUF_ALIGN_SZ 4 ++#else + #ifdef CONFIG_PCI_HCI + #define XMITBUF_ALIGN_SZ 4 + #else +@@ -68,6 +72,7 @@ + #else + #define XMITBUF_ALIGN_SZ 512 + #endif ++ #endif + #endif + + /* xmit extension buff defination */ +diff --git a/drivers/staging/rtl8812au/include/sdio_osintf.h b/drivers/staging/rtl8812au/include/sdio_osintf.h +index 2bff22ffd..7c2abd14d 100644 +--- a/drivers/staging/rtl8812au/include/sdio_osintf.h ++++ b/drivers/staging/rtl8812au/include/sdio_osintf.h +@@ -15,4 +15,11 @@ + #ifndef __SDIO_OSINTF_H__ + #define __SDIO_OSINTF_H__ + ++ ++#ifdef PLATFORM_OS_CE ++extern NDIS_STATUS ce_sd_get_dev_hdl(PADAPTER padapter); ++SD_API_STATUS ce_sd_int_callback(SD_DEVICE_HANDLE hDevice, PADAPTER padapter); ++extern void sd_setup_irs(PADAPTER padapter); ++#endif ++ + #endif +diff --git a/drivers/staging/rtl8812au/os_dep/osdep_service.c b/drivers/staging/rtl8812au/os_dep/osdep_service.c +index 7d10c0ce5..7553f2c98 100644 +--- a/drivers/staging/rtl8812au/os_dep/osdep_service.c ++++ b/drivers/staging/rtl8812au/os_dep/osdep_service.c +@@ -1135,6 +1135,11 @@ void _rtw_init_sema(_sema *sema, int init_val) + sema_init(sema, init_val, "rtw_drv"); + #endif + ++#ifdef PLATFORM_OS_CE ++ if (*sema == NULL) ++ *sema = CreateSemaphore(NULL, init_val, SEMA_UPBND, NULL); ++#endif ++ + } + + void _rtw_free_sema(_sema *sema) +@@ -1142,6 +1147,9 @@ void _rtw_free_sema(_sema *sema) + #ifdef PLATFORM_FREEBSD + sema_destroy(sema); + #endif ++#ifdef PLATFORM_OS_CE ++ CloseHandle(*sema); ++#endif + + } + +@@ -1156,6 +1164,10 @@ void _rtw_up_sema(_sema *sema) + #ifdef PLATFORM_FREEBSD + sema_post(sema); + #endif ++ ++#ifdef PLATFORM_OS_CE ++ ReleaseSemaphore(*sema, 1, NULL); ++#endif + } + + u32 _rtw_down_sema(_sema *sema) +@@ -1173,6 +1185,13 @@ u32 _rtw_down_sema(_sema *sema) + sema_wait(sema); + return _SUCCESS; + #endif ++ ++#ifdef PLATFORM_OS_CE ++ if (WAIT_OBJECT_0 == WaitForSingleObject(*sema, INFINITE)) ++ return _SUCCESS; ++ else ++ return _FAIL; ++#endif + } + + #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) +@@ -1192,6 +1211,10 @@ inline void kthread_thread_exit(_completion *comp) + #ifdef PLATFORM_FREEBSD + printf("%s", "RTKTHREAD_exit"); + #endif ++ ++#ifdef PLATFORM_OS_CE ++ ExitThread(STATUS_SUCCESS); ++#endif + } + + inline void _rtw_init_completion(_completion *comp) +@@ -1227,6 +1250,10 @@ void _rtw_mutex_init(_mutex *pmutex) + #ifdef PLATFORM_FREEBSD + mtx_init(pmutex, "", NULL, MTX_DEF | MTX_RECURSE); + #endif ++ ++#ifdef PLATFORM_OS_CE ++ *pmutex = CreateMutex(NULL, _FALSE, NULL); ++#endif + } + + void _rtw_mutex_free(_mutex *pmutex); +@@ -1243,6 +1270,10 @@ void _rtw_mutex_free(_mutex *pmutex) + sema_destroy(pmutex); + #endif + ++#endif ++ ++#ifdef PLATFORM_OS_CE ++ + #endif + } + +-- +2.41.0 + + +From aae6908f32010c261877371d891c8163a1482572 Mon Sep 17 00:00:00 2001 +From: kimocoder +Date: Sun, 2 Jul 2023 02:50:24 +0200 +Subject: [PATCH 02/13] Address warning in createbss_hdl() + +--- + drivers/staging/rtl8812au/core/rtw_mlme_ext.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/rtl8812au/core/rtw_mlme_ext.c b/drivers/staging/rtl8812au/core/rtw_mlme_ext.c +index 01136fb37..57e7536c0 100644 +--- a/drivers/staging/rtl8812au/core/rtw_mlme_ext.c ++++ b/drivers/staging/rtl8812au/core/rtw_mlme_ext.c +@@ -13941,14 +13941,14 @@ u8 createbss_hdl(_adapter *padapter, u8 *pbuf) + flush_all_cam_entry(padapter); + + pdev_network->Length = get_WLAN_BSSID_EX_sz(pdev_network); +- _rtw_memcpy(pnetwork, pdev_network, FIELD_OFFSET(WLAN_BSSID_EX, IELength)); +- pnetwork->IELength = pdev_network->IELength; +- +- if (pnetwork->IELength > MAX_IE_SZ) { ++ if (FIELD_OFFSET(WLAN_BSSID_EX, IELength) > MAX_IE_SZ) { + ret = H2C_PARAMETERS_ERROR; + goto ibss_post_hdl; + } + ++ memcpy(pnetwork, pdev_network, FIELD_OFFSET(WLAN_BSSID_EX, IELength)); ++ pnetwork->IELength = pdev_network->IELength; ++ + _rtw_memcpy(pnetwork->IEs, pdev_network->IEs, pnetwork->IELength); + start_create_ibss(padapter); + } else { +-- +2.41.0 + + +From c80d9acb9ea350300cfe0e06065818640d989583 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Carlos=20Garc=C3=A9s?= +Date: Sun, 2 Jul 2023 12:11:29 +0000 +Subject: [PATCH 03/13] Use eth_hw_addr_set instead of dev_addr_set + +--- + drivers/staging/rtl8812au/include/drv_types_linux.h | 6 +++++- + drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c | 2 +- + drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c | 2 +- + drivers/staging/rtl8812au/os_dep/linux/os_intfs.c | 4 ++-- + drivers/staging/rtl8812au/os_dep/osdep_service.c | 2 +- + 5 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/staging/rtl8812au/include/drv_types_linux.h b/drivers/staging/rtl8812au/include/drv_types_linux.h +index 3d428d4d0..97c8576a2 100644 +--- a/drivers/staging/rtl8812au/include/drv_types_linux.h ++++ b/drivers/staging/rtl8812au/include/drv_types_linux.h +@@ -16,7 +16,11 @@ + #define __DRV_TYPES_LINUX_H__ + + #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) +-#define dev_addr_set(netdev, ethdata) _rtw_memcpy(netdev->dev_addr, ethdata, ETH_ALEN) ++/* Porting from linux kernel v5.15 48eab831ae8b9f7002a533fa4235eed63ea1f1a3 3f6cffb8604b537e3d7ea040d7f4368689638eaf*/ ++static inline void eth_hw_addr_set(struct net_device *dev, const u8 *addr) ++{ ++ memcpy(dev->dev_addr, addr, ETH_ALEN) ++} + #endif + + #endif +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c +index b2a7560d9..c5776117f 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c +@@ -9725,7 +9725,7 @@ static int rtw_mp_efuse_set(struct net_device *dev, + rtw_hal_read_chip_info(padapter); + /* set mac addr*/ + rtw_macaddr_cfg(adapter_mac_addr(padapter), get_hal_mac_addr(padapter)); +- dev_addr_set(padapter->pnetdev, get_hal_mac_addr(padapter)); /* set mac addr to net_device */ ++ eth_hw_addr_set(padapter->pnetdev, get_hal_mac_addr(padapter)); /* set mac addr to net_device */ + + #ifdef CONFIG_P2P + rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter)); +diff --git a/drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c b/drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c +index 771c6272e..74f098277 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c +@@ -404,7 +404,7 @@ int hostapd_mode_init(_adapter *padapter) + mac[4] = 0x11; + mac[5] = 0x12; + +- dev_addr_set(pnetdev, mac); ++ eth_hw_addr_set(pnetdev, mac); + + + rtw_netif_carrier_off(pnetdev); +diff --git a/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c b/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c +index 6d2801357..2dadae098 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c +@@ -1285,7 +1285,7 @@ static int rtw_net_set_mac_address(struct net_device *pnetdev, void *addr) + } + + _rtw_memcpy(adapter_mac_addr(padapter), sa->sa_data, ETH_ALEN); /* set mac addr to adapter */ +- dev_addr_set(pnetdev, sa->sa_data); /* set mac addr to net_device */ ++ eth_hw_addr_set(pnetdev, sa->sa_data); /* set mac addr to net_device */ + + #if 0 + if (rtw_is_hw_init_completed(padapter)) { +@@ -1754,7 +1754,7 @@ int rtw_os_ndev_register(_adapter *adapter, const char *name) + /* alloc netdev name */ + rtw_init_netdev_name(ndev, name); + +- dev_addr_set(ndev, adapter_mac_addr(adapter)); ++ eth_hw_addr_set(ndev, adapter_mac_addr(adapter)); + #if defined(CONFIG_NET_NS) + dev_net_set(ndev, wiphy_net(adapter_to_wiphy(adapter))); + #endif //defined(CONFIG_NET_NS) +diff --git a/drivers/staging/rtl8812au/os_dep/osdep_service.c b/drivers/staging/rtl8812au/os_dep/osdep_service.c +index 7553f2c98..d24b3e1f0 100644 +--- a/drivers/staging/rtl8812au/os_dep/osdep_service.c ++++ b/drivers/staging/rtl8812au/os_dep/osdep_service.c +@@ -2299,7 +2299,7 @@ int rtw_change_ifname(_adapter *padapter, const char *ifname) + + rtw_init_netdev_name(pnetdev, ifname); + +- dev_addr_set(pnetdev, adapter_mac_addr(padapter)); ++ eth_hw_addr_set(pnetdev, adapter_mac_addr(padapter)); + + if (rtnl_lock_needed) + ret = register_netdev(pnetdev); +-- +2.41.0 + + +From 8084e3fe2acd66f315c221184acea9576039fd35 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Carlos=20Garc=C3=A9s?= +Date: Mon, 3 Jul 2023 18:19:34 +0200 +Subject: [PATCH 04/13] Fix compilation error on kernels < 5.15 + +--- + drivers/staging/rtl8812au/include/drv_types_linux.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/rtl8812au/include/drv_types_linux.h b/drivers/staging/rtl8812au/include/drv_types_linux.h +index 97c8576a2..6264a4d30 100644 +--- a/drivers/staging/rtl8812au/include/drv_types_linux.h ++++ b/drivers/staging/rtl8812au/include/drv_types_linux.h +@@ -19,7 +19,7 @@ + /* Porting from linux kernel v5.15 48eab831ae8b9f7002a533fa4235eed63ea1f1a3 3f6cffb8604b537e3d7ea040d7f4368689638eaf*/ + static inline void eth_hw_addr_set(struct net_device *dev, const u8 *addr) + { +- memcpy(dev->dev_addr, addr, ETH_ALEN) ++ memcpy(dev->dev_addr, addr, ETH_ALEN); + } + #endif + +-- +2.41.0 + + +From b042f942026520d86350983bee7419267ba35e6c Mon Sep 17 00:00:00 2001 +From: Christian Stewart +Date: Mon, 3 Jul 2023 13:54:27 -0700 +Subject: [PATCH 05/13] ioctl_cfg80211: fix build against kernels < 4.10.x + +Kernel 4.10.x adjusted cfg80211_connect_bss to accept a timeout as the last +argument. Add a conditional statement which removes this extra parameter if the +kernel is less than version 4.10.x to fix build errors against version 4.9.x. + +Note that the Jetson TX2 kernel is still version 4.9.x even though this version +is technically deprecated upstream. + +Signed-off-by: Christian Stewart +--- + .../staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index 0d2a01326..6cf89b24c 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -1193,12 +1193,22 @@ void rtw_cfg80211_indicate_connect(_adapter *padapter) + struct cfg80211_bss *bss; + bss = cfg80211_get_bss(pwdev->wiphy, NULL, cur_network->network.MacAddress, NULL, 0, + IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); ++ #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) + cfg80211_connect_bss(wdev_to_ndev(pwdev), cur_network->network.MacAddress, bss + , pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + 2 + , pmlmepriv->assoc_req_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 2 + , pmlmepriv->assoc_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6 + , pmlmepriv->assoc_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6 + , WLAN_STATUS_SUCCESS, GFP_ATOMIC, NL80211_TIMEOUT_UNSPECIFIED); ++ #else // (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) ++ // Linux < 4.10.x does not accept the last argument (timeout). ++ cfg80211_connect_bss(wdev_to_ndev(pwdev), cur_network->network.MacAddress, bss ++ , pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + 2 ++ , pmlmepriv->assoc_req_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 2 ++ , pmlmepriv->assoc_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6 ++ , pmlmepriv->assoc_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6 ++ , WLAN_STATUS_SUCCESS, GFP_ATOMIC); ++ #endif + } + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) || defined(COMPAT_KERNEL_RELEASE) + RTW_INFO("pwdev->sme_state(a)=%d\n", pwdev->sme_state); +-- +2.41.0 + + +From 1d7babf42e6f7bd41f772ff9b78f1c242cc9a9c4 Mon Sep 17 00:00:00 2001 +From: seppzer0 +Date: Wed, 19 Jul 2023 00:12:47 +0200 +Subject: [PATCH 06/13] Add an extra definition for cfg80211_connect_bss() + usage + +--- + drivers/staging/rtl8812au/Makefile | 2 ++ + drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/rtl8812au/Makefile b/drivers/staging/rtl8812au/Makefile +index aa3cd789c..127850786 100644 +--- a/drivers/staging/rtl8812au/Makefile ++++ b/drivers/staging/rtl8812au/Makefile +@@ -851,6 +851,8 @@ EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC -DCONFIG_RADIO_WORK + #EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE + EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT + EXTRA_CFLAGS += -DCONFIG_P2P_IPS ++# A special rule for cfg80211_connect_bss() to receive all 10 arguments in an Android build ++EXTRA_CFLAGS += -DCONFIG_CFG80211_CONNECT_BSS_ANDROID + endif + + ifeq ($(CONFIG_PLATFORM_ANDROID_X86), y) +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index 6cf89b24c..24cd0c540 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -1193,7 +1193,7 @@ void rtw_cfg80211_indicate_connect(_adapter *padapter) + struct cfg80211_bss *bss; + bss = cfg80211_get_bss(pwdev->wiphy, NULL, cur_network->network.MacAddress, NULL, 0, + IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); +- #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) || defined(CONFIG_CFG80211_CONNECT_BSS_ANDROID)) + cfg80211_connect_bss(wdev_to_ndev(pwdev), cur_network->network.MacAddress, bss + , pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + 2 + , pmlmepriv->assoc_req_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 2 +-- +2.41.0 + + +From 123f15677922b20434acdd63cfc96de4772dd08b Mon Sep 17 00:00:00 2001 +From: kimocoder +Date: Sun, 29 Oct 2023 15:15:50 +0100 +Subject: [PATCH 07/13] Fix the VFS internal message + +--- + drivers/staging/rtl8812au/os_dep/linux/usb_intf.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +index b319e58c5..2ef96b386 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +@@ -1640,6 +1640,8 @@ static void __exit rtw_drv_halt(void) + rtw_mstat_dump(RTW_DBGDUMP); + } + ++MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); ++ + module_init(rtw_drv_entry); + module_exit(rtw_drv_halt); + +-- +2.41.0 + + +From 7e786378cc760e2e37d38669ba18488a1be5b139 Mon Sep 17 00:00:00 2001 +From: kimocoder +Date: Sun, 29 Oct 2023 16:29:30 +0100 +Subject: [PATCH 08/13] Add kernel v6.6 support + +--- + drivers/staging/rtl8812au/Makefile | 2 ++ + .../rtl8812au/os_dep/linux/ioctl_cfg80211.c | 19 ++++++++++++------- + .../rtl8812au/os_dep/linux/wifi_regd.c | 4 ++++ + 3 files changed, 18 insertions(+), 7 deletions(-) + +diff --git a/drivers/staging/rtl8812au/Makefile b/drivers/staging/rtl8812au/Makefile +index 127850786..ed3126ec3 100644 +--- a/drivers/staging/rtl8812au/Makefile ++++ b/drivers/staging/rtl8812au/Makefile +@@ -9,6 +9,8 @@ EXTRA_CFLAGS += -Wno-implicit-fallthrough + EXTRA_CFLAGS += -Wno-cast-function-type + #EXTRA_CFLAGS += -Wno-error=cast-function-type + #EXTRA_CFLAGS += -Wno-parentheses-equality ++EXTRA_CFLAGS += -Wno-error=incompatible-pointer-types ++EXTRA_CFLAGS += -Wno-stringop-overread + #EXTRA_CFLAGS += -Wno-pointer-bool-conversion + EXTRA_CFLAGS += -Wno-unknown-pragmas + #EXTRA_CFLAGS += -Wno-unused +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index 24cd0c540..af77f4c5d 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -478,7 +478,7 @@ u8 rtw_cfg80211_ch_switch_notify(_adapter *adapter, u8 ch, u8 bw, u8 offset, + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) + cfg80211_ch_switch_notify(adapter->pnetdev, &chdef, 0, 0); +-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5,19, 2)) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) + cfg80211_ch_switch_notify(adapter->pnetdev, &chdef, 0); + #else + cfg80211_ch_switch_notify(adapter->pnetdev, &chdef); +@@ -5267,10 +5267,10 @@ static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *nd + return ret; + } + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) +-static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev, unsigned int link_id) +-#else ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 2)) + static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) ++#else ++static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev, unsigned int link_id) + #endif + { + _adapter *adapter = (_adapter *)rtw_netdev_priv(ndev); +@@ -7813,6 +7813,9 @@ static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy, + const u8 *peer, + #else + u8 *peer, ++#endif ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) ++ int link_id, + #endif + u8 action_code, + u8 dialog_token, +@@ -10155,12 +10158,12 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + .del_pmksa = cfg80211_rtw_del_pmksa, + .flush_pmksa = cfg80211_rtw_flush_pmksa, + +-#ifdef CONFIG_AP_MODE + #ifdef RTW_VIRTUAL_INT + .add_virtual_intf = cfg80211_rtw_add_virtual_intf, + .del_virtual_intf = cfg80211_rtw_del_virtual_intf, + #endif + ++#ifdef CONFIG_AP_MODE + #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE) + .add_beacon = cfg80211_rtw_add_beacon, + .set_beacon = cfg80211_rtw_set_beacon, +@@ -10432,7 +10435,7 @@ void rtw_wdev_unregister(struct wireless_dev *wdev) + rtw_cfg80211_indicate_scan_done(adapter, _TRUE); + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) || defined(COMPAT_KERNEL_RELEASE) +- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) + if (wdev->links[0].client.current_bss) { + #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) + if (wdev->connected) { +@@ -10473,9 +10476,10 @@ int rtw_cfg80211_ndev_res_alloc(_adapter *adapter) + rtw_wiphy_free(wiphy); + adapter->wiphy = NULL; + } +-#endif + + exit: ++#endif ++ + return ret; + } + +@@ -10489,6 +10493,7 @@ void rtw_cfg80211_ndev_res_free(_adapter *adapter) + #endif + } + ++ + int rtw_cfg80211_ndev_res_register(_adapter *adapter) + { + int ret = _FAIL; +diff --git a/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c b/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c +index 5f2f90506..a36b7dcd0 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c +@@ -396,6 +396,10 @@ static void _rtw_regd_init_wiphy(struct rtw_regulatory *reg, struct wiphy *wiphy + wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS; + #endif + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) ++ wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; ++#endif ++ + regd = _rtw_regdomain_select(reg); + wiphy_apply_custom_regulatory(wiphy, regd); + +-- +2.41.0 + + +From 5e3274cbffe62f0baf4bd39a36af7edd3d359e37 Mon Sep 17 00:00:00 2001 +From: Christian Sarre +Date: Tue, 31 Oct 2023 21:04:54 +0200 +Subject: [PATCH 09/13] Fix build on 6.x kernels. + +It was broken due to kernel changes backported from 6.5 (torvalds/linux@e8c2af6). +Changes have been tested on the following configurations and observed to build: + - Debian Bullseye, kernel 6.1.38-4 (bullseye-backports) + - Debian Bookworm, kernel 6.1.52-1 + - Ubuntu 23.04 Lunar, kernel 6.2.0-36 + +There are also other kernel versions which are affected up to some point in their history, +but there were a few reasons I ended up not including them: + - Kernel 6.2: Not in use on Debian, likely skipped in favor of 6.4+. Ubuntu though has backported the change to 6.2 on Lunar. + - Kernel 6.3: Not in use on Debian/Ubuntu, seems to have been skipped in favor of 6.4/6.5+. + - Kernel 6.4: Not in use on Ubuntu. Debian Bookworm has this available in backports, but they now also offer 6.5 which does not have the issue. + +In case someone tries to build this module running kernel 6.2 on something other than Ubuntu, this fix is most likely necessary. +--- + drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c b/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c +index a36b7dcd0..2f642f4c4 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c +@@ -396,7 +396,7 @@ static void _rtw_regd_init_wiphy(struct rtw_regulatory *reg, struct wiphy *wiphy + wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS; + #endif + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 39)) + wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; + #endif + +-- +2.41.0 + + +From 517a6f38648501a02c97cac3ddc3be8e61843cd4 Mon Sep 17 00:00:00 2001 +From: Christian Sarre +Date: Wed, 1 Nov 2023 09:49:57 +0200 +Subject: [PATCH 10/13] Fix build on Ubuntu 23.04 (kernel 6.2). + +This is done by specifying the ranges for 6.3 and 6.4 versions which need the fix. +Kernel 6.2, to my knowledge, is not used in other popular distros than Ubuntu. + +Ubuntu had backported the change from kernel 6.5 to 6.2, which is why this is needed. + +Added a comment instructing what to do if one wants to build the module +running kernel 6.2 on something else than Ubuntu. +--- + drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c b/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c +index 2f642f4c4..45c5bd1a9 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c +@@ -396,7 +396,15 @@ static void _rtw_regd_init_wiphy(struct rtw_regulatory *reg, struct wiphy *wiphy + wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS; + #endif + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 39)) ++/* ++ * Ubuntu backported a specific upstream change to kernel 6.2 while others skipped 6.2 altogether. ++ * If build fails on kernel 6.2.x and you're not using Ubuntu, ++ * try changing the version "(6, 3, 0)" below to "(6, 2, 0)". ++ */ ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 39)) \ ++ || (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 13)) \ ++ || (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 4)) + wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; + #endif + +-- +2.41.0 + + +From e6da86ee01805bb64cf2db498767984b90d79877 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Thu, 2 Nov 2023 20:36:13 +0100 +Subject: [PATCH 11/13] ioctl_cfg80211: Add support for standard RSSI + notifications + +Currently background scanning with wpa_supplicant does not work very +well because rtl8812au does not notify it about changes to RSSI. To +fix this: + +* Implement the cfg80211_ops::set_cqm_rssi_config operation to set the + parameters for RSSI notifications. +* Add a rtw_cfg80211_cqm_rssi_update() function that calls + cfg80211_cqm_rssi_notify() if the RSSI has changed significantly + (based on those parameters). +* When connected in infrastructure mode, call + rtw_cfg80211_cqm_rssi_update() after processing a beacon and + updating the RSSI. + +Signed-off-by: Ben Hutchings +--- + drivers/staging/rtl8812au/core/rtw_mlme_ext.c | 6 +++ + .../rtl8812au/os_dep/linux/ioctl_cfg80211.c | 42 +++++++++++++++++++ + .../rtl8812au/os_dep/linux/ioctl_cfg80211.h | 7 ++++ + 3 files changed, 55 insertions(+) + +diff --git a/drivers/staging/rtl8812au/core/rtw_mlme_ext.c b/drivers/staging/rtl8812au/core/rtw_mlme_ext.c +index 57e7536c0..527e06dd5 100644 +--- a/drivers/staging/rtl8812au/core/rtw_mlme_ext.c ++++ b/drivers/staging/rtl8812au/core/rtw_mlme_ext.c +@@ -1971,6 +1971,12 @@ unsigned int OnBeacon(_adapter *padapter, union recv_frame *precv_frame) + #if 0 /* move to validate_recv_mgnt_frame */ + psta->sta_stats.rx_mgnt_pkts++; + #endif ++ ++#if defined(CONFIG_IOCTL_CFG80211) ++ rtw_cfg80211_cqm_rssi_update( ++ padapter, ++ pmlmepriv->cur_network_scanned->network.Rssi); ++#endif + } + + } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +index af77f4c5d..8dd6ea924 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +@@ -4476,6 +4476,47 @@ static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy, + return 0; + } + ++static int cfg80211_rtw_set_cqm_rssi_config(struct wiphy *wiphy, ++ struct net_device *ndev, ++ s32 rssi_thold, u32 rssi_hyst) ++{ ++ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); ++ struct rtw_wdev_priv *priv = adapter_wdev_data(padapter); ++ ++ priv->cqm_rssi_thold = rssi_thold; ++ priv->cqm_rssi_hyst = rssi_hyst; ++ priv->cqm_rssi_last = 0; ++ ++ return 0; ++} ++ ++void rtw_cfg80211_cqm_rssi_update(_adapter *padapter, s32 rssi) ++{ ++ struct rtw_wdev_priv *priv = adapter_wdev_data(padapter); ++ enum nl80211_cqm_rssi_threshold_event event; ++ ++ if (priv->cqm_rssi_thold == 0) ++ return; ++ ++ if (rssi < priv->cqm_rssi_thold && ++ (priv->cqm_rssi_last == 0 || ++ rssi < priv->cqm_rssi_last - priv->cqm_rssi_hyst)) ++ event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; ++ else if (rssi > priv->cqm_rssi_thold && ++ (priv->cqm_rssi_last == 0 || ++ rssi > priv->cqm_rssi_last + priv->cqm_rssi_hyst)) ++ event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; ++ else ++ return; ++ ++ priv->cqm_rssi_last = rssi; ++ cfg80211_cqm_rssi_notify(padapter->pnetdev, event, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) ++ rssi, ++#endif ++ GFP_ATOMIC); ++} ++ + #ifdef CONFIG_AP_MODE + void rtw_cfg80211_indicate_sta_assoc(_adapter *padapter, u8 *pmgmt_frame, uint frame_len) + { +@@ -10157,6 +10198,7 @@ static struct cfg80211_ops rtw_cfg80211_ops = { + .set_pmksa = cfg80211_rtw_set_pmksa, + .del_pmksa = cfg80211_rtw_del_pmksa, + .flush_pmksa = cfg80211_rtw_flush_pmksa, ++ .set_cqm_rssi_config = cfg80211_rtw_set_cqm_rssi_config, + + #ifdef RTW_VIRTUAL_INT + .add_virtual_intf = cfg80211_rtw_add_virtual_intf, +diff --git a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h +index e7dd8050e..d40a36e64 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h ++++ b/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h +@@ -185,6 +185,11 @@ struct rtw_wdev_priv { + u16 pno_scan_seq_num; + #endif + ++ /* Standard RSSI notification parameters */ ++ s32 cqm_rssi_thold; ++ u32 cqm_rssi_hyst; ++ s32 cqm_rssi_last; ++ + #ifdef CONFIG_RTW_CFGVEDNOR_RSSIMONITOR + s8 rssi_monitor_max; + s8 rssi_monitor_min; +@@ -351,6 +356,8 @@ void rtw_cfg80211_init_rfkill(struct wiphy *wiphy); + void rtw_cfg80211_deinit_rfkill(struct wiphy *wiphy); + #endif + ++void rtw_cfg80211_cqm_rssi_update(_adapter *padapter, s32 rssi); ++ + #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE) + #define rtw_cfg80211_rx_mgmt(wdev, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt(wdev_to_ndev(wdev), freq, buf, len, gfp) + #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) +-- +2.41.0 + + +From 18ed5cbdfc47c7021a42277f4c2c89eefd8886c2 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Tue, 7 Nov 2023 17:09:16 +0100 +Subject: [PATCH 12/13] Make use of MODULE_IMPORT_NS conditional + +Commit 8954f2b8d8a06db44bef9a1318f6e1cdb001b98d added an unconditional: + + MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); + +For compatibility with old kernel versions, guard this declaration +with #ifdef MODULE_IMPORT_NS. + +This specific symbol namespace is also Android-specific, so the +declaration should also be conditional on building for Android, but +there doesn't seem to be a single preprocessor symbol that indicates +that. + +Signed-off-by: Ben Hutchings +--- + drivers/staging/rtl8812au/os_dep/linux/usb_intf.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +index 2ef96b386..be0f654f0 100644 +--- a/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c ++++ b/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +@@ -1640,7 +1640,9 @@ static void __exit rtw_drv_halt(void) + rtw_mstat_dump(RTW_DBGDUMP); + } + ++#ifdef MODULE_IMPORT_NS + MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); ++#endif + + module_init(rtw_drv_entry); + module_exit(rtw_drv_halt); +-- +2.41.0 + + +From cc61eb8dd2bf753e5c70ea91414c299a6acdf665 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings +Date: Tue, 7 Nov 2023 18:12:18 +0100 +Subject: [PATCH 13/13] Fix eth_hw_addr_set() definition for compatibility with + stable branches + +eth_hw_addr_set() was added in Linux 5.15 but has now been backported +to 4.19.291, 5.4.251, and 5.10.188. This currently results in build +failure for these stable branches. + +There's no simple way to test for the addition of this function since +LINUX_VERSION_CODE limits version components to 255. + +Work around this by defining an inline function rtw_eth_hw_addr_set() +and a macro eth_hw_addr_set(). This effectively shadows any +backported definition of the eth_hw_addr_set() function without any +conflict. + +Signed-off-by: Ben Hutchings +--- + drivers/staging/rtl8812au/include/drv_types_linux.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/rtl8812au/include/drv_types_linux.h b/drivers/staging/rtl8812au/include/drv_types_linux.h +index 6264a4d30..56435c855 100644 +--- a/drivers/staging/rtl8812au/include/drv_types_linux.h ++++ b/drivers/staging/rtl8812au/include/drv_types_linux.h +@@ -17,10 +17,11 @@ + + #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) + /* Porting from linux kernel v5.15 48eab831ae8b9f7002a533fa4235eed63ea1f1a3 3f6cffb8604b537e3d7ea040d7f4368689638eaf*/ +-static inline void eth_hw_addr_set(struct net_device *dev, const u8 *addr) ++static inline void rtw_eth_hw_addr_set(struct net_device *dev, const u8 *addr) + { + memcpy(dev->dev_addr, addr, ETH_ALEN); + } ++#define eth_hw_addr_set rtw_eth_hw_addr_set + #endif + + #endif +-- +2.41.0 + diff --git a/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-Kconfig-Makefile.patch b/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-Kconfig-Makefile.patch new file mode 100644 index 0000000000..be0c79d0eb --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-Kconfig-Makefile.patch @@ -0,0 +1,33 @@ + +Hook up to module buildsystem. + +Signed-off-by: Thomas Backlund + +--- + drivers/staging/Kconfig | 2 ++ + drivers/staging/Makefile | 1 + + 2 files changed, 3 insertions(+) + +diff -Nurp linux-6.3/drivers/staging/Kconfig linux-6.3.rtl/drivers/staging/Kconfig +--- linux-6.3/drivers/staging/Kconfig 2023-04-23 22:02:52.000000000 +0300 ++++ linux-6.3.rtl/drivers/staging/Kconfig 2023-04-24 20:35:51.404482116 +0300 +@@ -36,6 +36,8 @@ source "drivers/staging/rtl8723bs/Kconfi + + source "drivers/staging/rtl8712/Kconfig" + ++source "drivers/staging/rtl8812au/Kconfig" ++ + source "drivers/staging/rts5208/Kconfig" + + source "drivers/staging/octeon/Kconfig" +diff -Nurp linux-6.3/drivers/staging/Makefile linux-6.3.rtl/drivers/staging/Makefile +--- linux-6.3/drivers/staging/Makefile 2023-04-23 22:02:52.000000000 +0300 ++++ linux-6.3.rtl/drivers/staging/Makefile 2023-04-24 20:36:34.117485089 +0300 +@@ -8,6 +8,7 @@ obj-$(CONFIG_RTL8192U) += rtl8192u/ + obj-$(CONFIG_RTL8192E) += rtl8192e/ + obj-$(CONFIG_RTL8723BS) += rtl8723bs/ + obj-$(CONFIG_R8712U) += rtl8712/ ++obj-$(CONFIG_RTL8812AU) += rtl8812au/ + obj-$(CONFIG_RTS5208) += rts5208/ + obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ + obj-$(CONFIG_VT6655) += vt6655/ diff --git a/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-rename.patch b/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-rename.patch new file mode 100644 index 0000000000..8eb29f2b56 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/staging-rtl8812au-rename.patch @@ -0,0 +1,78 @@ + +Adjust driver bits so it keeps the name of the replaced driver + +Signed-off-by: Thomas Backlund + +--- + drivers/staging/rtl8812au/Kconfig | 7 +++---- + drivers/staging/rtl8812au/Makefile | 8 ++++---- + drivers/staging/rtl8812au/hal/hal_com.c | 2 +- + drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c | 2 +- + 4 files changed, 9 insertions(+), 10 deletions(-) + +diff -Nurp linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_com.c linux-6.3.4-rtl8812au-rename/drivers/staging/rtl8812au/hal/hal_com.c +--- linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_com.c 2023-05-26 22:35:36.543136899 +0300 ++++ linux-6.3.4-rtl8812au-rename/drivers/staging/rtl8812au/hal/hal_com.c 2023-05-26 22:45:07.045079148 +0300 +@@ -12719,7 +12719,7 @@ bypass_hw_pg: + _rtw_memset(hal_data->EEPROMMACAddr, 0, ETH_ALEN); + ret = _FAIL; + exit: +- dev_info(&udev->dev, "88XXau %pM hw_info[%02x]", hw_addr, addr_offset); ++ dev_info(&udev->dev, "8812au %pM hw_info[%02x]", hw_addr, addr_offset); + return ret; + } + +diff -Nurp linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/Kconfig linux-6.3.4-rtl8812au-rename/drivers/staging/rtl8812au/Kconfig +--- linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/Kconfig 2022-01-28 22:59:35.486648197 +0200 ++++ linux-6.3.4-rtl8812au-rename/drivers/staging/rtl8812au/Kconfig 2023-05-26 22:45:07.045079148 +0300 +@@ -1,6 +1,5 @@ +-config 88XXAU +- tristate "Realtek 88XXau USB WiFi" ++config RTL8812AU ++ tristate "Realtek 8812au USB WiFi" + depends on USB + help +- Help message of 88XXau +- ++ Help message of 8812au +diff -Nurp linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/Makefile linux-6.3.4-rtl8812au-rename/drivers/staging/rtl8812au/Makefile +--- linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/Makefile 2023-05-26 22:35:36.539136900 +0300 ++++ linux-6.3.4-rtl8812au-rename/drivers/staging/rtl8812au/Makefile 2023-05-26 22:45:07.045079148 +0300 +@@ -185,9 +185,9 @@ endif + + ifeq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A)_$(CONFIG_RTL8814A), y_y_y) + +-EXTRA_CFLAGS += -DDRV_NAME=\"rtl88XXau\" ++EXTRA_CFLAGS += -DDRV_NAME=\"rtl8812au\" + ifeq ($(CONFIG_USB_HCI), y) +-USER_MODULE_NAME = 88XXau ++USER_MODULE_NAME = 8812au + endif + else + EXTRA_CFLAGS += -DDRV_NAME=\"rtl8812au\" +@@ -1712,11 +1712,11 @@ $(MODULE_NAME)-y += $(_PLATFORM_FILES) + + $(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o + +-obj-$(CONFIG_88XXAU) := $(MODULE_NAME).o ++obj-$(CONFIG_RTL8812AU) := $(MODULE_NAME).o + + else + +-export CONFIG_88XXAU = m ++export CONFIG_RTL8812AU = m + + all: modules + +diff -Nurp linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-6.3.4-rtl8812au-rename/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +--- linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c 2023-05-26 22:35:36.547136899 +0300 ++++ linux-6.3.4-rtl8812au-rename/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c 2023-05-26 22:45:07.046079148 +0300 +@@ -2682,7 +2682,7 @@ void rtw_cfg80211_unlink_bss(_adapter *p + #endif + + if (!wiphy) { +- pr_info("88XXAU: rtw_cfg80211_unlink_bss: wiphy is NULL\n"); ++ pr_info("8812AU: rtw_cfg80211_unlink_bss: wiphy is NULL\n"); + return; + } + diff --git a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au.patch b/kernel/tools/perf/files/patches/mageia/staging-rtl8812au.patch similarity index 95% rename from kernel/tools/perf/files/patches/mageia/3rd-rtl8812au.patch rename to kernel/tools/perf/files/patches/mageia/staging-rtl8812au.patch index 891f72c573..c7c7c0e125 100644 --- a/kernel/tools/perf/files/patches/mageia/3rd-rtl8812au.patch +++ b/kernel/tools/perf/files/patches/mageia/staging-rtl8812au.patch @@ -1,7 +1,509 @@ -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 @@ + +Cloned from: https://github.com/aircrack-ng/rtl8812au + +Topmost commit: + +commit b3227c731ec957b706f8eb2ebcf42ba1c2f0d610 (HEAD -> v5.6.4.2, origin/v5.6.4.2, origin/HEAD) +Author: kimocoder +Date: Fri May 26 06:36:51 2023 +0200 + + Some cleanup of unused chips + +--- + drivers/staging/rtl8812au/Kconfig | 6 + drivers/staging/rtl8812au/Makefile | 1819 +++++++++++ + drivers/staging/rtl8812au/core/efuse/rtw_efuse.c | 3279 +++++++++++++++++++ + drivers/staging/rtl8812au/core/mesh/rtw_mesh.c | 4080 ++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/mesh/rtw_mesh.h | 534 +++ + drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.c | 1665 ++++++++++ + drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.h | 60 + drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.c | 1237 +++++++ + drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.h | 208 + + drivers/staging/rtl8812au/core/rtw_ap.c | 5478 +++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_beamforming.c | 3155 +++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_br_ext.c | 1393 ++++++++ + drivers/staging/rtl8812au/core/rtw_bt_mp.c | 1575 +++++++++ + drivers/staging/rtl8812au/core/rtw_btcoex.c | 1767 ++++++++++ + drivers/staging/rtl8812au/core/rtw_btcoex_wifionly.c | 47 + drivers/staging/rtl8812au/core/rtw_chplan.c | 1193 +++++++ + drivers/staging/rtl8812au/core/rtw_chplan.h | 181 + + drivers/staging/rtl8812au/core/rtw_cmd.c | 5726 ++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_debug.c | 7096 +++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_eeprom.c | 369 ++ + drivers/staging/rtl8812au/core/rtw_ieee80211.c | 2896 +++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_io.c | 899 +++++ + drivers/staging/rtl8812au/core/rtw_ioctl_query.c | 19 + drivers/staging/rtl8812au/core/rtw_ioctl_rtl.c | 901 +++++ + drivers/staging/rtl8812au/core/rtw_ioctl_set.c | 853 +++++ + drivers/staging/rtl8812au/core/rtw_iol.c | 394 ++ + drivers/staging/rtl8812au/core/rtw_mem.c | 128 + drivers/staging/rtl8812au/core/rtw_mi.c | 1571 +++++++++ + drivers/staging/rtl8812au/core/rtw_mlme.c | 5358 ++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_mlme_ext.c |16825 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_mp.c | 3871 +++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_mp_ioctl.c | 2382 ++++++++++++++ + drivers/staging/rtl8812au/core/rtw_odm.c | 420 ++ + drivers/staging/rtl8812au/core/rtw_p2p.c | 5456 +++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_pwrctrl.c | 2761 ++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_recv.c | 5125 +++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_rf.c | 1395 ++++++++ + drivers/staging/rtl8812au/core/rtw_rm.c | 2470 +++++++++++++++ + drivers/staging/rtl8812au/core/rtw_rm_fsm.c | 998 ++++++ + drivers/staging/rtl8812au/core/rtw_rson.c | 595 +++ + drivers/staging/rtl8812au/core/rtw_sdio.c | 130 + drivers/staging/rtl8812au/core/rtw_security.c | 3122 ++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_sreset.c | 314 + + drivers/staging/rtl8812au/core/rtw_sta_mgt.c | 1319 ++++++++ + drivers/staging/rtl8812au/core/rtw_tdls.c | 3505 +++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_vht.c | 1135 ++++++ + drivers/staging/rtl8812au/core/rtw_wapi.c | 1312 +++++++ + drivers/staging/rtl8812au/core/rtw_wapi_sms4.c | 922 +++++ + drivers/staging/rtl8812au/core/rtw_wlan_util.c | 4973 ++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/core/rtw_xmit.c | 6097 +++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/HalPwrSeqCmd.c | 185 + + drivers/staging/rtl8812au/hal/efuse/efuse_mask.h | 164 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c | 94 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h | 33 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c | 94 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h | 34 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c | 93 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h | 33 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c | 96 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h | 31 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c | 95 + drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h | 31 + drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c | 93 + drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h | 33 + drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c | 90 + drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h | 33 + drivers/staging/rtl8812au/hal/hal_btcoex.c | 5706 ++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/hal_btcoex_wifionly.c | 224 + + drivers/staging/rtl8812au/hal/hal_com.c |14360 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/hal_com_c2h.h | 123 + drivers/staging/rtl8812au/hal/hal_com_phycfg.c | 5408 ++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/hal_dm.c | 1616 +++++++++ + drivers/staging/rtl8812au/hal/hal_dm.h | 111 + drivers/staging/rtl8812au/hal/hal_dm_acs.c | 556 +++ + drivers/staging/rtl8812au/hal/hal_dm_acs.h | 167 + + drivers/staging/rtl8812au/hal/hal_halmac.c | 5555 +++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/hal_halmac.h | 245 + + drivers/staging/rtl8812au/hal/hal_hci/hal_usb.c | 564 +++ + drivers/staging/rtl8812au/hal/hal_intf.c | 1698 ++++++++++ + drivers/staging/rtl8812au/hal/hal_mcc.c | 3488 +++++++++++++++++++++ + drivers/staging/rtl8812au/hal/hal_mp.c | 2244 +++++++++++++ + drivers/staging/rtl8812au/hal/hal_phy.c | 257 + + drivers/staging/rtl8812au/hal/led/hal_led.c | 254 + + drivers/staging/rtl8812au/hal/led/hal_usb_led.c | 4291 ++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/ap_makefile.mk | 188 + + drivers/staging/rtl8812au/hal/phydm/halhwimg.h | 96 + drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.c | 1359 ++++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.h | 139 + drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c | 920 +++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.h | 114 + drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.c | 528 +++ + drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.h | 124 + drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.c | 841 +++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.h | 125 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c | 2395 ++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf.h | 573 +++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c | 267 + + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.h | 123 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_dpk.h | 86 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_features.h | 43 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_iqk.h | 103 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c | 1191 +++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.h | 119 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.c | 152 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.h | 41 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c | 1220 +++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h | 398 ++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c | 869 +++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h | 327 + + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c | 741 ++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h | 349 ++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c | 861 +++++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h | 302 + + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.c | 428 ++ + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.h | 52 + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c | 300 + + drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h | 31 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c | 2169 +++++++++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h | 82 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c | 1975 +++++++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h | 63 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c | 2881 +++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h | 99 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c | 1742 ++++++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h | 164 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c | 564 +++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h | 112 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c | 528 +++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h | 106 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c | 557 +++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h | 58 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c | 313 + + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h | 53 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c | 1046 ++++++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h | 72 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c | 731 ++++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h | 42 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c | 773 ++++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h | 41 + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c | 774 ++++ + drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h | 42 + drivers/staging/rtl8812au/hal/phydm/mp_precomp.h | 24 + drivers/staging/rtl8812au/hal/phydm/phydm.c | 3265 +++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm.h | 1356 ++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm.mk | 226 + + drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c | 764 ++++ + drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.h | 122 + drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c | 1291 +++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.h | 151 + drivers/staging/rtl8812au/hal/phydm/phydm_antdect.c | 891 +++++ + drivers/staging/rtl8812au/hal/phydm/phydm_antdect.h | 78 + drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.c | 5897 +++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.h | 519 +++ + drivers/staging/rtl8812au/hal/phydm/phydm_api.c | 2949 +++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_api.h | 186 + + drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.c | 713 ++++ + drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.h | 113 + drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c | 2050 ++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.h | 363 ++ + drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c | 1086 ++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.h | 155 + drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c | 1802 ++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_ccx.h | 268 + + drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c | 594 +++ + drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.h | 73 + drivers/staging/rtl8812au/hal/phydm/phydm_debug.c | 4728 ++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_debug.h | 480 ++ + drivers/staging/rtl8812au/hal/phydm/phydm_dfs.c | 2323 ++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_dfs.h | 190 + + drivers/staging/rtl8812au/hal/phydm/phydm_dig.c | 2858 +++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_dig.h | 337 ++ + drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.c | 517 +++ + drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.h | 103 + drivers/staging/rtl8812au/hal/phydm/phydm_features.h | 72 + drivers/staging/rtl8812au/hal/phydm/phydm_features_ap.h | 196 + + drivers/staging/rtl8812au/hal/phydm/phydm_features_ce.h | 214 + + drivers/staging/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h | 84 + drivers/staging/rtl8812au/hal/phydm/phydm_features_iot.h | 174 + + drivers/staging/rtl8812au/hal/phydm/phydm_features_win.h | 185 + + drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.c | 1419 ++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.h | 79 + drivers/staging/rtl8812au/hal/phydm/phydm_interface.c | 1468 ++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_interface.h | 343 ++ + drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.c | 1343 ++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.h | 173 + + drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.c | 248 + + drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.h | 114 + drivers/staging/rtl8812au/hal/phydm/phydm_mp.c | 348 ++ + drivers/staging/rtl8812au/hal/phydm/phydm_mp.h | 94 + drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c | 457 ++ + drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.h | 48 + drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.c | 928 +++++ + drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.h | 123 + drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c | 3192 +++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.h | 1137 ++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c | 543 +++ + drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h | 152 + drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.c | 171 + + drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.h | 84 + drivers/staging/rtl8812au/hal/phydm/phydm_pre_define.h | 849 +++++ + drivers/staging/rtl8812au/hal/phydm/phydm_precomp.h | 514 +++ + drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.c | 173 + + drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.h | 87 + drivers/staging/rtl8812au/hal/phydm/phydm_psd.c | 459 ++ + drivers/staging/rtl8812au/hal/phydm/phydm_psd.h | 66 + drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c | 2085 ++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.h | 276 + + drivers/staging/rtl8812au/hal/phydm/phydm_reg.h | 241 + + drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11ac.h | 109 + drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11n.h | 219 + + drivers/staging/rtl8812au/hal/phydm/phydm_regtable.h | 849 +++++ + drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c | 170 + + drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.h | 55 + drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.c | 2277 +++++++++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.h | 210 + + drivers/staging/rtl8812au/hal/phydm/phydm_soml.c | 1111 ++++++ + drivers/staging/rtl8812au/hal/phydm/phydm_soml.h | 185 + + drivers/staging/rtl8812au/hal/phydm/phydm_types.h | 330 ++ + drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c | 1469 ++++++++ + drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h | 107 + drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c | 301 + + drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h | 33 + drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c | 3848 +++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h | 124 + drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c | 149 + drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h | 44 + drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c | 113 + drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h | 27 + drivers/staging/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h | 24 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h | 47 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c | 4308 ++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h | 99 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h | 56 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c | 325 + + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h | 39 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c | 8838 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h | 149 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c | 1741 ++++++++++ + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h | 164 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c | 528 +++ + drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h | 106 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c | 219 + + drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h | 109 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c | 503 +++ + drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h | 78 + drivers/staging/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h | 10 + drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c | 923 +++++ + drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h | 83 + drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c | 279 + + drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h | 33 + drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c | 5457 +++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h | 143 + drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c | 206 + + drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h | 90 + drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c | 129 + drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h | 31 + drivers/staging/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h | 24 + drivers/staging/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk | 188 + + drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c | 520 +++ + drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.h | 183 + + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.c | 384 ++ + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.h | 71 + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c | 675 ++++ + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.h | 77 + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.c | 1087 ++++++ + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.h | 78 + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.c | 1484 +++++++++ + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.h | 167 + + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c | 510 +++ + drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h | 78 + drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c | 425 ++ + drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h | 74 + drivers/staging/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c | 83 + drivers/staging/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c | 86 + drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.c |17941 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.h | 47 + drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.c |14005 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.h | 47 + drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c | 860 +++++ + drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_dm.c | 360 ++ + drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c | 5777 +++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c | 2045 ++++++++++++ + drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c | 158 + drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c | 62 + drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c | 106 + drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c | 515 +++ + drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c | 389 ++ + drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c | 28 + drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c | 1169 +++++++ + drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c | 2716 ++++++++++++++++ + drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c | 244 + + drivers/staging/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c | 98 + drivers/staging/rtl8812au/hal/rtl8814a/hal8814a_fw.c | 7741 +++++++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c | 1515 +++++++++ + drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_dm.c | 407 ++ + drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c | 6769 +++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c | 3027 ++++++++++++++++++ + drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c | 210 + + drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c | 68 + drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c | 114 + drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c | 515 +++ + drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c | 147 + drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c | 34 + drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c | 1129 ++++++ + drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c | 2416 ++++++++++++++ + drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c | 312 + + drivers/staging/rtl8812au/include/Hal8812PhyCfg.h | 143 + drivers/staging/rtl8812au/include/Hal8812PhyReg.h | 735 ++++ + drivers/staging/rtl8812au/include/Hal8812PwrSeq.h | 208 + + drivers/staging/rtl8812au/include/Hal8814PhyCfg.h | 264 + + drivers/staging/rtl8812au/include/Hal8814PhyReg.h | 863 +++++ + drivers/staging/rtl8812au/include/Hal8814PwrSeq.h | 231 + + drivers/staging/rtl8812au/include/Hal8821APwrSeq.h | 200 + + drivers/staging/rtl8812au/include/HalPwrSeqCmd.h | 130 + drivers/staging/rtl8812au/include/HalVerDef.h | 201 + + drivers/staging/rtl8812au/include/basic_types.h | 379 ++ + drivers/staging/rtl8812au/include/byteorder/big_endian.h | 82 + drivers/staging/rtl8812au/include/byteorder/generic.h | 195 + + drivers/staging/rtl8812au/include/byteorder/little_endian.h | 84 + drivers/staging/rtl8812au/include/byteorder/swab.h | 136 + drivers/staging/rtl8812au/include/byteorder/swabb.h | 151 + drivers/staging/rtl8812au/include/circ_buf.h | 23 + drivers/staging/rtl8812au/include/cmd_osdep.h | 26 + drivers/staging/rtl8812au/include/cmn_info/rtw_sta_info.h | 257 + + drivers/staging/rtl8812au/include/custom_gpio.h | 39 + drivers/staging/rtl8812au/include/drv_conf.h | 510 +++ + drivers/staging/rtl8812au/include/drv_types.h | 1797 ++++++++++ + drivers/staging/rtl8812au/include/drv_types_ce.h | 86 + drivers/staging/rtl8812au/include/drv_types_gspi.h | 49 + drivers/staging/rtl8812au/include/drv_types_linux.h | 22 + drivers/staging/rtl8812au/include/drv_types_pci.h | 266 + + drivers/staging/rtl8812au/include/drv_types_sdio.h | 64 + drivers/staging/rtl8812au/include/drv_types_xp.h | 88 + drivers/staging/rtl8812au/include/ethernet.h | 36 + drivers/staging/rtl8812au/include/gspi_hal.h | 30 + drivers/staging/rtl8812au/include/gspi_ops.h | 180 + + drivers/staging/rtl8812au/include/gspi_ops_linux.h | 18 + drivers/staging/rtl8812au/include/gspi_osintf.h | 18 + drivers/staging/rtl8812au/include/h2clbk.h | 26 + drivers/staging/rtl8812au/include/hal_btcoex.h | 97 + drivers/staging/rtl8812au/include/hal_btcoex_wifionly.h | 81 + drivers/staging/rtl8812au/include/hal_com.h | 719 ++++ + drivers/staging/rtl8812au/include/hal_com_h2c.h | 635 +++ + drivers/staging/rtl8812au/include/hal_com_led.h | 437 ++ + drivers/staging/rtl8812au/include/hal_com_phycfg.h | 299 + + drivers/staging/rtl8812au/include/hal_com_reg.h | 1887 +++++++++++ + drivers/staging/rtl8812au/include/hal_data.h | 1105 ++++++ + drivers/staging/rtl8812au/include/hal_gspi.h | 26 + drivers/staging/rtl8812au/include/hal_ic_cfg.h | 313 + + drivers/staging/rtl8812au/include/hal_intf.h | 849 +++++ + drivers/staging/rtl8812au/include/hal_pg.h | 880 +++++ + drivers/staging/rtl8812au/include/hal_phy.h | 234 + + drivers/staging/rtl8812au/include/hal_phy_reg.h | 25 + drivers/staging/rtl8812au/include/hal_sdio.h | 56 + drivers/staging/rtl8812au/include/ieee80211.h | 2044 ++++++++++++ + drivers/staging/rtl8812au/include/ieee80211_ext.h | 309 + + drivers/staging/rtl8812au/include/if_ether.h | 106 + drivers/staging/rtl8812au/include/ip.h | 135 + drivers/staging/rtl8812au/include/linux/old_unused_rtl_wireless.h | 87 + drivers/staging/rtl8812au/include/mlme_osdep.h | 25 + drivers/staging/rtl8812au/include/mp_custom_oid.h | 348 ++ + drivers/staging/rtl8812au/include/nic_spec.h | 41 + drivers/staging/rtl8812au/include/osdep_intf.h | 146 + drivers/staging/rtl8812au/include/osdep_service.h | 781 ++++ + drivers/staging/rtl8812au/include/osdep_service_bsd.h | 756 ++++ + drivers/staging/rtl8812au/include/osdep_service_ce.h | 200 + + drivers/staging/rtl8812au/include/osdep_service_linux.h | 543 +++ + drivers/staging/rtl8812au/include/osdep_service_xp.h | 210 + + drivers/staging/rtl8812au/include/pci_hal.h | 52 + drivers/staging/rtl8812au/include/pci_ops.h | 109 + drivers/staging/rtl8812au/include/pci_osintf.h | 50 + drivers/staging/rtl8812au/include/recv_osdep.h | 67 + drivers/staging/rtl8812au/include/rtl8812a_cmd.h | 158 + drivers/staging/rtl8812au/include/rtl8812a_dm.h | 27 + drivers/staging/rtl8812au/include/rtl8812a_hal.h | 369 ++ + drivers/staging/rtl8812au/include/rtl8812a_led.h | 41 + drivers/staging/rtl8812au/include/rtl8812a_recv.h | 149 + drivers/staging/rtl8812au/include/rtl8812a_rf.h | 28 + drivers/staging/rtl8812au/include/rtl8812a_spec.h | 263 + + drivers/staging/rtl8812au/include/rtl8812a_sreset.h | 24 + drivers/staging/rtl8812au/include/rtl8812a_xmit.h | 367 ++ + drivers/staging/rtl8812au/include/rtl8814a_cmd.h | 162 + drivers/staging/rtl8812au/include/rtl8814a_dm.h | 23 + drivers/staging/rtl8812au/include/rtl8814a_hal.h | 330 ++ + drivers/staging/rtl8812au/include/rtl8814a_led.h | 36 + drivers/staging/rtl8812au/include/rtl8814a_recv.h | 182 + + drivers/staging/rtl8812au/include/rtl8814a_rf.h | 28 + drivers/staging/rtl8812au/include/rtl8814a_spec.h | 656 +++ + drivers/staging/rtl8812au/include/rtl8814a_sreset.h | 24 + drivers/staging/rtl8812au/include/rtl8814a_xmit.h | 311 + + drivers/staging/rtl8812au/include/rtl8821a_spec.h | 90 + drivers/staging/rtl8812au/include/rtl8821a_xmit.h | 173 + + drivers/staging/rtl8812au/include/rtl_autoconf.h | 363 ++ + drivers/staging/rtl8812au/include/rtw_android.h | 108 + drivers/staging/rtl8812au/include/rtw_ap.h | 112 + drivers/staging/rtl8812au/include/rtw_beamforming.h | 401 ++ + drivers/staging/rtl8812au/include/rtw_br_ext.h | 69 + drivers/staging/rtl8812au/include/rtw_bt_mp.h | 287 + + drivers/staging/rtl8812au/include/rtw_btcoex.h | 455 ++ + drivers/staging/rtl8812au/include/rtw_btcoex_wifionly.h | 24 + drivers/staging/rtl8812au/include/rtw_byteorder.h | 45 + drivers/staging/rtl8812au/include/rtw_cmd.h | 1356 ++++++++ + drivers/staging/rtl8812au/include/rtw_debug.h | 624 +++ + drivers/staging/rtl8812au/include/rtw_eeprom.h | 116 + drivers/staging/rtl8812au/include/rtw_efuse.h | 255 + + drivers/staging/rtl8812au/include/rtw_event.h | 130 + drivers/staging/rtl8812au/include/rtw_ht.h | 217 + + drivers/staging/rtl8812au/include/rtw_io.h | 548 +++ + drivers/staging/rtl8812au/include/rtw_ioctl.h | 127 + drivers/staging/rtl8812au/include/rtw_ioctl_rtl.h | 75 + drivers/staging/rtl8812au/include/rtw_ioctl_set.h | 45 + drivers/staging/rtl8812au/include/rtw_iol.h | 131 + drivers/staging/rtl8812au/include/rtw_mcc.h | 271 + + drivers/staging/rtl8812au/include/rtw_mem.h | 36 + drivers/staging/rtl8812au/include/rtw_mi.h | 306 + + drivers/staging/rtl8812au/include/rtw_mlme.h | 1427 ++++++++ + drivers/staging/rtl8812au/include/rtw_mlme_ext.h | 1311 +++++++ + drivers/staging/rtl8812au/include/rtw_mp.h | 894 +++++ + drivers/staging/rtl8812au/include/rtw_mp_ioctl.h | 553 +++ + drivers/staging/rtl8812au/include/rtw_mp_phy_regdef.h | 1094 ++++++ + drivers/staging/rtl8812au/include/rtw_odm.h | 97 + drivers/staging/rtl8812au/include/rtw_p2p.h | 169 + + drivers/staging/rtl8812au/include/rtw_pwrctrl.h | 609 +++ + drivers/staging/rtl8812au/include/rtw_qos.h | 66 + drivers/staging/rtl8812au/include/rtw_recv.h | 852 +++++ + drivers/staging/rtl8812au/include/rtw_rf.h | 240 + + drivers/staging/rtl8812au/include/rtw_rm.h | 88 + drivers/staging/rtl8812au/include/rtw_rm_fsm.h | 389 ++ + drivers/staging/rtl8812au/include/rtw_rson.h | 61 + drivers/staging/rtl8812au/include/rtw_sdio.h | 26 + drivers/staging/rtl8812au/include/rtw_security.h | 499 +++ + drivers/staging/rtl8812au/include/rtw_sreset.h | 66 + drivers/staging/rtl8812au/include/rtw_tdls.h | 185 + + drivers/staging/rtl8812au/include/rtw_version.h | 1 + drivers/staging/rtl8812au/include/rtw_vht.h | 176 + + drivers/staging/rtl8812au/include/rtw_wapi.h | 230 + + drivers/staging/rtl8812au/include/rtw_wifi_regd.h | 34 + drivers/staging/rtl8812au/include/rtw_xmit.h | 1045 ++++++ + drivers/staging/rtl8812au/include/sdio_hal.h | 57 + drivers/staging/rtl8812au/include/sdio_ops.h | 206 + + drivers/staging/rtl8812au/include/sdio_ops_linux.h | 58 + drivers/staging/rtl8812au/include/sdio_osintf.h | 18 + drivers/staging/rtl8812au/include/sta_info.h | 748 ++++ + drivers/staging/rtl8812au/include/usb_hal.h | 74 + drivers/staging/rtl8812au/include/usb_ops.h | 153 + drivers/staging/rtl8812au/include/usb_ops_linux.h | 98 + drivers/staging/rtl8812au/include/usb_osintf.h | 26 + drivers/staging/rtl8812au/include/usb_vendor_req.h | 56 + drivers/staging/rtl8812au/include/wifi.h | 1349 ++++++++ + drivers/staging/rtl8812au/include/wlan_bssdef.h | 655 +++ + drivers/staging/rtl8812au/include/xmit_osdep.h | 68 + drivers/staging/rtl8812au/os_dep/linux/custom_gpio_linux.c | 340 ++ + drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c |10566 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h | 427 ++ + drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c |12823 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/os_dep/linux/ioctl_mp.c | 2591 +++++++++++++++ + drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c | 436 ++ + drivers/staging/rtl8812au/os_dep/linux/os_intfs.c | 5188 +++++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/os_dep/linux/recv_linux.c | 729 ++++ + drivers/staging/rtl8812au/os_dep/linux/rhashtable.c | 844 +++++ + drivers/staging/rtl8812au/os_dep/linux/rhashtable.h | 827 +++++ + drivers/staging/rtl8812au/os_dep/linux/rtw_android.c | 1304 +++++++ + drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c | 4777 +++++++++++++++++++++++++++++ + drivers/staging/rtl8812au/os_dep/linux/rtw_proc.h | 63 + drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.c | 74 + drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.h | 55 + drivers/staging/rtl8812au/os_dep/linux/usb_intf.c | 1652 ++++++++++ + drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c | 1135 ++++++ + drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c | 437 ++ + drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c | 567 +++ + drivers/staging/rtl8812au/os_dep/osdep_service.c | 2928 +++++++++++++++++ + drivers/staging/rtl8812au/platform/custom_country_chplan.h | 22 + drivers/staging/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c | 86 + drivers/staging/rtl8812au/platform/platform_ARM_SUNnI_sdio.c | 130 + drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_sdio.c | 90 + drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_usb.c | 136 + drivers/staging/rtl8812au/platform/platform_ARM_WMT_sdio.c | 46 + drivers/staging/rtl8812au/platform/platform_RTK_DMP_usb.c | 30 + drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.c | 54 + drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.h | 32 + drivers/staging/rtl8812au/platform/platform_arm_act_sdio.c | 53 + drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c | 110 + drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h | 28 + drivers/staging/rtl8812au/platform/platform_ops.c | 32 + drivers/staging/rtl8812au/platform/platform_ops.h | 26 + drivers/staging/rtl8812au/platform/platform_sprd_sdio.c | 84 + drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.c | 53 + drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.h | 25 + 488 files changed, 458937 insertions(+) + +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/efuse/rtw_efuse.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/efuse/rtw_efuse.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/efuse/rtw_efuse.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/efuse/rtw_efuse.c 2022-01-28 22:59:35.551651278 +0200 +@@ -0,0 +1,3279 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -782,13 +1284,14 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/efuse/rtw_efuse.c linux-5.11.4-r + j = 0; + + for (i = 0; i < mapLen; i++) { -+ if (i % 16 == 0) ++ if (i % 16 == 0) { + RTW_PRINT_SEL(RTW_DBGDUMP, "0x%03x: ", i); + _RTW_PRINT_SEL(RTW_DBGDUMP, "%02X%s" + , pEfuseHal->fakeEfuseInitMap[i] + , ((i + 1) % 16 == 0) ? "\n" : (((i + 1) % 8 == 0) ? " " : " ") + ); + } ++ } + _RTW_PRINT_SEL(RTW_DBGDUMP, "\n"); + +out_free_buffer: @@ -3280,9 +3783,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/efuse/rtw_efuse.c linux-5.11.4-r +#endif /* CONFIG_EFUSE_CONFIG_FILE */ + +#endif /* PLATFORM_LINUX */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh.c 2022-01-28 22:59:35.551651278 +0200 @@ -0,0 +1,4080 @@ +/****************************************************************************** + * @@ -7364,9 +7867,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh.c linux-5.11.4-rtl +} +#endif /* CONFIG_RTW_MESH */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh.h +--- linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh.h 2022-01-28 22:59:35.551651278 +0200 @@ -0,0 +1,534 @@ +/****************************************************************************** + * @@ -7902,9 +8405,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh.h linux-5.11.4-rtl +#include "rtw_mesh_hwmp.h" +#endif /* __RTW_MESH_H_ */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.c 2022-01-28 22:59:35.551651278 +0200 @@ -0,0 +1,1665 @@ +/****************************************************************************** + * @@ -9571,9 +10074,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.c linux-5.11. + +#endif /* CONFIG_RTW_MESH */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.h +--- linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh_hwmp.h 2022-01-28 22:59:35.551651278 +0200 @@ -0,0 +1,60 @@ +/****************************************************************************** + * @@ -9635,9 +10138,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_hwmp.h linux-5.11. +#endif /* __RTW_MESH_HWMP_H_ */ + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.c 2022-01-28 22:59:35.552651326 +0200 @@ -0,0 +1,1237 @@ +/****************************************************************************** + * @@ -10876,9 +11379,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.c linux-5. +} +#endif /* CONFIG_RTW_MESH */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.h +--- linux-6.3.4/drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/mesh/rtw_mesh_pathtbl.h 2022-01-28 22:59:35.552651326 +0200 @@ -0,0 +1,208 @@ +/****************************************************************************** + * @@ -11088,10 +11591,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/mesh/rtw_mesh_pathtbl.h linux-5. + +#endif /* __RTW_MESH_PATHTBL_H_ */ + -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ap.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ap.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ap.c 2022-01-28 22:59:35.552651326 +0200 +@@ -0,0 +1,5478 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -15601,12 +16104,14 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ap.c linux-5.11.4-rtl8812au/ + RT_CHANNEL_INFO *chset = adapter_to_chset(adapter); + u8 ret = _SUCCESS; + ++ // ignore reg domain check ++#if 0 + if (rtw_chset_search_ch(chset, ch) < 0) { + RTW_WARN("%s ch:%u doesn't fit in chplan\n", caller, ch); + ret = _FAIL; + goto exit; + } -+ ++#endif + rtw_adjust_chbw(adapter, ch, bw, offset); + + if (!rtw_get_offset_by_chbw(ch, *bw, offset)) { @@ -16568,9 +17073,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ap.c linux-5.11.4-rtl8812au/ +} +#endif /* CONFIG_AP_MODE */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_beamforming.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_beamforming.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_beamforming.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_beamforming.c 2022-01-28 22:59:35.552651326 +0200 @@ -0,0 +1,3155 @@ +/****************************************************************************** + * @@ -19727,10 +20232,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_beamforming.c linux-5.11.4-r +#endif /* !RTW_BEAMFORMING_VERSION_2 */ + +#endif /* CONFIG_BEAMFORMING */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_br_ext.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_br_ext.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_br_ext.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_br_ext.c 2023-05-26 22:35:36.539136900 +0300 +@@ -0,0 +1,1393 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -19750,7 +20255,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 +#ifdef __KERNEL__ + #include + #include -+ #include ++ #include + #include + #include + #include @@ -19801,6 +20306,29 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 +#define MAGIC_CODE_LEN 2 +#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */ + ++#define IPX_NODE_LEN 6 ++struct ipx_address { ++ __be32 net; ++ __u8 node[IPX_NODE_LEN]; ++ __be16 sock; ++}; ++ ++struct ipxhdr { ++ __be16 ipx_checksum __packed; ++#define IPX_NO_CHECKSUM cpu_to_be16(0xFFFF) ++ __be16 ipx_pktsize __packed; ++ __u8 ipx_tctrl; ++ __u8 ipx_type; ++#define IPX_TYPE_UNKNOWN 0x00 ++#define IPX_TYPE_RIP 0x01 /* may also be 0 */ ++#define IPX_TYPE_SAP 0x04 /* may also be 0 */ ++#define IPX_TYPE_SPX 0x05 /* SPX protocol */ ++#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */ ++#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast */ ++ struct ipx_address ipx_dest __packed; ++ struct ipx_address ipx_source __packed; ++}; ++ +/*----------------------------------------------------------------- + How database records network address: + 0 1 2 3 4 5 6 7 8 9 10 @@ -19847,7 +20375,13 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 + /* have a room for new tag */ + memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length)); + ph->length = htons(ntohs(ph->length) + data_len); ++#if (defined __GNUC__) && (__GNUC__ > 10) ++ #pragma GCC diagnostic ignored "-Wstringop-overread" ++#endif + memcpy((unsigned char *)ph->tag, tag, data_len); ++#if (defined __GNUC__) && (__GNUC__ > 10) ++ #pragma GCC diagnostic pop ++#endif + return data_len; +} + @@ -19902,6 +20436,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 +} + + ++#ifdef _NET_INET_IPX_H_ +static __inline__ void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, + unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr) +{ @@ -19922,6 +20457,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 + 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, @@ -20063,6 +20599,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 + 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; + @@ -20070,6 +20607,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 + 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; + @@ -20623,227 +21161,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 + } + + /*---------------------------------------------------*/ -+ /* Handle IPX and Apple Talk frame */ -+ /*---------------------------------------------------*/ -+ else if ((protocol == __constant_htons(ETH_P_IPX)) || -+ (protocol == __constant_htons(ETH_P_ATALK)) || -+ (protocol == __constant_htons(ETH_P_AARP))) { -+ unsigned char ipx_header[2] = {0xFF, 0xFF}; -+ struct ipxhdr *ipx = NULL; -+ struct elapaarp *ea = NULL; -+ struct ddpehdr *ddp = NULL; -+ unsigned char *framePtr = skb->data + ETH_HLEN; -+ -+ if (protocol == __constant_htons(ETH_P_IPX)) { -+ RTW_INFO("NAT25: Protocol=IPX (Ethernet II)\n"); -+ ipx = (struct ipxhdr *)framePtr; -+ } else { /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */ -+ if (!memcmp(ipx_header, framePtr, 2)) { -+ RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.3)\n"); -+ ipx = (struct ipxhdr *)framePtr; -+ } else { -+ unsigned char ipx_8022_type = 0xE0; -+ unsigned char snap_8022_type = 0xAA; -+ -+ if (*framePtr == snap_8022_type) { -+ unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37}; /* IPX SNAP ID */ -+ unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; /* Apple Talk AARP SNAP ID */ -+ unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B}; /* Apple Talk DDP SNAP ID */ -+ -+ framePtr += 3; /* eliminate the 802.2 header */ -+ -+ if (!memcmp(ipx_snap_id, framePtr, 5)) { -+ framePtr += 5; /* eliminate the SNAP header */ -+ -+ RTW_INFO("NAT25: Protocol=IPX (Ethernet SNAP)\n"); -+ ipx = (struct ipxhdr *)framePtr; -+ } else if (!memcmp(aarp_snap_id, framePtr, 5)) { -+ framePtr += 5; /* eliminate the SNAP header */ -+ -+ ea = (struct elapaarp *)framePtr; -+ } else if (!memcmp(ddp_snap_id, framePtr, 5)) { -+ framePtr += 5; /* eliminate the SNAP header */ -+ -+ ddp = (struct ddpehdr *)framePtr; -+ } else { -+ DEBUG_WARN("NAT25: Protocol=Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0], -+ framePtr[1], framePtr[2], framePtr[3], framePtr[4]); -+ return -1; -+ } -+ } else if (*framePtr == ipx_8022_type) { -+ framePtr += 3; /* eliminate the 802.2 header */ -+ -+ if (!memcmp(ipx_header, framePtr, 2)) { -+ RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.2)\n"); -+ ipx = (struct ipxhdr *)framePtr; -+ } else -+ return -1; -+ } -+ } -+ } -+ -+ /* IPX */ -+ if (ipx != NULL) { -+ switch (method) { -+ case NAT25_CHECK: -+ if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { -+ RTW_INFO("NAT25: Check IPX skb_copy\n"); -+ return 0; -+ } -+ return -1; -+ -+ case NAT25_INSERT: { -+ RTW_INFO("NAT25: Insert IPX, Dest=%08x,%02x%02x%02x%02x%02x%02x,%04x Source=%08x,%02x%02x%02x%02x%02x%02x,%04x\n", -+ ipx->ipx_dest.net, -+ ipx->ipx_dest.node[0], -+ ipx->ipx_dest.node[1], -+ ipx->ipx_dest.node[2], -+ ipx->ipx_dest.node[3], -+ ipx->ipx_dest.node[4], -+ ipx->ipx_dest.node[5], -+ ipx->ipx_dest.sock, -+ ipx->ipx_source.net, -+ ipx->ipx_source.node[0], -+ ipx->ipx_source.node[1], -+ ipx->ipx_source.node[2], -+ ipx->ipx_source.node[3], -+ ipx->ipx_source.node[4], -+ ipx->ipx_source.node[5], -+ ipx->ipx_source.sock); -+ -+ if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { -+ RTW_INFO("NAT25: Use IPX Net, and Socket as network addr\n"); -+ -+ __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock); -+ -+ /* change IPX source node addr to wlan STA address */ -+ memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN); -+ } else -+ __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node); -+ -+ __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); -+ -+ __nat25_db_print(priv); -+ } -+ return 0; -+ -+ case NAT25_LOOKUP: { -+ if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) { -+ RTW_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n"); -+ -+ __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock); -+ -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ -+ /* replace IPX destination node addr with Lookup destination MAC addr */ -+ memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN); -+ } else { -+ __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node); -+ -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ } -+ } -+ return 0; -+ -+ default: -+ return -1; -+ } -+ } -+ -+ /* AARP */ -+ else if (ea != NULL) { -+ /* Sanity check fields. */ -+ if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) { -+ DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n"); -+ return -1; -+ } -+ -+ switch (method) { -+ case NAT25_CHECK: -+ return 0; -+ -+ case NAT25_INSERT: { -+ /* change to AARP source mac address to wlan STA address */ -+ memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN); -+ -+ RTW_INFO("NAT25: Insert AARP, Source=%d,%d Destination=%d,%d\n", -+ ea->pa_src_net, -+ ea->pa_src_node, -+ ea->pa_dst_net, -+ ea->pa_dst_node); -+ -+ __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node); -+ -+ __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); -+ -+ __nat25_db_print(priv); -+ } -+ return 0; -+ -+ case NAT25_LOOKUP: { -+ RTW_INFO("NAT25: Lookup AARP, Source=%d,%d Destination=%d,%d\n", -+ ea->pa_src_net, -+ ea->pa_src_node, -+ ea->pa_dst_net, -+ ea->pa_dst_node); -+ -+ __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node); -+ -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ -+ /* change to AARP destination mac address to Lookup result */ -+ memcpy(ea->hw_dst, skb->data, ETH_ALEN); -+ } -+ return 0; -+ -+ default: -+ return -1; -+ } -+ } -+ -+ /* DDP */ -+ else if (ddp != NULL) { -+ switch (method) { -+ case NAT25_CHECK: -+ return -1; -+ -+ case NAT25_INSERT: { -+ RTW_INFO("NAT25: Insert DDP, Source=%d,%d Destination=%d,%d\n", -+ ddp->deh_snet, -+ ddp->deh_snode, -+ ddp->deh_dnet, -+ ddp->deh_dnode); -+ -+ __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode); -+ -+ __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); -+ -+ __nat25_db_print(priv); -+ } -+ return 0; -+ -+ case NAT25_LOOKUP: { -+ RTW_INFO("NAT25: Lookup DDP, Source=%d,%d Destination=%d,%d\n", -+ ddp->deh_snet, -+ ddp->deh_snode, -+ ddp->deh_dnet, -+ ddp->deh_dnode); -+ -+ __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode); -+ -+ __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); -+ } -+ return 0; -+ -+ default: -+ return -1; -+ } -+ } -+ -+ return -1; -+ } -+ -+ /*---------------------------------------------------*/ + /* Handle PPPoE frame */ + /*---------------------------------------------------*/ + else if ((protocol == __constant_htons(ETH_P_PPP_DISC)) || @@ -21312,9 +21629,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_br_ext.c linux-5.11.4-rtl881 +} + +#endif /* CONFIG_BR_EXT */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_btcoex.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_btcoex.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_btcoex.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_btcoex.c 2022-01-28 22:59:35.553651373 +0200 @@ -0,0 +1,1767 @@ +/****************************************************************************** + * @@ -23083,9 +23400,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_btcoex.c linux-5.11.4-rtl881 + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_btcoex_wifionly.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_btcoex_wifionly.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_btcoex_wifionly.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_btcoex_wifionly.c 2022-01-28 22:59:35.553651373 +0200 @@ -0,0 +1,47 @@ +/****************************************************************************** + * @@ -23134,9 +23451,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_btcoex_wifionly.c linux-5.11 +{ + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_bt_mp.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_bt_mp.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_bt_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_bt_mp.c 2022-01-28 22:59:35.553651373 +0200 @@ -0,0 +1,1575 @@ +/****************************************************************************** + * @@ -24713,9 +25030,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_bt_mp.c linux-5.11.4-rtl8812 +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_chplan.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_chplan.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_chplan.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_chplan.c 2022-01-28 22:59:35.553651373 +0200 @@ -0,0 +1,1193 @@ +/****************************************************************************** + * @@ -25910,9 +26227,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_chplan.c linux-5.11.4-rtl881 +{ + RTW_PRINT_SEL(sel, "%s-%s\n", RTW_DOMAIN_MAP_VER, RTW_COUNTRY_MAP_VER); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_chplan.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_chplan.h +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_chplan.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_chplan.h 2022-01-28 22:59:35.553651373 +0200 @@ -0,0 +1,181 @@ +/****************************************************************************** + * @@ -26095,10 +26412,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_chplan.h linux-5.11.4-rtl881 +void dump_chplan_ver(void *sel); + +#endif /* __RTW_CHPLAN_H__ */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_cmd.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_cmd.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_cmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_cmd.c 2022-12-18 17:40:24.573937030 +0200 +@@ -0,0 +1,5726 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -26265,21 +26582,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au + + pevtpriv->c2h_mem = pevtpriv->allocated_c2h_mem + 4\ + - ((u32)(pevtpriv->allocated_c2h_mem) & 3); -+#ifdef PLATFORM_OS_XP -+ pevtpriv->pc2h_mdl = IoAllocateMdl((u8 *)pevtpriv->c2h_mem, C2H_MEM_SZ , FALSE, FALSE, NULL); -+ -+ if (pevtpriv->pc2h_mdl == NULL) { -+ res = _FAIL; -+ goto exit; -+ } -+ MmBuildMdlForNonPagedPool(pevtpriv->pc2h_mdl); -+#endif +#endif /* end of CONFIG_SDIO_HCI */ -+ + _rtw_init_queue(&(pevtpriv->evt_queue)); + +exit: -+ +#endif /* end of CONFIG_EVENT_THREAD_MODE */ + +#ifdef CONFIG_C2H_WK @@ -26287,15 +26593,12 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au + pevtpriv->c2h_wk_alive = _FALSE; + pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN + 1); +#endif -+ -+ + return res; +} + +void _rtw_free_evt_priv(struct evt_priv *pevtpriv) +{ + -+ +#ifdef CONFIG_EVENT_THREAD_MODE + _rtw_free_sema(&(pevtpriv->evt_notify)); + @@ -26316,9 +26619,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au + } + rtw_cbuf_free(pevtpriv->c2h_queue); +#endif -+ -+ -+ +} + +void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) @@ -26410,7 +26710,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au + +exit: + -+ + return _SUCCESS; +} + @@ -26419,7 +26718,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au + _irqL irqL; + struct cmd_obj *obj; + -+ + /* _enter_critical_bh(&(queue->lock), &irqL); */ + _enter_critical(&queue->lock, &irqL); + @@ -26430,7 +26728,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au + } +#endif /* DBG_CMD_QUEUE */ + -+ + if (rtw_is_list_empty(&(queue->queue))) + obj = NULL; + else { @@ -27624,25 +27921,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au + + pcmd->cmdsz = sizeof(WLAN_BSSID_EX); + -+#ifdef CONFIG_RTL8712 -+ /* wlan_network endian conversion */ -+ psecnetwork->Length = cpu_to_le32(psecnetwork->Length); -+ psecnetwork->Ssid.SsidLength = cpu_to_le32(psecnetwork->Ssid.SsidLength); -+ psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy); -+ psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi); -+ psecnetwork->NetworkTypeInUse = cpu_to_le32(psecnetwork->NetworkTypeInUse); -+ psecnetwork->Configuration.ATIMWindow = cpu_to_le32(psecnetwork->Configuration.ATIMWindow); -+ psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(psecnetwork->Configuration.BeaconPeriod); -+ psecnetwork->Configuration.DSConfig = cpu_to_le32(psecnetwork->Configuration.DSConfig); -+ psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32(psecnetwork->Configuration.FHConfig.DwellTime); -+ psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopPattern); -+ psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopSet); -+ psecnetwork->Configuration.FHConfig.Length = cpu_to_le32(psecnetwork->Configuration.FHConfig.Length); -+ psecnetwork->Configuration.Length = cpu_to_le32(psecnetwork->Configuration.Length); -+ psecnetwork->InfrastructureMode = cpu_to_le32(psecnetwork->InfrastructureMode); -+ psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength); -+#endif -+ + _rtw_init_listhead(&pcmd->list); + pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */ + pcmd->parmbuf = (unsigned char *)psecnetwork; @@ -31864,9 +32142,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_cmd.c linux-5.11.4-rtl8812au + + +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_debug.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_debug.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_debug.c 2022-01-28 22:59:35.554651420 +0200 @@ -0,0 +1,7096 @@ +/****************************************************************************** + * @@ -38964,9 +39242,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_debug.c linux-5.11.4-rtl8812 + return count; +} +#endif /* CONFIG_RTW_SW_LED */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_eeprom.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_eeprom.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_eeprom.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_eeprom.c 2022-01-28 22:59:35.554651420 +0200 @@ -0,0 +1,369 @@ +/****************************************************************************** + * @@ -39337,10 +39615,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_eeprom.c linux-5.11.4-rtl881 + + +} -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ieee80211.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ieee80211.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ieee80211.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ieee80211.c 2023-05-26 22:35:36.540136899 +0300 +@@ -0,0 +1,2896 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -39357,9 +39635,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ieee80211.c linux-5.11.4-rtl + *****************************************************************************/ +#define _IEEE80211_C + -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+ #include -+#endif +#include + + @@ -40894,35 +41169,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ieee80211.c linux-5.11.4-rtl + return (key_char2num(hch) * 100) + (key_char2num(mch) * 10) + key_char2num(lch); +} + -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+#define MAC_ADDRESS_LEN 12 -+ -+int rtw_get_mac_addr_intel(unsigned char *buf) -+{ -+ int ret = 0; -+ int i; -+ struct file *fp = NULL; -+ mm_segment_t oldfs; -+ unsigned char c_mac[MAC_ADDRESS_LEN]; -+ char fname[] = "/config/wifi/mac.txt"; -+ int jj, kk; -+ -+ RTW_INFO("%s Enter\n", __FUNCTION__); -+ -+ ret = rtw_retrieve_from_file(fname, c_mac, MAC_ADDRESS_LEN); -+ if (ret < MAC_ADDRESS_LEN) -+ return -1; -+ -+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 2) -+ buf[jj] = key_2char2num(c_mac[kk], c_mac[kk + 1]); -+ -+ RTW_INFO("%s: read from file mac address: "MAC_FMT"\n", -+ __FUNCTION__, MAC_ARG(buf)); -+ -+ return 0; -+} -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ -+ +/* + * Description: + * rtw_check_invalid_mac_address: @@ -40996,12 +41242,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ieee80211.c linux-5.11.4-rtl + goto err_chk; + } + -+ /* platform specified */ -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+ if (rtw_get_mac_addr_intel(mac) == 0) -+ goto err_chk; -+#endif -+ + /* Use the mac address stored in the Efuse */ + if (hw_mac_addr) { + _rtw_memcpy(mac, hw_mac_addr, ETH_ALEN); @@ -42275,9 +42515,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ieee80211.c linux-5.11.4-rtl + return _action_public_str[action]; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_io.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_io.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_io.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_io.c 2022-01-28 22:59:35.555651468 +0200 @@ -0,0 +1,899 @@ +/****************************************************************************** + * @@ -43178,10 +43418,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_io.c linux-5.11.4-rtl8812au/ +#endif /* CONFIG_SDIO_HCI */ + +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ioctl_query.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ioctl_query.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ioctl_query.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ioctl_query.c 2023-05-26 22:35:36.540136899 +0300 +@@ -0,0 +1,19 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -43201,156 +43441,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_query.c linux-5.11.4-r +#include + + -+#ifdef PLATFORM_WINDOWS -+/* -+ * Added for WPA2-PSK, by Annie, 2005-09-20. -+ * */ -+u8 -+query_802_11_capability( -+ _adapter *Adapter, -+ u8 *pucBuf, -+ u32 *pulOutLen -+) -+{ -+ static NDIS_802_11_AUTHENTICATION_ENCRYPTION szAuthEnc[] = { -+ {Ndis802_11AuthModeOpen, Ndis802_11EncryptionDisabled}, -+ {Ndis802_11AuthModeOpen, Ndis802_11Encryption1Enabled}, -+ {Ndis802_11AuthModeShared, Ndis802_11EncryptionDisabled}, -+ {Ndis802_11AuthModeShared, Ndis802_11Encryption1Enabled}, -+ {Ndis802_11AuthModeWPA, Ndis802_11Encryption2Enabled}, -+ {Ndis802_11AuthModeWPA, Ndis802_11Encryption3Enabled}, -+ {Ndis802_11AuthModeWPAPSK, Ndis802_11Encryption2Enabled}, -+ {Ndis802_11AuthModeWPAPSK, Ndis802_11Encryption3Enabled}, -+ {Ndis802_11AuthModeWPANone, Ndis802_11Encryption2Enabled}, -+ {Ndis802_11AuthModeWPANone, Ndis802_11Encryption3Enabled}, -+ {Ndis802_11AuthModeWPA2, Ndis802_11Encryption2Enabled}, -+ {Ndis802_11AuthModeWPA2, Ndis802_11Encryption3Enabled}, -+ {Ndis802_11AuthModeWPA2PSK, Ndis802_11Encryption2Enabled}, -+ {Ndis802_11AuthModeWPA2PSK, Ndis802_11Encryption3Enabled} -+ }; -+ static ULONG ulNumOfPairSupported = sizeof(szAuthEnc) / sizeof(NDIS_802_11_AUTHENTICATION_ENCRYPTION); -+ NDIS_802_11_CAPABILITY *pCap = (NDIS_802_11_CAPABILITY *)pucBuf; -+ u8 *pucAuthEncryptionSupported = (u8 *) pCap->AuthenticationEncryptionSupported; -+ -+ -+ pCap->Length = sizeof(NDIS_802_11_CAPABILITY); -+ if (ulNumOfPairSupported > 1) -+ pCap->Length += (ulNumOfPairSupported - 1) * sizeof(NDIS_802_11_AUTHENTICATION_ENCRYPTION); -+ -+ pCap->Version = 2; -+ pCap->NoOfPMKIDs = NUM_PMKID_CACHE; -+ pCap->NoOfAuthEncryptPairsSupported = ulNumOfPairSupported; -+ -+ if (sizeof(szAuthEnc) <= 240) /* 240 = 256 - 4*4 */ { /* SecurityInfo.szCapability: only 256 bytes in size. */ -+ _rtw_memcpy(pucAuthEncryptionSupported, (u8 *)szAuthEnc, sizeof(szAuthEnc)); -+ *pulOutLen = pCap->Length; -+ return _TRUE; -+ } else { -+ *pulOutLen = 0; -+ return _FALSE; -+ } -+} -+ -+u8 query_802_11_association_information(_adapter *padapter, PNDIS_802_11_ASSOCIATION_INFORMATION pAssocInfo) -+{ -+ struct wlan_network *tgt_network; -+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ struct security_priv *psecuritypriv = &(padapter->securitypriv); -+ WLAN_BSSID_EX *psecnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; -+ u8 *pDest = (u8 *)pAssocInfo + sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); -+ unsigned char i, *auth_ie, *supp_ie; -+ -+ /* NdisZeroMemory(pAssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); */ -+ _rtw_memset(pAssocInfo, 0, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); -+ /* pAssocInfo->Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); */ -+ -+ /* ------------------------------------------------------ */ -+ /* Association Request related information */ -+ /* ------------------------------------------------------ */ -+ /* Req_1. AvailableRequestFixedIEs */ -+ if (psecnetwork != NULL) { -+ -+ pAssocInfo->AvailableRequestFixedIEs |= NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_CURRENTAPADDRESS; -+ pAssocInfo->RequestFixedIEs.Capabilities = (unsigned short) *&psecnetwork->IEs[10]; -+ _rtw_memcpy(pAssocInfo->RequestFixedIEs.CurrentAPAddress, -+ &psecnetwork->MacAddress, 6); -+ -+ pAssocInfo->OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); -+ -+ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING | _FW_LINKED) == _TRUE) { -+ -+ if (psecuritypriv->ndisauthtype >= Ndis802_11AuthModeWPA2) -+ pDest[0] = 48; /* RSN Information Element */ -+ else -+ pDest[0] = 221; /* WPA(SSN) Information Element */ -+ -+ supp_ie = &psecuritypriv->supplicant_ie[0]; -+ -+ i = 13; /* 0~11 is fixed information element */ -+ while ((i < supp_ie[0]) && (i < 256)) { -+ if ((unsigned char)supp_ie[i] == pDest[0]) { -+ _rtw_memcpy((u8 *)(pDest), -+ &supp_ie[i], -+ supp_ie[1 + i] + 2); -+ -+ break; -+ } -+ -+ i = i + supp_ie[i + 1] + 2; -+ if (supp_ie[1 + i] == 0) -+ i = i + 1; -+ -+ } -+ -+ -+ pAssocInfo->RequestIELength += (2 + supp_ie[1 + i]); /* (2 + psecnetwork->IEs[1+i]+4); */ -+ -+ } -+ -+ -+ -+ } -+ -+ -+ /* ------------------------------------------------------ */ -+ /* Association Response related information */ -+ /* ------------------------------------------------------ */ -+ -+ if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { -+ tgt_network = &(pmlmepriv->cur_network); -+ if (tgt_network != NULL) { -+ pAssocInfo->AvailableResponseFixedIEs = -+ NDIS_802_11_AI_RESFI_CAPABILITIES -+ | NDIS_802_11_AI_RESFI_ASSOCIATIONID -+ ; -+ -+ pAssocInfo->ResponseFixedIEs.Capabilities = (unsigned short) *&tgt_network->network.IEs[10]; -+ pAssocInfo->ResponseFixedIEs.StatusCode = 0; -+ pAssocInfo->ResponseFixedIEs.AssociationId = (unsigned short) tgt_network->aid; -+ -+ pDest = (u8 *)pAssocInfo + sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAssocInfo->RequestIELength; -+ auth_ie = &psecuritypriv->authenticator_ie[0]; -+ -+ -+ i = auth_ie[0] - 12; -+ if (i > 0) { -+ _rtw_memcpy((u8 *)&pDest[0], &auth_ie[1], i); -+ pAssocInfo->ResponseIELength = i; -+ } -+ -+ -+ pAssocInfo->OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAssocInfo->RequestIELength; -+ -+ -+ } -+ } -+ -+ return _TRUE; -+} -+#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ioctl_rtl.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ioctl_rtl.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ioctl_rtl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ioctl_rtl.c 2022-01-28 22:59:35.555651468 +0200 @@ -0,0 +1,901 @@ +/****************************************************************************** + * @@ -44253,10 +44346,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_rtl.c linux-5.11.4-rtl + return status; +} +/* ************** oid_rtl_seg_03_00 section end ************** */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ioctl_set.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ioctl_set.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_ioctl_set.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_ioctl_set.c 2023-05-26 22:35:36.540136899 +0300 +@@ -0,0 +1,853 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -44456,83 +44549,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_set.c linux-5.11.4-rtl + return ret; +} + -+#ifdef PLATFORM_WINDOWS -+u8 rtw_pnp_set_power_wakeup(_adapter *padapter) -+{ -+ u8 res = _SUCCESS; -+ -+ -+ -+ res = rtw_setstandby_cmd(padapter, 0); -+ -+ -+ -+ return res; -+} -+ -+u8 rtw_pnp_set_power_sleep(_adapter *padapter) -+{ -+ u8 res = _SUCCESS; -+ -+ -+ /* DbgPrint("+rtw_pnp_set_power_sleep\n"); */ -+ -+ res = rtw_setstandby_cmd(padapter, 1); -+ -+ -+ -+ return res; -+} -+ -+u8 rtw_set_802_11_reload_defaults(_adapter *padapter, NDIS_802_11_RELOAD_DEFAULTS reloadDefaults) -+{ -+ -+ -+ -+ /* SecClearAllKeys(Adapter); */ -+ /* 8711 CAM was not for En/Decrypt only */ -+ /* so, we can't clear all keys. */ -+ /* should we disable WPAcfg (ox0088) bit 1-2, instead of clear all CAM */ -+ -+ /* TO DO... */ -+ -+ -+ return _TRUE; -+} -+ -+u8 set_802_11_test(_adapter *padapter, NDIS_802_11_TEST *test) -+{ -+ u8 ret = _TRUE; -+ -+ -+ switch (test->Type) { -+ case 1: -+ NdisMIndicateStatus(padapter->hndis_adapter, NDIS_STATUS_MEDIA_SPECIFIC_INDICATION, (PVOID)&test->AuthenticationEvent, test->Length - 8); -+ NdisMIndicateStatusComplete(padapter->hndis_adapter); -+ break; -+ -+ case 2: -+ NdisMIndicateStatus(padapter->hndis_adapter, NDIS_STATUS_MEDIA_SPECIFIC_INDICATION, (PVOID)&test->RssiTrigger, sizeof(NDIS_802_11_RSSI)); -+ NdisMIndicateStatusComplete(padapter->hndis_adapter); -+ break; -+ -+ default: -+ ret = _FALSE; -+ break; -+ } -+ -+ -+ return ret; -+} -+ -+u8 rtw_set_802_11_pmkid(_adapter *padapter, NDIS_802_11_PMKID *pmkid) -+{ -+ u8 ret = _SUCCESS; -+ -+ return ret; -+} -+ -+#endif + +u8 rtw_set_802_11_bssid(_adapter *padapter, u8 *bssid) +{ @@ -45187,9 +45203,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_ioctl_set.c linux-5.11.4-rtl + RTW_PRINT(FUNC_ADPT_FMT" band:%d fail\n", FUNC_ADPT_ARG(adapter), band); + return _FAIL; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_iol.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_iol.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_iol.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_iol.c 2022-01-28 22:59:35.555651468 +0200 @@ -0,0 +1,394 @@ +/****************************************************************************** + * @@ -45585,9 +45601,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_iol.c linux-5.11.4-rtl8812au + + +#endif /* CONFIG_IOL */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mem.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mem.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mem.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mem.c 2022-01-28 22:59:35.555651468 +0200 @@ -0,0 +1,128 @@ +/****************************************************************************** + * @@ -45717,9 +45733,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mem.c linux-5.11.4-rtl8812au + +module_init(rtw_mem_init); +module_exit(rtw_mem_exit); -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mi.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mi.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mi.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mi.c 2022-01-28 22:59:35.555651468 +0200 @@ -0,0 +1,1571 @@ +/****************************************************************************** + * @@ -47292,10 +47308,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mi.c linux-5.11.4-rtl8812au/ +#endif + return n_assoc_iface; +} -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mlme.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mlme.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mlme.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mlme.c 2023-05-26 22:35:36.540136899 +0300 +@@ -0,0 +1,5358 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -50139,10 +50155,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mlme.c linux-5.11.4-rtl8812a + psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress); + if (psta) + rtw_sta_mstatus_disc_rpt(adapter, psta->cmn.mac_id); -+ else { ++ else + RTW_INFO("%s "ADPT_FMT" - mac_addr: "MAC_FMT" psta == NULL\n", __func__, ADPT_ARG(adapter), MAC_ARG(tgt_network->network.MacAddress)); -+ rtw_warn_on(1); -+ } + } +} + @@ -50491,10 +50505,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mlme.c linux-5.11.4-rtl8812a + #ifdef CONFIG_LAYER2_ROAMING + if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE) && pmlmepriv->need_to_roam == _TRUE) + RTW_INFO(FUNC_ADPT_FMT" need to roam, don't care BusyTraffic\n", FUNC_ADPT_ARG(padapter)); -+ else ++ else { + #endif + RTW_INFO(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter)); + goto exit; ++ } + } + else if (ssc_chk != SS_ALLOW) + goto exit; @@ -52655,9 +52670,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mlme.c linux-5.11.4-rtl8812a + , MAC_ARG(ARP_TARGET_MAC_ADDR(arp)), IP_ARG(ARP_TARGET_IP_ADDR(arp))); +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mlme_ext.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mlme_ext.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mlme_ext.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mlme_ext.c 2022-01-28 22:59:35.558651610 +0200 @@ -0,0 +1,16825 @@ +/****************************************************************************** + * @@ -69484,10 +69499,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mlme_ext.c linux-5.11.4-rtl8 +#endif /* CONFIG_IOCTL_CFG80211 */ +} + -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mp.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mp.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mp.c 2022-12-18 17:40:24.573937030 +0200 +@@ -0,0 +1,3871 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -70904,7 +70919,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp.c linux-5.11.4-rtl8812au/ + pmptx->pallocated_buf = NULL; + pmptx->stop = 1; + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + thread_exit(NULL); ++#else ++ kthread_thread_exit(NULL); ++#endif + return 0; +} + @@ -73355,10 +73374,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp.c linux-5.11.4-rtl8812au/ + +#endif +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mp_ioctl.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mp_ioctl.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_mp_ioctl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_mp_ioctl.c 2023-05-26 22:35:36.541136899 +0300 +@@ -0,0 +1,2382 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -73403,9 +73422,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* **************** oid_rtl_seg_81_87_80 section start **************** */ +NDIS_STATUS oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + struct bb_reg_param *pbbreg; + u16 offset; + u32 value; @@ -73439,9 +73455,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + struct bb_reg_param *pbbreg; + u16 offset; + u32 value; @@ -73475,9 +73488,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + struct rf_reg_param *pbbreg; + u8 path; + u8 offset; @@ -73517,9 +73527,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + struct rf_reg_param *pbbreg; + u8 path; + u8 offset; @@ -73564,9 +73571,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + * ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 ratevalue;/* 4 */ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -73595,9 +73599,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 mode; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -73632,9 +73633,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + @@ -73654,9 +73652,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 Channel; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -73689,9 +73684,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u16 bandwidth; + u16 channel_offset; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; @@ -73724,9 +73716,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 antenna; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -73756,9 +73745,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + +NDIS_STATUS oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 tx_pwr_idx; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -73891,9 +73877,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + @@ -73913,9 +73896,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + @@ -73940,9 +73920,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + @@ -73968,9 +73945,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* **************** oid_rtl_seg_81_80_20 section end **************** */ +NDIS_STATUS oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 bStartTest; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74003,9 +73977,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + +NDIS_STATUS oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 bStartTest; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74038,9 +74009,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + +NDIS_STATUS oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 bStartTest; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74073,9 +74041,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + +NDIS_STATUS oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 bStartTest; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74104,9 +74069,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +{ + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + if (poid_par_priv->type_of_oid != SET_OID) @@ -74126,9 +74088,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + PNDIS_802_11_SSID pssid; @@ -74162,9 +74121,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + pRW_Reg RegRWStruct; + u32 offset, width; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; @@ -74207,9 +74163,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + pRW_Reg RegRWStruct; + u32 offset, width, value; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; @@ -74263,9 +74216,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +NDIS_STATUS oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + pBurst_RW_Reg pBstRwReg; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74294,9 +74244,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +NDIS_STATUS oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + pBurst_RW_Reg pBstRwReg; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74327,9 +74274,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + + TX_CMD_Desc *TxCmd_Info; + @@ -74360,9 +74304,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +NDIS_STATUS oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + pEEPROM_RWParam pEEPROM; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74392,9 +74333,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +NDIS_STATUS oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + pEEPROM_RWParam pEEPROM; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74487,9 +74425,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + struct io_queue *pio_queue = (struct io_queue *)Adapter->pio_queue; + struct intf_hdl *pintfhdl = &pio_queue->intf; + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + +#ifdef CONFIG_SDIO_HCI @@ -74527,9 +74462,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + struct io_queue *pio_queue = (struct io_queue *)Adapter->pio_queue; + struct intf_hdl *pintfhdl = &pio_queue->intf; + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + +#ifdef CONFIG_SDIO_HCI @@ -74563,9 +74495,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + @@ -74648,9 +74577,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +{ + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + @@ -74671,9 +74597,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ----------------------------------------------------------------------------- */ +NDIS_STATUS oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + u8 thermal = 0; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -74702,9 +74625,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + @@ -74741,9 +74661,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + @@ -74773,9 +74690,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +NDIS_STATUS oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u32 ratevalue; + u8 datarates[NumRates]; + int i; @@ -74874,9 +74788,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + struct setratable_parm *prate_table; @@ -75048,9 +74959,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + struct sta_info *psta = NULL; @@ -75092,9 +75000,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + struct sta_info *psta = NULL; @@ -75227,9 +75132,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + DR_VARIABLE_STRUCT *pdrv_var; @@ -75291,9 +75193,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + PEFUSE_ACCESS_STRUCT pefuse; + u8 *data; + u16 addr = 0, cnts = 0, max_available_size = 0; @@ -75332,9 +75231,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + PEFUSE_ACCESS_STRUCT pefuse; + u8 *data; + u16 addr = 0, cnts = 0, max_available_size = 0; @@ -75369,9 +75265,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + PPGPKT_STRUCT ppgpkt; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -75414,9 +75307,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u16 size; + u8 ret; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; @@ -75480,9 +75370,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u8 *data; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); @@ -75531,9 +75418,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + + u32 crystal_cap = 0; + @@ -75561,9 +75445,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + +NDIS_STATUS oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u8 rx_pkt_type; + /* u32 rcr_val32; */ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; @@ -75643,9 +75524,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + u32 txagc; @@ -75821,9 +75699,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv) +{ -+#ifdef PLATFORM_OS_XP -+ _irqL oldirql; -+#endif + u8 bpwrup; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; +#ifdef PLATFORM_LINUX @@ -75862,9 +75737,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 +#if 0 + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); -+ /* #ifdef PLATFORM_OS_XP */ -+ /* _irqL oldirql; -+ * #endif */ + + + if (poid_par_priv->type_of_oid != QUERY_OID) { @@ -75888,9 +75760,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_mp_ioctl.c linux-5.11.4-rtl8 + return 0; +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_odm.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_odm.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_odm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_odm.c 2023-05-26 22:35:36.541136899 +0300 @@ -0,0 +1,420 @@ +/****************************************************************************** + * @@ -76167,7 +76039,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_odm.c linux-5.11.4-rtl8812au + RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, l_rxsc:%u)\n" + , *phys & 0xf + , MAC_ARG(get_ta(wlanhdr)) -+ , is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC" ++ , is_broadcast_mac_addr(wifi_get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(wifi_get_ra(wlanhdr)) ? "MC" : "UC" + , HDATA_RATE(attrib->data_rate) + , phys_t0->band, phys_t0->channel, phys_t0->rxsc + ); @@ -76283,7 +76155,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_odm.c linux-5.11.4-rtl8812au + RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, rf_mode:%u, l_rxsc:%u, ht_rxsc:%u) => %u,%u\n" + , *phys & 0xf + , MAC_ARG(get_ta(wlanhdr)) -+ , is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC" ++ , is_broadcast_mac_addr(wifi_get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(wifi_get_ra(wlanhdr)) ? "MC" : "UC" + , HDATA_RATE(attrib->data_rate) + , phys_t1->band, phys_t1->channel, phys_t1->rf_mode, phys_t1->l_rxsc, phys_t1->ht_rxsc + , pkt_cch, pkt_bw @@ -76301,7 +76173,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_odm.c linux-5.11.4-rtl8812au + RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, l_rxsc:%u, ht_rxsc:%u)\n" + , *phys & 0xf + , MAC_ARG(get_ta(wlanhdr)) -+ , is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC" ++ , is_broadcast_mac_addr(wifi_get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(wifi_get_ra(wlanhdr)) ? "MC" : "UC" + , HDATA_RATE(attrib->data_rate) + , phys_t2->band, phys_t2->channel, phys_t2->l_rxsc, phys_t2->ht_rxsc + ); @@ -76312,9 +76184,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_odm.c linux-5.11.4-rtl8812au + +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_p2p.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_p2p.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_p2p.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_p2p.c 2022-01-28 22:59:35.559651657 +0200 @@ -0,0 +1,5456 @@ +/****************************************************************************** + * @@ -81772,10 +81644,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_p2p.c linux-5.11.4-rtl8812au +} + +#endif /* CONFIG_P2P */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_pwrctrl.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_pwrctrl.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_pwrctrl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_pwrctrl.c 2023-05-26 22:35:36.541136899 +0300 +@@ -0,0 +1,2761 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -83868,10 +83740,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_pwrctrl.c linux-5.11.4-rtl88 + return; +#endif + -+#ifdef PLATFORM_WINDOWS -+ pwrctrlpriv->pnp_current_pwr_state = NdisDeviceStateD0; -+#endif -+ + _init_pwrlock(&pwrctrlpriv->lock); + _init_pwrlock(&pwrctrlpriv->check_32k_lock); + pwrctrlpriv->rf_pwrstate = rf_on; @@ -84541,10 +84409,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_pwrctrl.c linux-5.11.4-rtl88 + _rtw_ssmps(adapter, sta); +} + -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_recv.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_recv.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_recv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_recv.c 2023-05-26 22:35:36.541136899 +0300 +@@ -0,0 +1,5125 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -87119,21 +86987,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_recv.c linux-5.11.4-rtl8812a + /* ptr -= 16; */ + /* _rtw_memcpy(ptr, get_rxmem(precvframe), 16); */ + } else { -+#ifdef PLATFORM_OS_XP -+ NDIS_PACKET_8021Q_INFO VlanPriInfo; -+ UINT32 UserPriority = precvframe->u.hdr.attrib.priority; -+ UINT32 VlanID = (pvlan != NULL ? get_vlan_id(pvlan) : 0); + -+ VlanPriInfo.Value = /* Get current value. */ -+ NDIS_PER_PACKET_INFO_FROM_PACKET(precvframe->u.hdr.pkt, Ieee8021QInfo); -+ -+ VlanPriInfo.TagHeader.UserPriority = UserPriority; -+ VlanPriInfo.TagHeader.VlanId = VlanID ; -+ -+ VlanPriInfo.TagHeader.CanonicalFormatId = 0; /* Should be zero. */ -+ VlanPriInfo.TagHeader.Reserved = 0; /* Should be zero. */ -+ NDIS_PER_PACKET_INFO_FROM_PACKET(precvframe->u.hdr.pkt, Ieee8021QInfo) = VlanPriInfo.Value; -+#endif + } + + if (eth_type == 0x8712) { /* append rx status for mp test packets */ @@ -87150,8 +87004,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_recv.c linux-5.11.4-rtl8812a + _rtw_memcpy(ptr + 12, ð_type, 2); + +exit: -+ -+ + return ret; +} +#endif @@ -89398,7 +89250,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_recv.c linux-5.11.4-rtl8812a + wlanhdr = get_recvframe_data(precvframe); + + ta = get_ta(wlanhdr); -+ ra = get_ra(wlanhdr); ++ ra = wifi_get_ra(wlanhdr); + is_ra_bmc = IS_MCAST(ra); + + if (_rtw_memcmp(adapter_mac_addr(padapter), ta, ETH_ALEN) == _TRUE) { @@ -89538,7 +89390,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_recv.c linux-5.11.4-rtl8812a +{ + s32 ret = _SUCCESS; + u8 *pbuf = precvframe->u.hdr.rx_data; -+ u8 *pda = get_ra(pbuf); ++ u8 *pda = wifi_get_ra(pbuf); + u8 ra_is_bmc = IS_MCAST(pda); + _adapter *primary_padapter = precvframe->u.hdr.adapter; +#ifdef CONFIG_CONCURRENT_MODE @@ -89686,10 +89538,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_recv.c linux-5.11.4-rtl8812a + ); +} +#endif /* DBG_RX_BH_TRACKING */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_rf.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_rf.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_rf.c 2022-01-28 22:59:35.560651705 +0200 +@@ -0,0 +1,1395 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -90143,7 +89995,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rf.c linux-5.11.4-rtl8812au/ + return 2484; + else if (chan < 14) + return 2407 + chan * 5; -+ } else if (chan >= 36 && chan <= 177) ++ } else if (chan >= 15 && chan <= 177) + return 5000 + chan * 5; + + return 0; /* not supported */ @@ -90464,9 +90316,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rf.c linux-5.11.4-rtl8812au/ + + RTW_PRINT_SEL(sel, "txpwr_lmt_2g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_2g_cck_ofdm_state); + #ifdef CONFIG_IEEE80211_BAND_5GHZ -+ if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) ++ if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) { + RTW_PRINT_SEL(sel, "txpwr_lmt_5g_cck_ofdm_state:0x%02x\n", rfctl->txpwr_lmt_5g_cck_ofdm_state); + RTW_PRINT_SEL(sel, "txpwr_lmt_5g_20_40_ref:0x%02x\n", rfctl->txpwr_lmt_5g_20_40_ref); ++ } + #endif + RTW_PRINT_SEL(sel, "\n"); + @@ -91084,9 +90937,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rf.c linux-5.11.4-rtl8812au/ + + return rtw_is_long_cac_range(hi, lo, dfs_region) ? _TRUE : _FALSE; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_rm.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_rm.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_rm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_rm.c 2022-01-28 22:59:35.561651752 +0200 @@ -0,0 +1,2470 @@ +/****************************************************************************** + * @@ -93558,9 +93411,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rm.c linux-5.11.4-rtl8812au/ +#endif +} +#endif /* CONFIG_RTW_80211K */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_rm_fsm.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_rm_fsm.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_rm_fsm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_rm_fsm.c 2022-01-28 22:59:35.561651752 +0200 @@ -0,0 +1,998 @@ +/****************************************************************************** + * @@ -94560,9 +94413,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rm_fsm.c linux-5.11.4-rtl881 + rm_state_run(prm, RM_EV_state_in); +} +#endif /* CONFIG_RTW_80211K */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_rson.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_rson.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_rson.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_rson.c 2022-01-28 22:59:35.561651752 +0200 @@ -0,0 +1,595 @@ +/****************************************************************************** + * @@ -95159,9 +95012,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_rson.c linux-5.11.4-rtl8812a +} + +#endif /* CONFIG_RTW_REPEATER_SON */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_sdio.c 2022-01-28 22:59:35.561651752 +0200 @@ -0,0 +1,130 @@ +/****************************************************************************** + * @@ -95293,9 +95146,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_sdio.c linux-5.11.4-rtl8812a + + return ret; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_security.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_security.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_security.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_security.c 2022-12-18 17:40:24.573937030 +0200 @@ -0,0 +1,3122 @@ +/****************************************************************************** + * @@ -96872,7 +96725,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_security.c linux-5.11.4-rtl8 + pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; + + /* 4 start to encrypt each fragment */ -+ if ((pattrib->encrypt == _AES_)) { ++ if (pattrib->encrypt == _AES_) { + /* + if(pattrib->psta) + { @@ -97227,7 +97080,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_security.c linux-5.11.4-rtl8 + u32 res = _SUCCESS; + pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; + /* 4 start to encrypt each fragment */ -+ if ((prxattrib->encrypt == _AES_)) { ++ if (prxattrib->encrypt == _AES_) { + + stainfo = rtw_get_stainfo(&padapter->stapriv , &prxattrib->ta[0]); + if (stainfo != NULL) { @@ -98419,9 +98272,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_security.c linux-5.11.4-rtl8 + return crc; +} +#endif /*CONFIG_WOWLAN*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_sreset.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_sreset.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_sreset.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_sreset.c 2022-01-28 22:59:35.561651752 +0200 @@ -0,0 +1,314 @@ +/****************************************************************************** + * @@ -98737,10 +98590,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_sreset.c linux-5.11.4-rtl881 + psrtpriv->rx_cnt = 0; +#endif +} -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_sta_mgt.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_sta_mgt.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_sta_mgt.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_sta_mgt.c 2022-12-18 17:40:24.573937030 +0200 +@@ -0,0 +1,1319 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -99108,21 +98961,17 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_sta_mgt.c linux-5.11.4-rtl88 + +} + -+void rtw_mfree_stainfo(struct sta_info *psta); +void rtw_mfree_stainfo(struct sta_info *psta) +{ + -+ if (&psta->lock != NULL) -+ _rtw_spinlock_free(&psta->lock); ++ _rtw_spinlock_free(&psta->lock); + + _rtw_free_sta_xmit_priv_lock(&psta->sta_xmitpriv); + _rtw_free_sta_recv_priv_lock(&psta->sta_recvpriv); + +} + -+ +/* this function is used to free the memory of lock || sema for all stainfos */ -+void rtw_mfree_all_stainfo(struct sta_priv *pstapriv); +void rtw_mfree_all_stainfo(struct sta_priv *pstapriv) +{ + _irqL irqL; @@ -100064,9 +99913,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_sta_mgt.c linux-5.11.4-rtl88 +} +#endif /* CONFIG_RTW_PRE_LINK_STA */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_tdls.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_tdls.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_tdls.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_tdls.c 2022-01-28 22:59:35.562651800 +0200 @@ -0,0 +1,3505 @@ +/****************************************************************************** + * @@ -103573,9 +103422,1148 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_tdls.c linux-5.11.4-rtl8812a +} + +#endif /* CONFIG_TDLS */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_vht.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_vht.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_vht.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_vht.c 2022-01-28 22:59:35.562651800 +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-6.3.4/drivers/staging/rtl8812au/core/rtw_wapi.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_wapi.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_wapi.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_wapi.c 2022-01-28 22:59:35.562651800 +0200 @@ -0,0 +1,1312 @@ +/****************************************************************************** + * @@ -104889,9 +105877,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_wapi.c linux-5.11.4-rtl8812a + } +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_wapi_sms4.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_wapi_sms4.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_wapi_sms4.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_wapi_sms4.c 2022-01-28 22:59:35.562651800 +0200 @@ -0,0 +1,922 @@ +/****************************************************************************** + * @@ -105815,1149 +106803,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_wapi_sms4.c linux-5.11.4-rtl +#endif + +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_wlan_util.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_wlan_util.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_wlan_util.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_wlan_util.c 2022-01-28 22:59:35.563651847 +0200 +@@ -0,0 +1,4973 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -110183,12 +110032,13 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_wlan_util.c linux-5.11.4-rtl + goto exit; + else { + if(*(p+1) > 6 ) { -+ for(i=0; i<9;i++) ++ for(i=0; i<9;i++) { + RTW_INFO("p[%d]=0x%x",i,*(p+i) ); + RTW_INFO("\n"); ++ } + if(*(p+6) != 2) + goto exit; -+ ++ + if(*(p+8) == RT_HT_CAP_USE_JAGUAR_BCUT) + sta->vendor_8812 = TRUE; + else if (*(p+8) == RT_HT_CAP_USE_JAGUAR_CCUT) @@ -111930,9 +111780,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_wlan_util.c linux-5.11.4-rtl + /*TODO get offset of bcn's timestamp*/ + /*pmlmeext->bcn_timestamp;*/ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/core/rtw_xmit.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_xmit.c +--- linux-6.3.4/drivers/staging/rtl8812au/core/rtw_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/core/rtw_xmit.c 2022-01-28 22:59:35.563651847 +0200 @@ -0,0 +1,6097 @@ +/****************************************************************************** + * @@ -118031,9 +117881,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/core/rtw_xmit.c linux-5.11.4-rtl8812a + RTW_INFO("%s ack_tx not set\n", __func__); +} +#endif /* CONFIG_XMIT_ACK */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/efuse_mask.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/efuse_mask.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/efuse_mask.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/efuse_mask.h 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,164 @@ +/****************************************************************************** + * @@ -118199,9 +118049,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/efuse_mask.h linux-5.11.4-r + #endif + +#endif /*CONFIG_SDIO_HCI*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.c 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,94 @@ +/****************************************************************************** + * @@ -118297,9 +118147,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_ + + return (result > 0) ? 0 : 1; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_PCIE.h 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** + * @@ -118334,9 +118184,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_ +EFUSE_IsAddressMasked_MP_8812A_MPCIE(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.c 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,94 @@ +/****************************************************************************** + * @@ -118432,9 +118282,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_ + + return (result > 0) ? 0 : 1; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_USB.h 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,34 @@ +/****************************************************************************** + * @@ -118470,9 +118320,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8812A_ +EFUSE_IsAddressMasked_MP_8812A_MUSB(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.c 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,93 @@ +/****************************************************************************** + * @@ -118567,9 +118417,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_ + + return (result > 0) ? 0 : 1; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_PCIE.h 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** + * @@ -118604,9 +118454,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_ +EFUSE_IsAddressMasked_MP_8821A_MPCIE(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.c 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,96 @@ +/****************************************************************************** + * @@ -118704,9 +118554,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_ + + return (result > 0) ? 0 : 1; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_SDIO.h 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,31 @@ +/****************************************************************************** + * @@ -118739,9 +118589,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_ +EFUSE_IsAddressMasked_MP_8821A_MSDIO(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.c 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,95 @@ +/****************************************************************************** + * @@ -118838,9 +118688,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_ + + return (result > 0) ? 0 : 1; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_USB.h 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,31 @@ +/****************************************************************************** + * @@ -118873,9 +118723,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8812a/HalEfuseMask8821A_ +EFUSE_IsAddressMasked_MP_8821A_MUSB(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.c 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,93 @@ +/****************************************************************************** +* @@ -118970,9 +118820,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_ + return (result > 0) ? 0 : 1; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_PCIE.h 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** +* @@ -119007,9 +118857,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_ +BOOLEAN EFUSE_IsAddressMasked_MP_8814A_MPCIE(u2Byte Offset); + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.c 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** +* @@ -119101,9 +118951,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_ + return (result > 0) ? 0 : 1; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_USB.h 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** +* @@ -119138,9 +118988,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/efuse/rtl8814a/HalEfuseMask8814A_ + +BOOLEAN EFUSE_IsAddressMasked_MP_8814A_MUSB(u2Byte Offset); + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_btcoex.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_btcoex.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_btcoex.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_btcoex.c 2022-01-28 22:59:35.585652890 +0200 @@ -0,0 +1,5706 @@ +/****************************************************************************** + * @@ -124848,9 +124698,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_btcoex.c linux-5.11.4-rtl8812 + EXhalbtcoutsrc_rx_rate_change_notify(&GLBtCoexist, is_data_frame, EXhalbtcoutsrc_rate_id_to_btc_rate_id(rate_id)); +} +#endif /* CONFIG_BT_COEXIST */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_btcoex_wifionly.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_btcoex_wifionly.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_btcoex_wifionly.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_btcoex_wifionly.c 2022-01-28 22:59:35.585652890 +0200 @@ -0,0 +1,224 @@ +/****************************************************************************** + * @@ -125076,10 +124926,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_btcoex_wifionly.c linux-5.11. + +#endif + -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_com.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_com.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_com.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_com.c 2023-05-26 22:35:36.543136899 +0300 +@@ -0,0 +1,14360 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -129412,28 +129262,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + if (ret != _SUCCESS) + goto exit; + -+#if defined(CONFIG_RTL8188E) -+ if (rtw_get_chip_type(adapter) == RTL8188E) { -+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); -+ -+ /* 8188E FW doesn't set macid no link, driver does it by self */ -+ if (opmode) -+ rtw_hal_set_hwreg(adapter, HW_VAR_MACID_LINK, &macid); -+ else -+ rtw_hal_set_hwreg(adapter, HW_VAR_MACID_NOLINK, &macid); -+ -+ /* for 8188E RA */ -+#if (RATE_ADAPTIVE_SUPPORT == 1) -+ if (hal_data->fw_ractrl == _FALSE) { -+ u8 max_macid; -+ -+ max_macid = rtw_search_max_mac_id(adapter); -+ rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, &max_macid); -+ } -+#endif -+ } -+#endif -+ +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + /* TODO: this should move to IOT issue area */ + if (rtw_get_chip_type(adapter) == RTL8812 @@ -129838,21 +129666,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + rtw_write32(adapter, REG_RXPKT_NUM, + (rtw_read32(adapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN))); +} -+#if defined(CONFIG_RTL8188E) -+static void rtw_hal_disable_tx_report(_adapter *adapter) -+{ -+ rtw_write8(adapter, REG_TX_RPT_CTRL, -+ ((rtw_read8(adapter, REG_TX_RPT_CTRL) & ~BIT(1))) & ~BIT(5)); -+ RTW_INFO("disable TXRPT:0x%02x\n", rtw_read8(adapter, REG_TX_RPT_CTRL)); -+} -+ -+static void rtw_hal_enable_tx_report(_adapter *adapter) -+{ -+ rtw_write8(adapter, REG_TX_RPT_CTRL, -+ ((rtw_read8(adapter, REG_TX_RPT_CTRL) | BIT(1))) | BIT(5)); -+ RTW_INFO("enable TX_RPT:0x%02x\n", rtw_read8(adapter, REG_TX_RPT_CTRL)); -+} -+#endif +static void rtw_hal_release_rx_dma(_adapter *adapter) +{ + u32 val32 = 0; @@ -130938,10 +130751,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + issue_beacon(padapter, 0); + + rtw_msleep_os(2); -+ #if defined(CONFIG_RTL8188E) -+ if (IS_HARDWARE_TYPE_8188E(padapter)) -+ rtw_hal_disable_tx_report(padapter); -+ #endif + /* RX DMA stop */ + res = rtw_hal_pause_rx_dma(padapter); + if (res == _FAIL) @@ -131002,11 +130811,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + } +#endif /*DBG_CHECK_FW_PS_STATE*/ + -+ #if defined(CONFIG_RTL8188E) -+ if (IS_HARDWARE_TYPE_8188E(padapter)) -+ rtw_hal_enable_tx_report(padapter); -+ #endif -+ + rtw_hal_force_enable_rxdma(padapter); + + rtw_hal_fw_dl(padapter, _FALSE); @@ -134686,10 +134490,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + (u8 *)&media_status_rpt); + + /* RX DMA stop */ -+ #if defined(CONFIG_RTL8188E) -+ if (IS_HARDWARE_TYPE_8188E(adapter)) -+ rtw_hal_disable_tx_report(adapter); -+ #endif + + res = rtw_hal_pause_rx_dma(adapter); + if (res == _FAIL) @@ -134878,11 +134678,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + #endif + rtw_hal_release_rx_dma(adapter); + -+ #if defined(CONFIG_RTL8188E) -+ if (IS_HARDWARE_TYPE_8188E(adapter)) -+ rtw_hal_enable_tx_report(adapter); -+ #endif -+ + if ((pwrctl->wowlan_wake_reason != RX_DISASSOC) && + (pwrctl->wowlan_wake_reason != RX_DEAUTH) && + (pwrctl->wowlan_wake_reason != FW_DECISION_DISCONNECT)) { @@ -137651,7 +137446,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + + /*RTW_INFO("=>%s WIFI_DATA_TYPE or WIFI_QOS_DATA_TYPE\n", __FUNCTION__);*/ + if (psta) { -+ if (IS_MCAST(get_ra(get_recvframe_data(prframe)))) ++ if (IS_MCAST(wifi_get_ra(get_recvframe_data(prframe)))) + psta_dframe_info = &psta->sta_dframe_info_bmc; + else + psta_dframe_info = &psta->sta_dframe_info; @@ -137686,61 +137481,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + interface_type = rtw_get_intf_type(adapter); + + switch (rtw_get_chip_type(adapter)) { -+#ifdef CONFIG_RTL8723B -+ case RTL8723B: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8723BU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8723BS; -+ else if (interface_type == RTW_PCIE) -+ addr_offset = EEPROM_MAC_ADDR_8723BE; -+ break; -+#endif -+#ifdef CONFIG_RTL8703B -+ case RTL8703B: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8703BU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8703BS; -+ break; -+#endif -+#ifdef CONFIG_RTL8723D -+ case RTL8723D: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8723DU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8723DS; -+ else if (interface_type == RTW_PCIE) -+ addr_offset = EEPROM_MAC_ADDR_8723DE; -+ break; -+#endif -+ -+#ifdef CONFIG_RTL8188E -+ case RTL8188E: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_88EU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_88ES; -+ else if (interface_type == RTW_PCIE) -+ addr_offset = EEPROM_MAC_ADDR_88EE; -+ break; -+#endif -+#ifdef CONFIG_RTL8188F -+ case RTL8188F: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8188FU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8188FS; -+ break; -+#endif -+#ifdef CONFIG_RTL8188GTV -+ case RTL8188GTV: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8188GTVU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8188GTVS; -+ break; -+#endif +#ifdef CONFIG_RTL8812A + case RTL8812: + if (interface_type == RTW_USB) @@ -137759,16 +137499,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + addr_offset = EEPROM_MAC_ADDR_8821AE; + break; +#endif -+#ifdef CONFIG_RTL8192E -+ case RTL8192E: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8192EU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8192ES; -+ else if (interface_type == RTW_PCIE) -+ addr_offset = EEPROM_MAC_ADDR_8192EE; -+ break; -+#endif +#ifdef CONFIG_RTL8814A + case RTL8814A: + if (interface_type == RTW_USB) @@ -137778,46 +137508,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + break; +#endif + -+#ifdef CONFIG_RTL8822B -+ case RTL8822B: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8822BU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8822BS; -+ else if (interface_type == RTW_PCIE) -+ addr_offset = EEPROM_MAC_ADDR_8822BE; -+ break; -+#endif /* CONFIG_RTL8822B */ -+ -+#ifdef CONFIG_RTL8821C -+ case RTL8821C: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8821CU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8821CS; -+ else if (interface_type == RTW_PCIE) -+ addr_offset = EEPROM_MAC_ADDR_8821CE; -+ break; -+#endif /* CONFIG_RTL8821C */ -+ -+#ifdef CONFIG_RTL8710B -+ case RTL8710B: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8710B; -+ break; -+#endif -+ -+#ifdef CONFIG_RTL8192F -+ case RTL8192F: -+ if (interface_type == RTW_USB) -+ addr_offset = EEPROM_MAC_ADDR_8192FU; -+ else if (interface_type == RTW_SDIO) -+ addr_offset = EEPROM_MAC_ADDR_8192FS; -+ else if (interface_type == RTW_PCIE) -+ addr_offset = EEPROM_MAC_ADDR_8192FE; -+ break; -+#endif /* CONFIG_RTL8192F */ -+ + } + + if (addr_offset == -1) { @@ -138035,32 +137725,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + } else + RTW_INFO("Using the default RF gain.\n"); + -+#elif defined(CONFIG_RTL8188E) -+ if (value & BIT4 && (registry_par->RegPwrTrimEnable == 1)) { -+ RTW_INFO("8188ES Offset RF Gain.\n"); -+ RTW_INFO("8188ES Offset RF Gain. EEPROMRFGainVal=0x%x\n", -+ pHalData->EEPROMRFGainVal); -+ -+ if (pHalData->EEPROMRFGainVal != 0xff) { -+ res = rtw_hal_read_rfreg(padapter, RF_PATH_A, -+ REG_RF_BB_GAIN_OFFSET, 0xffffffff); -+ -+ RTW_INFO("Offset RF Gain. reg 0x55=0x%x\n", res); -+ res &= 0xfff87fff; -+ -+ res |= (pHalData->EEPROMRFGainVal & 0x0f) << 15; -+ RTW_INFO("Offset RF Gain. res=0x%x\n", res); -+ -+ rtw_hal_write_rfreg(padapter, RF_PATH_A, -+ REG_RF_BB_GAIN_OFFSET, -+ RF_GAIN_OFFSET_MASK, res); -+ } else { -+ RTW_INFO("Offset RF Gain. EEPROMRFGainVal=0x%x == 0xff, didn't run Kfree\n", -+ pHalData->EEPROMRFGainVal); -+ } -+ } else -+ RTW_INFO("Using the default RF gain.\n"); -+#else + /* TODO: call this when channel switch */ + if (kfree_data->flag & KFREE_FLAG_ON) + rtw_rf_apply_tx_gain_offset(padapter, 6); /* input ch6 to select BB_GAIN_2G */ @@ -138792,14 +138456,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + return curr_tx_sgi; + + if (padapter->fix_rate == 0xff) { -+#if defined(CONFIG_RTL8188E) -+#if (RATE_ADAPTIVE_SUPPORT == 1) -+ curr_tx_sgi = hal_data->odmpriv.ra_info[psta->cmn.mac_id].rate_sgi; -+#endif /* (RATE_ADAPTIVE_SUPPORT == 1)*/ -+#else + ra_info = &psta->cmn.ra_info; + curr_tx_sgi = ((ra_info->curr_tx_rate) & 0x80) >> 7; -+#endif + } else { + curr_tx_sgi = ((padapter->fix_rate) & 0x80) >> 7; + } @@ -138817,14 +138475,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + return rate_id; + + if (padapter->fix_rate == 0xff) { -+#if defined(CONFIG_RTL8188E) -+#if (RATE_ADAPTIVE_SUPPORT == 1) -+ rate_id = hal_data->odmpriv.ra_info[psta->cmn.mac_id].decision_rate; -+#endif /* (RATE_ADAPTIVE_SUPPORT == 1)*/ -+#else + ra_info = &psta->cmn.ra_info; + rate_id = ra_info->curr_tx_rate & 0x7f; -+#endif + } else { + rate_id = padapter->fix_rate & 0x7f; + } @@ -138908,14 +138560,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + crystal_cap = crystal_cap & 0x3F; + + switch (rtw_get_chip_type(adapter)) { -+#if defined(CONFIG_RTL8188E) || defined(CONFIG_RTL8188F) || defined(CONFIG_RTL8188GTV) -+ case RTL8188E: -+ case RTL8188F: -+ case RTL8188GTV: -+ /* write 0x24[16:11] = 0x24[22:17] = CrystalCap */ -+ phy_set_bb_reg(adapter, REG_AFE_XTAL_CTRL, 0x007FF800, (crystal_cap | (crystal_cap << 6))); -+ break; -+#endif +#if defined(CONFIG_RTL8812A) + case RTL8812: + /* write 0x2C[30:25] = 0x2C[24:19] = CrystalCap */ @@ -138940,25 +138584,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + phy_set_bb_reg(adapter, REG_MAC_PHY_CTRL, 0x07FF8000, (crystal_cap | (crystal_cap << 6))); + break; +#endif -+#if defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) || defined(CONFIG_RTL8192F) -+ -+ case RTL8822B: -+ case RTL8821C: -+ case RTL8192F: -+ /* write 0x28[6:1] = 0x24[30:25] = CrystalCap */ -+ crystal_cap = crystal_cap & 0x3F; -+ phy_set_bb_reg(adapter, REG_AFE_XTAL_CTRL, 0x7E000000, crystal_cap); -+ phy_set_bb_reg(adapter, REG_AFE_PLL_CTRL, 0x7E, crystal_cap); -+ break; -+#endif -+#if defined(CONFIG_RTL8710B) -+ case RTL8710B: -+ /*Change by ylb 20160728, Becase 0x2C[23:12] is removed to syson 0x60[29:18] */ -+ /* 0x2C[23:18] = 0x2C[29:24] = CrystalCap //Xo:[29:24], Xi:[23:18]*/ -+ crystal_cap = crystal_cap & 0x3F; -+ hal_set_syson_reg(adapter, REG_SYS_XTAL_CTRL0, 0x3FFC0000, (crystal_cap | (crystal_cap << 6))); -+ break; -+#endif + default: + rtw_warn_on(1); + } @@ -138972,36 +138597,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + interface_type = rtw_get_intf_type(adapter); + + switch (rtw_get_chip_type(adapter)) { -+#ifdef CONFIG_RTL8723B -+ case RTL8723B: -+ init_hal_spec_8723b(adapter); -+ break; -+#endif -+#ifdef CONFIG_RTL8703B -+ case RTL8703B: -+ init_hal_spec_8703b(adapter); -+ break; -+#endif -+#ifdef CONFIG_RTL8723D -+ case RTL8723D: -+ init_hal_spec_8723d(adapter); -+ break; -+#endif -+#ifdef CONFIG_RTL8188E -+ case RTL8188E: -+ init_hal_spec_8188e(adapter); -+ break; -+#endif -+#ifdef CONFIG_RTL8188F -+ case RTL8188F: -+ init_hal_spec_8188f(adapter); -+ break; -+#endif -+#ifdef CONFIG_RTL8188GTV -+ case RTL8188GTV: -+ init_hal_spec_8188gtv(adapter); -+ break; -+#endif +#ifdef CONFIG_RTL8812A + case RTL8812: + init_hal_spec_8812a(adapter); @@ -139012,36 +138607,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ + init_hal_spec_8821a(adapter); + break; +#endif -+#ifdef CONFIG_RTL8192E -+ case RTL8192E: -+ init_hal_spec_8192e(adapter); -+ break; -+#endif +#ifdef CONFIG_RTL8814A + case RTL8814A: + init_hal_spec_8814a(adapter); + break; +#endif -+#ifdef CONFIG_RTL8822B -+ case RTL8822B: -+ rtl8822b_init_hal_spec(adapter); -+ break; -+#endif -+#ifdef CONFIG_RTL8821C -+ case RTL8821C: -+ init_hal_spec_rtl8821c(adapter); -+ break; -+#endif -+#ifdef CONFIG_RTL8710B -+ case RTL8710B: -+ init_hal_spec_8710b(adapter); -+ break; -+#endif -+#ifdef CONFIG_RTL8192F -+ case RTL8192F: -+ init_hal_spec_8192f(adapter); -+ break; -+#endif + + default: + RTW_ERR("%s: unknown chip_type:%u\n" @@ -139720,9 +139290,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com.c linux-5.11.4-rtl8812au/ +} +#endif /*CONFIG_RTL8812A*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_com_c2h.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_com_c2h.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_com_c2h.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_com_c2h.h 2022-01-28 22:59:35.586652938 +0200 @@ -0,0 +1,123 @@ +/****************************************************************************** + * @@ -139847,9 +139417,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com_c2h.h linux-5.11.4-rtl881 +#endif + +#endif /* __COMMON_C2H_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_com_phycfg.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_com_phycfg.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_com_phycfg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_com_phycfg.c 2022-01-28 22:59:35.587652985 +0200 @@ -0,0 +1,5408 @@ +/****************************************************************************** + * @@ -145259,9 +144829,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_com_phycfg.c linux-5.11.4-rtl +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_dm_acs.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_dm_acs.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_dm_acs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_dm_acs.c 2022-01-28 22:59:35.587652985 +0200 @@ -0,0 +1,556 @@ +/****************************************************************************** + * @@ -145819,9 +145389,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm_acs.c linux-5.11.4-rtl8812 +} +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_dm_acs.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_dm_acs.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_dm_acs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_dm_acs.h 2022-01-28 22:59:35.587652985 +0200 @@ -0,0 +1,167 @@ +/****************************************************************************** + * @@ -145990,9 +145560,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm_acs.h linux-5.11.4-rtl8812 +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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_dm.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_dm.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_dm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_dm.c 2022-12-18 17:40:24.574937030 +0200 @@ -0,0 +1,1616 @@ +/****************************************************************************** + * @@ -146572,7 +146142,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm.c linux-5.11.4-rtl8812au/3 + return; + } + -+ if ((pregpriv->wifi_spec == 1)) { /* || (pmlmeinfo->HT_enable == 0)) */ ++ if (pregpriv->wifi_spec == 1) { /* || (pmlmeinfo->HT_enable == 0)) */ + precvpriv->is_any_non_be_pkts = _FALSE; + return; + } @@ -147610,9 +147180,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm.c linux-5.11.4-rtl8812au/3 + return; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_dm.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_dm.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_dm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_dm.h 2022-01-28 22:59:35.587652985 +0200 @@ -0,0 +1,111 @@ +/****************************************************************************** + * @@ -147725,9 +147295,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_dm.h linux-5.11.4-rtl8812au/3 +#endif + +#endif /* __HAL_DM_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_halmac.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_halmac.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_halmac.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_halmac.c 2022-01-28 22:59:35.587652985 +0200 @@ -0,0 +1,5555 @@ +/****************************************************************************** + * @@ -153284,9 +152854,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_halmac.c linux-5.11.4-rtl8812 + +#endif /* RTW_BEAMFORMING_VERSION_2 */ +#endif /* CONFIG_BEAMFORMING */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_halmac.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_halmac.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_halmac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_halmac.h 2022-01-28 22:59:35.587652985 +0200 @@ -0,0 +1,245 @@ +/****************************************************************************** + * @@ -153533,9 +153103,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_halmac.h linux-5.11.4-rtl8812 +#endif /* CONFIG_BEAMFORMING */ + +#endif /* _HAL_HALMAC_H_ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_hci/hal_usb.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_hci/hal_usb.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_hci/hal_usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_hci/hal_usb.c 2022-01-28 22:59:35.588653032 +0200 @@ -0,0 +1,564 @@ +/****************************************************************************** + * @@ -154101,10 +153671,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_hci/hal_usb.c linux-5.11.4-rt +#endif + +} -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_intf.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_intf.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_intf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_intf.c 2023-05-26 22:35:36.543136899 +0300 +@@ -0,0 +1,1698 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -154127,20 +153697,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_intf.c linux-5.11.4-rtl8812au + +const u32 _chip_type_to_odm_ic_type[] = { + 0, -+ ODM_RTL8188E, -+ ODM_RTL8192E, + ODM_RTL8812, + ODM_RTL8821, -+ ODM_RTL8723B, + ODM_RTL8814A, -+ ODM_RTL8703B, -+ ODM_RTL8188F, -+ ODM_RTL8188F, -+ ODM_RTL8822B, -+ ODM_RTL8723D, -+ ODM_RTL8821C, -+ ODM_RTL8710B, -+ ODM_RTL8192F, + 0, +}; + @@ -155520,7 +155079,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_intf.c linux-5.11.4-rtl8812au +u8 rtw_hal_ops_check(_adapter *padapter) +{ + u8 ret = _SUCCESS; -+#if 1 + /*** initialize section ***/ + if (NULL == padapter->hal_func.read_chip_version) { + rtw_hal_error_msg("read_chip_version"); @@ -155710,12 +155268,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_intf.c linux-5.11.4-rtl8812au + rtw_hal_error_msg("hal_mac_c2h_handler"); + ret = _FAIL; + } -+#elif !defined(CONFIG_RTL8188E) -+ if (NULL == padapter->hal_func.c2h_handler) { -+ rtw_hal_error_msg("c2h_handler"); -+ ret = _FAIL; -+ } -+#endif + +#if defined(CONFIG_LPS) || defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) + if (NULL == padapter->hal_func.fill_fake_txdesc) { @@ -155821,9 +155373,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_intf.c linux-5.11.4-rtl8812au +#endif + return ret; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_mcc.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_mcc.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_mcc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_mcc.c 2022-01-28 22:59:35.588653032 +0200 @@ -0,0 +1,3488 @@ +/****************************************************************************** + * @@ -159313,10 +158865,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_mcc.c linux-5.11.4-rtl8812au/ +} + +#endif /* CONFIG_MCC_MODE */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_mp.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_mp.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_mp.c 2023-05-26 22:35:36.543136899 +0300 +@@ -0,0 +1,2244 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -159340,39 +158892,12 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_mp.c linux-5.11.4-rtl8812au/3 +#ifdef RTW_HALMAC + #include /* struct HAL_DATA_TYPE, RF register definition and etc. */ +#else /* !RTW_HALMAC */ -+ #ifdef CONFIG_RTL8188E -+ #include -+ #endif -+ #ifdef CONFIG_RTL8723B -+ #include -+ #endif -+ #ifdef CONFIG_RTL8192E -+ #include -+ #endif + #if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8812A) + #include + #endif + #if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + #include + #endif -+ #ifdef CONFIG_RTL8703B -+ #include -+ #endif -+ #ifdef CONFIG_RTL8723D -+ #include -+ #endif -+ #ifdef CONFIG_RTL8710B -+ #include -+ #endif -+ #ifdef CONFIG_RTL8188F -+ #include -+ #endif -+ #ifdef CONFIG_RTL8188GTV -+ #include -+ #endif -+ #ifdef CONFIG_RTL8192F -+ #include -+ #endif +#endif /* !RTW_HALMAC */ + + @@ -159500,7 +159025,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_mp.c linux-5.11.4-rtl8812au/3 + } else if (IS_HARDWARE_TYPE_8723D(Adapter)) { + /* 2.4G CCK TX DFIR */ + /* 2016.01.20 Suggest from RS BB mingzhi*/ -+ if ((u1Channel == 14)) { ++ if (u1Channel == 14) { + phy_set_bb_reg(Adapter, rCCK0_TxFilter2, bMaskDWord, 0x0000B81C); + phy_set_bb_reg(Adapter, rCCK0_DebugPort, bMaskDWord, 0x00000000); + phy_set_bb_reg(Adapter, 0xAAC, bMaskDWord, 0x00003667); @@ -159927,6 +159452,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_mp.c linux-5.11.4-rtl8812au/3 + u1Byte Path = 0; + u4Byte IGReg = rA_IGI_Jaguar, IGvalue = 0; + ++ /* // kimocoder: Disable below as it's not in use. + for (Path; Path <= RF_PATH_D; Path++) { + switch (Path) { + case RF_PATH_B: @@ -159942,11 +159468,12 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_mp.c linux-5.11.4-rtl8812au/3 + IGReg = rA_IGI_Jaguar; + break; + } ++ */ ++ ++ IGvalue = phy_query_bb_reg(pAdapter, IGReg, bMaskByte0); ++ phy_set_bb_reg(pAdapter, IGReg, bMaskByte0, IGvalue + 2); ++ phy_set_bb_reg(pAdapter, IGReg, bMaskByte0, IGvalue); + -+ IGvalue = phy_query_bb_reg(pAdapter, IGReg, bMaskByte0); -+ phy_set_bb_reg(pAdapter, IGReg, bMaskByte0, IGvalue + 2); -+ phy_set_bb_reg(pAdapter, IGReg, bMaskByte0, IGvalue); -+ } +} + +VOID mpt_SetRFPath_8814A(PADAPTER pAdapter) @@ -161586,9 +161113,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_mp.c linux-5.11.4-rtl8812au/3 +} + +#endif /* CONFIG_MP_INCLUDE*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/hal_phy.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_phy.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/hal_phy.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/hal_phy.c 2022-01-28 22:59:35.588653032 +0200 @@ -0,0 +1,257 @@ +/****************************************************************************** + * @@ -161847,9 +161374,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/hal_phy.c linux-5.11.4-rtl8812au/ + +} /* PHY_RFShadowRead */ +#endif /*CONFIG_RF_SHADOW_RW*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/HalPwrSeqCmd.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/HalPwrSeqCmd.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/HalPwrSeqCmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/HalPwrSeqCmd.c 2022-01-28 22:59:35.584652843 +0200 @@ -0,0 +1,185 @@ +/****************************************************************************** + * @@ -162036,9 +161563,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/HalPwrSeqCmd.c linux-5.11.4-rtl88 + + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/led/hal_led.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/led/hal_led.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/led/hal_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/led/hal_led.c 2022-01-28 22:59:35.588653032 +0200 @@ -0,0 +1,254 @@ +/****************************************************************************** + * @@ -162294,9 +161821,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/led/hal_led.c linux-5.11.4-rtl881 + +#endif /* CONFIG_RTW_LED */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/led/hal_usb_led.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/led/hal_usb_led.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/led/hal_usb_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/led/hal_usb_led.c 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,4291 @@ +/****************************************************************************** + * @@ -166589,9 +166116,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/led/hal_usb_led.c linux-5.11.4-rt + ResetLedStatus(pLed); +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/ap_makefile.mk linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/ap_makefile.mk +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/ap_makefile.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/ap_makefile.mk 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,188 @@ + +_PHYDM_FILES :=\ @@ -166781,9 +166308,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/ap_makefile.mk linux-5.11.4 + + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halhwimg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halhwimg.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halhwimg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halhwimg.h 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,96 @@ +/****************************************************************************** + * @@ -166881,9 +166408,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halhwimg.h linux-5.11.4-rtl +#endif + +#endif /* @__INC_HW_IMG_H */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.c 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,1359 @@ +/****************************************************************************** + * @@ -168244,9 +167771,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.c linux-5 + odm_iq_calibrate(dm); +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ap.h 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,139 @@ +/****************************************************************************** + * @@ -168387,9 +167914,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ap.h linux-5 +void phydm_rf_watchdog(void *dm_void); + +#endif /*#ifndef __HALPHYRF_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.c 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,920 @@ +/****************************************************************************** + * @@ -169311,9 +168838,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.c linux-5 +#endif +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_ce.h 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,114 @@ +/****************************************************************************** + * @@ -169429,9 +168956,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_ce.h linux-5 +void phydm_rf_watchdog(void *dm_void); + +#endif /*__HALPHYRF_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.c 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,528 @@ +/****************************************************************************** + * @@ -169961,9 +169488,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.c linux- + + odm_txpowertracking_check(dm); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_iot.h 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,124 @@ +/****************************************************************************** + * @@ -170089,9 +169616,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_iot.h linux- +void phydm_rf_watchdog(void *dm_void); + +#endif /*#ifndef __HALPHYRF_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.c 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,841 @@ +/****************************************************************************** + * @@ -170934,9 +170461,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.c linux- + odm_iq_calibrate(dm); +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halphyrf_win.h 2022-01-28 22:59:35.589653080 +0200 @@ -0,0 +1,125 @@ +/****************************************************************************** + * @@ -171063,9 +170590,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halphyrf_win.h linux- +void phydm_rf_watchdog(struct dm_struct *dm); + +#endif /*#ifndef __HALPHYRF_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.c 2022-01-28 22:59:35.590653127 +0200 @@ -0,0 +1,2395 @@ +/****************************************************************************** + * @@ -173462,9 +172989,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf.c linux-5.11.4- +#endif +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.c 2022-01-28 22:59:35.590653127 +0200 @@ -0,0 +1,267 @@ +/****************************************************************************** + * @@ -173733,9 +173260,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.c linux-5 +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_debug.h 2022-01-28 22:59:35.590653127 +0200 @@ -0,0 +1,123 @@ +/****************************************************************************** + * @@ -173860,9 +173387,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_debug.h linux-5 +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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_dpk.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_dpk.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_dpk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_dpk.h 2022-01-28 22:59:35.590653127 +0200 @@ -0,0 +1,86 @@ +/****************************************************************************** + * @@ -173950,9 +173477,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_dpk.h linux-5.1 +}; + +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_features.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_features.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_features.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_features.h 2022-01-28 22:59:35.590653127 +0200 @@ -0,0 +1,43 @@ +/****************************************************************************** + * @@ -173997,9 +173524,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_features.h linu +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf.h 2022-01-28 22:59:35.590653127 +0200 @@ -0,0 +1,573 @@ +/****************************************************************************** + * @@ -174574,9 +174101,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf.h linux-5.11.4- +u32 halrf_query_tssi_value(void *dm_void); + +#endif /*__HALRF_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_iqk.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_iqk.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_iqk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_iqk.h 2022-01-28 22:59:35.590653127 +0200 @@ -0,0 +1,103 @@ +/****************************************************************************** + * @@ -174681,9 +174208,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_iqk.h linux-5.1 +}; + +#endif /*__HALRF_IQK_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.c 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,1191 @@ +/****************************************************************************** + * @@ -175876,9 +175403,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.c linux-5 + } + RF_DBG(dm, DBG_RF_MP, "<===[kfree] phy_ConfigKFree()\n"); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_kfree.h 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,119 @@ +/****************************************************************************** + * @@ -175999,9 +175526,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_kfree.h linux-5 +void phydm_config_kfree(void *dm_void, u8 channel_to_sw); + +#endif /*__HALRF_KFREE_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.c 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,1220 @@ +/****************************************************************************** + * @@ -177223,9 +176750,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_a +#endif + +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ap.h 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,398 @@ +/****************************************************************************** + * @@ -177625,9 +177152,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_a + + +#endif /*#ifndef __HALRF_POWER_TRACKING_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.c 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,152 @@ +/****************************************************************************** + * @@ -177781,9 +177308,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.c + } +} +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.c 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,869 @@ +/****************************************************************************** + * @@ -178654,9 +178181,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_c + +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_ce.h 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,327 @@ +/****************************************************************************** + * @@ -178985,9 +178512,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_c +#endif + +#endif /*__HALRF_POWER_TRACKING_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking.h 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,41 @@ +/****************************************************************************** + * @@ -179030,9 +178557,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking.h +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.c 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,741 @@ +/****************************************************************************** + * @@ -179775,9 +179302,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_i + +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_iot.h 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,349 @@ +/****************************************************************************** + * @@ -180128,9 +179655,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_i +#endif + +#endif /*#ifndef __HALRF_POWER_TRACKING_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.c 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,861 @@ +/****************************************************************************** + * @@ -180993,9 +180520,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_w +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_powertracking_win.h 2022-01-28 22:59:35.591653174 +0200 @@ -0,0 +1,302 @@ +/****************************************************************************** + * @@ -181299,9 +180826,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_powertracking_w + + +#endif /*#ifndef __HALRF_POWER_TRACKING_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.c 2022-01-28 22:59:35.592653222 +0200 @@ -0,0 +1,428 @@ +/****************************************************************************** + * @@ -181731,9 +181258,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.c linux-5.1 +} + +#endif /*#if (DM_ODM_SUPPORT_TYPE & ODM_WIN)*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_psd.h 2022-01-28 22:59:35.592653222 +0200 @@ -0,0 +1,52 @@ +/****************************************************************************** + * @@ -181787,9 +181314,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_psd.h linux-5.1 + +#endif /*#if (DM_ODM_SUPPORT_TYPE & ODM_WIN)*/ +#endif /*#__HALRF_PSD_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c 2022-01-28 22:59:35.592653222 +0200 @@ -0,0 +1,300 @@ +/****************************************************************************** + * @@ -182091,9 +181618,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.c linu + odm_tx_gain_gap_calibration_8197f(dm_void); +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h 2022-01-28 22:59:35.592653222 +0200 @@ -0,0 +1,31 @@ +/****************************************************************************** + * @@ -182126,9 +181653,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/halrf_txgapcal.h linu +void odm_tx_gain_gap_calibration(void *dm_void); + +#endif /*__HALRF_TXGAPCAL_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.c 2022-01-28 22:59:35.592653222 +0200 @@ -0,0 +1,2169 @@ +/****************************************************************************** + * @@ -184299,9 +183826,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ + _phy_set_rf_path_switch_8812a(dm, is_main, false); + } +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ap.h 2022-01-28 22:59:35.592653222 +0200 @@ -0,0 +1,82 @@ +/****************************************************************************** + * @@ -184385,9 +183912,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ + + +#endif /*#ifndef __HALRF_8812A_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.c 2022-01-28 22:59:35.592653222 +0200 @@ -0,0 +1,1975 @@ +/****************************************************************************** + * @@ -186364,9 +185891,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ + RF_DBG(dm, DBG_RF_IQK, "<=== %s\n", __func__); +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ce.h 2022-01-28 22:59:35.592653222 +0200 @@ -0,0 +1,63 @@ +/****************************************************************************** + * @@ -186431,9 +185958,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ +#endif + boolean is_main); +#endif /*#ifndef __HALRF_8812A_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.c 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,2881 @@ +/****************************************************************************** + * @@ -189316,9 +188843,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ +#endif +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_win.h 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,99 @@ +/****************************************************************************** + * @@ -189419,10 +188946,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8812a/halrf_8812a_ + + +#endif /*#ifndef __HALRF_8812A_H__*/ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.c 2023-05-26 22:35:36.543136899 +0300 +@@ -0,0 +1,1742 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. @@ -190615,11 +190142,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ +#define DP_DPK_VALUE_NUM 2 + + -+ -+ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +//digital predistortion -+VOID ++VOID + phy_DigitalPredistortion_8814A( +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PADAPTER pAdapter, @@ -190629,36 +190154,26 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ + IN BOOLEAN is2T + ) +{ -+#if (RT_PLATFORM == PLATFORM_WINDOWS) -+#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); -+#if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; -+#endif -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; -+#endif -+#endif + -+ u4Byte tmpReg, tmpReg2, index, i; ++ u4Byte tmpReg, tmpReg2, index, i; + u1Byte path, pathbound = PATH_NUM; + u4Byte AFE_backup[IQK_ADDA_REG_NUM]; -+ u4Byte AFE_REG[IQK_ADDA_REG_NUM] = { -+ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ u4Byte AFE_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, + rRx_Wait_CCA, rTx_CCK_RFON, -+ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, -+ rTx_To_Tx, rRx_CCK, ++ rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, -+ rRx_TO_Rx, rStandby, ++ rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN }; + -+ u4Byte BB_backup[DP_BB_REG_NUM]; ++ u4Byte BB_backup[DP_BB_REG_NUM]; + u4Byte BB_REG[DP_BB_REG_NUM] = { -+ rOFDM0_TRxPathEnable, rFPGA0_RFMOD, ++ rOFDM0_TRxPathEnable, rFPGA0_RFMOD, + rOFDM0_TRMuxPar, rFPGA0_XCD_RFInterfaceSW, -+ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, -+ rFPGA0_XB_RFInterfaceOE}; ++ rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, ++ rFPGA0_XB_RFInterfaceOE}; + u4Byte BB_settings[DP_BB_REG_NUM] = { + 0x00a05430, 0x02040000, 0x000800e4, 0x22208000, + 0x0, 0x0, 0x0}; @@ -191177,9 +190692,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ +#endif + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ap.h 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,164 @@ +/****************************************************************************** + * @@ -191345,9 +190860,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ + +#endif // #ifndef __HAL_PHY_RF_8814A_H__ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.c 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,564 @@ +/****************************************************************************** + * @@ -191913,9 +191428,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ + + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ce.h 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,112 @@ +/****************************************************************************** + * @@ -192029,9 +191544,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ + +#endif // #ifndef __HAL_PHY_RF_8188E_H__ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.c 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,528 @@ +/****************************************************************************** + * @@ -192561,9 +192076,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ + IN BOOLEAN bReCovery + ){} +#endif /* (RTL8814A_SUPPORT == 0)*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_win.h 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,106 @@ +/****************************************************************************** + * @@ -192671,9 +192186,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_8814a_ + +#endif // #ifndef __HAL_PHY_RF_8188E_H__ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.c 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,557 @@ +/****************************************************************************** + * @@ -193232,9 +192747,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_88 + } +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_8814a.h 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,58 @@ +/****************************************************************************** + * @@ -193294,9 +192809,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8814a/halrf_iqk_88 + ); + + #endif /* #ifndef __PHYDM_IQK_8814A_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.c 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,313 @@ +/****************************************************************************** + * @@ -193611,9 +193126,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ + + phy_lc_calibrate_8812a(dm); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ce.h 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,53 @@ +/****************************************************************************** + * @@ -193668,9 +193183,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ +); + +#endif /* #ifndef __HAL_PHY_RF_8821A_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.c 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,1046 @@ +/****************************************************************************** + * @@ -194718,9 +194233,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ + + phy_lc_calibrate_8812a(dm); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_win.h 2022-01-28 22:59:35.593653269 +0200 @@ -0,0 +1,72 @@ +/****************************************************************************** + * @@ -194794,9 +194309,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_8821a_ +); + +#endif /* #ifndef __HAL_PHY_RF_8821A_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.c 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,731 @@ +/****************************************************************************** + * @@ -195530,9 +195045,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_88 + _phy_iq_calibrate_8821a(dm); +} \ 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ap.h 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,42 @@ +/****************************************************************************** + * @@ -195576,9 +195091,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_88 +); +#endif +#endif /* #ifndef __PHYDM_IQK_8821A_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.c 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,773 @@ +/****************************************************************************** + * @@ -196353,9 +195868,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_88 + _phy_iq_calibrate_8821a(dm); +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_ce.h 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,41 @@ +/****************************************************************************** + * @@ -196398,9 +195913,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_88 +); +#endif +#endif /* #ifndef __PHYDM_IQK_8821A_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.c 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,774 @@ +/****************************************************************************** + * @@ -197176,9 +196691,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_88 + _phy_iq_calibrate_8821a(dm); +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_8821a_win.h 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,42 @@ +/****************************************************************************** + * @@ -197222,9 +196737,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/halrf/rtl8821a/halrf_iqk_88 +); +#endif +#endif /* #ifndef __PHYDM_IQK_8821A_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/mp_precomp.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/mp_precomp.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/mp_precomp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/mp_precomp.h 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -197250,9 +196765,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/mp_precomp.h linux-5.11.4-r + * Larry Finger + * + *****************************************************************************/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.c 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,764 @@ +/****************************************************************************** + * @@ -198018,9 +197533,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.c linux-5. + return; +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_adaptivity.h 2022-01-28 22:59:35.595653364 +0200 @@ -0,0 +1,122 @@ +/****************************************************************************** + * @@ -198144,9 +197659,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adaptivity.h linux-5. +void phydm_adaptivity(void *dm_void); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.c 2022-01-28 22:59:35.595653364 +0200 @@ -0,0 +1,1291 @@ +/****************************************************************************** + * @@ -199439,9 +198954,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.c linux- +} + +#endif /*@endif PHYDM_LA_MODE_SUPPORT*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_adc_sampling.h 2022-01-28 22:59:35.595653364 +0200 @@ -0,0 +1,151 @@ +/****************************************************************************** + * @@ -199594,9 +199109,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_adc_sampling.h linux- + +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_antdect.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_antdect.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_antdect.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_antdect.c 2022-01-28 22:59:35.595653364 +0200 @@ -0,0 +1,891 @@ +/****************************************************************************** + * @@ -200489,9 +200004,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdect.c linux-5.11. +} +#endif + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_antdect.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_antdect.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_antdect.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_antdect.h 2022-01-28 22:59:35.595653364 +0200 @@ -0,0 +1,78 @@ +/****************************************************************************** + * @@ -200571,9 +200086,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdect.h linux-5.11. +void odm_sw_ant_detect_init(void *dm_void); +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.c 2022-01-28 22:59:35.596653411 +0200 @@ -0,0 +1,5897 @@ +/****************************************************************************** + * @@ -206472,9 +205987,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.c linux-5.11.4 +} +#endif /*@#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_antdiv.h 2022-01-28 22:59:35.596653411 +0200 @@ -0,0 +1,519 @@ +/****************************************************************************** + * @@ -206995,9 +206510,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_antdiv.h linux-5.11.4 +void odm_antenna_diversity(void *dm_void); +#endif /*@#ifdef CONFIG_PHYDM_ANTENNA_DIVERSITY*/ +#endif /*@#ifndef __ODMANTDIV_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_api.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_api.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_api.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_api.c 2022-01-28 22:59:35.596653411 +0200 @@ -0,0 +1,2949 @@ +/****************************************************************************** + * @@ -209948,9 +209463,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_api.c linux-5.11.4-rt +#endif +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_api.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_api.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_api.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_api.h 2022-01-28 22:59:35.596653411 +0200 @@ -0,0 +1,186 @@ +/****************************************************************************** + * @@ -210138,9 +209653,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_api.h linux-5.11.4-rt +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.c 2022-01-28 22:59:35.596653411 +0200 @@ -0,0 +1,713 @@ +/****************************************************************************** + * @@ -210855,9 +210370,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.c linux-5.11 + phydm_check_hang_init(dm); +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_auto_dbg.h 2022-01-28 22:59:35.596653411 +0200 @@ -0,0 +1,113 @@ +/****************************************************************************** + * @@ -210972,9 +210487,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_auto_dbg.h linux-5.11 +void phydm_auto_dbg_engine_init(void *dm_void); +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.c 2022-01-28 22:59:35.596653411 +0200 @@ -0,0 +1,2050 @@ +/****************************************************************************** + * @@ -213026,9 +212541,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.c linux-5 +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_beamforming.h 2022-01-28 22:59:35.596653411 +0200 @@ -0,0 +1,363 @@ +/****************************************************************************** + * @@ -213393,9 +212908,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_beamforming.h linux-5 +#endif /*@(DM_ODM_SUPPORT_TYPE & (ODM_CE | ODM_AP))*/ +#endif /*@#ifdef PHYDM_BEAMFORMING_SUPPORT*/ +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm.c 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,3265 @@ +/****************************************************************************** + * @@ -216662,9 +216177,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.c linux-5.11.4-rtl881 + } +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.c 2022-01-28 22:59:35.597653459 +0200 @@ -0,0 +1,1086 @@ +/****************************************************************************** + * @@ -217752,9 +217267,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.c linux-5.11.4 +} +#endif /*#ifdef PHYDM_SUPPORT_CCKPD*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_cck_pd.h 2022-01-28 22:59:35.597653459 +0200 @@ -0,0 +1,155 @@ +/****************************************************************************** + * @@ -217911,9 +217426,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cck_pd.h linux-5.11.4 + +void phydm_cck_pd_init(void *dm_void); +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.c 2022-01-28 22:59:35.597653459 +0200 @@ -0,0 +1,1802 @@ +/****************************************************************************** + * @@ -219717,9 +219232,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_ccx.c linux-5.11.4-rt + *_out_len = out_len; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_ccx.h 2022-01-28 22:59:35.597653459 +0200 @@ -0,0 +1,268 @@ +/****************************************************************************** + * @@ -219989,9 +219504,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_ccx.h linux-5.11.4-rt + char *output, u32 *_out_len); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.c 2022-01-28 22:59:35.597653459 +0200 @@ -0,0 +1,594 @@ +/****************************************************************************** + * @@ -220587,9 +220102,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.c linux-5 + *_out_len = out_len; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_cfotracking.h 2022-01-28 22:59:35.597653459 +0200 @@ -0,0 +1,73 @@ +/****************************************************************************** + * @@ -220664,9 +220179,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_cfotracking.h linux-5 +void phy_Init_crystal_capacity(void *dm_void, u8 crystal_cap); +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_debug.c 2022-01-28 22:59:35.597653459 +0200 @@ -0,0 +1,4728 @@ +/****************************************************************************** + * @@ -225396,9 +224911,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_debug.c linux-5.11.4- +#endif +#endif /*@#ifdef CONFIG_PHYDM_DEBUG_FUNCTION*/ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_debug.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_debug.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_debug.h 2022-01-28 22:59:35.597653459 +0200 @@ -0,0 +1,480 @@ +/****************************************************************************** + * @@ -225880,9 +225395,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_debug.h linux-5.11.4- +void phydm_fw_trace_handler_8051(void *dm_void, u8 *cmd_buf, u8 cmd_len); + +#endif /* @__ODM_DBG_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dfs.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dfs.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dfs.c 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,2323 @@ +/****************************************************************************** + * @@ -228207,9 +227722,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dfs.c linux-5.11.4-rt +} +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dfs.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dfs.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dfs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dfs.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,190 @@ +/****************************************************************************** + * @@ -228401,9 +227916,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dfs.h linux-5.11.4-rt +#endif + +#endif /*@#ifndef __PHYDM_DFS_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dig.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dig.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dig.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dig.c 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,2858 @@ +/****************************************************************************** + * @@ -231263,9 +230778,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dig.c linux-5.11.4-rt +} +#endif /*#if (RTL8822B_SUPPORT)*/ +#endif /*#ifdef CONFIG_MCC_DM*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dig.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dig.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dig.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dig.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,337 @@ +/****************************************************************************** + * @@ -231604,9 +231119,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dig.h linux-5.11.4-rt + + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.c 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,517 @@ +/****************************************************************************** + * @@ -232125,9 +231640,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.c linu +} +#endif /*@#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)*/ +#endif /* @#ifdef CONFIG_DYNAMIC_TX_TWR */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_dynamictxpower.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,103 @@ +/****************************************************************************** + * @@ -232232,9 +231747,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_dynamictxpower.h linu + +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_ap.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_ap.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_ap.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,196 @@ +/****************************************************************************** + * @@ -232432,9 +231947,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ap.h linux-5 +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,84 @@ +/****************************************************************************** + * @@ -232520,9 +232035,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ce2_kernel.h +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_ce.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,214 @@ +/****************************************************************************** + * @@ -232738,9 +232253,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_ce.h linux-5 + + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,72 @@ +/****************************************************************************** + * @@ -232814,9 +232329,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features.h linux-5.11 +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_iot.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_iot.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_iot.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_iot.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,174 @@ +/****************************************************************************** + * @@ -232992,9 +232507,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_iot.h linux- +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_win.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_win.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_features_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_features_win.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,185 @@ +/****************************************************************************** + * @@ -233181,9 +232696,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_features_win.h linux- +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm.h 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,1356 @@ +/****************************************************************************** + * @@ -234541,9 +234056,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.h linux-5.11.4-rtl881 +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.c 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,1419 @@ +/****************************************************************************** + * @@ -235964,9 +235479,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.c linux-5.11 +#endif + return value32; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_hwconfig.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,79 @@ +/****************************************************************************** + * @@ -236047,9 +235562,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_hwconfig.h linux-5.11 +u32 query_phydm_txbf_capability(struct dm_struct *dm); + +#endif /*@#ifndef __HALHWOUTSRC_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_interface.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_interface.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_interface.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_interface.c 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,1468 @@ +/****************************************************************************** + * @@ -237519,9 +237034,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_interface.c linux-5.1 + return tx_rate; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_interface.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_interface.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_interface.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_interface.h 2022-01-28 22:59:35.598653506 +0200 @@ -0,0 +1,343 @@ +/****************************************************************************** + * @@ -237866,9 +237381,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_interface.h linux-5.1 + void *context); +u32 phydm_get_tx_rate(struct dm_struct *dm); +#endif /* @__ODM_INTERFACE_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.c 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,1343 @@ +/****************************************************************************** + * @@ -239213,9 +238728,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.c linux-5.11. +} + +#endif /*@#ifdef PHYDM_LNA_SAT_CHK_SUPPORT*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_lna_sat.h 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,173 @@ +/****************************************************************************** + * @@ -239390,9 +238905,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_lna_sat.h linux-5.11. + +#endif /*@#if (PHYDM_LNA_SAT_CHK_SUPPORT == 1)*/ +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.c 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,248 @@ +/****************************************************************************** + * @@ -239642,9 +239157,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.c linux-5.11 + return val; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_math_lib.h 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,114 @@ +/****************************************************************************** + * @@ -239760,9 +239275,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_math_lib.h linux-5.11 + +s32 phydm_cnvrt_2_sign(u32 val, u8 bit_num); +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm.mk linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm.mk +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm.mk 2022-01-28 22:59:35.594653317 +0200 @@ -0,0 +1,226 @@ +EXTRA_CFLAGS += -I$(src)/hal/phydm + @@ -239991,9 +239506,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm.mk linux-5.11.4-rtl88 + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_mp.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_mp.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_mp.c 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,348 @@ +/****************************************************************************** + * @@ -240343,9 +239858,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_mp.c linux-5.11.4-rtl + mp->io_value = (u32)mp->rx_phy_ok_cnt; +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_mp.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_mp.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_mp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_mp.h 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,94 @@ +/****************************************************************************** + * @@ -240441,9 +239956,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_mp.h linux-5.11.4-rtl + +void phydm_mp_get_rx_ok(void *dm_void); +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.c 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,457 @@ +/****************************************************************************** + * @@ -240902,9 +240417,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.c linux- + total_cca_cnt, total_fa_cnt, dm->noisy_decision_smooth, score, + score_smooth, dm->noisy_decision); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_noisemonitor.h 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,48 @@ +/****************************************************************************** + * @@ -240954,9 +240469,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_noisemonitor.h linux- +void phydm_noisy_detection(void *dm_void); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.c 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,928 @@ +/****************************************************************************** + * @@ -241886,9 +241401,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.c linux-5.11. +} + +#endif /* @#ifdef CONFIG_PATH_DIVERSITY */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pathdiv.h 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,123 @@ +/****************************************************************************** + * @@ -242013,9 +241528,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pathdiv.h linux-5.11. +#endif /* @#ifdef CONFIG_PATH_DIVERSITY */ +#endif /* @#ifndef __PHYDMPATHDIV_H__ */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.c 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,3192 @@ +/****************************************************************************** + * @@ -245209,9 +244724,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.c linux-5.1 + + phydm_avg_phystatus_init(dm); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_phystatus.h 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,1137 @@ +/****************************************************************************** + * @@ -246350,9 +245865,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_phystatus.h linux-5.1 +void phydm_rx_phy_status_init(void *dm_void); + +#endif /*@#ifndef __HALHWOUTSRC_H__*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,543 @@ +/****************************************************************************** + * @@ -246897,9 +246412,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.c lin +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h 2022-01-28 22:59:35.599653554 +0200 @@ -0,0 +1,152 @@ +/****************************************************************************** + * @@ -247053,9 +246568,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pmac_tx_setting.h lin +void phydm_set_tmac_tx(void *dm_void); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.c 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,171 @@ +/****************************************************************************** + * @@ -247228,9 +246743,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.c linux-5.1 +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pow_train.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,84 @@ +/****************************************************************************** + * @@ -247316,9 +246831,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pow_train.h linux-5.1 + +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_precomp.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_precomp.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_precomp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_precomp.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,514 @@ +/****************************************************************************** + * @@ -247834,9 +247349,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_precomp.h linux-5.11. + #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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pre_define.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pre_define.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_pre_define.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_pre_define.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,849 @@ +/****************************************************************************** + * @@ -248687,9 +248202,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_pre_define.h linux-5. +}; + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.c 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,173 @@ +/****************************************************************************** + * @@ -248864,9 +248379,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.c linux-5 +#endif +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_primary_cca.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,87 @@ +/****************************************************************************** + * @@ -248955,9 +248470,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_primary_cca.h linux-5 +#endif /*@#ifdef PHYDM_PRIMARY_CCA*/ +#endif /*@#ifndef __PHYDM_PRIMARYCCA_H__*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_psd.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_psd.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_psd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_psd.c 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,459 @@ +/****************************************************************************** + * @@ -249418,9 +248933,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_psd.c linux-5.11.4-rt +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_psd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_psd.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_psd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_psd.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,66 @@ +/****************************************************************************** + * @@ -249488,9 +249003,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_psd.h linux-5.11.4-rt + +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.c 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,2085 @@ +/****************************************************************************** + * @@ -251577,9 +251092,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.c linux-5.11.4 +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_rainfo.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,276 @@ +/****************************************************************************** + * @@ -251857,9 +251372,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rainfo.h linux-5.11.4 + void *dm_void); +#endif +#endif /*@#ifndef __PHYDMRAINFO_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11ac.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11ac.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11ac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11ac.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,109 @@ +/****************************************************************************** + * @@ -251970,9 +251485,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11ac.h linux +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11n.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11n.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11n.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_regdefine11n.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,219 @@ +/****************************************************************************** + * @@ -252193,9 +251708,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regdefine11n.h linux- +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_reg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_reg.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_reg.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,241 @@ +/****************************************************************************** + * @@ -252438,9 +251953,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_reg.h linux-5.11.4-rt +#define BIT_FA_RESET BIT(0) + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_regtable.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_regtable.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_regtable.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_regtable.h 2022-01-28 22:59:35.600653601 +0200 @@ -0,0 +1,849 @@ +#define R_0x0 0x0 +#define R_0x00 0x00 @@ -253291,9 +252806,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_regtable.h linux-5.11 +#define RF_0xee 0xee +#define RF_0xef 0xef +#define RF_0xf5 0xf5 -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.c 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,170 @@ +/****************************************************************************** + * @@ -253465,9 +252980,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.c linux- +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_rssi_monitor.h 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,55 @@ +/****************************************************************************** + * @@ -253524,9 +253039,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_rssi_monitor.h linux- +void phydm_rssi_monitor_init(void *dm_void); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.c 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,2277 @@ +/****************************************************************************** + * @@ -255805,9 +255320,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.c linux-5.11. + } +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_smt_ant.h 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,210 @@ +/****************************************************************************** + * @@ -256020,9 +255535,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_smt_ant.h linux-5.11. +#endif /*@#if (defined(CONFIG_SMART_ANTENNA))*/ +#endif \ 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_soml.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_soml.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_soml.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_soml.c 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,1111 @@ +/****************************************************************************** + * @@ -257135,9 +256650,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_soml.c linux-5.11.4-r + } +#endif +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_soml.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_soml.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_soml.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_soml.h 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,185 @@ +/****************************************************************************** + * @@ -257324,9 +256839,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_soml.h linux-5.11.4-r +#endif +void phydm_init_soft_ml_setting(void *dm_void); +#endif /*@#ifndef __PHYDMSOML_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_types.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_types.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/phydm_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/phydm_types.h 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,330 @@ +/****************************************************************************** + * @@ -257658,9 +257173,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/phydm_types.h linux-5.11.4- +#define MASKL3BYTES 0x00ffffff + +#endif /* __ODM_TYPES_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,1469 @@ +/****************************************************************************** + * @@ -259131,9 +258646,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.c + +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,107 @@ +/****************************************************************************** + * @@ -259242,9 +258757,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_bb.h +#endif +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.c 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,301 @@ +/****************************************************************************** + * @@ -259547,9 +259062,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac. + +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac.h 2022-01-28 22:59:35.601653648 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** + * @@ -259584,9 +259099,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_mac. +#endif +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,3848 @@ +/****************************************************************************** + * @@ -263436,9 +262951,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.c + +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,124 @@ +/****************************************************************************** + * @@ -263564,9 +263079,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/halhwimg8812a_rf.h +#endif +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.c 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,149 @@ +/****************************************************************************** + * @@ -263717,9 +263232,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig881 + enum rf_path RF_PATH, u32 reg_addr) {} + +#endif /* #if (RTL8812A_SUPPORT == 1) */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig8812a.h 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,44 @@ +/****************************************************************************** + * @@ -263765,9 +263280,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_regconfig881 + +#endif +#endif /* end of SUPPORT */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,113 @@ +/****************************************************************************** + * @@ -263882,9 +263397,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.c l +} + +#endif /* #if (RTL8812A_SUPPORT == 1) */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,27 @@ +/****************************************************************************** + * @@ -263913,9 +263428,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/phydm_rtl8812a.h l +void phydm_hwsetting_8812a(struct dm_struct *dm); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -263941,9 +263456,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8812a/version_rtl8812a.h +#define RELEASE_DATE_8812A 20150920 +#define COMMIT_BY_8812A "BB_LUKE" +#define RELEASE_VERSION_8812A 57 -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,47 @@ +/****************************************************************************** + * @@ -263992,9 +263507,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/hal8814areg_odm.h + +#endif + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,4308 @@ +/****************************************************************************** + * @@ -268304,9 +267819,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.c + +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,99 @@ +/****************************************************************************** +* @@ -268407,9 +267922,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_bb.h +#endif +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,56 @@ +/****************************************************************************** +* @@ -268467,9 +267982,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_fw.h +#endif +#endif // end of HWIMG_SUPPORT + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.c 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,325 @@ +/****************************************************************************** + * @@ -268796,9 +268311,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac. + +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac.h 2022-01-28 22:59:35.602653696 +0200 @@ -0,0 +1,39 @@ +/****************************************************************************** +* @@ -268839,9 +268354,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_mac. +#endif +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,8838 @@ +/****************************************************************************** + * @@ -277681,9 +277196,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.c + +#endif /* end of HWIMG_SUPPORT*/ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,149 @@ +/****************************************************************************** +* @@ -277834,10 +277349,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halhwimg8814a_rf.h +#endif +#endif /* end of HWIMG_SUPPORT*/ + -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.c 2023-05-26 22:35:36.544136899 +0300 +@@ -0,0 +1,1741 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. @@ -279029,12 +278544,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap. +#define DP_DPK_NUM 3 +#define DP_DPK_VALUE_NUM 2 + -+ -+ -+ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +//digital predistortion -+VOID ++VOID + phy_DigitalPredistortion_8814A( +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PADAPTER pAdapter, @@ -279044,39 +278556,29 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap. + IN BOOLEAN is2T + ) +{ -+#if (RT_PLATFORM == PLATFORM_WINDOWS) -+#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); -+#if (DM_ODM_SUPPORT_TYPE == ODM_CE) -+ PDM_ODM_T pDM_Odm = &pHalData->odmpriv; -+#endif -+#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) -+ PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; -+#endif -+#endif + -+ u32 tmpReg, tmpReg2, index, i; ++ u32 tmpReg, tmpReg2, index, i; + u8 path, pathbound = PATH_NUM; + u32 AFE_backup[IQK_ADDA_REG_NUM]; -+ u32 AFE_REG[IQK_ADDA_REG_NUM] = { -+ rFPGA0_XCD_SwitchControl, rBlue_Tooth, ++ u32 AFE_REG[IQK_ADDA_REG_NUM] = { ++ rFPGA0_XCD_SwitchControl, rBlue_Tooth, + rRx_Wait_CCA, rTx_CCK_RFON, -+ rTx_CCK_BBON, rTx_OFDM_RFON, ++ rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, -+ rTx_To_Tx, rRx_CCK, ++ rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, -+ rRx_TO_Rx, rStandby, ++ rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN }; + -+ u32 BB_backup[DP_BB_REG_NUM]; ++ u32 BB_backup[DP_BB_REG_NUM]; + u32 BB_REG[DP_BB_REG_NUM] = { -+ rOFDM0_TRxPathEnable, rFPGA0_RFMOD, ++ rOFDM0_TRxPathEnable, rFPGA0_RFMOD, + rOFDM0_TRMuxPar, rFPGA0_XCD_RFInterfaceSW, + rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, -+ rFPGA0_XB_RFInterfaceOE}; ++ rFPGA0_XB_RFInterfaceOE}; + u32 BB_settings[DP_BB_REG_NUM] = { + 0x00a05430, 0x02040000, 0x000800e4, 0x22208000, -+ 0x0, 0x0, 0x0}; ++ 0x0, 0x0, 0x0}; + + u32 RF_backup[DP_PATH_NUM][DP_RF_REG_NUM]; + u32 RF_REG[DP_RF_REG_NUM] = { @@ -279592,9 +279094,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap. +#endif + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap.h 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,164 @@ +/****************************************************************************** + * @@ -279760,9 +279262,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_ap. + +#endif // #ifndef __HAL_PHY_RF_8814A_H__ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.c 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,528 @@ +/****************************************************************************** + * @@ -280292,9 +279794,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win + IN BOOLEAN bReCovery + ){} +#endif /* (RTL8814A_SUPPORT == 0)*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win.h 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,106 @@ +/****************************************************************************** + * @@ -280402,9 +279904,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/halphyrf_8814a_win + +#endif // #ifndef __HAL_PHY_RF_8188E_H__ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.c 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,219 @@ +/****************************************************************************** + * @@ -280625,9 +280127,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig881 +} +#endif + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig8814a.h 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,109 @@ +/****************************************************************************** + * @@ -280738,9 +280240,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_regconfig881 +#endif +#endif // end of SUPPORT + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,503 @@ +/****************************************************************************** + * @@ -281245,9 +280747,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.c l + + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,78 @@ +/****************************************************************************** + * @@ -281327,9 +280829,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/phydm_rtl8814a.h l + ); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h 2022-01-28 22:59:35.603653744 +0200 @@ -0,0 +1,10 @@ +/*RTL8814A PHY Parameters*/ +/* @@ -281341,9 +280843,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8814a/version_rtl8814a.h +#define RELEASE_DATE_8814A 20150908 +#define COMMIT_BY_8814A "BB_LUKE" +#define RELEASE_VERSION_8814A 81 -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,923 @@ +/****************************************************************************** + * @@ -282268,9 +281770,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.c + + +#endif /* end of HWIMG_SUPPORT*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,83 @@ +/****************************************************************************** + * @@ -282355,9 +281857,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_bb.h + +#endif +#endif /* end of HWIMG_SUPPORT*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.c 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,279 @@ +/****************************************************************************** + * @@ -282638,9 +282140,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac. +} + +#endif /* end of HWIMG_SUPPORT*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac.h 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,33 @@ +/****************************************************************************** + * @@ -282675,9 +282177,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_mac. + +#endif +#endif /* end of HWIMG_SUPPORT*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,5457 @@ +/****************************************************************************** + * @@ -288136,9 +287638,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.c +} + +#endif /* end of HWIMG_SUPPORT*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,143 @@ +/****************************************************************************** + * @@ -288283,9 +287785,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/halhwimg8821a_rf.h + +#endif +#endif /* end of HWIMG_SUPPORT*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.c 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,206 @@ +/****************************************************************************** + * @@ -288493,9 +287995,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig882 +} + +#endif /* #if (RTL8821A_SUPPORT == 1)*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig8821a.h 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** + * @@ -288587,9 +288089,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_regconfig882 + +#endif +#endif /* end of SUPPORT */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,129 @@ +/****************************************************************************** + * @@ -288720,9 +288222,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.c l +} + +#endif /* #if (RTL8821A_SUPPORT == 1) */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,31 @@ +/****************************************************************************** + * @@ -288755,9 +288257,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/phydm_rtl8821a.h l +); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -288783,9 +288285,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/rtl8821a/version_rtl8821a.h +#define RELEASE_DATE_8821A 20150920 +#define COMMIT_BY_8821A "BB_LUKE" +#define RELEASE_VERSION_8821A 59 -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,188 @@ +EXTRA_CFLAGS += -I$(src)/hal/phydm + @@ -288975,9 +288477,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/sd4_phydm_2_kernel.mk linux + hal/phydm/$(RTL871X)/phydm_hal_api8198f.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8198f.o +endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.c 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,520 @@ +/****************************************************************************** + * @@ -289499,9 +289001,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.c linux-5.1 +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/halcomtxbf.h 2022-01-28 22:59:35.604653791 +0200 @@ -0,0 +1,183 @@ +/****************************************************************************** + * @@ -289686,9 +289188,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/halcomtxbf.h linux-5.1 +#endif + +#endif /* @#ifndef __HAL_COM_TXBF_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.c 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,384 @@ +/****************************************************************************** + * @@ -290074,9 +289576,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.c linux-5 +#endif /* @#if (RTL8192E_SUPPORT == 1)*/ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8192e.h 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,71 @@ +/****************************************************************************** + * @@ -290149,9 +289651,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8192e.h linux-5 +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.c 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,675 @@ +/****************************************************************************** + * @@ -290828,9 +290330,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.c linux-5 +#endif /* @(RTL8814A_SUPPORT == 1)*/ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8814a.h 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,77 @@ +/****************************************************************************** + * @@ -290909,9 +290411,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8814a.h linux-5 +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.c 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,1087 @@ +/****************************************************************************** + * @@ -292000,9 +291502,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.c linux-5 +} +#endif +#endif /* @(RTL8822B_SUPPORT == 1)*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbf8822b.h 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,78 @@ +/****************************************************************************** + * @@ -292082,9 +291584,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbf8822b.h linux-5 + +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.c 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,1484 @@ +/****************************************************************************** + * @@ -293570,9 +293072,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.c lin +} + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfinterface.h 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,167 @@ +/****************************************************************************** + * @@ -293741,9 +293243,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfinterface.h lin +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,510 @@ +/****************************************************************************** + * @@ -294255,9 +293757,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.c linux- +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,78 @@ +/****************************************************************************** + * @@ -294337,9 +293839,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/haltxbfjaguar.h linux- +#endif + +#endif /* @#ifndef __HAL_TXBF_JAGUAR_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,425 @@ +/****************************************************************************** + * @@ -294766,9 +294268,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.c l +#endif +#endif /*PHYSTS_3RD_TYPE_IC*/ +#endif /*CONFIG_BB_TXBF_API*/ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,74 @@ +/****************************************************************************** + * @@ -294844,9 +294346,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/phydm/txbf/phydm_hal_txbf_api.h l + +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.c 2022-01-28 22:59:35.610654075 +0200 @@ -0,0 +1,17941 @@ +/****************************************************************************** +* @@ -312789,9 +312291,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.c linux-5.11 +#endif /* end of LOAD_FW_HEADER_FROM_DRIVER */ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/hal8812a_fw.h 2022-01-28 22:59:35.610654075 +0200 @@ -0,0 +1,47 @@ +/****************************************************************************** +* @@ -312840,9 +312342,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8812a_fw.h linux-5.11 + +#endif + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,83 @@ +/****************************************************************************** + * @@ -312927,9 +312429,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/Hal8812PwrSeq.c linux-5. + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.c 2022-01-28 22:59:35.614654265 +0200 @@ -0,0 +1,14005 @@ +/****************************************************************************** +* @@ -326936,9 +326438,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.c linux-5.11 +#endif /* end of LOAD_FW_HEADER_FROM_DRIVER */ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.h +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/hal8821a_fw.h 2022-01-28 22:59:35.614654265 +0200 @@ -0,0 +1,47 @@ +/****************************************************************************** +* @@ -326987,9 +326489,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/hal8821a_fw.h linux-5.11 + +#endif + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c 2022-01-28 22:59:35.605653838 +0200 @@ -0,0 +1,86 @@ +/****************************************************************************** + * @@ -327077,9 +326579,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/Hal8821APwrSeq.c linux-5 + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c 2022-01-28 22:59:35.614654265 +0200 @@ -0,0 +1,860 @@ +/****************************************************************************** + * @@ -327941,9 +327443,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_cmd.c linux-5.1 +} + +#endif /* CONFIG_BT_COEXIST */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_dm.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_dm.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_dm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_dm.c 2022-01-28 22:59:35.614654265 +0200 @@ -0,0 +1,360 @@ +/****************************************************************************** + * @@ -328305,9 +327807,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_dm.c linux-5.11 + /* _rtw_spinlock_free(&pHalData->odm_stainfo_lock); */ + odm_cancel_all_timers(podmpriv); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c 2022-01-28 22:59:35.615654312 +0200 @@ -0,0 +1,5777 @@ +/****************************************************************************** + * @@ -334086,9 +333588,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_hal_init.c linu + pHalFunc->fw_dl = &FirmwareDownload8812; + pHalFunc->hal_get_tx_buff_rsvd_page_num = &GetTxBufferRsvdPageNum8812; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c 2022-01-28 22:59:35.615654312 +0200 @@ -0,0 +1,2045 @@ +/****************************************************************************** + * @@ -336135,9 +335637,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_phycfg.c linux- + + /* RTW_INFO("<==%s()\n",__FUNCTION__); */ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c 2022-01-28 22:59:35.615654312 +0200 @@ -0,0 +1,158 @@ +/****************************************************************************** + * @@ -336297,9 +335799,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rf6052.c linux- + + +/* End of HalRf6052.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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c 2022-01-28 22:59:35.615654312 +0200 @@ -0,0 +1,62 @@ +/****************************************************************************** + * @@ -336363,9 +335865,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_rxdesc.c linux- + /* Offset 20 */ + /* pattrib->tsfl=(u8)GET_RX_STATUS_DESC_TSFL_8812(pdesc); */ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c 2022-01-28 22:59:35.615654312 +0200 @@ -0,0 +1,106 @@ +/****************************************************************************** + * @@ -336473,9 +335975,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_sreset.c linux- + } +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c 2022-01-28 22:59:35.615654312 +0200 @@ -0,0 +1,515 @@ +/****************************************************************************** + * @@ -336992,9 +336494,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/rtl8812a_xmit.c linux-5. + + return SCSettingOfDesc; +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c 2022-01-28 22:59:35.615654312 +0200 @@ -0,0 +1,389 @@ +/****************************************************************************** + * @@ -337385,9 +336887,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_led.c linu + DeInitLed(&(ledpriv->SwLed2)); +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c 2022-01-28 22:59:35.615654312 +0200 @@ -0,0 +1,28 @@ +/****************************************************************************** + * @@ -337417,9 +336919,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_recv.c lin +{ + usb_free_recv_priv(padapter, INTERRUPT_MSG_FORMAT_LEN); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c 2022-01-28 22:59:35.616654360 +0200 @@ -0,0 +1,1169 @@ +/****************************************************************************** + * @@ -338590,9 +338092,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/rtl8812au_xmit.c lin + +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_halinit.c 2022-01-28 22:59:35.616654360 +0200 @@ -0,0 +1,2716 @@ +/****************************************************************************** + * @@ -341310,9 +340812,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_halinit.c linux- + rtl8812_set_hal_ops(pHalFunc); + +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c 2022-01-28 22:59:35.616654360 +0200 @@ -0,0 +1,244 @@ +/****************************************************************************** + * @@ -341558,9 +341060,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8812a/usb/usb_ops_linux.c linu + RTW_INFO("CHIP TYPE: RTL8811AU or RTL8821U\n"); + } +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/hal8814a_fw.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/hal8814a_fw.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/hal8814a_fw.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/hal8814a_fw.c 2022-01-28 22:59:35.617654407 +0200 @@ -0,0 +1,7741 @@ +/****************************************************************************** +* @@ -349303,9 +348805,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/hal8814a_fw.c linux-5.11 + +#endif // end of HWIMG_SUPPORT + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c 2022-01-28 22:59:35.616654360 +0200 @@ -0,0 +1,98 @@ +/****************************************************************************** + * @@ -349405,9 +348907,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/Hal8814PwrSeq.c linux-5. + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c 2022-01-28 22:59:35.617654407 +0200 @@ -0,0 +1,1515 @@ +/****************************************************************************** + * @@ -350924,9 +350426,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_cmd.c linux-5.1 + +#endif // CONFIG_BT_COEXIST + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_dm.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_dm.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_dm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_dm.c 2022-01-28 22:59:35.617654407 +0200 @@ -0,0 +1,407 @@ +/****************************************************************************** + * @@ -351335,9 +350837,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_dm.c linux-5.11 +} +#endif //CONFIG_ANTENNA_DIVERSITY + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c 2022-12-18 17:40:24.574937030 +0200 @@ -0,0 +1,6769 @@ +/****************************************************************************** + * @@ -351389,7 +350891,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c linu + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PEFUSE_HAL pEfuseHal = &(pHalData->EfuseHal); + pu2Byte ptr; -+ ++ + #define INIT_EFUSE(var,value) ptr = (pu2Byte)&var; *ptr = value + + RTW_INFO("====> %s \n", __func__); @@ -356174,7 +355676,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c linu + rtw_write8(Adapter,REG_BCN_CTRL_1, 0x11);//disable atim wnd and disable beacon function + //rtw_write8(Adapter,REG_BCN_CTRL_1, 0x18); + } -+ else if((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/) ++ else if (mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/ + { +#ifdef RTL8814AE_SW_BCN + /*Beacon is polled to TXBUF*/ @@ -356298,7 +355800,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c linu + rtw_write8(Adapter,REG_BCN_CTRL, 0x19);//disable atim wnd + //rtw_write8(Adapter,REG_BCN_CTRL, 0x18); + } -+ else if((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/) ++ else if (mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_)*/ + { +#ifdef RTL8814AE_SW_BCN + rtw_write16(Adapter, REG_CR, rtw_read16(Adapter, REG_CR)|BIT(8)); @@ -358108,9 +357610,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_hal_init.c linu +} + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c 2022-01-28 22:59:35.618654454 +0200 @@ -0,0 +1,3027 @@ +/****************************************************************************** + * @@ -361139,9 +360641,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_phycfg.c linux- + //RTW_INFO("<==%s()\n",__FUNCTION__); +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c 2022-01-28 22:59:35.618654454 +0200 @@ -0,0 +1,210 @@ +/****************************************************************************** + * @@ -361353,9 +360855,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rf6052.c linux- + +/* End of HalRf6052.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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c 2022-01-28 22:59:35.618654454 +0200 @@ -0,0 +1,68 @@ +/****************************************************************************** + * @@ -361425,9 +360927,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_rxdesc.c linux- + +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c 2022-01-28 22:59:35.618654454 +0200 @@ -0,0 +1,114 @@ +/****************************************************************************** + * @@ -361543,9 +361045,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_sreset.c linux- +} +#endif + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c 2022-01-28 22:59:35.618654454 +0200 @@ -0,0 +1,515 @@ +/****************************************************************************** + * @@ -362062,9 +361564,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/rtl8814a_xmit.c linux-5. +} + + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c 2022-01-28 22:59:35.618654454 +0200 @@ -0,0 +1,147 @@ +/****************************************************************************** + * @@ -362213,9 +361715,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_led.c linu + DeInitLed( &(ledpriv->SwLed2) ); +} +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c 2022-01-28 22:59:35.618654454 +0200 @@ -0,0 +1,34 @@ +/****************************************************************************** + * @@ -362251,9 +361753,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_recv.c lin + usb_free_recv_priv(padapter, INTERRUPT_MSG_FORMAT_LEN); +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,1129 @@ +/****************************************************************************** + * @@ -363384,9 +362886,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/rtl8814au_xmit.c lin +} +#endif + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_halinit.c 2023-05-26 22:35:36.544136899 +0300 @@ -0,0 +1,2416 @@ +/****************************************************************************** + * @@ -364975,9 +364477,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- + // Reset USB mode switch setting + rtw_write8(Adapter, REG_SDIO_CTRL_8814A, 0x0); + rtw_write8(Adapter, REG_ACLK_MON, 0x0); -+ ++ + //RT_TRACE(COMP_INIT, DBG_TRACE, ("InitializeAdapter8188EUsb() <====\n")); -+ ++ +HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK); + // 2010/08/26 MH Merge from 8192CE. + if(pwrctrlpriv->rf_pwrstate == rf_on) @@ -365438,19 +364940,19 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- + hal_ReadTxPowerInfo8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadBoardType8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_Read_TRX_antenna_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); -+ ++ + // + // Read Bluetooth co-exist and initialize + // + hal_EfuseParseBTCoexistInfo8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); -+ ++ + hal_ReadChannelPlan8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_EfuseParseXtal_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadThermalMeter_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadRemoteWakeup_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadAntennaDiversity8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + hal_ReadRFEType_8814A(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); -+ ++ + ReadLEDSetting_8814AU(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); + + hal_ReadUsbModeSwitch_8814AU(Adapter, pHalData->efuse_eeprom_data, pHalData->bautoload_fail_flag); @@ -365464,7 +364966,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- +static void hal_ReadPROMContent_8814A( + IN PADAPTER Adapter + ) -+{ ++{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + u8 eeValue; + @@ -365487,7 +364989,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- + ) +{ + Hal_InitEfuseVars_8814A(Adapter); -+ ++ + /* Read all content in Efuse/EEPROM. */ + hal_ReadPROMContent_8814A(Adapter); + @@ -365508,17 +365010,17 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- + himr = &(pHalData->IntrMask[0]); + else + himr = &(pHalData->IntrMask[1]); -+ ++ + if (AddMSR) + *himr |= AddMSR; + + if (RemoveMSR) + *himr &= (~RemoveMSR); + -+ if(bHIMR0) ++ if(bHIMR0) + rtw_write32(padapter, REG_HIMR0_8814A, *himr); + else -+ rtw_write32(padapter, REG_HIMR1_8814A, *himr); ++ rtw_write32(padapter, REG_HIMR1_8814A, *himr); + +} + @@ -365613,7 +365115,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- + +void GetHwReg8814AU(PADAPTER Adapter, u8 variable, u8* val) +{ -+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); ++ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + switch(variable) + { @@ -365730,7 +365232,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- +} + +static u8 rtl8814au_ps_func(PADAPTER Adapter,HAL_INTF_PS_FUNC efunc_id, u8 *val) -+{ ++{ + u8 bResult = _TRUE; + switch(efunc_id){ + @@ -365755,7 +365257,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- + + pHalFunc->hal_power_on = _InitPowerOn_8814AU; + pHalFunc->hal_power_off = hal_carddisable_8814; -+ ++ + pHalFunc->hal_init = &rtl8814au_hal_init; + pHalFunc->hal_deinit = &rtl8814au_hal_deinit; + @@ -365774,11 +365276,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- +// pHalFunc->InitSwLeds = NULL; +// pHalFunc->DeInitSwLeds = NULL; +#endif//CONFIG_RTW_LED -+ ++ + pHalFunc->init_default_value = &rtl8814au_init_default_value; + pHalFunc->intf_chip_configure = &rtl8814au_interface_configure; + pHalFunc->read_adapter_info = &ReadAdapterInfo8814AU; -+ ++ + pHalFunc->set_hw_reg_handler = &SetHwReg8814AU; + pHalFunc->GetHwRegHandler = &GetHwReg8814AU; + pHalFunc->get_hal_def_var_handler = &GetHalDefVar8814AUsb; @@ -365804,9 +365306,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_halinit.c linux- + +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c +--- linux-6.3.4/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,312 @@ +/****************************************************************************** + * @@ -366120,9 +365622,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/hal/rtl8814a/usb/usb_ops_linux.c linu + pdvobj->HardwareType = HARDWARE_TYPE_RTL8814AU; + RTW_INFO("CHIP TYPE: RTL8814\n"); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/basic_types.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/basic_types.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/basic_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/basic_types.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,379 @@ +/****************************************************************************** + * @@ -366503,9 +366005,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/basic_types.h linux-5.11.4-rt +#define TEST_FLAGS(__Flag, __testFlags) (((__Flag) & (__testFlags)) == (__testFlags)) + +#endif /* __BASIC_TYPES_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/big_endian.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/big_endian.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/big_endian.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/big_endian.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,82 @@ +/****************************************************************************** + * @@ -366589,10 +366091,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/big_endian.h linux- +#include + +#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/generic.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/generic.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/generic.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/generic.h 2023-05-26 22:35:36.544136899 +0300 +@@ -0,0 +1,195 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -366688,7 +366190,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/generic.h linux-5.1 + */ + + -+#if defined(PLATFORM_LINUX) || defined(PLATFORM_WINDOWS) || defined(PLATFORM_MPIXEL) || defined(PLATFORM_FREEBSD) ++#if defined(PLATFORM_LINUX) || defined(PLATFORM_MPIXEL) || defined(PLATFORM_FREEBSD) + /* + * inside the kernel, we can use nicknames; + * outside of it, we must avoid POSIX namespace pollution... @@ -366787,22 +366289,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/generic.h linux-5.1 + #define ntohs(x) ___ntohs(x) + +#endif /* OPTIMIZE */ -+ -+ -+#if defined(PLATFORM_WINDOWS) -+ -+ #define htonl(x) __cpu_to_be32(x) -+ #define ntohl(x) __be32_to_cpu(x) -+ #define htons(x) __cpu_to_be16(x) -+ #define ntohs(x) __be16_to_cpu(x) -+ -+ -+#endif -+ +#endif /* _LINUX_BYTEORDER_GENERIC_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/little_endian.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/little_endian.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/little_endian.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/little_endian.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,84 @@ +/****************************************************************************** + * @@ -366888,9 +366378,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/little_endian.h lin +#include + +#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/swabb.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/swabb.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/swabb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/swabb.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,151 @@ +/****************************************************************************** + * @@ -367043,9 +366533,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/swabb.h linux-5.11. +#endif + +#endif /* _LINUX_BYTEORDER_SWABB_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/swab.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/swab.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/byteorder/swab.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/byteorder/swab.h 2023-05-26 22:35:36.544136899 +0300 @@ -0,0 +1,136 @@ +/****************************************************************************** + * @@ -367170,7 +366660,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/swab.h linux-5.11.4 + return __arch__swab32(x); +} + -+#if defined(PLATFORM_LINUX) || defined(PLATFORM_WINDOWS) ++#if defined(PLATFORM_LINUX) + #define swab16 __swab16 + #define swab32 __swab32 + #define swab64 __swab64 @@ -367183,9 +366673,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/byteorder/swab.h linux-5.11.4 +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/circ_buf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/circ_buf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/circ_buf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/circ_buf.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,23 @@ +/****************************************************************************** + * @@ -367210,9 +366700,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/circ_buf.h linux-5.11.4-rtl88 + +#endif //_CIRC_BUF_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/cmd_osdep.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/cmd_osdep.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/cmd_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/cmd_osdep.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -367240,9 +366730,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/cmd_osdep.h linux-5.11.4-rtl8 +extern struct cmd_obj *_rtw_dequeue_cmd(_queue *queue); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/cmn_info/rtw_sta_info.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/cmn_info/rtw_sta_info.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/cmn_info/rtw_sta_info.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/cmn_info/rtw_sta_info.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,257 @@ +/****************************************************************************** + * @@ -367501,10 +366991,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/cmn_info/rtw_sta_info.h linux +/*--------------------Function declaration-----------------------------*/ + +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/custom_gpio.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/custom_gpio.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/custom_gpio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/custom_gpio.h 2023-05-26 22:35:36.544136899 +0300 +@@ -0,0 +1,39 @@ +/****************************************************************************** + * + * Copyright(c) 2016 - 2017 Realtek Corporation. @@ -367525,13 +367015,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/custom_gpio.h linux-5.11.4-rt +#include +#include + -+#ifdef PLATFORM_OS_XP -+ #include -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ #include -+#endif + +#ifdef PLATFORM_LINUX + #include @@ -367551,9 +367034,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/custom_gpio.h linux-5.11.4-rt +extern void rtw_wifi_gpio_wlan_ctrl(int onoff); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/drv_conf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_conf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/drv_conf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_conf.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,510 @@ +/****************************************************************************** + * @@ -368065,9 +367548,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_conf.h linux-5.11.4-rtl88 +#endif + +#endif /* __DRV_CONF_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_ce.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,86 @@ +/****************************************************************************** + * @@ -368155,9 +367638,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_ce.h linux-5.11.4-r + + +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_gspi.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_gspi.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_gspi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_gspi.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,49 @@ +/****************************************************************************** + * @@ -368208,10 +367691,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_gspi.h linux-5.11.4 +} 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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/drv_types.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/drv_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types.h 2023-05-26 22:35:36.544136899 +0300 +@@ -0,0 +1,1797 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -368306,7 +367789,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types.h linux-5.11.4-rtl8 +#include +#include +#include -+#include +#include +#include +#include @@ -369380,31 +368862,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types.h linux-5.11.4-rtl8 + u8 *usb_vendor_req_buf; +#endif + -+#ifdef PLATFORM_WINDOWS -+ /* related device objects */ -+ PDEVICE_OBJECT pphysdevobj;/* pPhysDevObj; */ -+ PDEVICE_OBJECT pfuncdevobj;/* pFuncDevObj; */ -+ PDEVICE_OBJECT pnextdevobj;/* pNextDevObj; */ -+ -+ u8 nextdevstacksz;/* unsigned char NextDeviceStackSize; */ /* = (CHAR)CEdevice->pUsbDevObj->StackSize + 1; */ -+ -+ /* urb for control diescriptor request */ -+ -+#ifdef PLATFORM_OS_XP -+ struct _URB_CONTROL_DESCRIPTOR_REQUEST descriptor_urb; -+ PUSB_CONFIGURATION_DESCRIPTOR pconfig_descriptor;/* UsbConfigurationDescriptor; */ -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ WCHAR active_path[MAX_ACTIVE_REG_PATH]; /* adapter regpath */ -+ USB_EXTENSION usb_extension; -+ -+ _nic_hdl pipehdls_r8192c[0x10]; -+#endif -+ -+ u32 config_descriptor_len;/* ULONG UsbConfigurationDescriptorLength; */ -+#endif/* PLATFORM_WINDOWS */ -+ +#ifdef PLATFORM_LINUX + struct usb_interface *pusbintf; + struct usb_device *pusbdev; @@ -369745,17 +369202,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types.h linux-5.11.4-rtl8 + void (*intf_start)(_adapter *adapter); + void (*intf_stop)(_adapter *adapter); + -+#ifdef PLATFORM_WINDOWS -+ _nic_hdl hndis_adapter;/* hNdisAdapter(NDISMiniportAdapterHandle); */ -+ _nic_hdl hndis_config;/* hNdisConfiguration; */ -+ NDIS_STRING fw_img; -+ -+ u32 NdisPacketFilter; -+ u8 MCList[MAX_MCAST_LIST_NUM][6]; -+ u32 MCAddrCount; -+#endif /* end of PLATFORM_WINDOWS */ -+ -+ +#ifdef PLATFORM_LINUX + _nic_hdl pnetdev; + char old_ifname[IFNAMSIZ]; @@ -370046,10 +369492,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types.h linux-5.11.4-rtl8 +#endif + +#endif /* __DRV_TYPES_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_linux.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_linux.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_linux.h 2022-12-18 17:40:24.574937030 +0200 +@@ -0,0 +1,22 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -370067,11 +369513,14 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_linux.h linux-5.11. +#ifndef __DRV_TYPES_LINUX_H__ +#define __DRV_TYPES_LINUX_H__ + ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) ++#define dev_addr_set(netdev, ethdata) _rtw_memcpy(netdev->dev_addr, ethdata, ETH_ALEN) ++#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_pci.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_pci.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_pci.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_pci.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,266 @@ +/****************************************************************************** + * @@ -370339,10 +369788,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_pci.h linux-5.11.4- + + +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_sdio.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_sdio.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_sdio.h 2023-05-26 22:35:36.544136899 +0300 +@@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -370373,15 +369822,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_sdio.h linux-5.11.4 + #endif /* CONFIG_PLATFORM_SPRD */ +#endif + -+#ifdef PLATFORM_OS_XP -+ #include -+ #include -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ #include -+#endif -+ +#define RTW_SDIO_CLK_33M 33000000 +#define RTW_SDIO_CLK_40M 40000000 +#define RTW_SDIO_CLK_80M 80000000 @@ -370401,23 +369841,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_sdio.h linux-5.11.4 + unsigned int timing; + u8 sd3_bus_mode; +#endif -+ -+#ifdef PLATFORM_OS_XP -+ PDEVICE_OBJECT pphysdevobj; -+ PDEVICE_OBJECT pfuncdevobj; -+ PDEVICE_OBJECT pnextdevobj; -+ SDBUS_INTERFACE_STANDARD sdbusinft; -+ u8 nextdevstacksz; -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ SD_DEVICE_HANDLE hDevice; -+ SD_CARD_RCA sd_rca; -+ SD_CARD_INTERFACE card_intf; -+ BOOLEAN enableIsarWithStatus; -+ WCHAR active_path[MAX_ACTIVE_REG_PATH]; -+ SD_HOST_BLOCK_CAPABILITY sd_host_blk_cap; -+#endif +} SDIO_DATA, *PSDIO_DATA; + +#define dvobj_to_sdio_func(d) ((d)->intf_data.func) @@ -370433,9 +369856,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_sdio.h linux-5.11.4 +#define RTW_SDIO_ADDR_F0_CHK(a) (a&RTW_SDIO_ADDR_F0_BIT ? 1 : 0) + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_xp.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_xp.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/drv_types_xp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/drv_types_xp.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,88 @@ +/****************************************************************************** + * @@ -370525,9 +369948,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/drv_types_xp.h linux-5.11.4-r + + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/ethernet.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/ethernet.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/ethernet.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/ethernet.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,36 @@ +/****************************************************************************** + * @@ -370565,9 +369988,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ethernet.h linux-5.11.4-rtl88 + + +#endif /* #ifndef __INC_ETHERNET_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/gspi_hal.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/gspi_hal.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/gspi_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/gspi_hal.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,30 @@ +/****************************************************************************** + * @@ -370599,9 +370022,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/gspi_hal.h linux-5.11.4-rtl88 +#endif + +#endif /* __GSPI_HAL_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/gspi_ops.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/gspi_ops.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/gspi_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/gspi_ops.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,180 @@ +/****************************************************************************** + * @@ -370783,9 +370206,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/gspi_ops.h linux-5.11.4-rtl88 +#endif /* CONFIG_WOWLAN */ + +#endif /* __GSPI_OPS_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/gspi_ops_linux.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/gspi_ops_linux.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/gspi_ops_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/gspi_ops_linux.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,18 @@ +/****************************************************************************** + * @@ -370805,10 +370228,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/gspi_ops_linux.h linux-5.11.4 +#define __SDIO_OPS_LINUX_H__ + +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/gspi_osintf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/gspi_osintf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/gspi_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/gspi_osintf.h 2023-05-26 22:35:36.544136899 +0300 +@@ -0,0 +1,18 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -370826,17 +370249,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/gspi_osintf.h linux-5.11.4-rt +#ifndef __SDIO_OSINTF_H__ +#define __SDIO_OSINTF_H__ + -+ -+#ifdef PLATFORM_OS_CE -+ extern NDIS_STATUS ce_sd_get_dev_hdl(PADAPTER padapter); -+ SD_API_STATUS ce_sd_int_callback(SD_DEVICE_HANDLE hDevice, PADAPTER padapter); -+ extern void sd_setup_irs(PADAPTER padapter); +#endif -+ -+#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/h2clbk.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/h2clbk.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/h2clbk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/h2clbk.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -370864,9 +370280,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/h2clbk.h linux-5.11.4-rtl8812 +void _lbk_evt(IN PADAPTER Adapter); + +void h2c_event_callback(unsigned char *dev, unsigned char *pbuf); -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/Hal8812PhyCfg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8812PhyCfg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/Hal8812PhyCfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8812PhyCfg.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,143 @@ +/****************************************************************************** + * @@ -371011,9 +370427,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PhyCfg.h linux-5.11.4- + +/*--------------------------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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/Hal8812PhyReg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8812PhyReg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/Hal8812PhyReg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8812PhyReg.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,735 @@ +/****************************************************************************** + * @@ -371750,9 +371166,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PhyReg.h linux-5.11.4- + + +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/Hal8812PwrSeq.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8812PwrSeq.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/Hal8812PwrSeq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8812PwrSeq.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,208 @@ +/****************************************************************************** + * @@ -371962,9 +371378,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8812PwrSeq.h linux-5.11.4- +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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/Hal8814PhyCfg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8814PhyCfg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/Hal8814PhyCfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8814PhyCfg.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,264 @@ +/****************************************************************************** + * @@ -372230,9 +371646,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PhyCfg.h linux-5.11.4- + +/*--------------------------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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/Hal8814PhyReg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8814PhyReg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/Hal8814PhyReg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8814PhyReg.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,863 @@ +/****************************************************************************** + * @@ -373097,9 +372513,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PhyReg.h linux-5.11.4- + + +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/Hal8814PwrSeq.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8814PwrSeq.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/Hal8814PwrSeq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8814PwrSeq.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,231 @@ +/****************************************************************************** + * @@ -373332,9 +372748,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8814PwrSeq.h linux-5.11.4- +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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/Hal8821APwrSeq.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8821APwrSeq.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/Hal8821APwrSeq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/Hal8821APwrSeq.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,200 @@ +/****************************************************************************** + * @@ -373536,9 +372952,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/Hal8821APwrSeq.h linux-5.11.4 + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_btcoex.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_btcoex.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_btcoex.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_btcoex.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,97 @@ +/****************************************************************************** + * @@ -373637,9 +373053,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_btcoex.h linux-5.11.4-rtl +u8 hal_btcoex_get_rf4ce_link_state(void); +#endif +#endif /* !__HAL_BTCOEX_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_btcoex_wifionly.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_btcoex_wifionly.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_btcoex_wifionly.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_btcoex_wifionly.h 2022-01-28 22:59:35.620654549 +0200 @@ -0,0 +1,81 @@ +/****************************************************************************** + * @@ -373722,9 +373138,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_btcoex_wifionly.h linux-5 +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_com.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_com.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,719 @@ +/****************************************************************************** + * @@ -374445,9 +373861,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com.h linux-5.11.4-rtl881 +#endif + +#endif /* __HAL_COMMON_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_com_h2c.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com_h2c.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_com_h2c.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com_h2c.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,635 @@ +/****************************************************************************** + * @@ -375084,9 +374500,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com_h2c.h linux-5.11.4-rt +u8 rtw_hal_set_req_per_rpt_cmd(_adapter *adapter, u8 group_macid, + u8 rpt_type, u32 macid_bitmap); +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_com_led.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com_led.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_com_led.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com_led.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,437 @@ +/****************************************************************************** + * @@ -375525,9 +374941,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com_led.h linux-5.11.4-rt + +#endif /*__HAL_COMMON_LED_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_com_phycfg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com_phycfg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_com_phycfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com_phycfg.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,299 @@ +/****************************************************************************** + * @@ -375828,9 +375244,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com_phycfg.h linux-5.11.4 +#endif /* CONFIG_LOAD_PHY_PARA_FROM_FILE */ +u8 phy_check_under_survey_ch(_adapter *adapter); +#endif /* __HAL_COMMON_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_com_reg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com_reg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_com_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_com_reg.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,1887 @@ +/****************************************************************************** + * @@ -377719,9 +377135,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_com_reg.h linux-5.11.4-rt +#define HAL_8188E_HW_GPIO_WPS_BIT BIT(7) + +#endif /* __HAL_COMMON_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_data.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_data.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_data.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_data.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,1105 @@ +/****************************************************************************** + * @@ -378828,9 +378244,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_data.h linux-5.11.4-rtl88 +*/ + +#endif /* __HAL_DATA_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_gspi.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_gspi.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_gspi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_gspi.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -378858,9 +378274,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_gspi.h linux-5.11.4-rtl88 +u32 rtw_hal_get_gspi_tx_max_length(PADAPTER padapter, u8 queue_idx); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_ic_cfg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_ic_cfg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_ic_cfg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_ic_cfg.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,313 @@ +/****************************************************************************** + * @@ -379175,9 +378591,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_ic_cfg.h linux-5.11.4-rtl +#endif + +#endif /*__HAL_IC_CFG_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_intf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_intf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_intf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_intf.h 2022-01-28 22:59:35.621654597 +0200 @@ -0,0 +1,849 @@ +/****************************************************************************** + * @@ -380028,9 +379444,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_intf.h linux-5.11.4-rtl88 +#endif + +#endif /* __HAL_INTF_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_pg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_pg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_pg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_pg.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,880 @@ +/****************************************************************************** + * @@ -380912,9 +380328,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_pg.h linux-5.11.4-rtl8812 + + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_phy.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_phy.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_phy.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_phy.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,234 @@ +/****************************************************************************** + * @@ -381150,9 +380566,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_phy.h linux-5.11.4-rtl881 + IN PADAPTER Adapter); +#endif /*#CONFIG_RF_SHADOW_RW*/ +#endif /* __HAL_COMMON_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_phy_reg.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_phy_reg.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_phy_reg.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_phy_reg.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,25 @@ +/****************************************************************************** + * @@ -381179,9 +380595,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_phy_reg.h linux-5.11.4-rt +/* #endif */ + +#endif /* __HAL_PHY_REG_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/HalPwrSeqCmd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/HalPwrSeqCmd.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/HalPwrSeqCmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/HalPwrSeqCmd.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,130 @@ +/****************************************************************************** + * @@ -381313,9 +380729,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/HalPwrSeqCmd.h linux-5.11.4-r + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/hal_sdio.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_sdio.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/hal_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/hal_sdio.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,56 @@ +/****************************************************************************** + * @@ -381373,9 +380789,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/hal_sdio.h linux-5.11.4-rtl88 +u32 cmd53_4byte_alignment(struct intf_hdl *pintfhdl, u32 addr); + +#endif /* __HAL_SDIO_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/HalVerDef.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/HalVerDef.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/HalVerDef.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/HalVerDef.h 2022-01-28 22:59:35.619654502 +0200 @@ -0,0 +1,201 @@ +/****************************************************************************** + * @@ -381578,10 +380994,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/HalVerDef.h linux-5.11.4-rtl8 +#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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/ieee80211_ext.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/ieee80211_ext.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/ieee80211_ext.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/ieee80211_ext.h 2023-05-26 22:35:36.544136899 +0300 +@@ -0,0 +1,309 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -381684,27 +381100,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211_ext.h linux-5.11.4- + +#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; \ @@ -381909,154 +381304,13 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211_ext.h linux-5.11.4- + +#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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/ieee80211.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/ieee80211.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/ieee80211.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/ieee80211.h 2023-05-26 22:35:36.544136899 +0300 +@@ -0,0 +1,2044 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -382075,15 +381329,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8 +#define __IEEE80211_H + + -+#ifndef CONFIG_RTL8711FW -+ -+ #if defined PLATFORM_OS_XP -+ #include -+ #endif -+#else -+ -+#endif -+ +#define MGMT_QUEUE_NUM 5 + +#define ETH_ALEN 6 @@ -382557,54 +381802,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8 +} __attribute__((packed)); +#endif + -+ -+ -+#ifdef PLATFORM_WINDOWS -+ -+#pragma pack(1) -+struct rtw_ieee80211_hdr { -+ u16 frame_ctl; -+ u16 duration_id; -+ u8 addr1[ETH_ALEN]; -+ u8 addr2[ETH_ALEN]; -+ u8 addr3[ETH_ALEN]; -+ u16 seq_ctl; -+ u8 addr4[ETH_ALEN]; -+}; -+ -+struct rtw_ieee80211_hdr_3addr { -+ u16 frame_ctl; -+ u16 duration_id; -+ u8 addr1[ETH_ALEN]; -+ u8 addr2[ETH_ALEN]; -+ u8 addr3[ETH_ALEN]; -+ u16 seq_ctl; -+}; -+ -+ -+struct rtw_ieee80211_hdr_qos { -+ struct rtw_ieee80211_hdr wlan_hdr; -+ u16 qc; -+}; -+ -+struct rtw_ieee80211_hdr_3addr_qos { -+ struct rtw_ieee80211_hdr_3addr wlan_hdr; -+ u16 qc; -+}; -+ -+struct eapol { -+ u8 snap[6]; -+ u16 ethertype; -+ u8 version; -+ u8 type; -+ u16 length; -+}; -+#pragma pack() -+ -+#endif -+ -+ -+ +enum eap_type { + EAP_PACKET = 0, + EAPOL_START, @@ -382726,22 +381923,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8 + +#endif + -+#ifdef PLATFORM_WINDOWS -+ -+#pragma pack(1) -+struct ieee80211_snap_hdr { -+ -+ u8 dsap; /* always 0xAA */ -+ u8 ssap; /* always 0xAA */ -+ u8 ctrl; /* always 0x03 */ -+ u8 oui[P80211_OUI_LEN]; /* organizational universal id */ -+ -+}; -+#pragma pack() -+ -+#endif -+ -+ +#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) + +#define WLAN_FC_GET_TYPE(fc) ((fc) & RTW_IEEE80211_FCTL_FTYPE) @@ -383317,24 +382498,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8 + +#endif + -+#ifdef PLATFORM_WINDOWS -+ -+#pragma pack(1) -+struct ieee80211_security { -+ u16 active_key:2, -+ enabled:1, -+ auth_mode:2, -+ auth_algo:4, -+ unicast_uses_group:1; -+ u8 key_sizes[WEP_KEYS]; -+ u8 keys[WEP_KEYS][WEP_KEY_LEN]; -+ u8 level; -+ u16 flags; -+} ; -+#pragma pack() -+ -+#endif -+ +/* + + 802.11 data frame from AP @@ -383389,24 +382552,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8 +} __attribute__((packed)); +#endif + -+#ifdef PLATFORM_WINDOWS -+ -+#pragma pack(1) -+struct ieee80211_info_element_hdr { -+ u8 id; -+ u8 len; -+} ; -+ -+struct ieee80211_info_element { -+ u8 id; -+ u8 len; -+ u8 data[0]; -+} ; -+#pragma pack() -+ -+#endif -+ -+ +/* + * These are the data types that can make up management packets + * @@ -383470,57 +382615,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8 +} __attribute__((packed)); +#endif + -+ -+ -+#ifdef PLATFORM_WINDOWS -+ -+#pragma pack(1) -+ -+struct ieee80211_authentication { -+ struct ieee80211_header_data header; -+ u16 algorithm; -+ u16 transaction; -+ u16 status; -+ /* struct ieee80211_info_element_hdr info_element; */ -+} ; -+ -+ -+struct ieee80211_probe_response { -+ struct ieee80211_header_data header; -+ u32 time_stamp[2]; -+ u16 beacon_interval; -+ u16 capability; -+ struct ieee80211_info_element info_element; -+} ; -+ -+struct ieee80211_probe_request { -+ struct ieee80211_header_data header; -+ /*struct ieee80211_info_element info_element;*/ -+} ; -+ -+struct ieee80211_assoc_request_frame { -+ struct rtw_ieee80211_hdr_3addr header; -+ u16 capability; -+ u16 listen_interval; -+ /* u8 current_ap[ETH_ALEN]; */ -+ struct ieee80211_info_element_hdr info_element; -+} ; -+ -+struct ieee80211_assoc_response_frame { -+ struct rtw_ieee80211_hdr_3addr header; -+ u16 capability; -+ u16 status; -+ u16 aid; -+ /* struct ieee80211_info_element info_element; supported rates */ -+}; -+ -+#pragma pack() -+ -+#endif -+ -+ -+ -+ +struct ieee80211_txb { + u8 nr_frags; + u8 encrypted; @@ -383675,18 +382769,18 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8 + (((Addr[2]) & 0xff) == 0xff) && (((Addr[3]) & 0xff) == 0xff) && (((Addr[4]) & 0xff) == 0xff) && \ + (((Addr[5]) & 0xff) == 0xff)) +#else -+extern __inline int is_multicast_mac_addr(const u8 *addr) ++static inline int is_multicast_mac_addr(const u8 *addr) +{ + return (addr[0] != 0xff) && (0x01 & addr[0]); +} + -+extern __inline int is_broadcast_mac_addr(const u8 *addr) ++static inline int is_broadcast_mac_addr(const u8 *addr) +{ + return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ + (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); +} + -+extern __inline int is_zero_mac_addr(const u8 *addr) ++static inline int is_zero_mac_addr(const u8 *addr) +{ + return ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && \ + (addr[3] == 0x00) && (addr[4] == 0x00) && (addr[5] == 0x00)); @@ -384261,9 +383355,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ieee80211.h linux-5.11.4-rtl8 + + +#endif /* IEEE80211_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/if_ether.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/if_ether.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/if_ether.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/if_ether.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,106 @@ +/****************************************************************************** + * @@ -384371,9 +383465,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/if_ether.h linux-5.11.4-rtl88 + + +#endif /* _LINUX_IF_ETHER_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/ip.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/ip.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/ip.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/ip.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,135 @@ +/****************************************************************************** + * @@ -384510,9 +383604,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/ip.h linux-5.11.4-rtl8812au/3 +}; + +#endif /* _LINUX_IP_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/linux/old_unused_rtl_wireless.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/linux/old_unused_rtl_wireless.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/linux/old_unused_rtl_wireless.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/linux/old_unused_rtl_wireless.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,87 @@ +/****************************************************************************** + * @@ -384601,9 +383695,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/linux/old_unused_rtl_wireless +}; + +#endif /* _LINUX_WIRELESS_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/mlme_osdep.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/mlme_osdep.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/mlme_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/mlme_osdep.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,25 @@ +/****************************************************************************** + * @@ -384630,9 +383724,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/mlme_osdep.h linux-5.11.4-rtl +void rtw_reset_securitypriv(_adapter *adapter); + +#endif /* _MLME_OSDEP_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/mp_custom_oid.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/mp_custom_oid.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/mp_custom_oid.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/mp_custom_oid.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,348 @@ +/****************************************************************************** + * @@ -384982,9 +384076,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/mp_custom_oid.h linux-5.11.4- +#define OID_RT_PRO_EFUSE_MAP 0xFF871217 /* Q, S */ + +#endif /* #ifndef __CUSTOM_OID_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/nic_spec.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/nic_spec.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/nic_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/nic_spec.h 2022-01-28 22:59:35.622654644 +0200 @@ -0,0 +1,41 @@ +/****************************************************************************** + * @@ -385027,10 +384121,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/nic_spec.h linux-5.11.4-rtl88 + + +#endif /* __RTL8711_SPEC_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/osdep_intf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_intf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/osdep_intf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_intf.h 2022-12-18 17:40:24.575937030 +0200 +@@ -0,0 +1,146 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -385090,29 +384184,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_intf.h linux-5.11.4-rtl +#endif +#endif + -+#ifdef PLATFORM_OS_XP -+#ifdef CONFIG_SDIO_HCI -+ /* below is for io_rwmem... */ -+ PMDL pmdl; -+ PSDBUS_REQUEST_PACKET sdrp; -+ PSDBUS_REQUEST_PACKET recv_sdrp; -+ PSDBUS_REQUEST_PACKET xmit_sdrp; -+ -+ PIRP piorw_irp; -+ -+#endif -+#ifdef CONFIG_USB_HCI -+ PURB piorw_urb; -+ PIRP piorw_irp; -+ u8 io_irp_cnt; -+ u8 bio_irp_pending; -+ _sema io_retevt; -+#endif -+#endif -+ +}; + -+ +#ifdef CONFIG_R871X_TEST + int rtw_start_pseudo_adhoc(_adapter *padapter); + int rtw_stop_pseudo_adhoc(_adapter *padapter); @@ -385198,9 +384271,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_intf.h linux-5.11.4-rtl +int rtw_resume_common(_adapter *padapter); + +#endif /* _OSDEP_INTF_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service_bsd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service_bsd.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service_bsd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service_bsd.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,756 @@ +/****************************************************************************** + * @@ -385958,9 +385031,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_bsd.h linux-5.1 + +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service_ce.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service_ce.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service_ce.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service_ce.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,200 @@ +/****************************************************************************** + * @@ -386162,10 +385235,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_ce.h linux-5.11 + +#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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,781 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -386226,14 +385299,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service.h linux-5.11.4- + #include +#endif + -+#ifdef PLATFORM_OS_XP -+ #include -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ #include -+#endif -+ +/* #include */ + +#ifndef BIT @@ -386586,7 +385651,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service.h linux-5.11.4- + printf("%s", "RTKTHREAD_enter"); +#endif +} ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) +void thread_exit(_completion *comp); ++#else ++void kthread_thread_exit(_completion *comp); ++#endif +void _rtw_init_completion(_completion *comp); +void _rtw_wait_for_comp_timeout(_completion *comp); +void _rtw_wait_for_comp(_completion *comp); @@ -386629,15 +385698,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service.h linux-5.11.4- + return res; +#endif + -+#ifdef PLATFORM_WINDOWS -+ -+ if (res == _SUCCESS) -+ return NDIS_STATUS_SUCCESS; -+ else -+ return NDIS_STATUS_FAILURE; -+ -+#endif -+ +} + +__inline static void rtw_dump_stack(void) @@ -386657,16 +385717,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service.h linux-5.11.4- +{ + int ret = _TRUE; + -+#ifdef PLATFORM_WINDOWS -+ if (((uint)parg1) <= 0x7fffffff || -+ ((uint)parg2) <= 0x7fffffff || -+ ((uint)parg3) <= 0x7fffffff || -+ ((uint)parg4) <= 0x7fffffff) { -+ ret = _FALSE; -+ KeBugCheckEx(0x87110000, (ULONG_PTR)parg1, (ULONG_PTR)parg2, (ULONG_PTR)parg3, (ULONG_PTR)parg4); -+ } -+#endif -+ + return ret; + +} @@ -386970,9 +386020,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service.h linux-5.11.4- +#endif /* !PLATFORM_LINUX */ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service_linux.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service_linux.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service_linux.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,543 @@ +/****************************************************************************** + * @@ -387517,9 +386567,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_linux.h linux-5 + + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service_xp.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service_xp.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/osdep_service_xp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/osdep_service_xp.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,210 @@ +/****************************************************************************** + * @@ -387731,9 +386781,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/osdep_service_xp.h linux-5.11 + +#endif + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/pci_hal.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/pci_hal.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/pci_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/pci_hal.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,52 @@ +/****************************************************************************** + * @@ -387787,9 +386837,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/pci_hal.h linux-5.11.4-rtl881 +u8 rtw_set_hal_ops(_adapter *padapter); + +#endif /* __PCIE_HAL_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/pci_ops.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/pci_ops.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/pci_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/pci_ops.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,109 @@ +/****************************************************************************** + * @@ -387900,9 +386950,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/pci_ops.h linux-5.11.4-rtl881 +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/pci_osintf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/pci_osintf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/pci_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/pci_osintf.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,50 @@ +/****************************************************************************** + * @@ -387954,9 +387004,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/pci_osintf.h linux-5.11.4-rtl +#endif + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/recv_osdep.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/recv_osdep.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/recv_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/recv_osdep.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,67 @@ +/****************************************************************************** + * @@ -388025,9 +387075,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/recv_osdep.h linux-5.11.4-rtl +#endif /* PLATFORM_LINUX */ + +#endif /* */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_cmd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_cmd.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_cmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_cmd.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,158 @@ +/****************************************************************************** + * @@ -388187,9 +387237,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_cmd.h linux-5.11.4-r +s32 c2h_handler_8812a(_adapter *adapter, u8 id, u8 seq, u8 plen, u8 *payload); + +#endif/* __RTL8812A_CMD_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_dm.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_dm.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_dm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_dm.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,27 @@ +/****************************************************************************** + * @@ -388218,9 +387268,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_dm.h linux-5.11.4-rt +/* void rtl8192c_dm_RF_Saving(IN PADAPTER pAdapter, IN u8 bForceInNormal); */ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_hal.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_hal.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_hal.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,369 @@ +/****************************************************************************** + * @@ -388591,9 +387641,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_hal.h linux-5.11.4-r +); + +#endif /* __RTL8188E_HAL_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_led.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_led.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_led.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_led.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,41 @@ +/****************************************************************************** + * @@ -388636,10 +387686,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_led.h linux-5.11.4-r +#endif + +#endif /*__RTL8812A_LED_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_recv.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_recv.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_recv.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,149 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -388660,9 +387710,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_recv.h linux-5.11.4- +#if defined(CONFIG_USB_HCI) + + #ifndef MAX_RECVBUF_SZ -+ #ifdef PLATFORM_OS_CE -+ #define MAX_RECVBUF_SZ (8192+1024) /* 8K+1k */ -+ #else + #ifndef CONFIG_MINIMAL_MEMORY_USAGE + #ifdef CONFIG_PREALLOC_RX_SKB_BUFFER + #define MAX_RECVBUF_SZ (rtw_rtkm_get_buff_size()) /*depend rtkm*/ @@ -388681,7 +387728,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_recv.h linux-5.11.4- + #else + #define MAX_RECVBUF_SZ (4000) /* about 4K */ + #endif -+ #endif + #endif /* !MAX_RECVBUF_SZ */ + +#elif defined(CONFIG_PCI_HCI) @@ -388793,9 +387839,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_recv.h linux-5.11.4- +void rtl8812_query_rx_desc_status(union recv_frame *precvframe, u8 *pdesc); + +#endif /* __RTL8812A_RECV_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_rf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_rf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_rf.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,28 @@ +/****************************************************************************** + * @@ -388825,9 +387871,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_rf.h linux-5.11.4-rt + IN PADAPTER Adapter); + +#endif/* __RTL8188E_RF_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_spec.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_spec.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_spec.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,263 @@ +/****************************************************************************** + * @@ -389092,9 +388138,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_spec.h linux-5.11.4- +#ifdef CONFIG_RTL8821A +#include "rtl8821a_spec.h" +#endif /* CONFIG_RTL8821A */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_sreset.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_sreset.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_sreset.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_sreset.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -389120,9 +388166,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_sreset.h linux-5.11. +extern void rtl8812_sreset_linked_status_check(_adapter *padapter); +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_xmit.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_xmit.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8812a_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8812a_xmit.h 2022-01-28 22:59:35.623654691 +0200 @@ -0,0 +1,367 @@ +/****************************************************************************** + * @@ -389491,9 +388537,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8812a_xmit.h linux-5.11.4- +#ifdef CONFIG_RTL8821A +#include "rtl8821a_xmit.h" +#endif /* CONFIG_RTL8821A */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_cmd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_cmd.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_cmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_cmd.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,162 @@ +/****************************************************************************** + * @@ -389657,9 +388703,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_cmd.h linux-5.11.4-r +#endif /* CONFIG_P2P */ + +#endif/* __RTL8814A_CMD_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_dm.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_dm.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_dm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_dm.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,23 @@ +/****************************************************************************** + * @@ -389684,9 +388730,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_dm.h linux-5.11.4-rt +void rtl8814_HalDmWatchDog(IN PADAPTER Adapter); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_hal.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_hal.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_hal.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,330 @@ +/****************************************************************************** + * @@ -390018,9 +389064,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_hal.h linux-5.11.4-r +#endif + +#endif /* __RTL8188E_HAL_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_led.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_led.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_led.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_led.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,36 @@ +/****************************************************************************** + * @@ -390058,10 +389104,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_led.h linux-5.11.4-r + +#endif /* __RTL8814A_LED_H__ */ +#endif /*CONFIG_RTW_SW_LED*/ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_recv.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_recv.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_recv.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,182 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -390082,9 +389128,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_recv.h linux-5.11.4- +#if defined(CONFIG_USB_HCI) + + #ifndef MAX_RECVBUF_SZ -+ #ifdef PLATFORM_OS_CE -+ #define MAX_RECVBUF_SZ (8192+1024) /* 8K+1k */ -+ #else + #ifndef CONFIG_MINIMAL_MEMORY_USAGE + #ifdef CONFIG_PLATFORM_MSTAR + #define MAX_RECVBUF_SZ (8192) /* 8K */ @@ -390099,7 +389142,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_recv.h linux-5.11.4- + #else + #define MAX_RECVBUF_SZ (4000) /* about 4K */ + #endif -+ #endif + #endif /* !MAX_RECVBUF_SZ */ + +#elif defined(CONFIG_PCI_HCI) @@ -390248,9 +389290,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_recv.h linux-5.11.4- +void rtl8814_query_rx_desc_status(union recv_frame *precvframe, u8 *pdesc); + +#endif /* __RTL8814A_RECV_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_rf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_rf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_rf.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,28 @@ +/****************************************************************************** + * @@ -390280,9 +389322,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_rf.h linux-5.11.4-rt + IN PADAPTER Adapter); + +#endif/* __RTL8188E_RF_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_spec.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_spec.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_spec.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,656 @@ +/****************************************************************************** + * @@ -390940,9 +389982,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_spec.h linux-5.11.4- +#define PROTO_CAP_8814A (PROTO_CAP_11B | PROTO_CAP_11G | PROTO_CAP_11N | PROTO_CAP_11AC) + +#endif /* __RTL8814A_SPEC_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_sreset.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_sreset.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_sreset.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_sreset.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -390968,9 +390010,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_sreset.h linux-5.11. + extern void rtl8814_sreset_linked_status_check(_adapter *padapter); +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_xmit.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_xmit.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8814a_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8814a_xmit.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,311 @@ +/****************************************************************************** + * @@ -391283,9 +390325,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8814a_xmit.h linux-5.11.4- + + +#endif /* __RTL8814_XMIT_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8821a_spec.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8821a_spec.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8821a_spec.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8821a_spec.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** + * @@ -391377,9 +390419,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8821a_spec.h linux-5.11.4- + * ************************************************************ */ + +#endif /* __RTL8821A_SPEC_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl8821a_xmit.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8821a_xmit.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl8821a_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl8821a_xmit.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,173 @@ +/****************************************************************************** + * @@ -391554,9 +390596,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl8821a_xmit.h linux-5.11.4- +#endif + +#endif /* __RTL8821_XMIT_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtl_autoconf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl_autoconf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtl_autoconf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtl_autoconf.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,363 @@ +/****************************************************************************** + * @@ -391921,10 +390963,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtl_autoconf.h linux-5.11.4-r +#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 -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_android.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_android.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_android.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_android.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,108 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -392030,17 +391072,12 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_android.h linux-5.11.4-rt +#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */ + +#ifdef CONFIG_GPIO_WAKEUP -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+int wifi_configure_gpio(void); -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ +void wifi_free_gpio(unsigned int gpio); +#endif /* CONFIG_GPIO_WAKEUP */ -+ -+ +#endif /* __RTW_ANDROID_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ap.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ap.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ap.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ap.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,112 @@ +/****************************************************************************** + * @@ -392154,9 +391191,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ap.h linux-5.11.4-rtl8812 + +#endif /* end of CONFIG_AP_MODE */ +#endif /*__RTW_AP_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_beamforming.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_beamforming.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_beamforming.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_beamforming.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,401 @@ +/****************************************************************************** + * @@ -392559,9 +391596,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_beamforming.h linux-5.11. +#endif /*#ifdef CONFIG_BEAMFORMING */ + +#endif /*__RTW_BEAMFORMING_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_br_ext.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_br_ext.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_br_ext.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_br_ext.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,69 @@ +/****************************************************************************** + * @@ -392632,9 +391669,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_br_ext.h linux-5.11.4-rtl +void nat25_db_cleanup(_adapter *priv); + +#endif /* _RTW_BR_EXT_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_btcoex.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_btcoex.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_btcoex.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_btcoex.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,455 @@ +/****************************************************************************** + * @@ -393091,9 +392128,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_btcoex.h linux-5.11.4-rtl + +void rtw_btcoex_set_ant_info(PADAPTER padapter); + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_btcoex_wifionly.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_btcoex_wifionly.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_btcoex_wifionly.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_btcoex_wifionly.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,24 @@ +/****************************************************************************** + * @@ -393119,10 +392156,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_btcoex_wifionly.h linux-5 +void rtw_btcoex_wifionly_initialize(PADAPTER padapter); +void rtw_btcoex_wifionly_AntInfoSetting(PADAPTER padapter); +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_bt_mp.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_bt_mp.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_bt_mp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_bt_mp.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,287 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -393144,7 +392181,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_bt_mp.h linux-5.11.4-rtl8 + +#if (MP_DRIVER == 1) + -+#pragma pack(1) + +/* definition for BT_UP_OP_BT_READY */ +#define MP_BT_NOT_READY 0 @@ -393411,9 +392447,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_bt_mp.h linux-5.11.4-rtl8 +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_byteorder.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_byteorder.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_byteorder.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_byteorder.h 2022-01-28 22:59:35.624654739 +0200 @@ -0,0 +1,45 @@ +/****************************************************************************** + * @@ -393460,10 +392496,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_byteorder.h linux-5.11.4- +#endif + +#endif /* _RTL871X_BYTEORDER_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_cmd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_cmd.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_cmd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_cmd.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,1356 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -393492,11 +392528,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_cmd.h linux-5.11.4-rtl881 +#define MAX_RSPSZ 512 +#define MAX_EVTSZ 1024 + -+#ifdef PLATFORM_OS_CE -+ #define CMDBUFF_ALIGN_SZ 4 -+#else -+ #define CMDBUFF_ALIGN_SZ 512 -+#endif ++#define CMDBUFF_ALIGN_SZ 512 + +struct cmd_obj { + _adapter *padapter; @@ -393580,9 +392612,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_cmd.h linux-5.11.4-rtl881 +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + u8 *c2h_mem; + u8 *allocated_c2h_mem; -+#ifdef PLATFORM_OS_XP -+ PMDL pc2h_mdl; -+#endif +#endif + +}; @@ -394827,10 +393856,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_cmd.h linux-5.11.4-rtl881 + (cmd)->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra) ? ((struct drvextra_cmd_parm *)(cmd)->parmbuf)->type : 0 + +#endif /* _CMD_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_debug.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_debug.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_debug.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,624 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -394861,37 +393890,18 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_debug.h linux-5.11.4-rtl8 + +#define DRIVER_PREFIX "RTW: " + -+#ifdef PLATFORM_OS_CE -+extern void rtl871x_cedbg(const char *fmt, ...); -+#endif -+ -+#ifdef PLATFORM_WINDOWS -+ #define RTW_PRINT do {} while (0) -+ #define RTW_ERR do {} while (0) -+ #define RTW_WARN do {} while (0) -+ #define RTW_INFO do {} while (0) -+ #define RTW_DBG do {} while (0) -+ #define RTW_PRINT_SEL do {} while (0) -+ #define _RTW_PRINT do {} while (0) -+ #define _RTW_ERR do {} while (0) -+ #define _RTW_WARN do {} while (0) -+ #define _RTW_INFO do {} while (0) -+ #define _RTW_DBG do {} while (0) -+ #define _RTW_PRINT_SEL do {} while (0) -+#else -+ #define RTW_PRINT(x, ...) do {} while (0) -+ #define RTW_ERR(x, ...) do {} while (0) -+ #define RTW_WARN(x,...) do {} while (0) -+ #define RTW_INFO(x,...) do {} while (0) -+ #define RTW_DBG(x,...) do {} while (0) -+ #define RTW_PRINT_SEL(x,...) do {} while (0) -+ #define _RTW_PRINT(x, ...) do {} while (0) -+ #define _RTW_ERR(x, ...) do {} while (0) -+ #define _RTW_WARN(x,...) do {} while (0) -+ #define _RTW_INFO(x,...) do {} while (0) -+ #define _RTW_DBG(x,...) do {} while (0) -+ #define _RTW_PRINT_SEL(x,...) do {} while (0) -+#endif ++#define RTW_PRINT(x, ...) do {} while (0) ++#define RTW_ERR(x, ...) do {} while (0) ++#define RTW_WARN(x,...) do {} while (0) ++#define RTW_INFO(x,...) do {} while (0) ++#define RTW_DBG(x,...) do {} while (0) ++#define RTW_PRINT_SEL(x,...) do {} while (0) ++#define _RTW_PRINT(x, ...) do {} while (0) ++#define _RTW_ERR(x, ...) do {} while (0) ++#define _RTW_WARN(x,...) do {} while (0) ++#define _RTW_INFO(x,...) do {} while (0) ++#define _RTW_DBG(x,...) do {} while (0) ++#define _RTW_PRINT_SEL(x,...) do {} while (0) + +#define RTW_INFO_DUMP(_TitleString, _HexData, _HexDataLen) do {} while (0) +#define RTW_DBG_DUMP(_TitleString, _HexData, _HexDataLen) do {} while (0) @@ -394901,20 +393911,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_debug.h linux-5.11.4-rtl8 + +#define RTW_DBGDUMP 0 /* 'stream' for _dbgdump */ + -+ -+ +#undef _dbgdump +#undef _seqdump + -+#if defined(PLATFORM_WINDOWS) && defined(PLATFORM_OS_XP) -+ #define _dbgdump DbgPrint -+ #define KERN_CONT -+ #define _seqdump(sel, fmt, arg...) _dbgdump(fmt, ##arg) -+#elif defined(PLATFORM_WINDOWS) && defined(PLATFORM_OS_CE) -+ #define _dbgdump rtl871x_cedbg -+ #define KERN_CONT -+ #define _seqdump(sel, fmt, arg...) _dbgdump(fmt, ##arg) -+#elif defined PLATFORM_LINUX ++#if defined PLATFORM_LINUX + #define _dbgdump printk + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) + #define KERN_CONT @@ -395484,9 +394484,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_debug.h linux-5.11.4-rtl8 +#define _module_rtl8712_led_c_ BIT(31) + +#endif /* __RTW_DEBUG_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_eeprom.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_eeprom.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_eeprom.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_eeprom.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,116 @@ +/****************************************************************************** + * @@ -395604,9 +394604,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_eeprom.h linux-5.11.4-rtl +#endif /* PLATFORM_LINUX */ + +#endif /* __RTL871X_EEPROM_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_efuse.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_efuse.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_efuse.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_efuse.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,255 @@ +/****************************************************************************** + * @@ -395863,9 +394863,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_efuse.h linux-5.11.4-rtl8 +#endif /* PLATFORM_LINUX */ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_event.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_event.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_event.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_event.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,130 @@ +/****************************************************************************** + * @@ -395997,9 +394997,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_event.h linux-5.11.4-rtl8 + + +#endif /* _WLANEVENT_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ht.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ht.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ht.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ht.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,217 @@ +/****************************************************************************** + * @@ -396218,10 +395218,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ht.h linux-5.11.4-rtl8812 +#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 -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ioctl.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ioctl.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ioctl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ioctl.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,127 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -396239,68 +395239,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl.h linux-5.11.4-rtl8 +#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 @@ -396372,143 +395310,13 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl.h linux-5.11.4-rtl8 +}; + +#if (defined(CONFIG_MP_INCLUDED) && defined(_RTW_MP_IOCTL_C_)) || \ -+ (defined(PLATFORM_WINDOWS) && defined(_RTW_IOCTL_RTL_C_)) ++ (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 @@ -396541,38 +395349,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl.h linux-5.11.4-rtl8 +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ioctl_rtl.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ioctl_rtl.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ioctl_rtl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ioctl_rtl.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,75 @@ +/****************************************************************************** + * @@ -396649,10 +395428,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_rtl.h linux-5.11.4- + + +#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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ioctl_set.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ioctl_set.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_ioctl_set.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_ioctl_set.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,45 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -396679,28 +395458,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_set.h linux-5.11.4- +} 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); @@ -396720,10 +395477,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_ioctl_set.h linux-5.11.4- +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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_io.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_io.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_io.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_io.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,548 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -396744,9 +395501,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_io.h linux-5.11.4-rtl8812 + +#define NUM_IOREQ 8 + -+#ifdef PLATFORM_WINDOWS -+ #define MAX_PROT_SZ 64 -+#endif +#ifdef PLATFORM_LINUX + #define MAX_PROT_SZ (64-16) +#endif @@ -396867,27 +395621,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_io.h linux-5.11.4-rtl8812 + u8 *pbuf; + _sema sema; + -+#ifdef PLATFORM_OS_CE -+#ifdef CONFIG_USB_HCI -+ /* URB handler for rtw_write_mem */ -+ USB_TRANSFER usb_transfer_write_mem; -+#endif -+#endif + + void (*_async_io_callback)(_adapter *padater, struct io_req *pio_req, u8 *cnxt); + u8 *cnxt; -+ -+#ifdef PLATFORM_OS_XP -+ PMDL pmdl; -+ PIRP pirp; -+ -+#ifdef CONFIG_SDIO_HCI -+ PSDBUS_REQUEST_PACKET sdrp; -+#endif -+ -+#endif -+ -+ +}; + +struct intf_hdl { @@ -397293,9 +396029,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_io.h linux-5.11.4-rtl8812 + rtw_read32(_a, _b) + +#endif /* _RTL8711_IO_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_iol.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_iol.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_iol.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_iol.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,131 @@ +/****************************************************************************** + * @@ -397428,9 +396164,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_iol.h linux-5.11.4-rtl881 + + +#endif /* __RTW_IOL_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mcc.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mcc.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mcc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mcc.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,271 @@ +/****************************************************************************** + * @@ -397703,9 +396439,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mcc.h linux-5.11.4-rtl881 +u8 rtw_set_mcc_duration_cmd(_adapter *adapter, u8 type, u8 val); +#endif /* _RTW_MCC_H_ */ +#endif /* CONFIG_MCC_MODE */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mem.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mem.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mem.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mem.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,36 @@ +/****************************************************************************** + * @@ -397743,9 +396479,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mem.h linux-5.11.4-rtl881 + + +#endif /* __RTW_MEM_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mi.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mi.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mi.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,306 @@ +/****************************************************************************** + * @@ -398053,9 +396789,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mi.h linux-5.11.4-rtl8812 +void rtw_mi_update_ap_bmc_camid(_adapter *padapter, u8 camid_a, u8 camid_b); + +#endif /*__RTW_MI_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mlme_ext.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mlme_ext.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mlme_ext.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mlme_ext.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,1311 @@ +/****************************************************************************** + * @@ -399368,9 +398104,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mlme_ext.h linux-5.11.4-r +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mlme.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mlme.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mlme.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mlme.h 2022-01-28 22:59:35.625654787 +0200 @@ -0,0 +1,1427 @@ +/****************************************************************************** + * @@ -400799,10 +399535,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mlme.h linux-5.11.4-rtl88 +#define GET_TCP_CWR(_tcphdr) BE_BITS_TO_1BYTE(((u8 *)(_tcphdr)) + 13, 7, 1) + +#endif /* __RTL871X_MLME_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mp.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mp.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mp.h 2022-12-18 17:40:24.575937030 +0200 +@@ -0,0 +1,894 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -400844,14 +399580,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp.h linux-5.11.4-rtl8812 + u8 *mem_addr; + u32 sz[8]; + -+#if defined(PLATFORM_OS_XP) || defined(PLATFORM_LINUX) ++#if defined(PLATFORM_LINUX) + PURB pxmit_urb[8]; +#endif + -+#ifdef PLATFORM_OS_XP -+ PIRP pxmit_irp[8]; -+#endif -+ + u8 bpending[8]; + sint ac_tag[8]; + sint last[8]; @@ -400871,21 +399603,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp.h linux-5.11.4-rtl8812 + +typedef void(*wi_act_func)(void *padapter); + -+#ifdef PLATFORM_WINDOWS -+struct mp_wi_cntx { -+ u8 bmpdrv_unload; -+ -+ /* Work Item */ -+ NDIS_WORK_ITEM mp_wi; -+ NDIS_EVENT mp_wi_evt; -+ _lock mp_wi_lock; -+ u8 bmp_wi_progress; -+ wi_act_func curractfunc; -+ /* Variable needed in each implementation of CurrActFunc. */ -+ struct mp_wiparam param; -+}; -+#endif -+ +struct mp_tx { + u8 stop; + u32 count, sended; @@ -401188,31 +399905,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp.h linux-5.11.4-rtl8812 + struct wlan_network mp_network; + NDIS_802_11_MAC_ADDRESS network_macaddr; + -+#ifdef PLATFORM_WINDOWS -+ u32 rx_testcnt; -+ u32 rx_testcnt1; -+ u32 rx_testcnt2; -+ u32 tx_testcnt; -+ u32 tx_testcnt1; -+ -+ struct mp_wi_cntx wi_cntx; -+ -+ u8 h2c_result; -+ u8 h2c_seqnum; -+ u16 h2c_cmdcode; -+ u8 h2c_resp_parambuf[512]; -+ _lock h2c_lock; -+ _lock wkitm_lock; -+ u32 h2c_cmdcnt; -+ NDIS_EVENT h2c_cmd_evt; -+ NDIS_EVENT c2h_set; -+ NDIS_EVENT h2c_clr; -+ NDIS_EVENT cpwm_int; -+ -+ NDIS_EVENT scsir_full_evt; -+ NDIS_EVENT scsiw_empty_evt; -+#endif -+ + u8 *pallocated_mp_xmitframe_buf; + u8 *pmp_xmtframe_buf; + _queue free_mp_xmitqueue; @@ -401741,10 +400433,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp.h linux-5.11.4-rtl8812 + struct iw_request_info *info, + struct iw_point *wrqu, char *extra); +#endif /* _RTW_MP_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mp_ioctl.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mp_ioctl.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mp_ioctl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mp_ioctl.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,553 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -401820,24 +400512,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp_ioctl.h linux-5.11.4-r +/* int mp_start_joinbss(_adapter *padapter, NDIS_802_11_SSID *pssid); */ + +/* void _irqlevel_changed_(_irqL *irqlevel, BOOLEANunsigned char bLower); */ -+#ifdef PLATFORM_OS_XP -+static void _irqlevel_changed_(_irqL *irqlevel, u8 bLower) -+{ -+ -+ if (bLower == LOWER) { -+ *irqlevel = KeGetCurrentIrql(); -+ -+ if (*irqlevel > PASSIVE_LEVEL) -+ KeLowerIrql(PASSIVE_LEVEL); -+ } else { -+ if (KeGetCurrentIrql() == PASSIVE_LEVEL) -+ KeRaiseIrql(DISPATCH_LEVEL, irqlevel); -+ } -+ -+} -+#else +#define _irqlevel_changed_(a, b) -+#endif + +/* oid_rtl_seg_81_80_00 */ +NDIS_STATUS oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv); @@ -402315,9 +400990,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp_ioctl.h linux-5.11.4-r +#endif /* _RTW_MP_IOCTL_C_ */ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mp_phy_regdef.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mp_phy_regdef.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_mp_phy_regdef.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_mp_phy_regdef.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,1094 @@ +/****************************************************************************** + * @@ -403413,9 +402088,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_mp_phy_regdef.h linux-5.1 + + +#endif /* __INC_HAL8192SPHYREG_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_odm.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_odm.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_odm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_odm.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,97 @@ +/****************************************************************************** + * @@ -403514,9 +402189,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_odm.h linux-5.11.4-rtl881 +void rtw_odm_parse_rx_phy_status_chinfo(union recv_frame *rframe, u8 *phys); + +#endif /* __RTW_ODM_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_p2p.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_p2p.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_p2p.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_p2p.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,169 @@ +/****************************************************************************** + * @@ -403687,9 +402362,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_p2p.h linux-5.11.4-rtl881 +#endif /* CONFIG_P2P */ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_pwrctrl.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_pwrctrl.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_pwrctrl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_pwrctrl.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,609 @@ +/****************************************************************************** + * @@ -404300,9 +402975,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_pwrctrl.h linux-5.11.4-rt +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 -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_qos.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_qos.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_qos.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_qos.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,66 @@ +/****************************************************************************** + * @@ -404371,10 +403046,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_qos.h linux-5.11.4-rtl881 + +#endif /* _RTL871X_QOS_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_recv.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_recv.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_recv.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_recv.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,852 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -404396,19 +403071,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_recv.h linux-5.11.4-rtl88 +#define RTW_RX_MSDU_ACT_INDICATE BIT0 +#define RTW_RX_MSDU_ACT_FORWARD BIT1 + -+#ifdef PLATFORM_OS_XP -+ #ifdef CONFIG_SDIO_HCI -+ #define NR_RECVBUFF 1024/* 512 */ /* 128 */ -+ #else -+ #define NR_RECVBUFF (16) -+ #endif -+#elif defined(PLATFORM_OS_CE) -+ #ifdef CONFIG_SDIO_HCI -+ #define NR_RECVBUFF (128) -+ #else -+ #define NR_RECVBUFF (4) -+ #endif -+#else /* PLATFORM_LINUX /PLATFORM_BSD */ + +#include + @@ -404432,7 +403094,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_recv.h linux-5.11.4-rtl88 + #ifdef CONFIG_RTW_NAPI + #define RTL_NAPI_WEIGHT (32) + #endif -+#endif + +#if defined(CONFIG_RTL8821C) && defined(CONFIG_SDIO_HCI) && defined(CONFIG_RECV_THREAD_MODE) + #ifdef NR_RECVBUFF @@ -404731,17 +403392,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_recv.h linux-5.11.4-rtl88 + + _adapter *adapter; + -+#ifdef PLATFORM_WINDOWS -+ _nic_hdl RxPktPoolHdl; -+ _nic_hdl RxBufPoolHdl; -+ -+#ifdef PLATFORM_OS_XP -+ PMDL pbytecnt_mdl; -+#endif -+ uint counter; /* record the number that up-layer will return to drv; only when counter==0 can we release recv_priv */ -+ NDIS_EVENT recv_resource_evt ; -+#endif -+ + + u32 is_any_non_be_pkts; + @@ -404910,20 +403560,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_recv.h linux-5.11.4-rtl88 + +#ifdef CONFIG_USB_HCI + -+#if defined(PLATFORM_OS_XP) || defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) ++#if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) + PURB purb; + dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */ + u32 alloc_sz; +#endif -+ -+#ifdef PLATFORM_OS_XP -+ PIRP pirp; -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ USB_TRANSFER usb_transfer_read_port; -+#endif -+ + u8 irp_pending; + int transfer_len; + @@ -405261,9 +403902,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_recv.h linux-5.11.4-rtl88 +void count_rx_stats(_adapter *padapter, union recv_frame *prframe, struct sta_info *sta); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_rf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_rf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_rf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_rf.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,240 @@ +/****************************************************************************** + * @@ -405505,9 +404146,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_rf.h linux-5.11.4-rtl8812 +bool rtw_is_long_cac_ch(u8 ch, u8 bw, u8 offset, u8 dfs_region); + +#endif /* _RTL8711_RF_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_rm_fsm.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_rm_fsm.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_rm_fsm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_rm_fsm.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,389 @@ + +/****************************************************************************** @@ -405898,9 +404539,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_rm_fsm.h linux-5.11.4-rtl + +#endif /*CONFIG_RTW_80211K*/ +#endif /*__RTW_RM_FSM_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_rm.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_rm.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_rm.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_rm.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,88 @@ +/****************************************************************************** + * @@ -405990,9 +404631,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_rm.h linux-5.11.4-rtl8812 + +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_rson.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_rson.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_rson.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_rson.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,61 @@ +/****************************************************************************** + * @@ -406055,9 +404696,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_rson.h linux-5.11.4-rtl88 +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 -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_sdio.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_sdio.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_sdio.h 2022-01-28 22:59:35.626654834 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -406085,10 +404726,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_sdio.h linux-5.11.4-rtl88 +u8 rtw_sdio_f0_read(struct dvobj_priv *, u32 addr, void *buf, size_t len); + +#endif /* _RTW_SDIO_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_security.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_security.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_security.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_security.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,499 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -406285,9 +404926,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_security.h linux-5.11.4-r + u32 ndisencryptstatus; /* NDIS_802_11_ENCRYPTION_STATUS */ + + NDIS_802_11_WEP ndiswep; -+#ifdef PLATFORM_WINDOWS -+ u8 KeyMaterial[16];/* variable length depending on above field. */ -+#endif + + u8 assoc_info[600]; + u8 szofcapability[256]; /* for wpa2 usage */ @@ -406591,9 +405229,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_security.h linux-5.11.4-r + ((a)->securitypriv.auth_type == (s)) + +#endif /* __RTL871X_SECURITY_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_sreset.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_sreset.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_sreset.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_sreset.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,66 @@ +/****************************************************************************** + * @@ -406661,9 +405299,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_sreset.h linux-5.11.4-rtl +void sreset_reset(_adapter *padapter); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_tdls.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_tdls.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_tdls.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_tdls.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,185 @@ +/****************************************************************************** + * @@ -406850,9 +405488,194 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_tdls.h linux-5.11.4-rtl88 +#endif /* CONFIG_TDLS */ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_version.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_version.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_version.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_version.h 2022-01-28 22:59:35.627654881 +0200 +@@ -0,0 +1 @@ ++#define DRIVERVERSION "v5.6.4.2_35491.20191025" +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_vht.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_vht.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_vht.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_vht.h 2022-01-28 22:59:35.627654881 +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-6.3.4/drivers/staging/rtl8812au/include/rtw_wapi.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_wapi.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_wapi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_wapi.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,230 @@ +/****************************************************************************** + * @@ -407084,194 +405907,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_wapi.h linux-5.11.4-rtl88 +void rtw_wapi_set_set_encryption(_adapter *padapter, struct ieee_param *param); + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_wifi_regd.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_wifi_regd.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_wifi_regd.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_wifi_regd.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,34 @@ +/****************************************************************************** + * @@ -407307,10 +405945,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_wifi_regd.h linux-5.11.4- +int rtw_regd_init(struct wiphy *wiphy); + +#endif /* __RTW_WIFI_REGD_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/rtw_xmit.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_xmit.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/rtw_xmit.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/rtw_xmit.h 2023-05-26 22:35:36.545136899 +0300 +@@ -0,0 +1,1045 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -407373,10 +406011,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 +#endif + #define NR_XMITBUFF (128) +#endif -+ -+#ifdef PLATFORM_OS_CE -+ #define XMITBUF_ALIGN_SZ 4 -+#else + #ifdef CONFIG_PCI_HCI + #define XMITBUF_ALIGN_SZ 4 + #else @@ -407385,7 +406019,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 + #else + #define XMITBUF_ALIGN_SZ 512 + #endif -+ #endif +#endif + +/* xmit extension buff defination */ @@ -407907,19 +406540,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 + u8 bulkout_id; /* for halmac */ +#endif /* RTW_HALMAC */ + -+#if defined(PLATFORM_OS_XP) || defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) ++#if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) + PURB pxmit_urb[8]; + dma_addr_t dma_transfer_addr; /* (in) dma addr for transfer_buffer */ +#endif -+ -+#ifdef PLATFORM_OS_XP -+ PIRP pxmit_irp[8]; -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ USB_TRANSFER usb_transfer_write_port; -+#endif -+ + u8 bpending[8]; + + sint last[8]; @@ -407934,11 +406558,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 + u32 ff_hwaddr; + u8 pg_num; + u8 agg_num; -+#ifdef PLATFORM_OS_XP -+ PMDL pxmitbuf_mdl; -+ PIRP pxmitbuf_irp; -+ PSDBUS_REQUEST_PACKET pxmitbuf_sdrp; -+#endif +#endif + +#ifdef CONFIG_PCI_HCI @@ -407952,10 +406571,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 +#if defined(DBG_XMIT_BUF) || defined(DBG_XMIT_BUF_EXT) + u8 no; +#endif -+ +}; + -+ +struct xmit_frame { + _list list; + @@ -408004,7 +406621,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 + sint option; + sint apsd_setting; /* When bit mask is on, the associated edca queue supports APSD. */ + -+ + /* struct tx_servq blk_q[MAX_NUMBLKS]; */ + struct tx_servq be_q; /* priority == 0,3 */ + struct tx_servq bk_q; /* priority == 1,2 */ @@ -408019,7 +406635,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 + /* u64 sta_tx_pkts; */ + /* uint sta_tx_fail; */ + -+ +}; + + @@ -408105,10 +406720,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 + _sema tx_retevt;/* all tx return event; */ + u8 txirp_cnt; + -+#ifdef PLATFORM_OS_CE -+ USB_TRANSFER usb_transfer_write_port; -+ /* USB_TRANSFER usb_transfer_write_mem; */ -+#endif +#ifdef PLATFORM_LINUX + struct tasklet_struct xmit_tasklet; +#endif @@ -408383,9 +406994,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/rtw_xmit.h linux-5.11.4-rtl88 +#include + +#endif /* _RTL871X_XMIT_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/sdio_hal.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sdio_hal.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/sdio_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sdio_hal.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,57 @@ +/****************************************************************************** + * @@ -408444,63 +407055,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_hal.h linux-5.11.4-rtl88 +#endif + +#endif /* __SDIO_HAL_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/sdio_ops.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sdio_ops.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/sdio_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sdio_ops.h 2023-05-26 22:35:36.546136899 +0300 +@@ -0,0 +1,206 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -408528,24 +407086,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops.h linux-5.11.4-rtl88 +#include +#endif + -+#ifdef PLATFORM_WINDOWS -+ -+#ifdef PLATFORM_OS_XP -+#include -+struct async_context { -+ PMDL pmdl; -+ PSDBUS_REQUEST_PACKET sdrp; -+ unsigned char *r_buf; -+ unsigned char *padapter; -+}; -+#endif -+ -+#ifdef PLATFORM_OS_CE -+#include -+#endif -+ -+#endif /* PLATFORM_WINDOWS */ -+ + +extern void sdio_set_intf_ops(_adapter *padapter, struct _io_ops *pops); +void dump_sdio_card_info(void *sel, struct dvobj_priv *dvobj); @@ -408725,9 +407265,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops.h linux-5.11.4-rtl88 +} + +#endif /* !__SDIO_OPS_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/sdio_ops_linux.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sdio_ops_linux.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/sdio_ops_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sdio_ops_linux.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,58 @@ +/****************************************************************************** + * @@ -408787,63 +407327,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_ops_linux.h linux-5.11.4 + +#endif /* __SDIO_OPS_LINUX_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 @@ -+/****************************************************************************** -+ * -+ * 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_XP_H_ -+#define _SDIO_OPS_XP_H_ -+ -+#include -+#include -+#include -+#include -+ -+ -+#ifdef PLATFORM_OS_XP -+ -+ -+extern u8 sdbus_cmd52r_xp(struct intf_priv *pintfpriv, u32 addr); -+ -+ -+extern void sdbus_cmd52w_xp(struct intf_priv *pintfpriv, u32 addr, u8 val8); -+ -+ -+uint sdbus_read_blocks_to_membuf_xp(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); -+ -+extern uint sdbus_read_bytes_to_membuf_xp(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); -+ -+ -+extern uint sdbus_write_blocks_from_membuf_xp(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf, u8 async); -+ -+extern uint sdbus_write_bytes_from_membuf_xp(struct intf_priv *pintfpriv, u32 addr, u32 cnt, u8 *pbuf); -+extern u8 sdbus_func1cmd52r_xp(struct intf_priv *pintfpriv, u32 addr); -+extern void sdbus_func1cmd52w_xp(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_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/sdio_osintf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sdio_osintf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/sdio_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sdio_osintf.h 2023-05-26 22:35:36.546136899 +0300 +@@ -0,0 +1,18 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -408861,17 +407348,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sdio_osintf.h linux-5.11.4-rt +#ifndef __SDIO_OSINTF_H__ +#define __SDIO_OSINTF_H__ + -+ -+#ifdef PLATFORM_OS_CE -+extern NDIS_STATUS ce_sd_get_dev_hdl(PADAPTER padapter); -+SD_API_STATUS ce_sd_int_callback(SD_DEVICE_HANDLE hDevice, PADAPTER padapter); -+extern void sd_setup_irs(PADAPTER padapter); +#endif -+ -+#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/sta_info.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sta_info.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/sta_info.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/sta_info.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,748 @@ +/****************************************************************************** + * @@ -409621,9 +408101,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/sta_info.h linux-5.11.4-rtl88 +#endif /* CONFIG_RTW_PRE_LINK_STA */ + +#endif /* _STA_INFO_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/usb_hal.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_hal.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/usb_hal.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_hal.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,74 @@ +/****************************************************************************** + * @@ -409699,9 +408179,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_hal.h linux-5.11.4-rtl881 +extern _adapter *rtw_usb_get_sw_pointer(void); +#endif /* CONFIG_INTEL_PROXIM */ +#endif /* __USB_HAL_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/usb_ops.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_ops.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/usb_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_ops.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,153 @@ +/****************************************************************************** + * @@ -409856,9 +408336,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_ops.h linux-5.11.4-rtl881 + + +#endif /* __USB_OPS_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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/usb_ops_linux.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_ops_linux.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/usb_ops_linux.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_ops_linux.h 2023-05-26 22:35:36.546136899 +0300 @@ -0,0 +1,98 @@ +/****************************************************************************** + * @@ -409951,16 +408431,16 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_ops_linux.h linux-5.11.4- +int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val); +int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata); +u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem); -+void usb_recv_tasklet(void *priv); ++void usb_recv_tasklet(unsigned long priv); + +#ifdef CONFIG_USB_INTERRUPT_IN_PIPE +void usb_read_interrupt_complete(struct urb *purb, struct pt_regs *regs); +u32 usb_read_interrupt(struct intf_hdl *pintfhdl, u32 addr); +#endif +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/usb_osintf.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_osintf.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/usb_osintf.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_osintf.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -409988,9 +408468,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_osintf.h linux-5.11.4-rtl + + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/usb_vendor_req.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_vendor_req.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/usb_vendor_req.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/usb_vendor_req.h 2022-01-28 22:59:35.627654881 +0200 @@ -0,0 +1,56 @@ +/****************************************************************************** + * @@ -410048,10 +408528,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/usb_vendor_req.h linux-5.11.4 +#endif + +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/wifi.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/wifi.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/wifi.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/wifi.h 2023-05-26 22:35:36.546136899 +0300 +@@ -0,0 +1,1349 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -410508,7 +408988,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wifi.h linux-5.11.4-rtl8812au + return _FALSE; +} + -+__inline static unsigned char *get_ra(unsigned char *pframe) ++__inline static unsigned char *wifi_get_ra(unsigned char *pframe) +{ + unsigned char *ra; + ra = GetAddr1Ptr(pframe); @@ -410934,76 +409414,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wifi.h linux-5.11.4-rtl8812au + unsigned short BA_timeout_value; + unsigned short BA_starting_seqctrl; +} __attribute__((packed)); -+ -+ -+ -+#endif -+ -+ -+#ifdef PLATFORM_WINDOWS -+ -+#pragma pack(1) -+ -+struct rtw_ieee80211_ht_cap { -+ unsigned short cap_info; -+ unsigned char ampdu_params_info; -+ unsigned char supp_mcs_set[16]; -+ unsigned short extended_ht_cap_info; -+ unsigned int tx_BF_cap_info; -+ unsigned char antenna_selection_info; -+}; -+ -+ -+struct ieee80211_ht_addt_info { -+ unsigned char control_chan; -+ unsigned char ht_param; -+ unsigned short operation_mode; -+ unsigned short stbc_param; -+ unsigned char basic_set[16]; -+}; -+ -+struct HT_caps_element { -+ union { -+ struct { -+ unsigned short HT_caps_info; -+ unsigned char AMPDU_para; -+ unsigned char MCS_rate[16]; -+ unsigned short HT_ext_caps; -+ unsigned int Beamforming_caps; -+ unsigned char ASEL_caps; -+ } HT_cap_element; -+ unsigned char HT_cap[26]; -+ }; -+}; -+ -+struct HT_info_element { -+ unsigned char primary_channel; -+ unsigned char infos[5]; -+ unsigned char MCS_rate[16]; -+}; -+ -+struct AC_param { -+ unsigned char ACI_AIFSN; -+ unsigned char CW; -+ unsigned short TXOP_limit; -+}; -+ -+struct WMM_para_element { -+ unsigned char QoS_info; -+ unsigned char reserved; -+ struct AC_param ac_param[4]; -+}; -+ -+struct ADDBA_request { -+ unsigned char dialog_token; -+ unsigned short BA_para_set; -+ unsigned short BA_timeout_value; -+ unsigned short BA_starting_seqctrl; -+}; -+ -+ -+#pragma pack() -+ +#endif + +typedef enum _HT_CAP_AMPDU_FACTOR { @@ -411471,10 +409881,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wifi.h linux-5.11.4-rtl8812au +#endif + +#endif /* _WIFI_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/wlan_bssdef.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/wlan_bssdef.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/wlan_bssdef.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/wlan_bssdef.h 2023-05-26 22:35:36.546136899 +0300 +@@ -0,0 +1,655 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -412030,10 +410440,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wlan_bssdef.h linux-5.11.4-rt +/* temporally add #pragma pack for structure alignment issue of +* WLAN_BSSID_EX and get_WLAN_BSSID_EX_sz() +*/ -+#ifdef PLATFORM_WINDOWS -+#pragma pack(push) -+#pragma pack(1) -+#endif +typedef struct _WLAN_BSSID_EX { + ULONG Length; + NDIS_802_11_MAC_ADDRESS MacAddress; @@ -412050,13 +410456,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wlan_bssdef.h linux-5.11.4-rt + ULONG IELength; + UCHAR IEs[MAX_IE_SZ]; /* (timestamp, beacon interval, and capability information) */ +} -+#ifndef PLATFORM_WINDOWS -+__attribute__((packed)) -+#endif +WLAN_BSSID_EX, *PWLAN_BSSID_EX; -+#ifdef PLATFORM_WINDOWS -+#pragma pack(pop) -+#endif + +#define BSS_EX_IES(bss_ex) ((bss_ex)->IEs) +#define BSS_EX_IES_LEN(bss_ex) ((bss_ex)->IELength) @@ -412104,10 +410504,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wlan_bssdef.h linux-5.11.4-rt + int aid; /* will only be valid when a BSS is joinned. */ + int join_res; + WLAN_BSSID_EX network; /* must be the last item */ -+#ifdef PLATFORM_WINDOWS -+ unsigned char iebuf[MAX_IE_SZ]; -+#endif -+ +}; + +enum VRTL_CARRIER_SENSE { @@ -412122,16 +410518,12 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wlan_bssdef.h linux-5.11.4-rt + CTS_TO_SELF +}; + -+ -+ -+ +#define PWR_CAM 0 +#define PWR_MINPS 1 +#define PWR_MAXPS 2 +#define PWR_UAPSD 3 +#define PWR_VOIP 4 + -+ +enum UAPSD_MAX_SP { + NO_LIMIT, + TWO_MSDU, @@ -412139,7 +410531,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wlan_bssdef.h linux-5.11.4-rt + SIX_MSDU +}; + -+ +/* john */ +#define NUM_PRE_AUTH_KEY 16 +#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY @@ -412148,41 +410539,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/wlan_bssdef.h linux-5.11.4-rt +* WPA2 +*/ + -+#ifndef PLATFORM_OS_CE -+typedef struct _PMKID_CANDIDATE { -+ NDIS_802_11_MAC_ADDRESS BSSID; -+ ULONG Flags; -+} PMKID_CANDIDATE, *PPMKID_CANDIDATE; -+ -+typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST { -+ ULONG Version; /* Version of the structure */ -+ ULONG NumCandidates; /* No. of pmkid candidates */ -+ PMKID_CANDIDATE CandidateList[1]; -+} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST; -+ -+ -+typedef struct _NDIS_802_11_AUTHENTICATION_ENCRYPTION { -+ NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported; -+ NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported; -+ -+} NDIS_802_11_AUTHENTICATION_ENCRYPTION, *PNDIS_802_11_AUTHENTICATION_ENCRYPTION; -+ -+typedef struct _NDIS_802_11_CAPABILITY { -+ ULONG Length; -+ ULONG Version; -+ ULONG NoOfPMKIDs; -+ ULONG NoOfAuthEncryptPairsSupported; -+ NDIS_802_11_AUTHENTICATION_ENCRYPTION AuthenticationEncryptionSupported[1]; -+ -+} NDIS_802_11_CAPABILITY, *PNDIS_802_11_CAPABILITY; -+#endif -+ -+ +#endif /* #ifndef WLAN_BSSDEF_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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/include/xmit_osdep.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/xmit_osdep.h +--- linux-6.3.4/drivers/staging/rtl8812au/include/xmit_osdep.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/include/xmit_osdep.h 2023-05-26 22:35:36.546136899 +0300 +@@ -0,0 +1,68 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -412210,32 +410571,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/xmit_osdep.h linux-5.11.4-rtl + SIZE_T buf_len; +}; + -+#ifdef PLATFORM_WINDOWS -+ -+#ifdef PLATFORM_OS_XP -+#ifdef CONFIG_USB_HCI -+#include -+#include -+#include -+#endif -+#endif -+ -+#ifdef CONFIG_GSPI_HCI -+ #define NR_XMITFRAME 64 -+#else -+ #define NR_XMITFRAME 128 -+#endif -+ -+#define ETH_ALEN 6 -+ -+extern NDIS_STATUS rtw_xmit_entry( -+ IN _nic_hdl cnxt, -+ IN NDIS_PACKET *pkt, -+ IN UINT flags -+); -+ -+#endif /* PLATFORM_WINDOWS */ -+ +#ifdef PLATFORM_FREEBSD +#define NR_XMITFRAME 256 +extern int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); @@ -412252,8 +410587,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/xmit_osdep.h linux-5.11.4-rtl +struct xmit_frame; +struct xmit_buf; + -+extern int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); -+extern int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev); ++extern netdev_tx_t _rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev); ++extern netdev_tx_t rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev); + +#endif /* PLATFORM_LINUX */ + @@ -412277,9 +410612,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/include/xmit_osdep.h linux-5.11.4-rtl +void dump_os_queue(void *sel, _adapter *padapter); + +#endif /* __XMIT_OSDEP_H_ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/Kconfig linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/Kconfig +--- linux-6.3.4/drivers/staging/rtl8812au/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/Kconfig 2022-01-28 22:59:35.486648197 +0200 @@ -0,0 +1,6 @@ +config 88XXAU + tristate "Realtek 88XXau USB WiFi" @@ -412287,10 +410622,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Kconfig linux-5.11.4-rtl8812au/3rdpar + 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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/Makefile linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/Makefile +--- linux-6.3.4/drivers/staging/rtl8812au/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/Makefile 2023-05-26 22:35:36.539136900 +0300 +@@ -0,0 +1,1819 @@ +EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) -fno-pie +EXTRA_CFLAGS += -O3 +EXTRA_CFLAGS += -Wno-unused-variable @@ -412298,25 +410633,24 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +EXTRA_CFLAGS += -Wno-unused-label +#EXTRA_CFLAGS += -Wno-unused-parameter +EXTRA_CFLAGS += -Wno-unused-function -+EXTRA_CFLAGS += -Wimplicit-fallthrough=0 ++EXTRA_CFLAGS += -Wno-implicit-fallthrough ++EXTRA_CFLAGS += -Wno-cast-function-type ++#EXTRA_CFLAGS += -Wno-error=cast-function-type +#EXTRA_CFLAGS += -Wno-parentheses-equality +#EXTRA_CFLAGS += -Wno-pointer-bool-conversion +EXTRA_CFLAGS += -Wno-unknown-pragmas +#EXTRA_CFLAGS += -Wno-unused ++EXTRA_CFLAGS += -Wno-address +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_CFLAGS += -I$(src)/include -I$(srctree)/$(src)/include ++EXTRA_CFLAGS += -I$(src)/hal/phydm -I$(srctree)/$(src)/hal/phydm +EXTRA_LDFLAGS += --strip-all -O3 + +########################## WIFI IC ############################ +CONFIG_RTL8812A = y +CONFIG_RTL8821A = y -+CONFIG_RTL8814A = n ++CONFIG_RTL8814A = y +######################### Interface ########################### +CONFIG_USB_HCI = y +########################### Android ########################### @@ -412359,6 +410693,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +CONFIG_RTW_WIFI_HAL = n +CONFIG_ICMP_VOQ = n +CONFIG_IP_R_MONITOR = n #arp VOQ and high rate ++# disable virtual intf for openwrt 21.02 ++CONFIG_RTW_VIRTUAL_INTF = n +########################## Debug ########################### +CONFIG_RTW_DEBUG = n +# default log level is _DRV_INFO_ = 4, @@ -412458,6 +410794,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa + +CONFIG_DRVEXT_MODULE = n + ++ifeq ("","$(wildcard MOK.der)") ++NO_SKIP_SIGN := y ++endif ++ +ifeq ($(CONFIG_RTL8812AU), ) +ifneq (,$(findstring /usr/lib/dkms,$(PATH))) + export TopDIR ?= $(shell pwd) @@ -412471,7 +410811,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +HCI_NAME = usb +endif + -+ifeq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A)_$(CONFIG_RTL8814A), y_y_n) ++ifeq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A)_$(CONFIG_RTL8814A), y_y_y) + +EXTRA_CFLAGS += -DDRV_NAME=\"rtl88XXau\" +ifeq ($(CONFIG_USB_HCI), y) @@ -412514,85 +410854,19 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa + hal/led/hal_$(HCI_NAME)_led.o + + -+EXTRA_CFLAGS += -I$(src)/platform ++EXTRA_CFLAGS += -I$(src)/platform -I$(srctree)/$(src)/platform +_PLATFORM_FILES := platform/platform_ops.o + -+EXTRA_CFLAGS += -I$(src)/hal/btc ++EXTRA_CFLAGS += -I$(src)/hal/btc -I$(srctree)/$(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 \ @@ -412658,19 +410932,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +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) @@ -412683,66 +410949,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa + 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) @@ -412750,7 +410958,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +#EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE +CONFIG_MP_VHT_HW_TX_MODE = n +########################################## -+#RTL871X = rtl8814a ++RTL871X = rtl8814a +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8814au +endif @@ -412770,7 +410978,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa + 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 \ @@ -412793,371 +411000,16 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +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) @@ -413191,7 +411043,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +EXTRA_CFLAGS += -DCONFIG_WAPI_SUPPORT +endif + -+ +ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y) +EXTRA_CFLAGS += -DCONFIG_EFUSE_CONFIG_FILE + @@ -413424,13 +411275,17 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa + +EXTRA_CFLAGS += -DDM_ODM_SUPPORT_TYPE=0x04 + ++ifeq ($(CONFIG_RTW_VIRTUAL_INTF), y) ++EXTRA_CFLAGS += -DRTW_VIRTUAL_INTF=1 ++endif ++ +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/;") ++SUBARCH := $(shell uname -m | sed -e "s/i.86/i386/; s/ppc/powerpc/; s/armv.l/arm/; s/aarch64/arm64/; s/riscv.*/riscv/;") +ARCH ?= $(SUBARCH) +CROSS_COMPILE ?= -+KVER := $(shell uname -r) ++KVER ?= $(shell if [ -n "${NEW_VERSION}" ] && [ -n "${FLAVOR}" ]; then echo "${NEW_VERSION}-${FLAVOR}"; else uname -r; fi) +KSRC := /lib/modules/$(KVER)/build +MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ +INSTALL_PREFIX := @@ -413483,6 +411338,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa + +ifeq ($(CONFIG_PLATFORM_PPC), y) +EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN ++EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +SUBARCH := $(shell uname -m | sed -e s/ppc/powerpc/) +ARCH ?= $(SUBARCH) +CROSS_COMPILE ?= @@ -413636,7 +411492,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa + +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 @@ -414162,14 +412017,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +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 @@ -414180,9 +412027,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +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 @@ -414196,9 +412040,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +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 @@ -414377,14 +412218,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +# 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) @@ -414407,14 +412240,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +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) @@ -414460,16 +412285,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +########### 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 \ @@ -414591,12 +412406,12 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa +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) ++ @mkdir -vp /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 build -m 8812au -v $(DRIVER_VERSION) + dkms install -m 8812au -v $(DRIVER_VERSION) -+ dkms status ++ dkms status -m 8812au + +dkms_remove: + dkms remove 8812au/$(DRIVER_VERSION) --all @@ -414617,11 +412432,22 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/Makefile linux-5.11.4-rtl8812au/3rdpa + 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 ++ rm -fr .tmp_versions *.der *.priv +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 ++ ++sign: ++ifeq ($(NO_SKIP_SIGN), y) ++ @openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj "/CN=Custom MOK/" ++ @mokutil --import MOK.der ++else ++ echo "Skipping key creation" ++endif ++ @$(KSRC)/scripts/sign-file sha256 MOK.priv MOK.der 88XXau.ko ++ ++sign-install: all sign install +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/custom_gpio_linux.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/custom_gpio_linux.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/custom_gpio_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/custom_gpio_linux.c 2022-01-28 22:59:35.628654929 +0200 @@ -0,0 +1,340 @@ +/****************************************************************************** + * @@ -414963,10 +412789,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/custom_gpio_linux.c linu +{ +} +#endif /* CONFIG_PLATFORM_SPRD */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.c 2023-05-26 22:35:36.547136899 +0300 +@@ -0,0 +1,10566 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -415429,7 +413255,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) + if (started) { -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) ++ cfg80211_ch_switch_started_notify(adapter->pnetdev, &chdef, 0, 0, false, 0); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ cfg80211_ch_switch_started_notify(adapter->pnetdev, &chdef, 0, 0, false); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)) + cfg80211_ch_switch_started_notify(adapter->pnetdev, &chdef, 0, false); +#else + cfg80211_ch_switch_started_notify(adapter->pnetdev, &chdef, 0); @@ -415441,7 +413271,13 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + if (!rtw_cfg80211_allow_ch_switch_notify(adapter)) + goto exit; + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) ++ cfg80211_ch_switch_notify(adapter->pnetdev, &chdef, 0, 0); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5,19, 2)) ++ cfg80211_ch_switch_notify(adapter->pnetdev, &chdef, 0); ++#else + cfg80211_ch_switch_notify(adapter->pnetdev, &chdef); ++#endif + +#else + int freq = rtw_ch2freq(ch); @@ -416114,7 +413950,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + #endif + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) ++ #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0) ++ roam_info.channel = notify_channel; + roam_info.bssid = cur_network->network.MacAddress; ++ #endif + roam_info.req_ie = pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + 2; + roam_info.req_ie_len = pmlmepriv->assoc_req_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 2; + roam_info.resp_ie = pmlmepriv->assoc_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6; @@ -416145,13 +413984,17 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + RTW_INFO("pwdev->sme_state(b)=%d\n", pwdev->sme_state); + #endif + -+ if (check_fwstate(pmlmepriv, WIFI_MONITOR_STATE) != _TRUE) -+ rtw_cfg80211_connect_result(pwdev, cur_network->network.MacAddress -+ , pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + 2 -+ , pmlmepriv->assoc_req_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 2 -+ , pmlmepriv->assoc_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6 -+ , pmlmepriv->assoc_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6 -+ , WLAN_STATUS_SUCCESS, GFP_ATOMIC); ++ if (check_fwstate(pmlmepriv, WIFI_MONITOR_STATE) != _TRUE) { ++ struct cfg80211_bss *bss; ++ bss = cfg80211_get_bss(pwdev->wiphy, NULL, cur_network->network.MacAddress, NULL, 0, ++ IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); ++ cfg80211_connect_bss(wdev_to_ndev(pwdev), cur_network->network.MacAddress, bss ++ , pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + 2 ++ , pmlmepriv->assoc_req_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 2 ++ , pmlmepriv->assoc_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6 ++ , pmlmepriv->assoc_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6 ++ , WLAN_STATUS_SUCCESS, GFP_ATOMIC, NL80211_TIMEOUT_UNSPECIFIED); ++ } + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) || defined(COMPAT_KERNEL_RELEASE) + RTW_INFO("pwdev->sme_state(a)=%d\n", pwdev->sme_state); + #endif @@ -416680,6 +414523,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 +} + +static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ , int link_id ++#endif + , u8 key_index +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + , bool pairwise @@ -416824,6 +414670,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 +} + +static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ , int link_id ++#endif + , u8 keyid +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + , bool pairwise @@ -416989,6 +414838,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 +} + +static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ int link_id, ++#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + u8 key_index, bool pairwise, const u8 *mac_addr) +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) */ @@ -417009,7 +414861,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 +} + +static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, -+ struct net_device *ndev, u8 key_index ++ struct net_device *ndev, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ int link_id, ++#endif ++ u8 key_index + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE) + , bool unicast, bool multicast + #endif @@ -417057,7 +414913,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) +int cfg80211_rtw_set_default_mgmt_key(struct wiphy *wiphy, -+ struct net_device *ndev, u8 key_index) ++ struct net_device *ndev, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ int link_id, ++#endif ++ u8 key_index) +{ +#define SET_DEF_KEY_PARAM_FMT " key_index=%d" +#define SET_DEF_KEY_PARAM_ARG , key_index @@ -417302,6 +415162,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + + sinfo->filled |= STATION_INFO_BSS_PARAM; + ++#if defined (LINUX_VERSION_CODE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 20, 0)) + if (!psta->no_short_preamble_set) + sinfo->bss_param.flags |= STATION_INFO_BSS_PARAM_SHORT_PREAMBLE; + @@ -417317,6 +415178,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + sinfo->bss_param.dtim_period = pwrctl->dtim; + + sinfo->bss_param.beacon_interval = get_beacon_interval(&cur_network->network); ++#endif + + } + @@ -417741,6 +415603,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + RTW_INFO("%s, ielen=%d\n", __func__, len); +#endif + ++ if (!pmlmepriv) ++ return -EINVAL; + if (len > 0) { + wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen); + if (wps_ie) { @@ -419803,6 +417667,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + return ret; +} + ++#ifdef RTW_VIRTUAL_INT +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) +static struct wireless_dev * +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE) @@ -419958,6 +417823,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + rtw_set_rtnl_lock_holder(dvobj, NULL); + return ret; +} ++#endif /* RTW_VIRTUAL_INT */ + +static int rtw_add_beacon(_adapter *adapter, const u8 *head, size_t head_len, const u8 *tail, size_t tail_len) +{ @@ -420186,7 +418052,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + return ret; +} + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) ++static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev, unsigned int link_id) ++#else +static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) ++#endif +{ + _adapter *adapter = (_adapter *)rtw_netdev_priv(ndev); + @@ -421030,7 +418900,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); +#endif -+ + switch (channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: @@ -421059,7 +418928,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + return 0; +} + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) ++static int cfg80211_rtw_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, unsigned int link_id, struct cfg80211_chan_def *chandef){ ++#else +static int cfg80211_rtw_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_chan_def *chandef){ ++#endif + _adapter *padapter= wiphy_to_adapter(wiphy); + int channel; + int control_freq; @@ -421076,37 +418949,18 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + + if (!ndev) + return -ENODEV; -+ offset = rtw_get_oper_choffset(padapter); -+ //channel = adapter_to_dvobj(padapter)->oper_channel; -+ channel = pHalData->current_channel; ++ offset = rtw_get_oper_choffset(padapter); ++ bandWidth = rtw_get_oper_bw(padapter); ++ channel = rtw_get_oper_ch(padapter); + 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){ ++ switch(bandWidth){ + case CHANNEL_WIDTH_5: + width = NL80211_CHAN_WIDTH_5; + center_freq = control_freq; @@ -421414,7 +419268,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + +indicate: + #if defined(RTW_DEDICATED_P2P_DEVICE) -+ if (rtw_cfg80211_redirect_pd_wdev(dvobj_to_wiphy(dvobj), get_ra(frame), &wdev)) ++ if (rtw_cfg80211_redirect_pd_wdev(dvobj_to_wiphy(dvobj), wifi_get_ra(frame), &wdev)) + if (0) + RTW_INFO("redirect to pd_wdev:%p\n", wdev); + #endif @@ -422702,7 +420556,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + return ret; +} + -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)) || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)) +static void cfg80211_rtw_update_mgmt_frame_register(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct mgmt_frame_regs *upd) @@ -425087,8 +422941,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + .flush_pmksa = cfg80211_rtw_flush_pmksa, + +#ifdef CONFIG_AP_MODE ++#ifdef RTW_VIRTUAL_INT + .add_virtual_intf = cfg80211_rtw_add_virtual_intf, + .del_virtual_intf = cfg80211_rtw_del_virtual_intf, ++#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE) + .add_beacon = cfg80211_rtw_add_beacon, @@ -425154,7 +423010,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE) + .mgmt_tx = cfg80211_rtw_mgmt_tx, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,8,0)) || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)) + .update_mgmt_frame_registrations = cfg80211_rtw_update_mgmt_frame_register, +#else + .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register, @@ -425311,7 +423167,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + pwdev_priv->rssi_monitor_min = 0; +#endif + -+ +exit: + return ret; +} @@ -425362,7 +423217,13 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 + rtw_cfg80211_indicate_scan_done(adapter, _TRUE); + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) || defined(COMPAT_KERNEL_RELEASE) ++ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) ++ if (wdev->links[0].client.current_bss) { ++ #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) ++ if (wdev->connected) { ++ #else + if (wdev->current_bss) { ++ #endif + RTW_INFO(FUNC_ADPT_FMT" clear current_bss by cfg80211_disconnected\n", FUNC_ADPT_ARG(adapter)); + rtw_cfg80211_indicate_disconnect(adapter, 0, 1); + } @@ -425498,9 +423359,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.c linux-5 +} + +#endif /* CONFIG_IOCTL_CFG80211 */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_cfg80211.h 2022-01-28 22:59:35.629654976 +0200 @@ -0,0 +1,427 @@ +/****************************************************************************** + * @@ -425929,10 +423790,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_cfg80211.h linux-5 + + +#endif /* __IOCTL_CFG80211_H__ */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_linux.c 2022-12-18 17:40:24.577937030 +0200 +@@ -0,0 +1,12823 @@ + +/****************************************************************************** + * @@ -425967,7 +423828,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 +extern int rtw_ht_enable; +#endif + -+ +#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV+30) + +#define SCAN_ITEM_SIZE 768 @@ -426055,18 +423915,14 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 +#ifndef CONFIG_IOCTL_CFG80211 + wireless_send_event(padapter->pnetdev, IWEVCUSTOM, &wrqu, buff); +#endif -+ + rtw_mfree(buff, IW_CUSTOM_MAX + 1); -+ +} + -+ +static void request_wps_pbc_event(_adapter *padapter) +{ + u8 *buff, *p; + union iwreq_data wrqu; + -+ + buff = rtw_malloc(IW_CUSTOM_MAX); + if (!buff) + return; @@ -426104,7 +423960,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_NET_PBC); +#endif +#else -+ + if (padapter->pid[0] == 0) { + /* 0 is the default value and it means the application monitors the HW PBC doesn't privde its pid to driver. */ + return; @@ -426113,7 +423968,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + rtw_signal_process(padapter->pid[0], SIGUSR1); + +#endif -+ + rtw_led_control(padapter, LED_CTL_START_WPS_BOTTON); +} +#endif/* #ifdef CONFIG_SUPPORT_HW_WPS_PBC */ @@ -426130,7 +423984,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 +#endif +} + -+ +void rtw_indicate_wx_assoc_event(_adapter *padapter) +{ + union iwreq_data wrqu; @@ -426508,7 +424361,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + u8 *p; + sint out_len = 0; + -+ + if (pbuf) { + p = pbuf; + @@ -426616,7 +424468,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + RTW_INFO("rtw_wx_get_scan: %s ", pnetwork->network.Ssid.Ssid); + RTW_INFO("rtw_wx_get_scan: ssid = %d ", wapi_len); + -+ + if (wapi_len > 0) { + p = buf_wapi; + /* _rtw_memset(buf_wapi, 0, MAX_WAPI_IE_LEN*2); */ @@ -426809,8 +424660,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif /* CONFIG_P2P */ -+ -+ + param->u.crypt.err = 0; + param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; + @@ -426972,8 +424821,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 +#endif + +exit: -+ -+ + return ret; +} + @@ -427128,7 +424975,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + * || check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == _TRUE) */ + rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr); + -+ +exit: + + if (buf) @@ -427151,8 +424997,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network; + NDIS_802_11_RATES_EX *prates = NULL; + -+ -+ + if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) == _TRUE) { + /* parsing HT_CAP_IE */ + if( is_supported_ht(padapter->registrypriv.wireless_mode)&&(padapter->registrypriv.ht_enable)) { @@ -427206,8 +425050,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + /* snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); */ + snprintf(wrqu->name, IFNAMSIZ, "unassociated"); + } -+ -+ + return 0; +} + @@ -427371,8 +425213,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + rtw_indicate_connect(padapter); + +exit: -+ -+ + return ret; + +} @@ -427383,8 +425223,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + -+ -+ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) + wrqu->mode = IW_MODE_INFRA; + else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || @@ -427398,12 +425236,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + else + wrqu->mode = IW_MODE_AUTO; + -+ + return 0; + +} + -+ +static int rtw_wx_set_pmkid(struct net_device *dev, + struct iw_request_info *a, + union iwreq_data *wrqu, char *extra) @@ -427522,8 +425358,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + u16 val; + int i; + -+ -+ + wrqu->data.length = sizeof(*range); + _rtw_memset(range, 0, sizeof(*range)); + @@ -427659,9 +425493,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE | IW_SCAN_CAPA_BSSID | + IW_SCAN_CAPA_CHANNEL | IW_SCAN_CAPA_MODE | IW_SCAN_CAPA_RATE; +#endif -+ -+ -+ + return 0; + +} @@ -427796,8 +425627,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + + _rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); + -+ -+ + if (((check_fwstate(pmlmepriv, _FW_LINKED)) == _TRUE) || + ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == _TRUE) || + ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == _TRUE)) @@ -427806,7 +425635,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + else + _rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); + -+ + return 0; + +} @@ -427829,7 +425657,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct iw_mlme *mlme = (struct iw_mlme *) extra; + -+ + if (mlme == NULL) + return -1; + @@ -427837,10 +425664,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + + reason = cpu_to_le16(mlme->reason_code); + -+ + RTW_INFO("%s, cmd=%d, reason=%d\n", __FUNCTION__, mlme->cmd, reason); + -+ + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + if (!rtw_set_802_11_disassociate(padapter)) @@ -428047,7 +425872,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + len -= sec_len; + break; + -+ + case WEXT_CSCAN_CHANNEL_SECTION: + /* RTW_INFO("WEXT_CSCAN_CHANNEL_SECTION\n"); */ + pos += 1; @@ -428220,13 +426044,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + +exit: + -+ +#ifdef DBG_IOCTL + RTW_INFO("DBG_IOCTL %s:%d return %d\n", __FUNCTION__, __LINE__, ret); +#endif -+ + return ret ; -+ +} + +/* set ssid flow @@ -428250,7 +426071,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + + uint ret = 0, len; + -+ +#ifdef DBG_IOCTL + RTW_INFO("DBG_IOCTL %s:%d\n", __FUNCTION__, __LINE__); +#endif @@ -428268,8 +426088,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + goto exit; + } + -+ -+ + rtw_ps_deny(padapter, PS_DENY_JOIN); + if (_FAIL == rtw_pwr_wakeup(padapter)) { + ret = -1; @@ -428344,7 +426162,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + + dst_ssid = pnetwork->network.Ssid.Ssid; + -+ + if ((_rtw_memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength) == _TRUE) && + (pnetwork->network.Ssid.SsidLength == ndis_ssid.SsidLength)) { + @@ -428380,8 +426197,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 +#ifdef DBG_IOCTL + RTW_INFO("DBG_IOCTL %s:%d return %d\n", __FUNCTION__, __LINE__, ret); +#endif -+ -+ + return ret; +} + @@ -428489,7 +426304,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + ret = -1; + } + -+ + return ret; +} + @@ -428529,7 +426343,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + + RTW_INFO("%s, rts_thresh=%d\n", __func__, padapter->registrypriv.rts_thresh); + -+ + return 0; + +} @@ -428588,7 +426401,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + wrqu->frag.fixed = 0; /* no auto select */ + /* wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); */ + -+ + return 0; +} + @@ -428598,7 +426410,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 +{ + /* _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); */ + -+ + wrqu->retry.value = 7; + wrqu->retry.fixed = 0; /* no auto select */ + wrqu->retry.disabled = 1; @@ -428648,7 +426459,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + + key = erq->flags & IW_ENCODE_INDEX; + -+ + if (erq->flags & IW_ENCODE_DISABLED) { + RTW_INFO("EncryptionDisabled\n"); + padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; @@ -428754,8 +426564,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + } + +exit: -+ -+ + return ret; + +} @@ -428840,7 +426648,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + + } + -+ + return ret; + +} @@ -429277,7 +427084,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + u32 data32; + u32 bytes; + -+ + bytes = 0; + addr = 0; + data32 = 0; @@ -429667,7 +427473,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + break; + } + -+ + /* pdata->length = 0; */ /* ? */ + pdata->flags = 0; + if (pdata->length >= 32) { @@ -429731,7 +427536,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + } + +exit: -+ + return ret; + +} @@ -435717,7 +433521,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + rtw_hal_read_chip_info(padapter); + /* set mac addr*/ + rtw_macaddr_cfg(adapter_mac_addr(padapter), get_hal_mac_addr(padapter)); -+ _rtw_memcpy(padapter->pnetdev->dev_addr, get_hal_mac_addr(padapter), ETH_ALEN); /* set mac addr to net_device */ ++ dev_addr_set(padapter->pnetdev, get_hal_mac_addr(padapter)); /* set mac addr to net_device */ + +#ifdef CONFIG_P2P + rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter)); @@ -437739,7 +435543,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + + ploopback->bstop = _TRUE; + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + thread_exit(NULL); ++#else ++ kthread_thread_exit(NULL); ++#endif + return 0; +} + @@ -438809,9 +436617,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_linux.c linux-5.11 + return ret; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/ioctl_mp.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_mp.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/ioctl_mp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/ioctl_mp.c 2022-01-28 22:59:35.631655071 +0200 @@ -0,0 +1,2591 @@ +/****************************************************************************** + * @@ -441404,9 +439212,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/ioctl_mp.c linux-5.11.4- +#endif /*#ifdef CONFIG_RTL8723B*/ + +#endif -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/mlme_linux.c 2022-12-18 17:40:24.577937030 +0200 @@ -0,0 +1,436 @@ +/****************************************************************************** + * @@ -441814,7 +439622,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c linux-5.11. + mac[4] = 0x11; + mac[5] = 0x12; + -+ _rtw_memcpy(pnetdev->dev_addr, mac, ETH_ALEN); ++ dev_addr_set(pnetdev, mac); + + + rtw_netif_carrier_off(pnetdev); @@ -441844,10 +439652,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/mlme_linux.c linux-5.11. + +#endif +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/os_intfs.c 2023-05-26 22:35:36.548136899 +0300 +@@ -0,0 +1,5188 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -442584,9 +440392,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- +int _netdev_open(struct net_device *pnetdev); +int netdev_open(struct net_device *pnetdev); +static int netdev_close(struct net_device *pnetdev); -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+extern int rtw_sdio_set_power(int on); -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ + +#ifdef CONFIG_MCC_MODE +/* enable MCC mode or not */ @@ -443138,7 +440943,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- + } + + _rtw_memcpy(adapter_mac_addr(padapter), sa->sa_data, ETH_ALEN); /* set mac addr to adapter */ -+ _rtw_memcpy(pnetdev->dev_addr, sa->sa_data, ETH_ALEN); /* set mac addr to net_device */ ++ dev_addr_set(pnetdev, sa->sa_data); /* set mac addr to net_device */ + +#if 0 + if (rtw_is_hw_init_completed(padapter)) { @@ -443587,7 +441392,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- + u8 rtnl_lock_needed = rtw_rtnl_lock_needed(dvobj); + +#ifdef CONFIG_RTW_NAPI ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ netif_napi_add_weight(ndev, &adapter->napi, rtw_recv_napi_poll, RTL_NAPI_WEIGHT); ++#else + netif_napi_add(ndev, &adapter->napi, rtw_recv_napi_poll, RTL_NAPI_WEIGHT); ++#endif +#endif /* CONFIG_RTW_NAPI */ + +#if defined(CONFIG_IOCTL_CFG80211) @@ -443603,7 +441412,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- + /* alloc netdev name */ + rtw_init_netdev_name(ndev, name); + -+ _rtw_memcpy(ndev->dev_addr, adapter_mac_addr(adapter), ETH_ALEN); ++ dev_addr_set(ndev, adapter_mac_addr(adapter)); +#if defined(CONFIG_NET_NS) + dev_net_set(ndev, wiphy_net(adapter_to_wiphy(adapter))); +#endif //defined(CONFIG_NET_NS) @@ -444550,32 +442359,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- + if (!primary_padapter) + goto _netdev_virtual_iface_open_error; + -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+ if (padapter->bup == _FALSE) { -+ u8 mac[ETH_ALEN]; -+ -+ /* get mac address from primary_padapter */ -+ if (primary_padapter->bup == _FALSE) -+ rtw_macaddr_cfg(adapter_mac_addr(primary_padapter), get_hal_mac_addr(primary_padapter)); -+ -+ _rtw_memcpy(mac, adapter_mac_addr(primary_padapter), ETH_ALEN); -+ -+ /* -+ * If the BIT1 is 0, the address is universally administered. -+ * If it is 1, the address is locally administered -+ */ -+ mac[0] |= BIT(1); -+ -+ _rtw_memcpy(adapter_mac_addr(padapter), mac, ETH_ALEN); -+ -+#ifdef CONFIG_MI_WITH_MBSSID_CAM -+ rtw_mbid_camid_alloc(padapter, adapter_mac_addr(padapter)); -+#endif -+ rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter)); -+ _rtw_memcpy(pnetdev->dev_addr, adapter_mac_addr(padapter), ETH_ALEN); -+ } -+#endif /*CONFIG_PLATFORM_INTEL_BYT*/ -+ + if (primary_padapter->bup == _FALSE || !rtw_is_hw_init_completed(primary_padapter)) + _netdev_open(primary_padapter->pnetdev); + @@ -445303,10 +443086,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- + + padapter->netif_up = _TRUE; + -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+ rtw_sdio_set_power(1); -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ -+ + #ifdef CONFIG_AUTOSUSPEND + if (pwrctrlpriv->ps_flag == _TRUE) { + padapter->net_closed = _FALSE; @@ -445315,15 +443094,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- + #endif + + if (padapter->bup == _FALSE) { -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+ rtw_macaddr_cfg(adapter_mac_addr(padapter), get_hal_mac_addr(padapter)); -+#ifdef CONFIG_MI_WITH_MBSSID_CAM -+ rtw_mbid_camid_alloc(padapter, adapter_mac_addr(padapter)); -+#endif -+ rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter)); -+ _rtw_memcpy(pnetdev->dev_addr, adapter_mac_addr(padapter), ETH_ALEN); -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ -+ + rtw_clr_surprise_removed(padapter); + rtw_clr_drv_stopped(padapter); + @@ -445366,11 +443136,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- + padapter->bup = _TRUE; + pwrctrlpriv->bips_processing = _FALSE; + -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+#ifdef CONFIG_BT_COEXIST -+ rtw_btcoex_IpsNotify(padapter, IPS_NONE); -+#endif /* CONFIG_BT_COEXIST */ -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ + } + padapter->net_closed = _FALSE; + @@ -445709,7 +443474,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ + + RTW_INFO(FUNC_NDEV_FMT" , bup=%d\n", FUNC_NDEV_ARG(pnetdev), padapter->bup); -+#ifndef CONFIG_PLATFORM_INTEL_BYT + #ifdef CONFIG_AUTOSUSPEND + if (pwrctl->bInternalAutoSuspend == _TRUE) { + /* rtw_pwr_wakeup(padapter); */ @@ -445782,26 +443546,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- + else + RTW_INFO("CONFIG_BT_COEXIST: VIRTUAL_ADAPTER\n"); +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ -+#else /* !CONFIG_PLATFORM_INTEL_BYT */ -+ -+ if (pwrctl->bInSuspend == _TRUE) { -+ RTW_INFO("+871x_drv - drv_close, bInSuspend=%d\n", pwrctl->bInSuspend); -+ return 0; -+ } -+ -+ rtw_scan_abort(padapter); /* stop scanning process before wifi is going to down */ -+#ifdef CONFIG_IOCTL_CFG80211 -+ rtw_cfg80211_wait_scan_req_empty(padapter, 200); -+#endif -+ -+ RTW_INFO("netdev_close, bips_processing=%d\n", pwrctl->bips_processing); -+ while (pwrctl->bips_processing == _TRUE) /* waiting for ips_processing done before call rtw_dev_unload() */ -+ rtw_msleep_os(1); -+ -+ rtw_dev_unload(padapter); -+ rtw_sdio_set_power(0); -+ -+#endif /* !CONFIG_PLATFORM_INTEL_BYT */ + + RTW_INFO("-871x_drv - drv_close, bup=%d\n", padapter->bup); + @@ -447100,10 +444844,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/os_intfs.c linux-5.11.4- +EXPORT_SYMBOL(rtw_vendor_ie_set_api); + +#endif -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/recv_linux.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/recv_linux.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/recv_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/recv_linux.c 2022-12-18 17:40:24.577937030 +0200 +@@ -0,0 +1,729 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -447173,7 +444917,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. + return res; + } + -+ + /* Modified by Albert 20101213 */ + /* For 8 bytes IP header alignment. */ + shift_sz = pattrib->qos ? 6 : 0; /* Qos data, wireless lan header length is 26 */ @@ -447280,7 +445023,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. +#ifdef CONFIG_RTW_NAPI + skb_queue_head_init(&precvpriv->rx_napi_skb_queue); +#endif /* CONFIG_RTW_NAPI */ -+ + return res; +} + @@ -447288,9 +445030,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. +int rtw_os_recv_resource_alloc(_adapter *padapter, union recv_frame *precvframe) +{ + int res = _SUCCESS; -+ + precvframe->u.hdr.pkt = NULL; -+ + return res; +} + @@ -447300,14 +445040,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. + sint i; + union recv_frame *precvframe; + precvframe = (union recv_frame *) precvpriv->precv_frame_buf; -+ -+ +#ifdef CONFIG_RTW_NAPI + if (skb_queue_len(&precvpriv->rx_napi_skb_queue)) + RTW_WARN("rx_napi_skb_queue not empty\n"); + rtw_skb_queue_purge(&precvpriv->rx_napi_skb_queue); +#endif /* CONFIG_RTW_NAPI */ -+ + for (i = 0; i < NR_RECVFRAME; i++) { + rtw_os_free_recvframe(precvframe); + precvframe++; @@ -447346,9 +445083,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. + if (precvbuf->pallocated_buf == NULL) + return _FAIL; +#endif /* CONFIG_USE_USB_BUFFER_ALLOC_RX */ -+ +#endif /* CONFIG_USB_HCI */ -+ + return res; +} + @@ -447358,7 +445093,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. + int ret = _SUCCESS; + +#ifdef CONFIG_USB_HCI -+ +#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX + + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); @@ -447385,7 +445119,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. + rtw_skb_free(precvbuf->pskb); + } + return ret; -+ +} + +_pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, const u8 *da, const u8 *sa, u8 *msdu ,u16 msdu_len) @@ -447461,8 +445194,13 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. + +#ifdef CONFIG_RTW_GRO + if (pregistrypriv->en_gro) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) + if (rtw_napi_gro_receive(&padapter->napi, pskb) != GRO_DROP) + rx_ok = _TRUE; ++#else ++ rtw_napi_gro_receive(&padapter->napi, pskb); ++ rx_ok = _TRUE; ++#endif + goto next; + } +#endif /* CONFIG_RTW_GRO */ @@ -447510,7 +445248,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. + if (adapter->registrypriv.en_napi) { + struct dvobj_priv *dvobj; + struct registry_priv *registry; -+ + dvobj = adapter_to_dvobj(adapter); + registry = &adapter->registrypriv; + if (dvobj->traffic_stat.cur_rx_tp > registry->napi_threshold) @@ -447626,8 +445363,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. +#ifdef CONFIG_RTW_NAPI +#ifdef CONFIG_RTW_NAPI_DYNAMIC + if (!skb_queue_empty(&precvpriv->rx_napi_skb_queue) -+ && !adapter_to_dvobj(padapter)->en_napi_dynamic -+ ) ++ && !adapter_to_dvobj(padapter)->en_napi_dynamic) + napi_recv(padapter, RTL_NAPI_WEIGHT); +#endif + @@ -447835,17 +445571,15 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/recv_linux.c linux-5.11. + if (precvbuf->irp_pending == _FALSE) + rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf); + -+ +#endif +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + precvbuf->pskb = NULL; +#endif + +} -+ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rhashtable.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rhashtable.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rhashtable.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rhashtable.c 2022-01-28 22:59:35.631655071 +0200 @@ -0,0 +1,844 @@ +/* + * Resizable, Scalable, Concurrent Hash Table @@ -448691,9 +446425,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rhashtable.c linux-5.11. + return rhashtable_free_and_destroy(ht, NULL, NULL); +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rhashtable.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rhashtable.h +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rhashtable.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rhashtable.h 2022-01-28 22:59:35.632655118 +0200 @@ -0,0 +1,827 @@ +/* + * Resizable, Scalable, Concurrent Hash Table @@ -449522,10 +447256,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rhashtable.h linux-5.11. + +#endif /* _LINUX_RHASHTABLE_H */ + -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_android.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_android.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_android.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_android.c 2023-05-26 22:35:36.548136899 +0300 +@@ -0,0 +1,1304 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -450192,7 +447926,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_android.c linux-5.11 + goto exit; + } + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,0)) -+ if (!access_ok(priv_cmd.buf, priv_cmd.total_len)) { ++ if (!access_ok(&priv_cmd.buf, priv_cmd.total_len)) { + #else + if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)) { + #endif @@ -450641,13 +448375,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_android.c linux-5.11 + (int)wifi_irqres->start, wifi_wake_gpio); + + if (wifi_wake_gpio > 0) { -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+ wifi_configure_gpio(); -+#else /* CONFIG_PLATFORM_INTEL_BYT */ + gpio_request(wifi_wake_gpio, "oob_irq"); + gpio_direction_input(wifi_wake_gpio); + oob_irq = gpio_to_irq(wifi_wake_gpio); -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ + RTW_INFO("%s oob_irq:%d\n", __func__, oob_irq); + } else if (wifi_irqres) { + oob_irq = wifi_irqres->start; @@ -450830,41 +448560,14 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_android.c linux-5.11 +#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */ + +#ifdef CONFIG_GPIO_WAKEUP -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+int wifi_configure_gpio(void) -+{ -+ if (gpio_request(oob_gpio, "oob_irq")) { -+ RTW_INFO("## %s Cannot request GPIO\n", __FUNCTION__); -+ return -1; -+ } -+ gpio_export(oob_gpio, 0); -+ if (gpio_direction_input(oob_gpio)) { -+ RTW_INFO("## %s Cannot set GPIO direction input\n", __FUNCTION__); -+ return -1; -+ } -+ oob_irq = gpio_to_irq(oob_gpio); -+ if (oob_irq < 0) { -+ RTW_INFO("## %s Cannot convert GPIO to IRQ\n", __FUNCTION__); -+ return -1; -+ } -+ -+ RTW_INFO("## %s OOB_IRQ=%d\n", __FUNCTION__, oob_irq); -+ -+ return 0; -+} -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ +void wifi_free_gpio(unsigned int gpio) +{ -+#ifdef CONFIG_PLATFORM_INTEL_BYT -+ if (gpio) -+ gpio_free(gpio); -+#endif /* CONFIG_PLATFORM_INTEL_BYT */ +} +#endif /* CONFIG_GPIO_WAKEUP */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.c 2022-12-18 17:40:24.578937030 +0200 +@@ -0,0 +1,4777 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -451080,7 +448783,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- +static int rtw_drv_proc_open(struct inode *inode, struct file *file) +{ + /* struct net_device *dev = proc_get_parent_data(inode); */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + ssize_t index = (ssize_t)PDE_DATA(inode); ++#else ++ ssize_t index = (ssize_t)inode->i_private; ++#endif + const struct rtw_proc_hdl *hdl = drv_proc_hdls + index; + void *private = NULL; + @@ -451102,7 +448809,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- + +static ssize_t rtw_drv_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) +{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + ssize_t index = (ssize_t)PDE_DATA(file_inode(file)); ++#else ++ ssize_t index = (ssize_t)file_inode(file)->i_private; ++#endif + const struct rtw_proc_hdl *hdl = drv_proc_hdls + index; + ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write; + @@ -455022,7 +452733,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- + +static int rtw_adapter_proc_open(struct inode *inode, struct file *file) +{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + ssize_t index = (ssize_t)PDE_DATA(inode); ++#else ++ ssize_t index = (ssize_t)inode->i_private; ++#endif + const struct rtw_proc_hdl *hdl = adapter_proc_hdls + index; + void *private = proc_get_parent_data(inode); + @@ -455044,7 +452759,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- + +static ssize_t rtw_adapter_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) +{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + ssize_t index = (ssize_t)PDE_DATA(file_inode(file)); ++#else ++ ssize_t index = (ssize_t)file_inode(file)->i_private; ++#endif + const struct rtw_proc_hdl *hdl = adapter_proc_hdls + index; + ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write; + @@ -455209,7 +452928,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- + +static int rtw_odm_proc_open(struct inode *inode, struct file *file) +{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + ssize_t index = (ssize_t)PDE_DATA(inode); ++#else ++ ssize_t index = (ssize_t)inode->i_private; ++#endif + const struct rtw_proc_hdl *hdl = odm_proc_hdls + index; + void *private = proc_get_parent_data(inode); + @@ -455231,7 +452954,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- + +static ssize_t rtw_odm_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) +{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + ssize_t index = (ssize_t)PDE_DATA(file_inode(file)); ++#else ++ ssize_t index = (ssize_t)file_inode(file)->i_private; ++#endif + const struct rtw_proc_hdl *hdl = odm_proc_hdls + index; + ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write; + @@ -455368,7 +453095,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- + +static int rtw_mcc_proc_open(struct inode *inode, struct file *file) +{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + ssize_t index = (ssize_t)PDE_DATA(inode); ++#else ++ ssize_t index = (ssize_t)inode->i_private; ++#endif + const struct rtw_proc_hdl *hdl = mcc_proc_hdls + index; + void *private = proc_get_parent_data(inode); + @@ -455390,7 +453121,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- + +static ssize_t rtw_mcc_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) +{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + ssize_t index = (ssize_t)PDE_DATA(file_inode(file)); ++#else ++ ssize_t index = (ssize_t)file_inode(file)->i_private; ++#endif + const struct rtw_proc_hdl *hdl = mcc_proc_hdls + index; + ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write; + @@ -455610,10 +453345,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.c linux-5.11.4- +} + +#endif /* CONFIG_PROC_DEBUG */ -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.h +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_proc.h 2022-12-18 17:40:24.578937030 +0200 +@@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -455633,6 +453368,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h linux-5.11.4- + +#include +#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) ++#define PDE_DATA pde_data ++#endif + +#define RTW_PROC_HDL_TYPE_SEQ 0 +#define RTW_PROC_HDL_TYPE_SSEQ 1 @@ -455674,9 +453412,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_proc.h linux-5.11.4- +#endif /* !CONFIG_PROC_DEBUG */ + +#endif /* __RTW_PROC_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.c 2022-01-28 22:59:35.632655118 +0200 @@ -0,0 +1,74 @@ +/****************************************************************************** + * @@ -455752,9 +453490,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.c linux-5 + +#endif /* CONFIG_RTW_MESH */ + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.h +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/rtw_rhashtable.h 2022-01-28 22:59:35.632655118 +0200 @@ -0,0 +1,55 @@ +/****************************************************************************** + * @@ -455811,10 +453549,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/rtw_rhashtable.h linux-5 + +#endif /* __RTW_RHASHTABLE_H__ */ + -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/usb_intf.c 2023-05-26 22:35:36.548136899 +0300 +@@ -0,0 +1,1652 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -455967,40 +453705,36 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_intf.c linux-5.11.4- + {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x881B), .driver_info = RTL8812}, /* Default ID */ + {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x881C), .driver_info = RTL8812}, /* Default ID */ + /*=== Customer ID ===*/ -+ {USB_DEVICE(0x050D, 0x1106), .driver_info = RTL8812}, /* Belkin - sercomm */ -+ {USB_DEVICE(0x7392, 0xA822), .driver_info = RTL8812}, /* Edimax - Edimax */ -+ {USB_DEVICE(0x0DF6, 0x0074), .driver_info = RTL8812}, /* Sitecom - Edimax */ -+ {USB_DEVICE(0x04BB, 0x0952), .driver_info = RTL8812}, /* I-O DATA - Edimax */ -+ {USB_DEVICE(0x0789, 0x016E), .driver_info = RTL8812}, /* Logitec - Edimax */ + {USB_DEVICE(0x0409, 0x0408), .driver_info = RTL8812}, /* NEC - */ -+ {USB_DEVICE(0x0B05, 0x17D2), .driver_info = RTL8812}, /* ASUS - Edimax */ -+ {USB_DEVICE(0x0E66, 0x0022), .driver_info = RTL8812}, /* HAWKING - Edimax */ ++ {USB_DEVICE(0x0411, 0x025D), .driver_info = RTL8812}, /* Buffalo - WI-U3-866D */ ++ {USB_DEVICE(0x04BB, 0x0952), .driver_info = RTL8812}, /* I-O DATA - Edimax */ ++ {USB_DEVICE(0x050D, 0x1106), .driver_info = RTL8812}, /* Belkin - sercomm */ ++ {USB_DEVICE(0x050D, 0x1109), .driver_info = RTL8812}, /* Belkin F9L1109 - SerComm */ + {USB_DEVICE(0x0586, 0x3426), .driver_info = RTL8812}, /* ZyXEL - */ -+ {USB_DEVICE(0x2001, 0x3313), .driver_info = RTL8812}, /* D-Link - ALPHA */ -+ {USB_DEVICE(0x1058, 0x0632), .driver_info = RTL8812}, /* WD - Cybertan */ -+ {USB_DEVICE(0x1740, 0x0100), .driver_info = RTL8812}, /* EnGenius - EnGenius */ -+ {USB_DEVICE(0x2019, 0xAB30), .driver_info = RTL8812}, /* Planex - Abocom */ ++ {USB_DEVICE(0x0789, 0x016E), .driver_info = RTL8812}, /* Logitec - Edimax */ + {USB_DEVICE(0x07B8, 0x8812), .driver_info = RTL8812}, /* Abocom - Abocom */ + {USB_DEVICE(0x0846, 0x9051), .driver_info = RTL8812}, /* Netgear A6200 v2 */ ++ {USB_DEVICE(0x0B05, 0x17D2), .driver_info = RTL8812}, /* ASUS - Edimax */ ++ {USB_DEVICE(0x0DF6, 0x0074), .driver_info = RTL8812}, /* Sitecom - Edimax */ ++ {USB_DEVICE(0x0E66, 0x0022), .driver_info = RTL8812}, /* HAWKING - Edimax */ ++ {USB_DEVICE(0x1058, 0x0632), .driver_info = RTL8812}, /* WD - Cybertan */ ++ {USB_DEVICE(0x13B1, 0x003F), .driver_info = RTL8812}, /* Linksys - WUSB6300 */ ++ {USB_DEVICE(0x148F, 0x9097), .driver_info = RTL8812}, /* Amped Wireless ACA1 */ ++ {USB_DEVICE(0x1740, 0x0100), .driver_info = RTL8812}, /* EnGenius - EnGenius */ + {USB_DEVICE(0x2001, 0x330E), .driver_info = RTL8812}, /* D-Link - ALPHA */ + {USB_DEVICE(0x2001, 0x3313), .driver_info = RTL8812}, /* D-Link - ALPHA */ + {USB_DEVICE(0x2001, 0x3315), .driver_info = RTL8812}, /* D-Link - Cameo */ + {USB_DEVICE(0x2001, 0x3316), .driver_info = RTL8812}, /* D-Link - Cameo */ -+ {USB_DEVICE(0x13B1, 0x003F), .driver_info = RTL8812}, /* Linksys - WUSB6300 */ ++ {USB_DEVICE(0x2019, 0xAB30), .driver_info = RTL8812}, /* Planex - Abocom */ ++ {USB_DEVICE(0x20F4, 0x805B), .driver_info = RTL8812}, /* TRENDnet - */ + {USB_DEVICE(0x2357, 0x0101), .driver_info = RTL8812}, /* TP-Link - Archer T4U AC1200 */ + {USB_DEVICE(0x2357, 0x0103), .driver_info = RTL8812}, /* TP-Link - T4UH */ + {USB_DEVICE(0x2357, 0x010D), .driver_info = RTL8812}, /* TP-Link - Archer T4U AC1300 */ -+ {USB_DEVICE(0x2357, 0x0115), .driver_info = RTL8812}, /* TP-Link - Archer T4U AC1300 */ + {USB_DEVICE(0x2357, 0x010E), .driver_info = RTL8812}, /* TP-Link - Archer T4UH AC1300 */ + {USB_DEVICE(0x2357, 0x010F), .driver_info = RTL8812}, /* TP-Link - T4UHP */ + {USB_DEVICE(0x2357, 0x0122), .driver_info = RTL8812}, /* TP-Link - T4UHP (other) */ -+ {USB_DEVICE(0x20F4, 0x805B), .driver_info = RTL8812}, /* TRENDnet - */ -+ {USB_DEVICE(0x0411, 0x025D), .driver_info = RTL8812}, /* Buffalo - WI-U3-866D */ -+ {USB_DEVICE(0x050D, 0x1109), .driver_info = RTL8812}, /* Belkin F9L1109 - SerComm */ -+ {USB_DEVICE(0x148F, 0x9097), .driver_info = RTL8812}, /* Amped Wireless ACA1 */ -+ {USB_DEVICE(0x0BDA, 0x8812), .driver_info = RTL8812}, /* Alfa - AWUS036AC, AWUS036ACH & AWUS036EAC */ + {USB_DEVICE(0x2604, 0x0012), .driver_info = RTL8812}, /* Tenda U12 */ -+ {USB_DEVICE(0x0BDA, 0x881A), .driver_info = RTL8812}, /* Unex DAUK-W8812 */ ++ {USB_DEVICE(0x7392, 0xA822), .driver_info = RTL8812}, /* Edimax - Edimax */ +#endif + +#ifdef CONFIG_RTL8821A @@ -456012,45 +453746,43 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_intf.c linux-5.11.4- + {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0820, 0xff, 0xff, 0xff), .driver_info = RTL8821}, /* 8821AU */ + {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0823, 0xff, 0xff, 0xff), .driver_info = RTL8821}, /* 8821AU */ + /*=== Customer ID ===*/ ++ {USB_DEVICE(0x0411, 0x0242), .driver_info = RTL8821}, /* ELECOM - WDC-433DU2H */ ++ {USB_DEVICE(0x0411, 0x029B), .driver_info = RTL8821}, /* Buffalo - WI-U2-433DHP */ ++ {USB_DEVICE(0x04BB, 0x0953), .driver_info = RTL8821}, /* I-O DATA - Edimax */ ++ {USB_DEVICE(0x056E, 0x4007), .driver_info = RTL8821}, /* Elecom - WDC-433DU2HBK */ ++ {USB_DEVICE(0x056E, 0x400E), .driver_info = RTL8821}, /* ELECOM - ELECOM */ ++ {USB_DEVICE(0x056E, 0x400F), .driver_info = RTL8821}, /* ELECOM - ELECOM */ ++ {USB_DEVICE(0x056E, 0x4010), .driver_info = RTL8821}, /* ELECOM - ELECOM */ ++ {USB_DEVICE(0x0846, 0x9052), .driver_info = RTL8821}, /* Netgear - A6100 */ ++ {USB_DEVICE(0x0E66, 0x0023), .driver_info = RTL8821}, /* HAWKING - Edimax */ ++ {USB_DEVICE(0x2001, 0x3314), .driver_info = RTL8821}, /* D-Link - Cameo */ ++ {USB_DEVICE(0x2001, 0x3318), .driver_info = RTL8821}, /* D-Link - Cameo */ ++ {USB_DEVICE(0x2019, 0xAB32), .driver_info = RTL8821}, /* Planex - GW-450S */ ++ {USB_DEVICE(0x2357, 0x011E), .driver_info = RTL8821}, /* TP Link - T2U Nano */ ++ {USB_DEVICE(0x2357, 0x011F), .driver_info = RTL8821}, /* TP-Link - Archer AC600 T2U Nano */ ++ {USB_DEVICE(0x2357, 0x0120), .driver_info = RTL8821}, /* TP Link - T2U Plus */ ++ {USB_DEVICE(0x3823, 0x6249), .driver_info = RTL8821}, /* Obihai - OBiWiFi */ + {USB_DEVICE(0x7392, 0xA811), .driver_info = RTL8821}, /* Edimax - Edimax */ + {USB_DEVICE(0x7392, 0xA812), .driver_info = RTL8821}, /* Edimax - EW-7811UTC */ + {USB_DEVICE(0x7392, 0xA813), .driver_info = RTL8821}, /* Edimax - EW-7811UAC */ + {USB_DEVICE(0x7392, 0xB611), .driver_info = RTL8821}, /* Edimax - EW-7811UCB */ -+ {USB_DEVICE(0x04BB, 0x0953), .driver_info = RTL8821}, /* I-O DATA - Edimax */ -+ {USB_DEVICE(0x2001, 0x3314), .driver_info = RTL8821}, /* D-Link - Cameo */ -+ {USB_DEVICE(0x2001, 0x3318), .driver_info = RTL8821}, /* D-Link - Cameo */ -+ {USB_DEVICE(0x0E66, 0x0023), .driver_info = RTL8821}, /* HAWKING - Edimax */ -+ {USB_DEVICE(0x056E, 0x400E), .driver_info = RTL8821}, /* ELECOM - ELECOM */ -+ {USB_DEVICE(0x056E, 0x400F), .driver_info = RTL8821}, /* ELECOM - ELECOM */ -+ {USB_DEVICE(0x0411, 0x0242), .driver_info = RTL8821}, /* ELECOM - WDC-433DU2H */ -+ {USB_DEVICE(0x2019, 0xAB32), .driver_info = RTL8821}, /* Planex - GW-450S */ -+ {USB_DEVICE(0x0846, 0x9052), .driver_info = RTL8821}, /* Netgear - A6100 */ -+ {USB_DEVICE(0x0411, 0x029B), .driver_info = RTL8821}, /* Buffalo - WI-U2-433DHP */ -+ {USB_DEVICE(0x056E, 0x4007), .driver_info = RTL8821}, /* Elecom - WDC-433DU2HBK */ -+ {USB_DEVICE(0x0BDA, 0xA811), .driver_info = RTL8821}, /* GMYLE - AC450 */ -+ {USB_DEVICE(0x3823, 0x6249), .driver_info = RTL8821}, /* Obihai - OBiWiFi */ -+ {USB_DEVICE(0x2357, 0x011E), .driver_info = RTL8821}, /* TP Link - T2U Nano */ -+ {USB_DEVICE(0x2357, 0x0122), .driver_info = RTL8821}, /* TP Link - T2U Nano */ -+ {USB_DEVICE(0x2357, 0x0120), .driver_info = RTL8821}, /* TP Link - T2U Plus */ -+ {USB_DEVICE(0x2357, 0x011F), .driver_info = RTL8821}, /* TP-Link - Archer AC600 T2U Nano */ +#endif + +#ifdef CONFIG_RTL8814A + {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8813), .driver_info = RTL8814A}, -+ {USB_DEVICE(0x2001, 0x331A), .driver_info = RTL8814A}, /* D-Link - D-Link */ + {USB_DEVICE(0x0B05, 0x1817), .driver_info = RTL8814A}, /* ASUS - ASUSTeK */ + {USB_DEVICE(0x0B05, 0x1852), .driver_info = RTL8814A}, /* ASUS - ASUSTeK */ + {USB_DEVICE(0x0B05, 0x1853), .driver_info = RTL8814A}, /* ASUS - ASUSTeK */ + {USB_DEVICE(0x056E, 0x400B), .driver_info = RTL8814A}, /* ELECOM - ELECOM */ + {USB_DEVICE(0x056E, 0x400D), .driver_info = RTL8814A}, /* ELECOM - ELECOM */ -+ {USB_DEVICE(0x7392, 0xA834), .driver_info = RTL8814A}, /* Edimax - Edimax */ -+ {USB_DEVICE(0x7392, 0xA833), .driver_info = RTL8814A}, /* Edimax - AC1750 */ -+ {USB_DEVICE(0x0BDA, 0x8813), .driver_info = RTL8814A}, /* Edimax - EDUP Adapters */ -+ {USB_DEVICE(0x0e66, 0x0026), .driver_info = RTL8814A}, /* Hawking Technologies - HW17ACU*/ -+ {USB_DEVICE(0x2357, 0x0106), .driver_info = RTL8814A}, /* TP-LINK Archer T9UH */ ++ {USB_DEVICE(0x0846, 0x9054), .driver_info = RTL8814A}, /* Netgear A7000 */ ++ {USB_DEVICE(0x0E66, 0x0026), .driver_info = RTL8814A}, /* Hawking Technologies - HW17ACU*/ ++ {USB_DEVICE(0x2001, 0x331A), .driver_info = RTL8814A}, /* D-Link - D-Link */ + {USB_DEVICE(0x20F4, 0x809A), .driver_info = RTL8814A}, /* TRENDnet - TRENDnet */ + {USB_DEVICE(0x20F4, 0x809B), .driver_info = RTL8814A}, /* TRENDnet TEW-809UB */ -+ {USB_DEVICE(0x0846, 0x9054), .driver_info = RTL8814A}, /* Netgear A7000 */ ++ {USB_DEVICE(0x2357, 0x0106), .driver_info = RTL8814A}, /* TP-LINK Archer T9UH */ ++ {USB_DEVICE(0x7392, 0xA834), .driver_info = RTL8814A}, /* Edimax - Edimax */ ++ {USB_DEVICE(0x7392, 0xA833), .driver_info = RTL8814A}, /* Edimax - AC1750 */ +#endif /* CONFIG_RTL8814A */ + + {} /* Terminating entry */ @@ -457473,9 +455205,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_intf.c linux-5.11.4- +} +EXPORT_SYMBOL(rtw_usb_get_sw_pointer); +#endif /* CONFIG_INTEL_PROXIM */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/usb_ops_linux.c 2023-05-26 22:35:36.548136899 +0300 @@ -0,0 +1,1135 @@ +/****************************************************************************** + * @@ -458203,7 +455935,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c linux-5. +int recvbuf2recvframe(PADAPTER padapter, void *ptr); + +#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX -+void usb_recv_tasklet(void *priv) ++void usb_recv_tasklet(unsigned long priv) +{ + struct recv_buf *precvbuf = NULL; + _adapter *padapter = (_adapter *)priv; @@ -458341,7 +456073,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c linux-5. +} +#else /* CONFIG_USE_USB_BUFFER_ALLOC_RX */ + -+void usb_recv_tasklet(void *priv) ++void usb_recv_tasklet(unsigned long priv) +{ + _pkt *pskb; + _adapter *padapter = (_adapter *)priv; @@ -458612,9 +456344,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/usb_ops_linux.c linux-5. + return ret; +} +#endif /* CONFIG_USB_INTERRUPT_IN_PIPE */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/wifi_regd.c 2022-01-28 22:59:35.632655118 +0200 @@ -0,0 +1,437 @@ +/****************************************************************************** + * @@ -459053,9 +456785,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/wifi_regd.c linux-5.11.4 + return 0; +} +#endif /* CONFIG_IOCTL_CFG80211 */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/linux/xmit_linux.c 2023-05-26 22:35:36.548136899 +0300 @@ -0,0 +1,567 @@ +/****************************************************************************** + * @@ -459503,7 +457235,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c linux-5.11. +#endif /* CONFIG_TX_MCAST2UNI */ + + -+int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) ++netdev_tx_t _rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev) +{ + _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; @@ -459603,11 +457335,11 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c linux-5.11. + return 0; +} + -+int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) ++netdev_tx_t rtw_xmit_entry(struct sk_buff *pkt, struct net_device *pnetdev) +{ + _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); -+ int ret = 0; ++ netdev_tx_t ret = NETDEV_TX_OK; + + if (pkt) { + if (check_fwstate(pmlmepriv, WIFI_MONITOR_STATE) == _TRUE) { @@ -459624,10 +457356,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/linux/xmit_linux.c linux-5.11. + + return ret; +} -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 @@ +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/os_dep/osdep_service.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/osdep_service.c +--- linux-6.3.4/drivers/staging/rtl8812au/os_dep/osdep_service.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/os_dep/osdep_service.c 2023-05-26 22:35:36.548136899 +0300 +@@ -0,0 +1,2928 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2017 Realtek Corporation. @@ -459656,6 +457388,10 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#endif +#endif /* DBG_MEMORY_LEAK */ + ++#if defined(MODULE_IMPORT_NS) ++MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); ++#endif ++ +#if defined(PLATFORM_LINUX) +/* +* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE @@ -459711,10 +457447,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + pbuf = malloc(sz, M_DEVBUF, M_NOWAIT); +#endif + -+#ifdef PLATFORM_WINDOWS -+ NdisAllocateMemoryWithTag(&pbuf, sz, RT_TAG); -+#endif -+ +#ifdef DBG_MEMORY_LEAK +#ifdef PLATFORM_LINUX + if (pbuf != NULL) { @@ -459738,11 +457470,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + pbuf = malloc(sz, M_DEVBUF, M_ZERO | M_NOWAIT); +#endif -+#ifdef PLATFORM_WINDOWS -+ NdisAllocateMemoryWithTag(&pbuf, sz, RT_TAG); -+ if (pbuf != NULL) -+ NdisFillMemory(pbuf, sz, 0); -+#endif + + return pbuf; +} @@ -459755,9 +457482,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + free(pbuf, M_DEVBUF); +#endif -+#ifdef PLATFORM_WINDOWS -+ NdisFreeMemory(pbuf, sz, 0); -+#endif + +#ifdef DBG_MEMORY_LEAK +#ifdef PLATFORM_LINUX @@ -459783,11 +457507,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + pbuf = malloc(sz, M_DEVBUF, M_NOWAIT); +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisAllocateMemoryWithTag(&pbuf, sz, RT_TAG); -+ -+#endif + +#ifdef DBG_MEMORY_LEAK +#ifdef PLATFORM_LINUX @@ -459816,10 +457535,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + memset(pbuf, 0, sz); +#endif + -+#ifdef PLATFORM_WINDOWS -+ NdisFillMemory(pbuf, sz, 0); -+#endif -+ + } + + return pbuf; @@ -459841,11 +457556,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + free(pbuf, M_DEVBUF); +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisFreeMemory(pbuf, sz, 0); -+ -+#endif + +#ifdef DBG_MEMORY_LEAK +#ifdef PLATFORM_LINUX @@ -460559,12 +458269,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + +#endif + -+#ifdef PLATFORM_WINDOWS -+ -+ NdisMoveMemory(dst, src, sz); -+ -+#endif -+ +} + +inline void _rtw_memmove(void *dst, const void *src, u32 sz) @@ -460588,19 +458292,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + return _FALSE; +#endif + -+ -+#ifdef PLATFORM_WINDOWS -+ /* under Windows, the return value of NdisEqualMemory for two same mem. chunk is 1 */ -+ -+ if (NdisEqualMemory(dst, src, sz)) -+ return _TRUE; -+ else -+ return _FALSE; -+ -+#endif -+ -+ -+ +} + +void _rtw_memset(void *pbuf, int c, u32 sz) @@ -460612,16 +458303,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + +#endif + -+#ifdef PLATFORM_WINDOWS -+#if 0 -+ NdisZeroMemory(pbuf, sz); -+ if (c != 0) -+ memset(pbuf, c, sz); -+#else -+ NdisFillMemory(pbuf, sz, c); -+#endif -+#endif -+ +} + +#ifdef PLATFORM_FREEBSD @@ -460648,11 +458329,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + list->next = list; + list->prev = list; +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisInitializeListHead(list); -+ -+#endif + +} + @@ -460682,17 +458358,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + +#endif + -+ -+#ifdef PLATFORM_WINDOWS -+ -+ if (IsListEmpty(phead)) -+ return _TRUE; -+ else -+ return _FALSE; -+ -+#endif -+ -+ +} + +void rtw_list_insert_head(_list *plist, _list *phead) @@ -460706,9 +458371,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + __list_add(plist, phead, phead->next); +#endif + -+#ifdef PLATFORM_WINDOWS -+ InsertHeadList(phead, plist); -+#endif +} + +void rtw_list_insert_tail(_list *plist, _list *phead) @@ -460724,11 +458386,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + __list_add(plist, phead->prev, phead); + +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ InsertTailList(phead, plist); -+ -+#endif + +} + @@ -460819,9 +458476,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + _init_timer(ptimer, adapter->pifp, pfunc, ctx); +#endif -+#ifdef PLATFORM_WINDOWS -+ _init_timer(ptimer, adapter->hndis_adapter, pfunc, ctx); -+#endif +} + +/* @@ -460842,16 +458496,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + sema_init(sema, init_val, "rtw_drv"); +#endif -+#ifdef PLATFORM_OS_XP -+ -+ KeInitializeSemaphore(sema, init_val, SEMA_UPBND); /* count=0; */ -+ -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ if (*sema == NULL) -+ *sema = CreateSemaphore(NULL, init_val, SEMA_UPBND, NULL); -+#endif + +} + @@ -460860,9 +458504,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + sema_destroy(sema); +#endif -+#ifdef PLATFORM_OS_CE -+ CloseHandle(*sema); -+#endif + +} + @@ -460877,15 +458518,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + sema_post(sema); +#endif -+#ifdef PLATFORM_OS_XP -+ -+ KeReleaseSemaphore(sema, IO_NETWORK_INCREMENT, 1, FALSE); -+ -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ ReleaseSemaphore(*sema, 1, NULL); -+#endif +} + +u32 _rtw_down_sema(_sema *sema) @@ -460903,39 +458535,25 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + sema_wait(sema); + return _SUCCESS; +#endif -+#ifdef PLATFORM_OS_XP -+ -+ if (STATUS_SUCCESS == KeWaitForSingleObject(sema, Executive, KernelMode, TRUE, NULL)) -+ return _SUCCESS; -+ else -+ return _FAIL; -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ if (WAIT_OBJECT_0 == WaitForSingleObject(*sema, INFINITE)) -+ return _SUCCESS; -+ else -+ return _FAIL; -+#endif +} + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) +inline void thread_exit(_completion *comp) ++#else ++inline void kthread_thread_exit(_completion *comp) ++#endif +{ +#ifdef PLATFORM_LINUX ++#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + complete_and_exit(comp, 0); ++#else ++ kthread_complete_and_exit(comp, 0); ++#endif +#endif + +#ifdef PLATFORM_FREEBSD + printf("%s", "RTKTHREAD_exit"); +#endif -+ -+#ifdef PLATFORM_OS_CE -+ ExitThread(STATUS_SUCCESS); -+#endif -+ -+#ifdef PLATFORM_OS_XP -+ PsTerminateSystemThread(STATUS_SUCCESS); -+#endif +} + +inline void _rtw_init_completion(_completion *comp) @@ -460971,15 +458589,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + mtx_init(pmutex, "", NULL, MTX_DEF | MTX_RECURSE); +#endif -+#ifdef PLATFORM_OS_XP -+ -+ KeInitializeMutex(pmutex, 0); -+ -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ *pmutex = CreateMutex(NULL, _FALSE, NULL); -+#endif +} + +void _rtw_mutex_free(_mutex *pmutex); @@ -460997,14 +458606,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#endif + +#endif -+ -+#ifdef PLATFORM_OS_XP -+ -+#endif -+ -+#ifdef PLATFORM_OS_CE -+ -+#endif +} + +void _rtw_spinlock_init(_lock *plock) @@ -461018,11 +458619,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + mtx_init(plock, "", NULL, MTX_DEF | MTX_RECURSE); +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisAllocateSpinLock(plock); -+ -+#endif + +} + @@ -461032,12 +458628,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + mtx_destroy(plock); +#endif + -+#ifdef PLATFORM_WINDOWS -+ -+ NdisFreeSpinLock(plock); -+ -+#endif -+ +} +#ifdef PLATFORM_FREEBSD +extern PADAPTER prtw_lock; @@ -461071,11 +458661,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + mtx_lock(plock); +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisAcquireSpinLock(plock); -+ -+#endif + +} + @@ -461090,11 +458675,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + mtx_unlock(plock); +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisReleaseSpinLock(plock); -+ -+#endif +} + + @@ -461109,11 +458689,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + mtx_lock(plock); +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisDprAcquireSpinLock(plock); -+ -+#endif + +} + @@ -461128,15 +458703,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + mtx_unlock(plock); +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisDprReleaseSpinLock(plock); -+ -+#endif +} + -+ -+ +void _rtw_init_queue(_queue *pqueue) +{ + _rtw_init_listhead(&(pqueue->queue)); @@ -461174,11 +458742,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + getmicrotime(&tvp); + return tvp.tv_sec; +#endif -+#ifdef PLATFORM_WINDOWS -+ LARGE_INTEGER SystemTime; -+ NdisGetCurrentSystemTime(&SystemTime); -+ return SystemTime.LowPart;/* count of 100-nanosecond intervals */ -+#endif +} + +inline u32 _rtw_systime_to_ms(systime stime) @@ -461189,9 +458752,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + return stime * 1000; +#endif -+#ifdef PLATFORM_WINDOWS -+ return stime / 10000 ; -+#endif +} + +inline systime _rtw_ms_to_systime(u32 ms) @@ -461202,9 +458762,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + return ms / 1000; +#endif -+#ifdef PLATFORM_WINDOWS -+ return ms * 10000 ; -+#endif +} + +inline systime _rtw_us_to_systime(u32 us) @@ -461263,15 +458820,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + return ; +#endif + -+#ifdef PLATFORM_WINDOWS -+ -+ NdisMSleep(ms * 1000); /* (us)*1000=(ms) */ -+ -+#endif -+ +} + -+ +void rtw_msleep_os(int ms) +{ + @@ -461290,13 +458840,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + DELAY(ms * 1000); + return ; +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisMSleep(ms * 1000); /* (us)*1000=(ms) */ -+ -+#endif -+ -+ +} +void rtw_usleep_os(int us) +{ @@ -461319,16 +458862,8 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + + return ; +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisMSleep(us); /* (us) */ -+ -+#endif -+ -+ +} + -+ +#ifdef DBG_DELAY_OS +void _rtw_mdelay_os(int ms, const char *func, const int line) +{ @@ -461346,10 +458881,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + + mdelay((unsigned long)ms); + -+#elif defined(PLATFORM_WINDOWS) -+ -+ NdisStallExecution(ms * 1000); /* (us)*1000=(ms) */ -+ +#endif + + @@ -461373,10 +458904,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + + udelay((unsigned long)us); + -+#elif defined(PLATFORM_WINDOWS) -+ -+ NdisStallExecution(us); /* (us) */ -+ +#endif + +} @@ -461393,13 +458920,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + DELAY(ms * 1000); + return ; +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisStallExecution(ms * 1000); /* (us)*1000=(ms) */ -+ -+#endif -+ -+ +} +void rtw_udelay_os(int us) +{ @@ -461414,11 +458934,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + DELAY(us); + return ; +#endif -+#ifdef PLATFORM_WINDOWS -+ -+ NdisStallExecution(us); /* (us) */ -+ -+#endif + +} +#endif @@ -461431,9 +458946,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_FREEBSD + yield(); +#endif -+#ifdef PLATFORM_WINDOWS -+ SwitchToThread(); -+#endif +} + +bool rtw_macaddr_is_larger(const u8 *a, const u8 *b) @@ -461598,8 +459110,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + atomic_set(v, i); -+#elif defined(PLATFORM_WINDOWS) -+ *v = i; /* other choice???? */ +#elif defined(PLATFORM_FREEBSD) + atomic_set_int(v, i); +#endif @@ -461609,8 +459119,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + return atomic_read(v); -+#elif defined(PLATFORM_WINDOWS) -+ return *v; /* other choice???? */ +#elif defined(PLATFORM_FREEBSD) + return atomic_load_acq_32(v); +#endif @@ -461620,8 +459128,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + atomic_add(i, v); -+#elif defined(PLATFORM_WINDOWS) -+ InterlockedAdd(v, i); +#elif defined(PLATFORM_FREEBSD) + atomic_add_int(v, i); +#endif @@ -461630,8 +459136,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + atomic_sub(i, v); -+#elif defined(PLATFORM_WINDOWS) -+ InterlockedAdd(v, -i); +#elif defined(PLATFORM_FREEBSD) + atomic_subtract_int(v, i); +#endif @@ -461641,8 +459145,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + atomic_inc(v); -+#elif defined(PLATFORM_WINDOWS) -+ InterlockedIncrement(v); +#elif defined(PLATFORM_FREEBSD) + atomic_add_int(v, 1); +#endif @@ -461652,8 +459154,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + atomic_dec(v); -+#elif defined(PLATFORM_WINDOWS) -+ InterlockedDecrement(v); +#elif defined(PLATFORM_FREEBSD) + atomic_subtract_int(v, 1); +#endif @@ -461663,8 +459163,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + return atomic_add_return(i, v); -+#elif defined(PLATFORM_WINDOWS) -+ return InterlockedAdd(v, i); +#elif defined(PLATFORM_FREEBSD) + atomic_add_int(v, i); + return atomic_load_acq_32(v); @@ -461675,8 +459173,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + return atomic_sub_return(i, v); -+#elif defined(PLATFORM_WINDOWS) -+ return InterlockedAdd(v, -i); +#elif defined(PLATFORM_FREEBSD) + atomic_subtract_int(v, i); + return atomic_load_acq_32(v); @@ -461687,8 +459183,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + return atomic_inc_return(v); -+#elif defined(PLATFORM_WINDOWS) -+ return InterlockedIncrement(v); +#elif defined(PLATFORM_FREEBSD) + atomic_add_int(v, 1); + return atomic_load_acq_32(v); @@ -461699,8 +459193,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + return atomic_dec_return(v); -+#elif defined(PLATFORM_WINDOWS) -+ return InterlockedDecrement(v); +#elif defined(PLATFORM_FREEBSD) + atomic_subtract_int(v, 1); + return atomic_load_acq_32(v); @@ -462138,7 +459630,7 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + + rtw_init_netdev_name(pnetdev, ifname); + -+ _rtw_memcpy(pnetdev->dev_addr, adapter_mac_addr(padapter), ETH_ALEN); ++ dev_addr_set(pnetdev, adapter_mac_addr(padapter)); + + if (rtnl_lock_needed) + ret = register_netdev(pnetdev); @@ -462239,8 +459731,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +{ +#ifdef PLATFORM_LINUX + return do_div(x, y); -+#elif defined(PLATFORM_WINDOWS) -+ return x % y; +#elif defined(PLATFORM_FREEBSD) + return x % y; +#endif @@ -462251,8 +459741,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#ifdef PLATFORM_LINUX + do_div(x, y); + return x; -+#elif defined(PLATFORM_WINDOWS) -+ return x / y; +#elif defined(PLATFORM_FREEBSD) + return x / y; +#endif @@ -462261,7 +459749,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +inline u32 rtw_random32(void) +{ +#ifdef PLATFORM_LINUX -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) ++ return get_random_u32(); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) + return prandom_u32(); +#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)) + u32 random_int; @@ -462270,8 +459760,6 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r +#else + return random32(); +#endif -+#elif defined(PLATFORM_WINDOWS) -+#error "to be implemented\n" +#elif defined(PLATFORM_FREEBSD) +#error "to be implemented\n" +#endif @@ -462800,9 +460288,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/os_dep/osdep_service.c linux-5.11.4-r + return 0; +} + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/custom_country_chplan.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/custom_country_chplan.h +--- linux-6.3.4/drivers/staging/rtl8812au/platform/custom_country_chplan.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/custom_country_chplan.h 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,22 @@ +/****************************************************************************** + * @@ -462826,9 +460314,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/custom_country_chplan.h linu + COUNTRY_CHPLAN_ENT("TW", 0x76, 1, 0x3FF), /* Taiwan */ +}; + -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,54 @@ +/****************************************************************************** + * @@ -462884,9 +460372,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.c lin + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.h +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_aml_s905_sdio.h 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,32 @@ +/****************************************************************************** + * @@ -462920,9 +460408,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_aml_s905_sdio.h lin +#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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_arm_act_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_arm_act_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_arm_act_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_arm_act_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,53 @@ +/****************************************************************************** + * @@ -462977,9 +460465,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_arm_act_sdio.c linu + 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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,86 @@ +/****************************************************************************** + * @@ -463067,9 +460555,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUN50IW1P1_sdio + RTW_INFO("%s: remove card, power off.\n", __FUNCTION__); +#endif /* CONFIG_MMC */ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_SUNnI_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_SUNnI_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_SUNnI_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_SUNnI_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,130 @@ +/****************************************************************************** + * @@ -463201,9 +460689,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNnI_sdio.c li + RTW_INFO("%s: remove card, power off.\n", __FUNCTION__); +#endif /* CONFIG_MMC */ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,90 @@ +/****************************************************************************** + * @@ -463295,9 +460783,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_sdio.c li +#endif /* CONFIG_RTL8188E */ +#endif /* CONFIG_MMC_SUNXI_POWER_CONTROL */ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_usb.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_usb.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_SUNxI_usb.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,136 @@ +/****************************************************************************** + * @@ -463435,9 +460923,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_SUNxI_usb.c lin +#endif /* defined(CONFIG_PLATFORM_ARM_SUN8I) */ + +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_WMT_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_WMT_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ARM_WMT_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ARM_WMT_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,46 @@ +/****************************************************************************** + * @@ -463485,9 +460973,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ARM_WMT_sdio.c linu + gpio_free(WMT_PIN_GP62_SUSGPIO1); + printk("[rtl8189es] %s: remove card, power off.\n", __FUNCTION__); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,110 @@ +/****************************************************************************** + * @@ -463599,9 +461087,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sd + mdelay(100); + hi_gpio_set_value(gpio_wlan_reg_on, 0); +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_hisilicon_hi3798_sdio.h 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,28 @@ +/****************************************************************************** + * @@ -463631,9 +461119,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_hisilicon_hi3798_sd +extern HI_S32 HI_DRV_GPIO_WriteBit(HI_U32 u32GpioNo, HI_U32 u32BitValue); + +#endif /* __PLATFORM_HISILICON_HI3798_SDIO_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ops.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ops.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ops.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ops.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,32 @@ +/****************************************************************************** + * @@ -463667,9 +461155,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ops.c linux-5.11.4- +{ +} +#endif /* !CONFIG_PLATFORM_OPS */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ops.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ops.h +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_ops.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_ops.h 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,26 @@ +/****************************************************************************** + * @@ -463697,9 +461185,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_ops.h linux-5.11.4- +void platform_wifi_power_off(void); + +#endif /* __PLATFORM_OPS_H__ */ -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_RTK_DMP_usb.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_RTK_DMP_usb.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_RTK_DMP_usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_RTK_DMP_usb.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,30 @@ +/****************************************************************************** + * @@ -463731,9 +461219,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_RTK_DMP_usb.c linux +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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_sprd_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_sprd_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_sprd_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_sprd_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,84 @@ +/****************************************************************************** + * @@ -463819,9 +461307,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_sprd_sdio.c linux-5 + mmc_host->pm_flags &= ~MMC_PM_KEEP_POWER; +#endif /* CONFIG_WOWLAN */ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.c linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.c +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.c 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,53 @@ +/****************************************************************************** + * @@ -463876,9 +461364,9 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.c + + /*msleep(500);*/ +} -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 +diff -Nurp linux-6.3.4/drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.h linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.h +--- linux-6.3.4/drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-6.3.4-rtl8812au/drivers/staging/rtl8812au/platform/platform_zte_zx296716_sdio.h 2022-01-28 22:59:35.633655166 +0200 @@ -0,0 +1,25 @@ +/****************************************************************************** + * @@ -463905,14028 +461393,3 @@ diff -Nurp linux-5.11.4/3rdparty/rtl8812au/platform/platform_zte_zx296716_sdio.h +#endif /* CONFIG_A16T03_BOARD */ + +#endif /* __PLATFORM_ZTE_ZX296716_SDIO_H__ */ -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/python -+# -+# Tool for analyzing suspend/resume timing -+# Copyright (c) 2013, Intel Corporation. -+# -+# This program is free software; you can redistribute it and/or modify it -+# under the terms and conditions of the GNU General Public License, -+# version 2, as published by the Free Software Foundation. -+# -+# This program is distributed in the hope 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. -+# -+# Authors: -+# Todd Brandt -+# -+# Description: -+# This tool is designed to assist kernel and OS developers in optimizing -+# their linux stack's suspend/resume time. Using a kernel image built -+# with a few extra options enabled, the tool will execute a suspend and -+# will capture dmesg and ftrace data until resume is complete. This data -+# is transformed into a device timeline and a callgraph to give a quick -+# and detailed view of which devices and callbacks are taking the most -+# time in suspend/resume. The output is a single html file which can be -+# viewed in firefox or chrome. -+# -+# The following kernel build options are required: -+# CONFIG_PM_DEBUG=y -+# CONFIG_PM_SLEEP_DEBUG=y -+# CONFIG_FTRACE=y -+# CONFIG_FUNCTION_TRACER=y -+# CONFIG_FUNCTION_GRAPH_TRACER=y -+# -+# For kernel versions older than 3.15: -+# The following additional kernel parameters are required: -+# (e.g. in file /etc/default/grub) -+# GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..." -+# -+# ----------------- LIBRARIES -------------------- -+import sys -+import time -+import os -+import string -+import re -+import platform -+from datetime import datetime -+import struct -+# ----------------- CLASSES -------------------- -+# Class: SystemValues -+# Description: -+# A global, single-instance container used to -+# store system values and test parameters -+class SystemValues: -+ version = 3.0 -+ verbose = False -+ testdir = '.' -+ tpath = '/sys/kernel/debug/tracing/' -+ fpdtpath = '/sys/firmware/acpi/tables/FPDT' -+ epath = '/sys/kernel/debug/tracing/events/power/' -+ traceevents = [ -+ 'suspend_resume', -+ 'device_pm_callback_end', -+ 'device_pm_callback_start' -+ ] -+ modename = { -+ 'freeze': 'Suspend-To-Idle (S0)', -+ 'standby': 'Power-On Suspend (S1)', -+ 'mem': 'Suspend-to-RAM (S3)', -+ 'disk': 'Suspend-to-disk (S4)' -+ } -+ mempath = '/dev/mem' -+ powerfile = '/sys/power/state' -+ suspendmode = 'mem' -+ hostname = 'localhost' -+ prefix = 'test' -+ teststamp = '' -+ dmesgfile = '' -+ ftracefile = '' -+ htmlfile = '' -+ rtcwake = False -+ rtcwaketime = 10 -+ rtcpath = '' -+ android = False -+ adb = 'adb' -+ devicefilter = [] -+ stamp = 0 -+ execcount = 1 -+ x2delay = 0 -+ usecallgraph = False -+ usetraceevents = False -+ usetraceeventsonly = False -+ notestrun = False -+ altdevname = dict() -+ postresumetime = 0 -+ tracertypefmt = '# tracer: (?P.*)' -+ firmwarefmt = '# fwsuspend (?P[0-9]*) fwresume (?P[0-9]*)$' -+ postresumefmt = '# post resume time (?P[0-9]*)$' -+ stampfmt = '# suspend-(?P[0-9]{2})(?P[0-9]{2})(?P[0-9]{2})-'+\ -+ '(?P[0-9]{2})(?P[0-9]{2})(?P[0-9]{2})'+\ -+ ' (?P.*) (?P.*) (?P.*)$' -+ def __init__(self): -+ self.hostname = platform.node() -+ if(self.hostname == ''): -+ self.hostname = 'localhost' -+ rtc = "rtc0" -+ if os.path.exists('/dev/rtc'): -+ rtc = os.readlink('/dev/rtc') -+ rtc = '/sys/class/rtc/'+rtc -+ if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ -+ os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): -+ self.rtcpath = rtc -+ def setOutputFile(self): -+ if((self.htmlfile == '') and (self.dmesgfile != '')): -+ m = re.match('(?P.*)_dmesg\.txt$', self.dmesgfile) -+ if(m): -+ self.htmlfile = m.group('name')+'.html' -+ if((self.htmlfile == '') and (self.ftracefile != '')): -+ m = re.match('(?P.*)_ftrace\.txt$', self.ftracefile) -+ if(m): -+ self.htmlfile = m.group('name')+'.html' -+ if(self.htmlfile == ''): -+ self.htmlfile = 'output.html' -+ def initTestOutput(self, subdir): -+ if(not self.android): -+ self.prefix = self.hostname -+ v = open('/proc/version', 'r').read().strip() -+ kver = string.split(v)[2] -+ else: -+ self.prefix = 'android' -+ v = os.popen(self.adb+' shell cat /proc/version').read().strip() -+ kver = string.split(v)[2] -+ testtime = datetime.now().strftime('suspend-%m%d%y-%H%M%S') -+ if(subdir != "."): -+ self.testdir = subdir+"/"+testtime -+ else: -+ self.testdir = testtime -+ self.teststamp = \ -+ '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver -+ self.dmesgfile = \ -+ self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt' -+ self.ftracefile = \ -+ self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt' -+ self.htmlfile = \ -+ self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' -+ os.mkdir(self.testdir) -+ def setDeviceFilter(self, devnames): -+ self.devicefilter = string.split(devnames) -+ def rtcWakeAlarm(self): -+ os.system('echo 0 > '+self.rtcpath+'/wakealarm') -+ outD = open(self.rtcpath+'/date', 'r').read().strip() -+ outT = open(self.rtcpath+'/time', 'r').read().strip() -+ mD = re.match('^(?P[0-9]*)-(?P[0-9]*)-(?P[0-9]*)', outD) -+ mT = re.match('^(?P[0-9]*):(?P[0-9]*):(?P[0-9]*)', outT) -+ if(mD and mT): -+ # get the current time from hardware -+ utcoffset = int((datetime.now() - datetime.utcnow()).total_seconds()) -+ dt = datetime(\ -+ int(mD.group('y')), int(mD.group('m')), int(mD.group('d')), -+ int(mT.group('h')), int(mT.group('m')), int(mT.group('s'))) -+ nowtime = int(dt.strftime('%s')) + utcoffset -+ else: -+ # if hardware time fails, use the software time -+ nowtime = int(datetime.now().strftime('%s')) -+ alarm = nowtime + self.rtcwaketime -+ os.system('echo %d > %s/wakealarm' % (alarm, self.rtcpath)) -+sysvals = SystemValues() -+# Class: DeviceNode -+# Description: -+# A container used to create a device hierachy, with a single root node -+# and a tree of child nodes. Used by Data.deviceTopology() -+class DeviceNode: -+ name = '' -+ children = 0 -+ depth = 0 -+ def __init__(self, nodename, nodedepth): -+ self.name = nodename -+ self.children = [] -+ self.depth = nodedepth -+# Class: Data -+# Description: -+# The primary container for suspend/resume test data. There is one for -+# each test run. The data is organized into a cronological hierarchy: -+# Data.dmesg { -+# root structure, started as dmesg & ftrace, but now only ftrace -+# contents: times for suspend start/end, resume start/end, fwdata -+# phases { -+# 10 sequential, non-overlapping phases of S/R -+# contents: times for phase start/end, order/color data for html -+# devlist { -+# device callback or action list for this phase -+# device { -+# a single device callback or generic action -+# contents: start/stop times, pid/cpu/driver info -+# parents/children, html id for timeline/callgraph -+# optionally includes an ftrace callgraph -+# optionally includes intradev trace events -+# } -+# } -+# } -+# } -+# -+class Data: -+ dmesg = {} # root data structure -+ phases = [] # ordered list of phases -+ start = 0.0 # test start -+ end = 0.0 # test end -+ tSuspended = 0.0 # low-level suspend start -+ tResumed = 0.0 # low-level resume start -+ tLow = 0.0 # time spent in low-level suspend (standby/freeze) -+ fwValid = False # is firmware data available -+ fwSuspend = 0 # time spent in firmware suspend -+ fwResume = 0 # time spent in firmware resume -+ dmesgtext = [] # dmesg text file in memory -+ testnumber = 0 -+ idstr = '' -+ html_device_id = 0 -+ stamp = 0 -+ outfile = '' -+ def __init__(self, num): -+ idchar = 'abcdefghijklmnopqrstuvwxyz' -+ self.testnumber = num -+ self.idstr = idchar[num] -+ self.dmesgtext = [] -+ self.phases = [] -+ self.dmesg = { # fixed list of 10 phases -+ 'suspend_prepare': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#CCFFCC', 'order': 0}, -+ 'suspend': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#88FF88', 'order': 1}, -+ 'suspend_late': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#00AA00', 'order': 2}, -+ 'suspend_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#008888', 'order': 3}, -+ 'suspend_machine': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#0000FF', 'order': 4}, -+ 'resume_machine': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#FF0000', 'order': 5}, -+ 'resume_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#FF9900', 'order': 6}, -+ 'resume_early': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#FFCC00', 'order': 7}, -+ 'resume': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#FFFF88', 'order': 8}, -+ 'resume_complete': {'list': dict(), 'start': -1.0, 'end': -1.0, -+ 'row': 0, 'color': '#FFFFCC', 'order': 9} -+ } -+ self.phases = self.sortedPhases() -+ def getStart(self): -+ return self.dmesg[self.phases[0]]['start'] -+ def setStart(self, time): -+ self.start = time -+ self.dmesg[self.phases[0]]['start'] = time -+ def getEnd(self): -+ return self.dmesg[self.phases[-1]]['end'] -+ def setEnd(self, time): -+ self.end = time -+ self.dmesg[self.phases[-1]]['end'] = time -+ def isTraceEventOutsideDeviceCalls(self, pid, time): -+ for phase in self.phases: -+ list = self.dmesg[phase]['list'] -+ for dev in list: -+ d = list[dev] -+ if(d['pid'] == pid and time >= d['start'] and -+ time <= d['end']): -+ return False -+ return True -+ def addIntraDevTraceEvent(self, action, name, pid, time): -+ if(action == 'mutex_lock_try'): -+ color = 'red' -+ elif(action == 'mutex_lock_pass'): -+ color = 'green' -+ elif(action == 'mutex_unlock'): -+ color = 'blue' -+ else: -+ # create separate colors based on the name -+ v1 = len(name)*10 % 256 -+ v2 = string.count(name, 'e')*100 % 256 -+ v3 = ord(name[0])*20 % 256 -+ color = '#%06X' % ((v1*0x10000) + (v2*0x100) + v3) -+ for phase in self.phases: -+ list = self.dmesg[phase]['list'] -+ for dev in list: -+ d = list[dev] -+ if(d['pid'] == pid and time >= d['start'] and -+ time <= d['end']): -+ e = TraceEvent(action, name, color, time) -+ if('traceevents' not in d): -+ d['traceevents'] = [] -+ d['traceevents'].append(e) -+ return d -+ break -+ return 0 -+ def capIntraDevTraceEvent(self, action, name, pid, time): -+ for phase in self.phases: -+ list = self.dmesg[phase]['list'] -+ for dev in list: -+ d = list[dev] -+ if(d['pid'] == pid and time >= d['start'] and -+ time <= d['end']): -+ if('traceevents' not in d): -+ return -+ for e in d['traceevents']: -+ if(e.action == action and -+ e.name == name and not e.ready): -+ e.length = time - e.time -+ e.ready = True -+ break -+ return -+ def trimTimeVal(self, t, t0, dT, left): -+ if left: -+ if(t > t0): -+ if(t - dT < t0): -+ return t0 -+ return t - dT -+ else: -+ return t -+ else: -+ if(t < t0 + dT): -+ if(t > t0): -+ return t0 + dT -+ return t + dT -+ else: -+ return t -+ def trimTime(self, t0, dT, left): -+ self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left) -+ self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left) -+ self.start = self.trimTimeVal(self.start, t0, dT, left) -+ self.end = self.trimTimeVal(self.end, t0, dT, left) -+ for phase in self.phases: -+ p = self.dmesg[phase] -+ p['start'] = self.trimTimeVal(p['start'], t0, dT, left) -+ p['end'] = self.trimTimeVal(p['end'], t0, dT, left) -+ list = p['list'] -+ for name in list: -+ d = list[name] -+ d['start'] = self.trimTimeVal(d['start'], t0, dT, left) -+ d['end'] = self.trimTimeVal(d['end'], t0, dT, left) -+ if('ftrace' in d): -+ cg = d['ftrace'] -+ cg.start = self.trimTimeVal(cg.start, t0, dT, left) -+ cg.end = self.trimTimeVal(cg.end, t0, dT, left) -+ for line in cg.list: -+ line.time = self.trimTimeVal(line.time, t0, dT, left) -+ if('traceevents' in d): -+ for e in d['traceevents']: -+ e.time = self.trimTimeVal(e.time, t0, dT, left) -+ def normalizeTime(self, tZero): -+ # first trim out any standby or freeze clock time -+ if(self.tSuspended != self.tResumed): -+ if(self.tResumed > tZero): -+ self.trimTime(self.tSuspended, \ -+ self.tResumed-self.tSuspended, True) -+ else: -+ self.trimTime(self.tSuspended, \ -+ self.tResumed-self.tSuspended, False) -+ # shift the timeline so that tZero is the new 0 -+ self.tSuspended -= tZero -+ self.tResumed -= tZero -+ self.start -= tZero -+ self.end -= tZero -+ for phase in self.phases: -+ p = self.dmesg[phase] -+ p['start'] -= tZero -+ p['end'] -= tZero -+ list = p['list'] -+ for name in list: -+ d = list[name] -+ d['start'] -= tZero -+ d['end'] -= tZero -+ if('ftrace' in d): -+ cg = d['ftrace'] -+ cg.start -= tZero -+ cg.end -= tZero -+ for line in cg.list: -+ line.time -= tZero -+ if('traceevents' in d): -+ for e in d['traceevents']: -+ e.time -= tZero -+ def newPhaseWithSingleAction(self, phasename, devname, start, end, color): -+ for phase in self.phases: -+ self.dmesg[phase]['order'] += 1 -+ self.html_device_id += 1 -+ devid = '%s%d' % (self.idstr, self.html_device_id) -+ list = dict() -+ list[devname] = \ -+ {'start': start, 'end': end, 'pid': 0, 'par': '', -+ 'length': (end-start), 'row': 0, 'id': devid, 'drv': '' }; -+ self.dmesg[phasename] = \ -+ {'list': list, 'start': start, 'end': end, -+ 'row': 0, 'color': color, 'order': 0} -+ self.phases = self.sortedPhases() -+ def newPhase(self, phasename, start, end, color, order): -+ if(order < 0): -+ order = len(self.phases) -+ for phase in self.phases[order:]: -+ self.dmesg[phase]['order'] += 1 -+ if(order > 0): -+ p = self.phases[order-1] -+ self.dmesg[p]['end'] = start -+ if(order < len(self.phases)): -+ p = self.phases[order] -+ self.dmesg[p]['start'] = end -+ list = dict() -+ self.dmesg[phasename] = \ -+ {'list': list, 'start': start, 'end': end, -+ 'row': 0, 'color': color, 'order': order} -+ self.phases = self.sortedPhases() -+ def setPhase(self, phase, ktime, isbegin): -+ if(isbegin): -+ self.dmesg[phase]['start'] = ktime -+ else: -+ self.dmesg[phase]['end'] = ktime -+ def dmesgSortVal(self, phase): -+ return self.dmesg[phase]['order'] -+ def sortedPhases(self): -+ return sorted(self.dmesg, key=self.dmesgSortVal) -+ def sortedDevices(self, phase): -+ list = self.dmesg[phase]['list'] -+ slist = [] -+ tmp = dict() -+ for devname in list: -+ dev = list[devname] -+ tmp[dev['start']] = devname -+ for t in sorted(tmp): -+ slist.append(tmp[t]) -+ return slist -+ def fixupInitcalls(self, phase, end): -+ # if any calls never returned, clip them at system resume end -+ phaselist = self.dmesg[phase]['list'] -+ for devname in phaselist: -+ dev = phaselist[devname] -+ if(dev['end'] < 0): -+ dev['end'] = end -+ vprint('%s (%s): callback didnt return' % (devname, phase)) -+ def deviceFilter(self, devicefilter): -+ # remove all by the relatives of the filter devnames -+ filter = [] -+ for phase in self.phases: -+ list = self.dmesg[phase]['list'] -+ for name in devicefilter: -+ dev = name -+ while(dev in list): -+ if(dev not in filter): -+ filter.append(dev) -+ dev = list[dev]['par'] -+ children = self.deviceDescendants(name, phase) -+ for dev in children: -+ if(dev not in filter): -+ filter.append(dev) -+ for phase in self.phases: -+ list = self.dmesg[phase]['list'] -+ rmlist = [] -+ for name in list: -+ pid = list[name]['pid'] -+ if(name not in filter and pid >= 0): -+ rmlist.append(name) -+ for name in rmlist: -+ del list[name] -+ def fixupInitcallsThatDidntReturn(self): -+ # if any calls never returned, clip them at system resume end -+ for phase in self.phases: -+ self.fixupInitcalls(phase, self.getEnd()) -+ def newActionGlobal(self, name, start, end): -+ # which phase is this device callback or action "in" -+ targetphase = "none" -+ overlap = 0.0 -+ for phase in self.phases: -+ pstart = self.dmesg[phase]['start'] -+ pend = self.dmesg[phase]['end'] -+ o = max(0, min(end, pend) - max(start, pstart)) -+ if(o > overlap): -+ targetphase = phase -+ overlap = o -+ if targetphase in self.phases: -+ self.newAction(targetphase, name, -1, '', start, end, '') -+ return True -+ return False -+ def newAction(self, phase, name, pid, parent, start, end, drv): -+ # new device callback for a specific phase -+ self.html_device_id += 1 -+ devid = '%s%d' % (self.idstr, self.html_device_id) -+ list = self.dmesg[phase]['list'] -+ length = -1.0 -+ if(start >= 0 and end >= 0): -+ length = end - start -+ list[name] = {'start': start, 'end': end, 'pid': pid, 'par': parent, -+ 'length': length, 'row': 0, 'id': devid, 'drv': drv } -+ def deviceIDs(self, devlist, phase): -+ idlist = [] -+ list = self.dmesg[phase]['list'] -+ for devname in list: -+ if devname in devlist: -+ idlist.append(list[devname]['id']) -+ return idlist -+ def deviceParentID(self, devname, phase): -+ pdev = '' -+ pdevid = '' -+ list = self.dmesg[phase]['list'] -+ if devname in list: -+ pdev = list[devname]['par'] -+ if pdev in list: -+ return list[pdev]['id'] -+ return pdev -+ def deviceChildren(self, devname, phase): -+ devlist = [] -+ list = self.dmesg[phase]['list'] -+ for child in list: -+ if(list[child]['par'] == devname): -+ devlist.append(child) -+ return devlist -+ def deviceDescendants(self, devname, phase): -+ children = self.deviceChildren(devname, phase) -+ family = children -+ for child in children: -+ family += self.deviceDescendants(child, phase) -+ return family -+ def deviceChildrenIDs(self, devname, phase): -+ devlist = self.deviceChildren(devname, phase) -+ return self.deviceIDs(devlist, phase) -+ def printDetails(self): -+ vprint(' test start: %f' % self.start) -+ for phase in self.phases: -+ dc = len(self.dmesg[phase]['list']) -+ vprint(' %16s: %f - %f (%d devices)' % (phase, \ -+ self.dmesg[phase]['start'], self.dmesg[phase]['end'], dc)) -+ vprint(' test end: %f' % self.end) -+ def masterTopology(self, name, list, depth): -+ node = DeviceNode(name, depth) -+ for cname in list: -+ clist = self.deviceChildren(cname, 'resume') -+ cnode = self.masterTopology(cname, clist, depth+1) -+ node.children.append(cnode) -+ return node -+ def printTopology(self, node): -+ html = '' -+ if node.name: -+ info = '' -+ drv = '' -+ for phase in self.phases: -+ list = self.dmesg[phase]['list'] -+ if node.name in list: -+ s = list[node.name]['start'] -+ e = list[node.name]['end'] -+ if list[node.name]['drv']: -+ drv = ' {'+list[node.name]['drv']+'}' -+ info += ('
  • %s: %.3fms
  • ' % (phase, (e-s)*1000)) -+ html += '
  • '+node.name+drv+'' -+ if info: -+ html += '
      '+info+'
    ' -+ html += '
  • ' -+ if len(node.children) > 0: -+ html += '
      ' -+ for cnode in node.children: -+ html += self.printTopology(cnode) -+ html += '
    ' -+ return html -+ def rootDeviceList(self): -+ # list of devices graphed -+ real = [] -+ for phase in self.dmesg: -+ list = self.dmesg[phase]['list'] -+ for dev in list: -+ if list[dev]['pid'] >= 0 and dev not in real: -+ real.append(dev) -+ # list of top-most root devices -+ rootlist = [] -+ for phase in self.dmesg: -+ list = self.dmesg[phase]['list'] -+ for dev in list: -+ pdev = list[dev]['par'] -+ if(re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)): -+ continue -+ if pdev and pdev not in real and pdev not in rootlist: -+ rootlist.append(pdev) -+ return rootlist -+ def deviceTopology(self): -+ rootlist = self.rootDeviceList() -+ master = self.masterTopology('', rootlist, 0) -+ return self.printTopology(master) -+# Class: TraceEvent -+# Description: -+# A container for trace event data found in the ftrace file -+class TraceEvent: -+ ready = False -+ name = '' -+ time = 0.0 -+ color = '#FFFFFF' -+ length = 0.0 -+ action = '' -+ def __init__(self, a, n, c, t): -+ self.action = a -+ self.name = n -+ self.color = c -+ self.time = t -+# Class: FTraceLine -+# Description: -+# A container for a single line of ftrace data. There are six basic types: -+# callgraph line: -+# call: " dpm_run_callback() {" -+# return: " }" -+# leaf: " dpm_run_callback();" -+# trace event: -+# tracing_mark_write: SUSPEND START or RESUME COMPLETE -+# suspend_resume: phase or custom exec block data -+# device_pm_callback: device callback info -+class FTraceLine: -+ time = 0.0 -+ length = 0.0 -+ fcall = False -+ freturn = False -+ fevent = False -+ depth = 0 -+ name = '' -+ type = '' -+ def __init__(self, t, m, d): -+ self.time = float(t) -+ # is this a trace event -+ if(d == 'traceevent' or re.match('^ *\/\* *(?P.*) \*\/ *$', m)): -+ if(d == 'traceevent'): -+ # nop format trace event -+ msg = m -+ else: -+ # function_graph format trace event -+ em = re.match('^ *\/\* *(?P.*) \*\/ *$', m) -+ msg = em.group('msg') -+ emm = re.match('^(?P.*?): (?P.*)', msg) -+ if(emm): -+ self.name = emm.group('msg') -+ self.type = emm.group('call') -+ else: -+ self.name = msg -+ self.fevent = True -+ return -+ # convert the duration to seconds -+ if(d): -+ self.length = float(d)/1000000 -+ # the indentation determines the depth -+ match = re.match('^(?P *)(?P.*)$', m) -+ if(not match): -+ return -+ self.depth = self.getDepth(match.group('d')) -+ m = match.group('o') -+ # function return -+ if(m[0] == '}'): -+ self.freturn = True -+ if(len(m) > 1): -+ # includes comment with function name -+ match = re.match('^} *\/\* *(?P.*) *\*\/$', m) -+ if(match): -+ self.name = match.group('n') -+ # function call -+ else: -+ self.fcall = True -+ # function call with children -+ if(m[-1] == '{'): -+ match = re.match('^(?P.*) *\(.*', m) -+ if(match): -+ self.name = match.group('n') -+ # function call with no children (leaf) -+ elif(m[-1] == ';'): -+ self.freturn = True -+ match = re.match('^(?P.*) *\(.*', m) -+ if(match): -+ self.name = match.group('n') -+ # something else (possibly a trace marker) -+ else: -+ self.name = m -+ def getDepth(self, str): -+ return len(str)/2 -+ def debugPrint(self, dev): -+ if(self.freturn and self.fcall): -+ print('%s -- %f (%02d): %s(); (%.3f us)' % (dev, self.time, \ -+ self.depth, self.name, self.length*1000000)) -+ elif(self.freturn): -+ print('%s -- %f (%02d): %s} (%.3f us)' % (dev, self.time, \ -+ self.depth, self.name, self.length*1000000)) -+ else: -+ print('%s -- %f (%02d): %s() { (%.3f us)' % (dev, self.time, \ -+ self.depth, self.name, self.length*1000000)) -+# Class: FTraceCallGraph -+# Description: -+# A container for the ftrace callgraph of a single recursive function. -+# This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph -+# Each instance is tied to a single device in a single phase, and is -+# comprised of an ordered list of FTraceLine objects -+class FTraceCallGraph: -+ start = -1.0 -+ end = -1.0 -+ list = [] -+ invalid = False -+ depth = 0 -+ def __init__(self): -+ self.start = -1.0 -+ self.end = -1.0 -+ self.list = [] -+ self.depth = 0 -+ def setDepth(self, line): -+ if(line.fcall and not line.freturn): -+ line.depth = self.depth -+ self.depth += 1 -+ elif(line.freturn and not line.fcall): -+ self.depth -= 1 -+ line.depth = self.depth -+ else: -+ line.depth = self.depth -+ def addLine(self, line, match): -+ if(not self.invalid): -+ self.setDepth(line) -+ if(line.depth == 0 and line.freturn): -+ if(self.start < 0): -+ self.start = line.time -+ self.end = line.time -+ self.list.append(line) -+ return True -+ if(self.invalid): -+ return False -+ if(len(self.list) >= 1000000 or self.depth < 0): -+ if(len(self.list) > 0): -+ first = self.list[0] -+ self.list = [] -+ self.list.append(first) -+ self.invalid = True -+ if(not match): -+ return False -+ id = 'task %s cpu %s' % (match.group('pid'), match.group('cpu')) -+ window = '(%f - %f)' % (self.start, line.time) -+ if(self.depth < 0): -+ print('Too much data for '+id+\ -+ ' (buffer overflow), ignoring this callback') -+ else: -+ print('Too much data for '+id+\ -+ ' '+window+', ignoring this callback') -+ return False -+ self.list.append(line) -+ if(self.start < 0): -+ self.start = line.time -+ return False -+ def slice(self, t0, tN): -+ minicg = FTraceCallGraph() -+ count = -1 -+ firstdepth = 0 -+ for l in self.list: -+ if(l.time < t0 or l.time > tN): -+ continue -+ if(count < 0): -+ if(not l.fcall or l.name == 'dev_driver_string'): -+ continue -+ firstdepth = l.depth -+ count = 0 -+ l.depth -= firstdepth -+ minicg.addLine(l, 0) -+ if((count == 0 and l.freturn and l.fcall) or -+ (count > 0 and l.depth <= 0)): -+ break -+ count += 1 -+ return minicg -+ def sanityCheck(self): -+ stack = dict() -+ cnt = 0 -+ for l in self.list: -+ if(l.fcall and not l.freturn): -+ stack[l.depth] = l -+ cnt += 1 -+ elif(l.freturn and not l.fcall): -+ if(l.depth not in stack): -+ return False -+ stack[l.depth].length = l.length -+ stack[l.depth] = 0 -+ l.length = 0 -+ cnt -= 1 -+ if(cnt == 0): -+ return True -+ return False -+ def debugPrint(self, filename): -+ if(filename == 'stdout'): -+ print('[%f - %f]') % (self.start, self.end) -+ for l in self.list: -+ if(l.freturn and l.fcall): -+ print('%f (%02d): %s(); (%.3f us)' % (l.time, \ -+ l.depth, l.name, l.length*1000000)) -+ elif(l.freturn): -+ print('%f (%02d): %s} (%.3f us)' % (l.time, \ -+ l.depth, l.name, l.length*1000000)) -+ else: -+ print('%f (%02d): %s() { (%.3f us)' % (l.time, \ -+ l.depth, l.name, l.length*1000000)) -+ print(' ') -+ else: -+ fp = open(filename, 'w') -+ print(filename) -+ for l in self.list: -+ if(l.freturn and l.fcall): -+ fp.write('%f (%02d): %s(); (%.3f us)\n' % (l.time, \ -+ l.depth, l.name, l.length*1000000)) -+ elif(l.freturn): -+ fp.write('%f (%02d): %s} (%.3f us)\n' % (l.time, \ -+ l.depth, l.name, l.length*1000000)) -+ else: -+ fp.write('%f (%02d): %s() { (%.3f us)\n' % (l.time, \ -+ l.depth, l.name, l.length*1000000)) -+ fp.close() -+# Class: Timeline -+# Description: -+# A container for a suspend/resume html timeline. In older versions -+# of the script there were multiple timelines, but in the latest -+# there is only one. -+class Timeline: -+ html = {} -+ scaleH = 0.0 # height of the row as a percent of the timeline height -+ rowH = 0.0 # height of each row in percent of the timeline height -+ row_height_pixels = 30 -+ maxrows = 0 -+ height = 0 -+ def __init__(self): -+ self.html = { -+ 'timeline': '', -+ 'legend': '', -+ 'scale': '' -+ } -+ def setRows(self, rows): -+ self.maxrows = int(rows) -+ self.scaleH = 100.0/float(self.maxrows) -+ self.height = self.maxrows*self.row_height_pixels -+ r = float(self.maxrows - 1) -+ if(r < 1.0): -+ r = 1.0 -+ self.rowH = (100.0 - self.scaleH)/r -+# Class: TestRun -+# Description: -+# A container for a suspend/resume test run. This is necessary as -+# there could be more than one, and they need to be separate. -+class TestRun: -+ ftrace_line_fmt_fg = \ -+ '^ *(?P