diff --git a/config/kernel/linux-sunxi-current.config b/config/kernel/linux-sunxi-current.config index 5b09a74fc..2253024ec 100644 --- a/config/kernel/linux-sunxi-current.config +++ b/config/kernel/linux-sunxi-current.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 5.3.9 Kernel Configuration +# Linux/arm 5.3.13 Kernel Configuration # # @@ -2554,13 +2554,13 @@ CONFIG_WLAN_VENDOR_TI=y # CONFIG_WL18XX is not set # CONFIG_WLCORE is not set CONFIG_RTL8822BU=m -CONFIG_RTL8188EU=m -CONFIG_RTL8812AU=m +CONFIG_RTL8188EUS=m CONFIG_WLAN_VENDOR_XRADIO=m CONFIG_XRADIO_NON_POWER_OF_TWO_BLOCKSIZES=y # CONFIG_XRADIO_5GHZ_SUPPORT is not set # CONFIG_XRADIO_WAPI_SUPPORT is not set CONFIG_XRADIO_USE_EXTENSIONS=y +CONFIG_RTL8812AU=m CONFIG_WLAN_VENDOR_ZYDAS=y # CONFIG_USB_ZD1201 is not set # CONFIG_ZD1211RW is not set diff --git a/config/kernel/linux-sunxi-legacy.config b/config/kernel/linux-sunxi-legacy.config index 251cbc9e8..b9f64dfdf 100644 --- a/config/kernel/linux-sunxi-legacy.config +++ b/config/kernel/linux-sunxi-legacy.config @@ -1,13 +1,13 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 4.19.72 Kernel Configuration +# Linux/arm 4.19.88 Kernel Configuration # # -# Compiler: arm-linux-gnueabihf-gcc (Linaro GCC 7.4-2019.02) 7.4.1 20181213 [linaro-7.4-2019.02 revision 56ec6f6b99cc167ff0c2f8e1a2eed33b1edc85d4] +# Compiler: arm-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 8.3-2019.03 (arm-rel-8.36)) 8.3.0 # CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=70401 +CONFIG_GCC_VERSION=80300 CONFIG_CLANG_VERSION=0 CONFIG_CC_HAS_ASM_GOTO=y CONFIG_IRQ_WORK=y @@ -2429,7 +2429,7 @@ CONFIG_WLAN_VENDOR_TI=y # CONFIG_WL18XX is not set # CONFIG_WLCORE is not set CONFIG_RTL8822BU=m -CONFIG_RTL8188EU=m +CONFIG_RTL8188EUS=m CONFIG_RTL8812AU=m CONFIG_WLAN_VENDOR_XRADIO=m CONFIG_XRADIO_NON_POWER_OF_TWO_BLOCKSIZES=y @@ -4179,10 +4179,10 @@ CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y # # Frame buffer Devices # -CONFIG_FB=y -# CONFIG_FIRMWARE_EDID is not set CONFIG_FB_CMDLINE=y CONFIG_FB_NOTIFY=y +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y @@ -4795,7 +4795,6 @@ CONFIG_USB_SERIAL_DEBUG=m # CONFIG_USB_EMI26 is not set # CONFIG_USB_ADUTUX is not set # CONFIG_USB_SEVSEG is not set -# CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_CYPRESS_CY7C63 is not set @@ -5370,7 +5369,6 @@ CONFIG_ARM_SMMU=y # Rpmsg drivers # # CONFIG_RPMSG_VIRTIO is not set -# CONFIG_SOUNDWIRE is not set # # SOC (System On Chip) specific Drivers diff --git a/lib/compilation-prepare.sh b/lib/compilation-prepare.sh index ad42e0e53..a4d4d77ef 100644 --- a/lib/compilation-prepare.sh +++ b/lib/compilation-prepare.sh @@ -152,12 +152,34 @@ compilation_prepare() fi + # Wireless drivers for Xradio XR819 chipsets + if linux-version compare $version ge 3.14 && [ "$EXTRAWIFI" == yes ]; then + display_alert "Adding" "Wireless drivers for Xradio XR819 chipsets" "info" + fetch_from_repo "https://github.com/karabek/xradio" "xradio" "branch:master" "yes" + cd ${SRC}/cache/sources/${LINUXSOURCEDIR} + rm -rf ${SRC}/cache/sources/${LINUXSOURCEDIR}/drivers/net/wireless/xradio + mkdir -p ${SRC}/cache/sources/${LINUXSOURCEDIR}/drivers/net/wireless/xradio/ + cp ${SRC}/cache/sources/xradio/master/*.{h,c} \ + ${SRC}/cache/sources/${LINUXSOURCEDIR}/drivers/net/wireless/xradio/ + + # Makefile + cp ${SRC}/cache/sources/xradio/master/Makefile \ + ${SRC}/cache/sources/${LINUXSOURCEDIR}/drivers/net/wireless/xradio/Makefile + cp ${SRC}/cache/sources/xradio/master/Kconfig \ + ${SRC}/cache/sources/${LINUXSOURCEDIR}/drivers/net/wireless/xradio/Kconfig + + # Add to section Makefile + echo "obj-\$(CONFIG_WLAN_VENDOR_XRADIO) += xradio/" >> $SRC/cache/sources/${LINUXSOURCEDIR}/drivers/net/wireless/Makefile + sed -i '/source "drivers\/net\/wireless\/ti\/Kconfig"/a source "drivers\/net\/wireless\/xradio\/Kconfig"' \ + $SRC/cache/sources/${LINUXSOURCEDIR}/drivers/net/wireless/Kconfig + + fi # Wireless drivers for Realtek 8188EU 8188EUS and 8188ETV chipsets - if linux-version compare $version ge 3.14 && [ "$EXTRAWIFI" == yes ]; then + if linux-version compare $version ge 3.14 && [ "$LINUXFAMILY" == sunxi ] && [ "$EXTRAWIFI" == yes ]; then # attach to specifics tag or branch local rtl8811euver="branch:v5.3.9" diff --git a/patch/kernel/sunxi-current/wifi-add-xradio.patch b/patch/kernel/sunxi-current/wifi-add-xradio.patch deleted file mode 100644 index edf765e6d..000000000 --- a/patch/kernel/sunxi-current/wifi-add-xradio.patch +++ /dev/null @@ -1,18814 +0,0 @@ -diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig -index b84d8a3..7779c1d 100644 ---- a/drivers/net/wireless/Kconfig -+++ b/drivers/net/wireless/Kconfig -@@ -48,6 +48,7 @@ source "drivers/net/wireless/realtek/Kconfig" - source "drivers/net/wireless/rsi/Kconfig" - source "drivers/net/wireless/st/Kconfig" - source "drivers/net/wireless/ti/Kconfig" -+source "drivers/net/wireless/xradio/Kconfig" - source "drivers/net/wireless/zydas/Kconfig" - source "drivers/net/wireless/quantenna/Kconfig" - -diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile -index 1681dbc..ab14e53 100644 ---- a/drivers/net/wireless/Makefile -+++ b/drivers/net/wireless/Makefile -@@ -21,6 +21,7 @@ obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/ - obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/ - obj-$(CONFIG_WLAN_VENDOR_ST) += st/ - obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ -+obj-$(CONFIG_WLAN_VENDOR_XRADIO) += xradio/ - obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ - obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/ - -diff --git a/drivers/net/wireless/xradio/.7z b/drivers/net/wireless/xradio/.7z -new file mode 100644 -index 0000000..4f8fc9c -Binary files /dev/null and b/drivers/net/wireless/xradio/.7z differ -diff --git a/drivers/net/wireless/xradio/Kconfig b/drivers/net/wireless/xradio/Kconfig -new file mode 100644 -index 0000000..d3925ec ---- /dev/null -+++ b/drivers/net/wireless/xradio/Kconfig -@@ -0,0 +1,49 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+ -+config WLAN_VENDOR_XRADIO -+ tristate "XRADIO WLAN support" -+ depends on MAC80211 -+ default y -+ ---help--- -+ If you have a wireless card belonging to this class, say Y. -+ -+ Note that the answer to this question doesn't directly affect the -+ kernel: saying N will just cause the configurator to skip all -+ the questions about cards. If you say Y, you will be asked for -+ your specific card in the following questions. -+ -+if WLAN_VENDOR_XRADIO -+ -+config XRADIO_NON_POWER_OF_TWO_BLOCKSIZES -+ bool "Platform supports non-power-of-two SDIO transfer" -+ depends on WLAN_VENDOR_XRADIO -+ default y -+ ---help--- -+ Say N here only if you are running the driver on a platform -+ which does not have support for non-power-of-two SDIO transfer. -+ If unsure, say Y. -+ -+config XRADIO_5GHZ_SUPPORT -+ bool "5GHz band support" -+ depends on WLAN_VENDOR_XRADIO -+ default n -+ ---help--- -+ Say Y if your device supports 5GHz band. If unsure, say N. -+ -+config XRADIO_WAPI_SUPPORT -+ bool "WAPI support" -+ depends on WLAN_VENDOR_XRADIO -+ default n -+ ---help--- -+ Say Y if your compat-wireless support WAPI. -+ If unsure, say N. -+ -+config XRADIO_USE_EXTENSIONS -+ bool "Extensions for WFD and PS mode" -+ depends on WLAN_VENDOR_XRADIO -+ default y -+ ---help--- -+ Say Y if you want to include XR extensions -+ If unsure, say Y. -+ -+endif # WLAN_VENDOR_XRADIO -diff --git a/drivers/net/wireless/xradio/LICENSE b/drivers/net/wireless/xradio/LICENSE -new file mode 100644 -index 0000000..23cb790 ---- /dev/null -+++ b/drivers/net/wireless/xradio/LICENSE -@@ -0,0 +1,339 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Lesser General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ {description} -+ Copyright (C) {year} {fullname} -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License along -+ with this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) year name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ {signature of Ty Coon}, 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Lesser General -+Public License instead of this License. -diff --git a/drivers/net/wireless/xradio/Makefile b/drivers/net/wireless/xradio/Makefile -new file mode 100644 -index 0000000..3e7e5ed ---- /dev/null -+++ b/drivers/net/wireless/xradio/Makefile -@@ -0,0 +1,57 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+ -+# Standalone Makefile - uncomment for out-of-tree compilation -+#CONFIG_WLAN_VENDOR_XRADIO := m -+#CONFIG_XRADIO_USE_EXTENSIONS := y -+#CONFIG_XRADIO_WAPI_SUPPORT := n -+ -+# Kernel part -+ -+obj-$(CONFIG_WLAN_VENDOR_XRADIO) += xradio_wlan.o -+ -+xradio_wlan-objs := \ -+ fwio.o \ -+ tx.o \ -+ rx.o \ -+ main.o \ -+ queue.o \ -+ hwio.o \ -+ bh.o \ -+ wsm.o \ -+ sta.o \ -+ ap.o \ -+ keys.o \ -+ scan.o \ -+ module.o \ -+ sdio.o \ -+ pm.o \ -+ ht.o \ -+ p2p.o -+ -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DMCAST_FWDING -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DXRADIO_SUSPEND_RESUME_FILTER_ENABLE -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DAP_AGGREGATE_FW_FIX -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DAP_HT_CAP_UPDATE -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DAP_HT_COMPAT_FIX -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DCONFIG_XRADIO_DUMP_ON_ERROR -+ -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DCONFIG_XRADIO_SUSPEND_POWER_OFF -+ -+# Extra IE for probe response from upper layer is needed in P2P GO -+# For offloading probe response to FW, the extra IE must be included -+# in the probe response template -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DPROBE_RESP_EXTRA_IE -+ -+# Modified by wzw -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DTES_P2P_0002_ROC_RESTART -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DTES_P2P_000B_EXTEND_INACTIVITY_CNT -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DTES_P2P_000B_DISABLE_EAPOL_FILTER -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DXRADIO_USE_LONG_DTIM_PERIOD -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DXRADIO_USE_LONG_KEEP_ALIVE_PERIOD -+ -+#ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DDEBUG -+#ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DXRADIO_DISABLE_HW_CRYPTO -+ -+# <5.3> -+#ldflags-$(CONFIG_WLAN_VENDOR_XRADIO) += --strip-debug -+ -diff --git a/drivers/net/wireless/xradio/ap.c b/drivers/net/wireless/xradio/ap.c -new file mode 100644 -index 0000000..5276c5a ---- /dev/null -+++ b/drivers/net/wireless/xradio/ap.c -@@ -0,0 +1,1624 @@ -+/* -+ * STA and AP APIs for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "xradio.h" -+#include "sta.h" -+#include "ap.h" -+#include "bh.h" -+#include "net/mac80211.h" -+ -+#define XRADIO_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ)) -+#define XRADIO_ENABLE_ARP_FILTER_OFFLOAD 3 -+ -+#ifndef ERP_INFO_BYTE_OFFSET -+#define ERP_INFO_BYTE_OFFSET 2 -+#endif -+ -+static int xradio_upload_beacon(struct xradio_vif *priv); -+#ifdef PROBE_RESP_EXTRA_IE -+static int xradio_upload_proberesp(struct xradio_vif *priv); -+#endif -+static int xradio_upload_pspoll(struct xradio_vif *priv); -+static int xradio_upload_null(struct xradio_vif *priv); -+static int xradio_upload_qosnull(struct xradio_vif *priv); -+static int xradio_start_ap(struct xradio_vif *priv); -+static int xradio_update_beaconing(struct xradio_vif *priv); -+/* -+static int xradio_enable_beaconing(struct xradio_vif *priv, -+ bool enable); -+*/ -+static void __xradio_sta_notify(struct xradio_vif *priv, -+ enum sta_notify_cmd notify_cmd, -+ int link_id); -+ -+/* ******************************************************************** */ -+/* AP API */ -+int xradio_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta) -+{ -+ struct xradio_sta_priv *sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct xradio_link_entry *entry; -+ struct sk_buff *skb; -+#ifdef AP_AGGREGATE_FW_FIX -+ struct xradio_common *hw_priv = hw->priv; -+#endif -+ -+ if (priv->mode != NL80211_IFTYPE_AP) { -+ return 0; -+ } -+ -+ sta_priv->priv = priv; -+ sta_priv->link_id = xradio_find_link_id(priv, sta->addr); -+ if (WARN_ON(!sta_priv->link_id)) { -+ /* Impossible error */ -+ wiphy_debug(hw->wiphy, "No more link IDs available.\n"); -+ return -ENOENT; -+ } -+ -+ entry = &priv->link_id_db[sta_priv->link_id - 1]; -+ spin_lock_bh(&priv->ps_state_lock); -+ if ((sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) == -+ IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) { -+ priv->sta_asleep_mask |= BIT(sta_priv->link_id); -+ } -+ entry->status = XRADIO_LINK_HARD; -+ while ((skb = skb_dequeue(&entry->rx_queue))) -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+#ifdef AP_AGGREGATE_FW_FIX -+ hw_priv->connected_sta_cnt++; -+ if(hw_priv->connected_sta_cnt>1) { -+ wsm_lock_tx(hw_priv); -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_DISABLED_FOR_ALL_TID, -+ XRADIO_RX_BLOCK_ACK_DISABLED_FOR_ALL_TID, -+ priv->if_id)); -+ wsm_unlock_tx(hw_priv); -+ } -+#endif -+ -+ return 0; -+} -+ -+int xradio_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_sta_priv *sta_priv = -+ (struct xradio_sta_priv *)&sta->drv_priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct xradio_link_entry *entry; -+ -+ if (priv->mode != NL80211_IFTYPE_AP || !sta_priv->link_id) { -+ wiphy_warn(hw->wiphy, "no station to remove\n"); -+ return 0; -+ } -+ -+ entry = &priv->link_id_db[sta_priv->link_id - 1]; -+ spin_lock_bh(&priv->ps_state_lock); -+ entry->status = XRADIO_LINK_RESERVE; -+ entry->timestamp = jiffies; -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->link_id_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ spin_unlock_bh(&priv->ps_state_lock); -+ flush_workqueue(hw_priv->workqueue); -+ -+#ifdef AP_AGGREGATE_FW_FIX -+ hw_priv->connected_sta_cnt--; -+ if(hw_priv->connected_sta_cnt <= 1) { -+ if ((priv->if_id != 1) || -+ ((priv->if_id == 1) && hw_priv->is_go_thru_go_neg)) { -+ wsm_lock_tx(hw_priv); -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID, -+ XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID, -+ priv->if_id)); -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+#endif -+ -+ return 0; -+} -+ -+static void __xradio_sta_notify(struct xradio_vif *priv, -+ enum sta_notify_cmd notify_cmd, -+ int link_id) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u32 bit, prev; -+ -+ /* Zero link id means "for all link IDs" */ -+ if (link_id) -+ bit = BIT(link_id); -+ else if (WARN_ON_ONCE(notify_cmd != STA_NOTIFY_AWAKE)) -+ bit = 0; -+ else -+ bit = priv->link_id_map; -+ prev = priv->sta_asleep_mask & bit; -+ -+ switch (notify_cmd) { -+ case STA_NOTIFY_SLEEP: -+ if (!prev) { -+ if (priv->buffered_multicasts && -+ !priv->sta_asleep_mask) -+ queue_work(hw_priv->workqueue, -+ &priv->multicast_start_work); -+ priv->sta_asleep_mask |= bit; -+ } -+ break; -+ case STA_NOTIFY_AWAKE: -+ if (prev) { -+ priv->sta_asleep_mask &= ~bit; -+ priv->pspoll_mask &= ~bit; -+ if (priv->tx_multicast && link_id && -+ !priv->sta_asleep_mask) -+ queue_work(hw_priv->workqueue, -+ &priv->multicast_stop_work); -+ xradio_bh_wakeup(hw_priv); -+ } -+ break; -+ } -+} -+ -+void xradio_sta_notify(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ enum sta_notify_cmd notify_cmd, -+ struct ieee80211_sta *sta) -+{ -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct xradio_sta_priv *sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ __xradio_sta_notify(priv, notify_cmd, sta_priv->link_id); -+ spin_unlock_bh(&priv->ps_state_lock); -+} -+ -+static void xradio_ps_notify(struct xradio_vif *priv, -+ int link_id, bool ps) -+{ -+ if (link_id > MAX_STA_IN_AP_MODE) { -+ ap_printk(XRADIO_DBG_WARN,"link_id is invalid=%d\n", link_id); -+ return; -+ } -+ -+ ap_printk(XRADIO_DBG_NIY, "%s for LinkId: %d. STAs asleep: %.8X\n", -+ ps ? "Stop" : "Start", link_id, priv->sta_asleep_mask); -+ -+ /* TODO:COMBO: __xradio_sta_notify changed. */ -+ __xradio_sta_notify(priv, ps ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE, link_id); -+} -+ -+static int xradio_set_tim_impl(struct xradio_vif *priv, bool aid0_bit_set) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct sk_buff *skb; -+ struct wsm_update_ie update_ie = { -+ .what = WSM_UPDATE_IE_BEACON, -+ .count = 1, -+ }; -+ u16 tim_offset, tim_length; -+ ap_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ ap_printk(XRADIO_DBG_MSG, "%s mcast: %s.\n", __func__, -+ aid0_bit_set ? "ena" : "dis"); -+ -+ skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, &tim_offset, &tim_length); -+ if (!skb) { -+ __xradio_flush(hw_priv, true, priv->if_id); -+ return -ENOENT; -+ } -+ -+ if (tim_offset && tim_length >= 6) { -+ /* Ignore DTIM count from mac80211: -+ * firmware handles DTIM internally. */ -+ skb->data[tim_offset + 2] = 0; -+ -+ /* Set/reset aid0 bit */ -+ if (aid0_bit_set) -+ skb->data[tim_offset + 4] |= 1; -+ else -+ skb->data[tim_offset + 4] &= ~1; -+ } -+ -+ update_ie.ies = &skb->data[tim_offset]; -+ update_ie.length = tim_length; -+ //filter same tim info, yangfh -+ if(memcmp(priv->last_tim, update_ie.ies, tim_length)) { -+ WARN_ON(wsm_update_ie(hw_priv, &update_ie, priv->if_id)); -+ memcpy(priv->last_tim, update_ie.ies, tim_length); -+ ap_printk(XRADIO_DBG_MSG,"%02x %02x %02x %02x %02x %02x\n", -+ update_ie.ies[0], update_ie.ies[1], update_ie.ies[2], -+ update_ie.ies[3], update_ie.ies[4], update_ie.ies[5]); -+ } -+ -+ dev_kfree_skb(skb); -+ -+ return 0; -+} -+ -+void xradio_set_tim_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = container_of(work, struct xradio_vif, set_tim_work); -+ xradio_set_tim_impl(priv, priv->aid0_bit_set); -+} -+ -+int xradio_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, -+ bool set) -+{ -+ struct xradio_sta_priv *sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; -+ struct xradio_vif *priv = sta_priv->priv; -+ -+ WARN_ON(priv->mode != NL80211_IFTYPE_AP); -+ queue_work(priv->hw_priv->workqueue, &priv->set_tim_work); -+ return 0; -+} -+ -+void xradio_set_cts_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, set_cts_work.work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u8 erp_ie[3] = {WLAN_EID_ERP_INFO, 0x1, 0}; -+ struct wsm_update_ie update_ie = { -+ .what = WSM_UPDATE_IE_BEACON, -+ .count = 1, -+ .ies = erp_ie, -+ .length = 3, -+ }; -+ u32 erp_info; -+ __le32 use_cts_prot; -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ erp_info = priv->erp_info; -+ mutex_unlock(&hw_priv->conf_mutex); -+ use_cts_prot = (erp_info & WLAN_ERP_USE_PROTECTION)? __cpu_to_le32(1) : 0; -+ -+ erp_ie[ERP_INFO_BYTE_OFFSET] = erp_info; -+ -+ ap_printk(XRADIO_DBG_MSG, "ERP information 0x%x\n", erp_info); -+ -+ /* TODO:COMBO: If 2 interfaces are on the same channel they share -+ the same ERP values */ -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_NON_ERP_PROTECTION, -+ &use_cts_prot, sizeof(use_cts_prot), priv->if_id)); -+ /* If STA Mode update_ie is not required */ -+ if (priv->mode != NL80211_IFTYPE_STATION) { -+ WARN_ON(wsm_update_ie(hw_priv, &update_ie, priv->if_id)); -+ } -+ -+ return; -+} -+ -+static int xradio_set_btcoexinfo(struct xradio_vif *priv) -+{ -+ struct wsm_override_internal_txrate arg; -+ int ret = 0; -+ -+ if (priv->mode == NL80211_IFTYPE_STATION) { -+ /* Plumb PSPOLL and NULL template */ -+ WARN_ON(xradio_upload_pspoll(priv)); -+ WARN_ON(xradio_upload_null(priv)); -+ } else { -+ return 0; -+ } -+ -+ memset(&arg, 0, sizeof(struct wsm_override_internal_txrate)); -+ -+ if (!priv->vif->p2p) { -+ /* STATION mode */ -+ if (priv->bss_params.operationalRateSet & ~0xF) { -+ ap_printk(XRADIO_DBG_NIY, "STA has ERP rates\n"); -+ /* G or BG mode */ -+ arg.internalTxRate = (__ffs( -+ priv->bss_params.operationalRateSet & ~0xF)); -+ } else { -+ ap_printk(XRADIO_DBG_NIY, "STA has non ERP rates\n"); -+ /* B only mode */ -+ arg.internalTxRate = (__ffs( -+ priv->association_mode.basicRateSet)); -+ } -+ arg.nonErpInternalTxRate = (__ffs( -+ priv->association_mode.basicRateSet)); -+ } else { -+ /* P2P mode */ -+ arg.internalTxRate = (__ffs( -+ priv->bss_params.operationalRateSet & ~0xF)); -+ arg.nonErpInternalTxRate = (__ffs( -+ priv->bss_params.operationalRateSet & ~0xF)); -+ } -+ -+ ap_printk(XRADIO_DBG_NIY, "BTCOEX_INFO" "MODE %d, internalTxRate : %x," -+ "nonErpInternalTxRate: %x\n", priv->mode, arg.internalTxRate, -+ arg.nonErpInternalTxRate); -+ -+ ret = WARN_ON(wsm_write_mib(xrwl_vifpriv_to_hwpriv(priv), -+ WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, -+ &arg, sizeof(arg), priv->if_id)); -+ -+ return ret; -+} -+ -+void xradio_bss_info_changed(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ struct ieee80211_bss_conf *info, -+ u32 changed) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ if (changed & BSS_CHANGED_BSSID) { -+ memcpy(priv->bssid, info->bssid, ETH_ALEN); -+ xradio_setup_mac_pvif(priv); -+ } -+ -+ /* TODO: BSS_CHANGED_IBSS */ -+ if (changed & BSS_CHANGED_ARP_FILTER) { -+ struct wsm_arp_ipv4_filter filter = {0}; -+ int i; -+ ap_printk(XRADIO_DBG_MSG, "[STA] BSS_CHANGED_ARP_FILTER cnt: %d\n", -+ info->arp_addr_cnt); -+ -+ if (info->arp_addr_cnt){ -+ if (vif->type == NL80211_IFTYPE_STATION) -+ filter.enable = (u32)XRADIO_ENABLE_ARP_FILTER_OFFLOAD; -+ else if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ filter.enable = (u32)(1<<1); -+ else -+ filter.enable = 0; -+ } -+ -+ /* Currently only one IP address is supported by firmware. -+ * In case of more IPs arp filtering will be disabled. */ -+ if (info->arp_addr_cnt > 0 && -+ info->arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { -+ for (i = 0; i < info->arp_addr_cnt; i++) { -+ filter.ipv4Address[i] = info->arp_addr_list[i]; -+ ap_printk(XRADIO_DBG_NIY, "[STA]addr[%d]: 0x%X\n", i, filter.ipv4Address[i]); -+ } -+ } else -+ filter.enable = 0; -+ -+ if (filter.enable) -+ xradio_set_arpreply(dev, vif); -+ -+ priv->filter4.enable = filter.enable; -+ ap_printk(XRADIO_DBG_NIY, "[STA]arp ip filter enable: %d\n", __le32_to_cpu(filter.enable)); -+ -+ if (wsm_set_arp_ipv4_filter(hw_priv, &filter, priv->if_id)) -+ WARN_ON(1); -+ -+ if (filter.enable && -+ (priv->join_status == XRADIO_JOIN_STATUS_STA)) { -+ /* Firmware requires that value for this 1-byte field must -+ * be specified in units of 500us. Values above the 128ms -+ * threshold are not supported. */ -+ //if (info->dynamic_ps_timeout >= 0x80) -+ // priv->powersave_mode.fastPsmIdlePeriod = 0xFF; -+ //else -+ // priv->powersave_mode.fastPsmIdlePeriod = info->dynamic_ps_timeout << 1; -+ -+ priv->powersave_mode.fastPsmIdlePeriod = 200;//when connected,the dev->conf.dynamic_ps_timeout value is 0 -+ priv->powersave_mode.apPsmChangePeriod = 200; //100ms, add by yangfh -+ ap_printk(XRADIO_DBG_NIY, "[STA]fastPsmIdle=%d, apPsmChange=%d\n", -+ priv->powersave_mode.fastPsmIdlePeriod, -+ priv->powersave_mode.apPsmChangePeriod); -+ -+ if (priv->setbssparams_done) { -+ int ret = 0; -+ struct wsm_set_pm pm = priv->powersave_mode; -+ if (priv->user_power_set_true) -+ priv->powersave_mode.pmMode = priv->user_pm_mode; -+ else if ((priv->power_set_true && -+ ((priv->powersave_mode.pmMode == WSM_PSM_ACTIVE) || -+ (priv->powersave_mode.pmMode == WSM_PSM_PS))) || -+ !priv->power_set_true) -+ priv->powersave_mode.pmMode = WSM_PSM_FAST_PS; -+ -+ ret = xradio_set_pm (priv, &priv->powersave_mode); -+ if(ret) -+ priv->powersave_mode = pm; -+ } else { -+ priv->powersave_mode.pmMode = WSM_PSM_FAST_PS; -+ } -+ priv->power_set_true = 0; -+ priv->user_power_set_true = 0; -+ } -+ } -+ -+ if (changed & BSS_CHANGED_BEACON) { -+ ap_printk(XRADIO_DBG_NIY, "BSS_CHANGED_BEACON\n"); -+#ifdef HIDDEN_SSID -+ if(priv->join_status != XRADIO_JOIN_STATUS_AP) { -+ priv->hidden_ssid = info->hidden_ssid; -+ priv->ssid_length = info->ssid_len; -+ memcpy(priv->ssid, info->ssid, info->ssid_len); -+ } else -+ ap_printk(XRADIO_DBG_NIY, "priv->join_status=%d\n", priv->join_status); -+#endif -+ WARN_ON(xradio_upload_beacon(priv)); -+ WARN_ON(xradio_update_beaconing(priv)); -+ } -+ -+ if (changed & BSS_CHANGED_BEACON_ENABLED) { -+ ap_printk(XRADIO_DBG_NIY, "BSS_CHANGED_BEACON_ENABLED dummy\n"); -+ priv->enable_beacon = info->enable_beacon; -+ } -+ -+ if (changed & BSS_CHANGED_BEACON_INT) { -+ ap_printk(XRADIO_DBG_NIY, "CHANGED_BEACON_INT\n"); -+ /* Restart AP only when connected */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(xradio_update_beaconing(priv)); -+ } -+ -+ -+ if (changed & BSS_CHANGED_ASSOC) { -+ wsm_lock_tx(hw_priv); -+ priv->wep_default_key_id = -1; -+ wsm_unlock_tx(hw_priv); -+ -+ if (!info->assoc /* && !info->ibss_joined */) { -+ priv->cqm_link_loss_count = XRADIO_LINK_LOSS_THOLD_DEF; -+ priv->cqm_beacon_loss_count = XRADIO_BSS_LOSS_THOLD_DEF; -+ priv->cqm_tx_failure_thold = 0; -+ } -+ priv->cqm_tx_failure_count = 0; -+ } -+ -+ if (changed & -+ (BSS_CHANGED_ASSOC | -+ BSS_CHANGED_BASIC_RATES | -+ BSS_CHANGED_ERP_PREAMBLE | -+ BSS_CHANGED_HT | -+ BSS_CHANGED_ERP_SLOT)) { -+ int is_combo = 0; -+ int i; -+ struct xradio_vif *tmp_priv; -+ ap_printk(XRADIO_DBG_NIY, "BSS_CHANGED_ASSOC.\n"); -+ if (info->assoc) { /* TODO: ibss_joined */ -+ struct ieee80211_sta *sta = NULL; -+ if (info->dtim_period) -+ priv->join_dtim_period = info->dtim_period; -+ priv->beacon_int = info->beacon_int; -+ -+ /* Associated: kill join timeout */ -+ cancel_delayed_work_sync(&priv->join_timeout); -+ -+ rcu_read_lock(); -+ if (info->bssid) -+ sta = ieee80211_find_sta(vif, info->bssid); -+ if (sta) { -+ /* TODO:COMBO:Change this once -+ * mac80211 changes are available */ -+ BUG_ON(!hw_priv->channel); -+ hw_priv->ht_oper.ht_cap = sta->ht_cap; -+ priv->bss_params.operationalRateSet =__cpu_to_le32( -+ xradio_rate_mask_to_wsm(hw_priv, sta->supp_rates[hw_priv->channel->band])); -+ /* TODO by Icenowy: I think this may lead to some problems. */ -+// hw_priv->ht_oper.channel_type = info->channel_type; -+ hw_priv->ht_oper.operation_mode = info->ht_operation_mode; -+ } else { -+ memset(&hw_priv->ht_oper, 0, sizeof(hw_priv->ht_oper)); -+ priv->bss_params.operationalRateSet = -1; -+ } -+ rcu_read_unlock(); -+ priv->htcap = (sta && xradio_is_ht(&hw_priv->ht_oper)); -+ xradio_for_each_vif(hw_priv, tmp_priv, i) { -+ if (!tmp_priv) -+ continue; -+ if (tmp_priv->join_status >= XRADIO_JOIN_STATUS_STA) -+ is_combo++; -+ } -+ -+ if (is_combo > 1) { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ ap_printk(XRADIO_DBG_WARN, "%sASSOC is_combo %d\n", -+ (priv->join_status == XRADIO_JOIN_STATUS_STA)?"[STA] ":"", -+ hw_priv->vif0_throttle); -+ } else if ((priv->join_status == XRADIO_JOIN_STATUS_STA) && priv->htcap) { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11N_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11N_THROTTLE; -+ ap_printk(XRADIO_DBG_WARN, "[STA] ASSOC HTCAP 11N %d\n",hw_priv->vif0_throttle); -+ } else { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ ap_printk(XRADIO_DBG_WARN, "ASSOC not_combo 11BG %d\n",hw_priv->vif0_throttle); -+ } -+ -+ if (sta) { -+ __le32 val = 0; -+ if (hw_priv->ht_oper.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) { -+ ap_printk(XRADIO_DBG_NIY,"[STA] Non-GF STA present\n"); -+ /* Non Green field capable STA */ -+ val = __cpu_to_le32(BIT(1)); -+ } -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MID_ID_SET_HT_PROTECTION, -+ &val, sizeof(val), priv->if_id)); -+ } -+ -+ priv->association_mode.greenfieldMode = xradio_ht_greenfield(&hw_priv->ht_oper); -+ priv->association_mode.flags = -+ WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES | -+ WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE | -+ WSM_ASSOCIATION_MODE_USE_HT_MODE | -+ WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET | -+ WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING; -+ -+ priv->association_mode.preambleType = -+ (info->use_short_preamble ? WSM_JOIN_PREAMBLE_SHORT : WSM_JOIN_PREAMBLE_LONG); -+ priv->association_mode.basicRateSet = __cpu_to_le32( -+ xradio_rate_mask_to_wsm(hw_priv,info->basic_rates)); -+ priv->association_mode.mpduStartSpacing = -+ xradio_ht_ampdu_density(&hw_priv->ht_oper); -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //priv->cqm_beacon_loss_count = info->cqm_beacon_miss_thold; -+ //priv->cqm_tx_failure_thold = info->cqm_tx_fail_thold; -+ //priv->cqm_tx_failure_count = 0; -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ -+ priv->bss_params.beaconLostCount = (priv->cqm_beacon_loss_count ? -+ priv->cqm_beacon_loss_count : priv->cqm_link_loss_count); -+ -+ priv->bss_params.aid = info->aid; -+ -+ if (priv->join_dtim_period < 1) -+ priv->join_dtim_period = 1; -+ -+ ap_printk(XRADIO_DBG_MSG, "[STA] DTIM %d, interval: %d\n", -+ priv->join_dtim_period, priv->beacon_int); -+ ap_printk(XRADIO_DBG_MSG, "[STA] Preamble: %d, " \ -+ "Greenfield: %d, Aid: %d, Rates: 0x%.8X, Basic: 0x%.8X\n", -+ priv->association_mode.preambleType, -+ priv->association_mode.greenfieldMode, -+ priv->bss_params.aid, -+ priv->bss_params.operationalRateSet, -+ priv->association_mode.basicRateSet); -+ WARN_ON(wsm_set_association_mode(hw_priv, &priv->association_mode, priv->if_id)); -+ WARN_ON(wsm_keep_alive_period(hw_priv, XRADIO_KEEP_ALIVE_PERIOD /* sec */, -+ priv->if_id)); -+ WARN_ON(wsm_set_bss_params(hw_priv, &priv->bss_params, priv->if_id)); -+ priv->setbssparams_done = true; -+#ifdef XRADIO_USE_LONG_DTIM_PERIOD -+{ -+ int join_dtim_period_extend; -+ if (priv->join_dtim_period <= 3) { -+ join_dtim_period_extend = priv->join_dtim_period * 3; -+ } else if (priv->join_dtim_period <= 5) { -+ join_dtim_period_extend = priv->join_dtim_period * 2; -+ } else { -+ join_dtim_period_extend = priv->join_dtim_period; -+ } -+ WARN_ON(wsm_set_beacon_wakeup_period(hw_priv, -+ ((priv->beacon_int * join_dtim_period_extend) > MAX_BEACON_SKIP_TIME_MS -+ ? 1 : join_dtim_period_extend) , 0, priv->if_id)); -+} -+#else -+ WARN_ON(wsm_set_beacon_wakeup_period(hw_priv, -+ ((priv->beacon_int * priv->join_dtim_period) > MAX_BEACON_SKIP_TIME_MS -+ ? 1 : priv->join_dtim_period) , 0, priv->if_id)); -+#endif -+ if (priv->htcap) { -+ wsm_lock_tx(hw_priv); -+ /* Statically enabling block ack for TX/RX */ -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, hw_priv->ba_tid_mask, -+ hw_priv->ba_tid_mask, priv->if_id)); -+ wsm_unlock_tx(hw_priv); -+ } -+ /*set ps active,avoid that when connecting process,the device sleeps,then can't receive pkts.*/ -+ if (changed & BSS_CHANGED_ASSOC) -+ priv->powersave_mode.pmMode = WSM_PSM_ACTIVE; -+ xradio_set_pm(priv, &priv->powersave_mode); -+ if (priv->vif->p2p) { -+ ap_printk(XRADIO_DBG_NIY, "[STA] Setting p2p powersave configuration.\n"); -+ WARN_ON(wsm_set_p2p_ps_modeinfo(hw_priv, &priv->p2p_ps_modeinfo, priv->if_id)); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //xradio_notify_noa(priv, XRADIO_NOA_NOTIFICATION_DELAY); -+#endif -+ } -+ -+ if (priv->mode == NL80211_IFTYPE_STATION) -+ WARN_ON(xradio_upload_qosnull(priv)); -+ -+ if (hw_priv->is_BT_Present) -+ WARN_ON(xradio_set_btcoexinfo(priv)); -+#if 0 -+ /* It's better to override internal TX rete; otherwise -+ * device sends RTS at too high rate. However device -+ * can't receive CTS at 1 and 2 Mbps. Well, 5.5 is a -+ * good choice for RTS/CTS, but that means PS poll -+ * will be sent at the same rate - impact on link -+ * budget. Not sure what is better.. */ -+ -+ /* Update: internal rate selection algorythm is not -+ * bad: if device is not receiving CTS at high rate, -+ * it drops RTS rate. -+ * So, conclusion: if-0 the code. Keep code just for -+ * information: -+ * Do not touch WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE! */ -+ -+ /* ~3 is a bug in device: RTS/CTS is not working at -+ * low rates */ -+ __le32 internal_tx_rate = __cpu_to_le32( -+ __ffs(priv->association_mode.basicRateSet & ~3)); -+ WARN_ON(wsm_write_mib(priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, -+ &internal_tx_rate,sizeof(internal_tx_rate))); -+#endif -+ } else { -+ memset(&priv->association_mode, 0, sizeof(priv->association_mode)); -+ memset(&priv->bss_params, 0, sizeof(priv->bss_params)); -+ } -+ } -+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT)) { -+ u32 prev_erp_info = priv->erp_info; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ if (info->use_cts_prot) -+ priv->erp_info |= WLAN_ERP_USE_PROTECTION; -+ else if (!(prev_erp_info & WLAN_ERP_NON_ERP_PRESENT)) -+ priv->erp_info &= ~WLAN_ERP_USE_PROTECTION; -+ -+ if (prev_erp_info != priv->erp_info) -+ queue_delayed_work(hw_priv->workqueue, &priv->set_cts_work, 0*HZ); -+ } -+ } -+ -+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_SLOT)) { -+ __le32 slot_time = info->use_short_slot ? __cpu_to_le32(9) : __cpu_to_le32(20); -+ ap_printk(XRADIO_DBG_MSG, "[STA] Slot time :%d us.\n", __le32_to_cpu(slot_time)); -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_SLOT_TIME, &slot_time, -+ sizeof(slot_time), priv->if_id)); -+ } -+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_CQM)) { -+ struct wsm_rcpi_rssi_threshold threshold = { -+ .rollingAverageCount = 8, -+ }; -+ -+#if 0 -+ /* For verification purposes */ -+ info->cqm_rssi_thold = -50; -+ info->cqm_rssi_hyst = 4; -+#endif /* 0 */ -+ -+ ap_printk(XRADIO_DBG_NIY, "[CQM] RSSI threshold subscribe: %d(+-%d)\n", -+ info->cqm_rssi_thold, info->cqm_rssi_hyst); -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ priv->cqm_rssi_thold = info->cqm_rssi_thold; -+ priv->cqm_rssi_hyst = info->cqm_rssi_hyst; -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ -+ if (info->cqm_rssi_thold || info->cqm_rssi_hyst) { -+ /* RSSI subscription enabled */ -+ /* TODO: It's not a correct way of setting threshold. -+ * Upper and lower must be set equal here and adjusted -+ * in callback. However current implementation is much -+ * more relaible and stable. */ -+ if (priv->cqm_use_rssi) { -+ threshold.upperThreshold = info->cqm_rssi_thold + info->cqm_rssi_hyst; -+ threshold.lowerThreshold = info->cqm_rssi_thold; -+ } else { -+ /* convert RSSI to RCPI, RCPI = (RSSI + 110) * 2 */ -+ threshold.upperThreshold = (info->cqm_rssi_thold + info->cqm_rssi_hyst + 110)<<1; -+ threshold.lowerThreshold = (info->cqm_rssi_thold + 110)<<1; -+ } -+ threshold.rssiRcpiMode |= WSM_RCPI_RSSI_THRESHOLD_ENABLE; -+ } else { -+ /* There is a bug in FW, see sta.c. We have to enable -+ * dummy subscription to get correct RSSI values. */ -+ threshold.rssiRcpiMode |= WSM_RCPI_RSSI_THRESHOLD_ENABLE | -+ WSM_RCPI_RSSI_DONT_USE_UPPER | -+ WSM_RCPI_RSSI_DONT_USE_LOWER; -+ } -+ WARN_ON(wsm_set_rcpi_rssi_threshold(hw_priv, &threshold, priv->if_id)); -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //priv->cqm_tx_failure_thold = info->cqm_tx_fail_thold; -+ //priv->cqm_tx_failure_count = 0; -+ -+ //if (priv->cqm_beacon_loss_count != info->cqm_beacon_miss_thold) { -+ // priv->cqm_beacon_loss_count = info->cqm_beacon_miss_thold; -+ // priv->bss_params.beaconLostCount = (priv->cqm_beacon_loss_count? -+ // priv->cqm_beacon_loss_count : priv->cqm_link_loss_count); -+ /* Make sure we are associated before sending -+ * set_bss_params to firmware */ -+ if (priv->bss_params.aid) { -+ WARN_ON(wsm_set_bss_params(hw_priv, &priv->bss_params, priv->if_id)); -+ priv->setbssparams_done = true; -+ } -+ //} -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ } -+ /* -+ * in linux3.4 mac,the enum ieee80211_bss_change variable doesn't have -+ * BSS_CHANGED_PS and BSS_CHANGED_RETRY_LIMITS enum value. -+ */ -+#if 0 -+ if (changed & BSS_CHANGED_PS) { -+ if (info->ps_enabled == false) -+ priv->powersave_mode.pmMode = WSM_PSM_ACTIVE; -+ else if (info->dynamic_ps_timeout <= 0) -+ priv->powersave_mode.pmMode = WSM_PSM_PS; -+ else -+ priv->powersave_mode.pmMode = WSM_PSM_FAST_PS; -+ -+ ap_printk(XRADIO_DBG_MSG, "[STA] Aid: %d, Joined: %s, Powersave: %s\n", -+ priv->bss_params.aid, -+ priv->join_status == XRADIO_JOIN_STATUS_STA ? "yes" : "no", -+ (priv->powersave_mode.pmMode == WSM_PSM_ACTIVE ? "WSM_PSM_ACTIVE" : -+ priv->powersave_mode.pmMode == WSM_PSM_PS ? "WSM_PSM_PS" : -+ priv->powersave_mode.pmMode == WSM_PSM_FAST_PS ? "WSM_PSM_FAST_PS" : -+ "UNKNOWN")); -+ -+ /* Firmware requires that value for this 1-byte field must -+ * be specified in units of 500us. Values above the 128ms -+ * threshold are not supported. */ -+ if (info->dynamic_ps_timeout >= 0x80) -+ priv->powersave_mode.fastPsmIdlePeriod = 0xFF; -+ else -+ priv->powersave_mode.fastPsmIdlePeriod = info->dynamic_ps_timeout << 1; -+ ap_printk(XRADIO_DBG_NIY, "[STA]CHANGED_PS fastPsmIdle=%d, apPsmChange=%d\n", -+ priv->powersave_mode.fastPsmIdlePeriod, -+ priv->powersave_mode.apPsmChangePeriod); -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA && priv->bss_params.aid && -+ priv->setbssparams_done && priv->filter4.enable) -+ xradio_set_pm(priv, &priv->powersave_mode); -+ else -+ priv->power_set_true = 1; -+ } -+ -+ if (changed & BSS_CHANGED_RETRY_LIMITS) { -+ ap_printk(XRADIO_DBG_NIY, "Retry limits: %d (long), %d (short).\n", -+ info->retry_long, info->retry_short); -+ spin_lock_bh(&hw_priv->tx_policy_cache.lock); -+ /*TODO:COMBO: for now it's still handled per hw and kept -+ * in xradio_common */ -+ hw_priv->long_frame_max_tx_count = info->retry_long; -+ hw_priv->short_frame_max_tx_count = -+ (info->retry_short < 0x0F ? info->retry_short : 0x0F); -+ hw_priv->hw->max_rate_tries = hw_priv->short_frame_max_tx_count; -+ spin_unlock_bh(&hw_priv->tx_policy_cache.lock); -+ /* TBD: I think we don't need tx_policy_force_upload(). -+ * Outdated policies will leave cache in a normal way. */ -+ /* WARN_ON(tx_policy_force_upload(priv)); */ -+ } -+#endif -+ /*in linux3.4 mac,the enum ieee80211_bss_change variable doesn't have BSS_CHANGED_P2P_PS enum value*/ -+#if 0 -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ if (changed & BSS_CHANGED_P2P_PS) { -+ struct wsm_p2p_ps_modeinfo *modeinfo; -+ modeinfo = &priv->p2p_ps_modeinfo; -+ ap_printk(XRADIO_DBG_NIY, "[AP] BSS_CHANGED_P2P_PS\n"); -+ ap_printk(XRADIO_DBG_NIY, "[AP] Legacy PS: %d for AID %d in %d mode.\n", -+ info->p2p_ps.legacy_ps, priv->bss_params.aid, priv->join_status); -+ -+ if (info->p2p_ps.legacy_ps >= 0) { -+ if (info->p2p_ps.legacy_ps > 0) -+ priv->powersave_mode.pmMode = WSM_PSM_PS; -+ else -+ priv->powersave_mode.pmMode = WSM_PSM_ACTIVE; -+ -+ if(info->p2p_ps.ctwindow && info->p2p_ps.opp_ps) -+ priv->powersave_mode.pmMode = WSM_PSM_PS; -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) -+ xradio_set_pm(priv, &priv->powersave_mode); -+ } -+ -+ ap_printk(XRADIO_DBG_MSG, "[AP] CTWindow: %d\n", info->p2p_ps.ctwindow); -+ if (info->p2p_ps.ctwindow >= 128) -+ modeinfo->oppPsCTWindow = 127; -+ else if (info->p2p_ps.ctwindow >= 0) -+ modeinfo->oppPsCTWindow = info->p2p_ps.ctwindow; -+ -+ ap_printk(XRADIO_DBG_MSG, "[AP] Opportunistic: %d\n", info->p2p_ps.opp_ps); -+ switch (info->p2p_ps.opp_ps) { -+ case 0: -+ modeinfo->oppPsCTWindow &= ~(BIT(7)); -+ break; -+ case 1: -+ modeinfo->oppPsCTWindow |= BIT(7); -+ break; -+ default: -+ break; -+ } -+ -+ ap_printk(XRADIO_DBG_MSG, "[AP] NOA: %d, %d, %d, %d\n", -+ info->p2p_ps.count, info->p2p_ps.start, -+ info->p2p_ps.duration, info->p2p_ps.interval); -+ /* Notice of Absence */ -+ modeinfo->count = info->p2p_ps.count; -+ -+ if (info->p2p_ps.count) { -+ /* In case P2P_GO we need some extra time to be sure -+ * we will update beacon/probe_resp IEs correctly */ -+#define NOA_DELAY_START_MS 300 -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ modeinfo->startTime = __cpu_to_le32(info->p2p_ps.start + NOA_DELAY_START_MS); -+ else -+ modeinfo->startTime = __cpu_to_le32(info->p2p_ps.start); -+ modeinfo->duration = __cpu_to_le32(info->p2p_ps.duration); -+ modeinfo->interval = __cpu_to_le32(info->p2p_ps.interval); -+ modeinfo->dtimCount = 1; -+ modeinfo->reserved = 0; -+ } else { -+ modeinfo->dtimCount = 0; -+ modeinfo->startTime = 0; -+ modeinfo->reserved = 0; -+ modeinfo->duration = 0; -+ modeinfo->interval = 0; -+ } -+ -+#if defined(CONFIG_XRADIO_DEBUG) -+ print_hex_dump_bytes("p2p_set_ps_modeinfo: ", DUMP_PREFIX_NONE, -+ (u8 *)modeinfo, sizeof(*modeinfo)); -+#endif /* CONFIG_XRADIO_DEBUG */ -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA || -+ priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ WARN_ON(wsm_set_p2p_ps_modeinfo(hw_priv, modeinfo, priv->if_id)); -+ } -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ /* Temporary solution while firmware don't support NOA change -+ * notification yet */ -+ xradio_notify_noa(priv, 10); -+#endif -+ } -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+#endif -+ mutex_unlock(&hw_priv->conf_mutex); -+} -+ -+void xradio_multicast_start_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, multicast_start_work); -+ long tmo = priv->join_dtim_period * (priv->beacon_int + 20) * HZ / 1024; -+ -+ cancel_work_sync(&priv->multicast_stop_work); -+ if (!priv->aid0_bit_set) { -+ wsm_lock_tx(priv->hw_priv); -+ xradio_set_tim_impl(priv, true); -+ priv->aid0_bit_set = true; -+ mod_timer(&priv->mcast_timeout, jiffies + tmo); -+ wsm_unlock_tx(priv->hw_priv); -+ } -+} -+ -+void xradio_multicast_stop_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, multicast_stop_work); -+ -+ if (priv->aid0_bit_set) { -+ del_timer_sync(&priv->mcast_timeout); -+ wsm_lock_tx(priv->hw_priv); -+ priv->aid0_bit_set = false; -+ xradio_set_tim_impl(priv, false); -+ wsm_unlock_tx(priv->hw_priv); -+ } -+} -+ -+void xradio_mcast_timeout(struct timer_list *t) -+{ -+ struct xradio_vif *priv = from_timer(priv, t, mcast_timeout); -+ -+ ap_printk(XRADIO_DBG_WARN, "Multicast delivery timeout.\n"); -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->tx_multicast = priv->aid0_bit_set && priv->buffered_multicasts; -+ if (priv->tx_multicast) -+ xradio_bh_wakeup(xrwl_vifpriv_to_hwpriv(priv)); -+ spin_unlock_bh(&priv->ps_state_lock); -+} -+ -+int xradio_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_ampdu_params *params) -+{ -+ /* Aggregation is implemented fully in firmware, -+ * including block ack negotiation. -+ * In case of AMPDU aggregation in RX direction -+ * re-ordering of packets takes place on host. mac80211 -+ * needs the ADDBA Request to setup reodering.mac80211 also -+ * sends ADDBA Response which is discarded in the driver as -+ * FW generates the ADDBA Response on its own.*/ -+ int ret; -+ -+ switch (params->action) { -+ case IEEE80211_AMPDU_RX_START: -+ case IEEE80211_AMPDU_RX_STOP: -+ /* Just return OK to mac80211 */ -+ ret = 0; -+ break; -+ default: -+ ret = -ENOTSUPP; -+ } -+ return ret; -+} -+ -+/* ******************************************************************** */ -+/* WSM callback */ -+void xradio_suspend_resume(struct xradio_vif *priv, struct wsm_suspend_resume *arg) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+#if 0 -+ ap_printk(XRADIO_DBG_MSG, "[AP] %s: %s\n", -+ arg->stop ? "stop" : "start", -+ arg->multicast ? "broadcast" : "unicast"); -+#endif -+ if (arg->multicast) { -+ bool cancel_tmo = false; -+ spin_lock_bh(&priv->ps_state_lock); -+ if (arg->stop) { -+ priv->tx_multicast = false; -+ } else { -+ /* Firmware sends this indication every DTIM if there -+ * is a STA in powersave connected. There is no reason -+ * to suspend, following wakeup will consume much more -+ * power than it could be saved. */ -+ xradio_pm_stay_awake(&hw_priv->pm_state, (priv->join_dtim_period * -+ (priv->beacon_int + 20) * HZ / 1024)); -+ priv->tx_multicast = priv->aid0_bit_set && priv->buffered_multicasts; -+ if (priv->tx_multicast) { -+ cancel_tmo = true; -+ xradio_bh_wakeup(hw_priv); -+ } -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ if (cancel_tmo) -+ del_timer_sync(&priv->mcast_timeout); -+ } else { -+ spin_lock_bh(&priv->ps_state_lock); -+ xradio_ps_notify(priv, arg->link_id, arg->stop); -+ spin_unlock_bh(&priv->ps_state_lock); -+ if (!arg->stop) -+ xradio_bh_wakeup(hw_priv); -+ } -+ return; -+} -+ -+/* ******************************************************************** */ -+/* AP privates */ -+ -+static int xradio_upload_beacon(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_BEACON, -+ }; -+ struct ieee80211_mgmt *mgmt; -+ u8 *erp_inf, *ies, *ht_oper; -+ u32 ies_len; -+ -+ if (priv->vif->p2p || hw_priv->channel->band == NL80211_BAND_5GHZ) -+ frame.rate = WSM_TRANSMIT_RATE_6; -+ -+ frame.skb = ieee80211_beacon_get(priv->hw, priv->vif); -+ if (WARN_ON(!frame.skb)) -+ return -ENOMEM; -+ -+ mgmt = (void *)frame.skb->data; -+ ies = mgmt->u.beacon.variable; -+ ies_len = frame.skb->len - (u32)(ies - (u8 *)mgmt); -+ -+ ht_oper = (u8 *)cfg80211_find_ie( WLAN_EID_HT_OPERATION, ies, ies_len); -+ if (ht_oper) { -+ /* Enable RIFS*/ -+ ht_oper[3] |= 8; -+ } -+ -+ erp_inf = (u8 *)cfg80211_find_ie(WLAN_EID_ERP_INFO, ies, ies_len); -+ if (erp_inf) { -+ if (erp_inf[ERP_INFO_BYTE_OFFSET] -+ & WLAN_ERP_BARKER_PREAMBLE) -+ priv->erp_info |= WLAN_ERP_BARKER_PREAMBLE; -+ else -+ priv->erp_info &= ~WLAN_ERP_BARKER_PREAMBLE; -+ -+ if (erp_inf[ERP_INFO_BYTE_OFFSET] -+ & WLAN_ERP_NON_ERP_PRESENT) { -+ priv->erp_info |= WLAN_ERP_USE_PROTECTION; -+ priv->erp_info |= WLAN_ERP_NON_ERP_PRESENT; -+ } else { -+ priv->erp_info &= ~WLAN_ERP_USE_PROTECTION; -+ priv->erp_info &= ~WLAN_ERP_NON_ERP_PRESENT; -+ } -+ } -+ -+#ifdef HIDDEN_SSID -+ if (priv->hidden_ssid) { -+ u8 *ssid_ie; -+ u8 ssid_len; -+ -+ ap_printk(XRADIO_DBG_NIY, "%s: hidden_ssid set\n", __func__); -+ ssid_ie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len); -+ WARN_ON(!ssid_ie); -+ ssid_len = ssid_ie[1]; -+ if (ssid_len) { -+ ap_printk(XRADIO_DBG_MSG, "hidden_ssid with zero content ssid\n"); -+ ssid_ie[1] = 0; -+ memmove(ssid_ie + 2, ssid_ie + 2 + ssid_len, -+ (ies + ies_len - -+ (ssid_ie + 2 + ssid_len))); -+ frame.skb->len -= ssid_len; -+ } else { -+ ap_printk(XRADIO_DBG_WARN, "hidden ssid with ssid len 0 not supported"); -+ dev_kfree_skb(frame.skb); -+ return -1; -+ } -+ } -+#endif -+ -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ if (!ret) { -+#ifdef PROBE_RESP_EXTRA_IE -+ ret = xradio_upload_proberesp(priv); -+#else -+ /* TODO: Distille probe resp; remove TIM -+ * and other beacon-specific IEs */ -+ *(__le16 *)frame.skb->data = __cpu_to_le16( -+ IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); -+ frame.frame_type = WSM_FRAME_TYPE_PROBE_RESPONSE; -+ /* TODO: Ideally probe response template should separately -+ configured by supplicant through openmac. This is a -+ temporary work-around known to fail p2p group info -+ attribute related tests -+ */ -+ if (0 /* priv->vif->p2p */) -+ ret = wsm_set_probe_responder(priv, true); -+ else { -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ WARN_ON(wsm_set_probe_responder(priv, false)); -+ } -+#endif -+ } -+ dev_kfree_skb(frame.skb); -+ -+ return ret; -+} -+ -+#ifdef PROBE_RESP_EXTRA_IE -+static int xradio_upload_proberesp(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PROBE_RESPONSE, -+ }; -+#ifdef HIDDEN_SSID -+ u8 *ssid_ie; -+#endif -+ -+ if (priv->vif->p2p || hw_priv->channel->band == NL80211_BAND_5GHZ) -+ frame.rate = WSM_TRANSMIT_RATE_6; -+ -+ frame.skb = ieee80211_proberesp_get(priv->hw, priv->vif); -+ if (WARN_ON(!frame.skb)) -+ return -ENOMEM; -+ -+#ifdef HIDDEN_SSID -+ if (priv->hidden_ssid) { -+ int offset; -+ u8 ssid_len; -+ /* we are assuming beacon from upper layer will always contain -+ zero filled ssid for hidden ap. The beacon shall never have -+ ssid len = 0. -+ */ -+ -+ offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); -+ ssid_ie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, frame.skb->data + offset, -+ frame.skb->len - offset); -+ ssid_len = ssid_ie[1]; -+ if (ssid_len && (ssid_len == priv->ssid_length)) { -+ memcpy(ssid_ie + 2, priv->ssid, ssid_len); -+ } else { -+ ap_printk(XRADIO_DBG_ERROR, "%s: hidden ssid with mismatched ssid_len %d\n", -+ __func__, ssid_len); -+ dev_kfree_skb(frame.skb); -+ return -1; -+ } -+ } -+#endif -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ WARN_ON(wsm_set_probe_responder(priv, false)); -+ -+ dev_kfree_skb(frame.skb); -+ -+ return ret; -+} -+#endif -+ -+static int xradio_upload_pspoll(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PS_POLL, -+ .rate = 0xFF, -+ }; -+ -+ frame.skb = ieee80211_pspoll_get(priv->hw, priv->vif); -+ if (WARN_ON(!frame.skb)) -+ return -ENOMEM; -+ ret = wsm_set_template_frame(xrwl_vifpriv_to_hwpriv(priv), &frame, priv->if_id); -+ dev_kfree_skb(frame.skb); -+ return ret; -+} -+ -+static int xradio_upload_null(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_NULL, -+ .rate = 0xFF, -+ }; -+ -+ frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false); -+ if (WARN_ON(!frame.skb)) -+ return -ENOMEM; -+ -+ ret = wsm_set_template_frame(xrwl_vifpriv_to_hwpriv(priv), &frame, priv->if_id); -+ dev_kfree_skb(frame.skb); -+ return ret; -+} -+ -+static int xradio_upload_qosnull(struct xradio_vif *priv) -+{ -+ struct ieee80211_qos_hdr* qos_null_template; -+ struct sk_buff* skb; -+ int ret = 0; -+ struct xradio_common *hw_priv =xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_QOS_NULL, -+ .rate = 0xFF, -+ }; -+ if (!hw_priv) -+ ap_printk(XRADIO_DBG_ERROR,"%s: Cannot find xradio_common pointer!\n",__FUNCTION__); -+ /*set qos template*/ -+ skb = dev_alloc_skb(hw_priv->hw->extra_tx_headroom + sizeof(struct ieee80211_qos_hdr)); -+ if (!skb) { -+ ap_printk(XRADIO_DBG_ERROR,"%s: failed to allocate buffer for qos nullfunc template!\n",__FUNCTION__); -+ return -1; -+ } -+ skb_reserve(skb, hw_priv->hw->extra_tx_headroom); -+ qos_null_template = (struct ieee80211_qos_hdr *)skb_put(skb,sizeof(struct ieee80211_qos_hdr)); -+ memset(qos_null_template, 0, sizeof(struct ieee80211_qos_hdr)); -+ memcpy(qos_null_template->addr1, priv->vif->bss_conf.bssid, ETH_ALEN); -+ memcpy(qos_null_template->addr2, priv->vif->addr, ETH_ALEN); -+ memcpy(qos_null_template->addr3, priv->vif->bss_conf.bssid, ETH_ALEN); -+ qos_null_template->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | -+ IEEE80211_STYPE_QOS_NULLFUNC | -+ IEEE80211_FCTL_TODS); -+ frame.skb = skb; -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ dev_kfree_skb(frame.skb); -+ return ret; -+} -+ -+/* This API is nolonegr present in WSC */ -+#if 0 -+static int xradio_enable_beaconing(struct xradio_vif *priv, -+ bool enable) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_beacon_transmit transmit = { -+ .enableBeaconing = enable, -+ }; -+ -+ return wsm_beacon_transmit(hw_priv, &transmit, priv->if_id); -+} -+#endif -+ -+static int xradio_start_ap(struct xradio_vif *priv) -+{ -+ int ret; -+#ifndef HIDDEN_SSID -+ const u8 *ssidie; -+ struct sk_buff *skb; -+ int offset; -+#endif -+ struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_start start = { -+ .mode = priv->vif->p2p ? WSM_START_MODE_P2P_GO : WSM_START_MODE_AP, -+ /* TODO:COMBO:Change once mac80211 support is available */ -+ .band = (hw_priv->channel->band == NL80211_BAND_5GHZ) ? -+ WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G, -+ .channelNumber = hw_priv->channel->hw_value, -+ .beaconInterval = conf->beacon_int, -+ .DTIMPeriod = conf->dtim_period, -+ .preambleType = conf->use_short_preamble ? -+ WSM_JOIN_PREAMBLE_SHORT :WSM_JOIN_PREAMBLE_LONG, -+ .probeDelay = 100, -+ .basicRateSet = xradio_rate_mask_to_wsm(hw_priv, conf->basic_rates), -+ }; -+ -+#ifdef TES_P2P_000B_EXTEND_INACTIVITY_CNT -+ ///w, TES_P2P_000B WorkAround: -+ ///w, when inactivity count of a peer device is zero, -+ ///w, which will reset while receiving a peer device frame, -+ ///w, firmware will disconnect with it. -+ ///w, due to some reason, such as scan/phy error, we miss these frame. -+ ///w, then we can't keep connection with peer device. -+ ///w, we set the min_inactivity value to large as WorkAround. -+ //min_inactivity be modified to 20, yangfh. -+ struct wsm_inactivity inactivity = { -+ .min_inactivity = 20, -+ .max_inactivity = 10, -+ }; -+#else -+ struct wsm_inactivity inactivity = { -+ .min_inactivity = 9, -+ .max_inactivity = 1, -+ }; -+#endif -+ -+ ap_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ -+ if (priv->if_id) -+ start.mode |= WSM_FLAG_MAC_INSTANCE_1; -+ else -+ start.mode &= ~WSM_FLAG_MAC_INSTANCE_1; -+ -+ hw_priv->connected_sta_cnt = 0; -+ -+#ifndef HIDDEN_SSID -+ /* Get SSID */ -+ skb = ieee80211_beacon_get(priv->hw, priv->vif); -+ if (WARN_ON(!skb)) { -+ ap_printk(XRADIO_DBG_ERROR,"%s, ieee80211_beacon_get failed\n", __func__); -+ return -ENOMEM; -+ } -+ -+ offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); -+ ssidie = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, skb->len - offset); -+ -+ memset(priv->ssid, 0, sizeof(priv->ssid)); -+ if (ssidie) { -+ priv->ssid_length = ssidie[1]; -+ if (WARN_ON(priv->ssid_length > sizeof(priv->ssid))) -+ priv->ssid_length = sizeof(priv->ssid); -+ memcpy(priv->ssid, &ssidie[2], priv->ssid_length); -+ } else { -+ priv->ssid_length = 0; -+ } -+ dev_kfree_skb(skb); -+#endif -+ -+ priv->beacon_int = conf->beacon_int; -+ priv->join_dtim_period = conf->dtim_period; -+ memset(&priv->last_tim[0], 0, sizeof(priv->last_tim)); //yangfh -+ -+ start.ssidLength = priv->ssid_length; -+ memcpy(&start.ssid[0], priv->ssid, start.ssidLength); -+ -+ memset(&priv->link_id_db, 0, sizeof(priv->link_id_db)); -+ -+ ap_printk(XRADIO_DBG_NIY, "[AP] ch: %d(%d), bcn: %d(%d)," -+ "bss_rate: 0x%.8X, ssid: %.*s.\n", -+ start.channelNumber, start.band, -+ start.beaconInterval, start.DTIMPeriod, -+ start.basicRateSet, start.ssidLength, start.ssid); -+ ret = WARN_ON(wsm_start(hw_priv, &start, priv->if_id)); -+ -+ if (!ret && priv->vif->p2p) { -+ ap_printk(XRADIO_DBG_NIY,"[AP] Setting p2p powersave configuration.\n"); -+ WARN_ON(wsm_set_p2p_ps_modeinfo(hw_priv, -+ &priv->p2p_ps_modeinfo, priv->if_id)); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //xradio_notify_noa(priv, XRADIO_NOA_NOTIFICATION_DELAY); -+#endif -+ } -+ -+ /*Set Inactivity time*/ -+ if(!(strstr(&start.ssid[0], "6.1.12"))) { -+ wsm_set_inactivity(hw_priv, &inactivity, priv->if_id); -+ } -+ if (!ret) { -+#ifndef AP_AGGREGATE_FW_FIX -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_DISABLED_FOR_ALL_TID, -+ XRADIO_RX_BLOCK_ACK_DISABLED_FOR_ALL_TID, priv->if_id)); -+#else -+ if ((priv->if_id ==1) && !hw_priv->is_go_thru_go_neg) -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID, //modified for WFD by yangfh -+ XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID, priv->if_id)); -+ else -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID, -+ XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID, priv->if_id)); -+#endif -+ priv->join_status = XRADIO_JOIN_STATUS_AP; -+ /* xradio_update_filtering(priv); */ -+ } -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ ap_printk(XRADIO_DBG_WARN, "vif%d, AP/GO mode THROTTLE=%d\n", priv->if_id, -+ priv->if_id==0?hw_priv->vif0_throttle:hw_priv->vif1_throttle); -+ return ret; -+} -+ -+static int xradio_update_beaconing(struct xradio_vif *priv) -+{ -+ struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_reset reset = { -+ .link_id = 0, -+ .reset_statistics = true, -+ }; -+ ap_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ -+ if (priv->mode == NL80211_IFTYPE_AP) { -+ /* TODO: check if changed channel, band */ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP || -+ priv->beacon_int != conf->beacon_int) { -+ ap_printk(XRADIO_DBG_WARN, "ap restarting!\n"); -+ wsm_lock_tx(hw_priv); -+ if (priv->join_status != XRADIO_JOIN_STATUS_PASSIVE) -+ WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id)); -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ WARN_ON(xradio_start_ap(priv)); -+ wsm_unlock_tx(hw_priv); -+ } else -+ ap_printk(XRADIO_DBG_NIY, "ap started join_status: %d\n", priv->join_status); -+ } -+ return 0; -+} -+ -+int xradio_find_link_id(struct xradio_vif *priv, const u8 *mac) -+{ -+ int i, ret = 0; -+ spin_lock_bh(&priv->ps_state_lock); -+ for (i = 0; i < MAX_STA_IN_AP_MODE; ++i) { -+ if (!memcmp(mac, priv->link_id_db[i].mac, ETH_ALEN) && -+ priv->link_id_db[i].status) { -+ priv->link_id_db[i].timestamp = jiffies; -+ ret = i + 1; -+ break; -+ } -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ return ret; -+} -+ -+int xradio_alloc_link_id(struct xradio_vif *priv, const u8 *mac) -+{ -+ int i, ret = 0; -+ unsigned long max_inactivity = 0; -+ unsigned long now = jiffies; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ for (i = 0; i < MAX_STA_IN_AP_MODE; ++i) { -+ if (!priv->link_id_db[i].status) { -+ ret = i + 1; -+ break; -+ } else if (priv->link_id_db[i].status != XRADIO_LINK_HARD && -+ !hw_priv->tx_queue_stats.link_map_cache[i + 1]) { -+ unsigned long inactivity = now - priv->link_id_db[i].timestamp; -+ if (inactivity < max_inactivity) -+ continue; -+ max_inactivity = inactivity; -+ ret = i + 1; -+ } -+ } -+ if (ret) { -+ struct xradio_link_entry *entry = &priv->link_id_db[ret - 1]; -+ ap_printk(XRADIO_DBG_NIY, "STA added, link_id: %d\n", ret); -+ entry->status = XRADIO_LINK_RESERVE; -+ memcpy(&entry->mac, mac, ETH_ALEN); -+ memset(&entry->buffered, 0, XRADIO_MAX_TID); -+ skb_queue_head_init(&entry->rx_queue); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->link_id_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } else { -+ ap_printk(XRADIO_DBG_WARN, "Early: no more link IDs available.\n"); -+ } -+ -+ spin_unlock_bh(&priv->ps_state_lock); -+ return ret; -+} -+ -+void xradio_link_id_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = container_of(work, struct xradio_vif, link_id_work); -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ wsm_flush_tx(hw_priv); -+ xradio_link_id_gc_work(&priv->link_id_gc_work.work); -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_link_id_gc_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, link_id_gc_work.work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_map_link map_link = { -+ .link_id = 0, -+ }; -+ unsigned long now = jiffies; -+ unsigned long next_gc = -1; -+ long ttl; -+ bool need_reset; -+ u32 mask; -+ int i; -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP) -+ return; -+ -+ wsm_lock_tx(hw_priv); -+ spin_lock_bh(&priv->ps_state_lock); -+ for (i = 0; i < MAX_STA_IN_AP_MODE; ++i) { -+ need_reset = false; -+ mask = BIT(i + 1); -+ if (priv->link_id_db[i].status == XRADIO_LINK_RESERVE || -+ (priv->link_id_db[i].status == XRADIO_LINK_HARD && -+ !(priv->link_id_map & mask))) { -+ if (priv->link_id_map & mask) { -+ priv->sta_asleep_mask &= ~mask; -+ priv->pspoll_mask &= ~mask; -+ need_reset = true; -+ } -+ priv->link_id_map |= mask; -+ if (priv->link_id_db[i].status != XRADIO_LINK_HARD) -+ priv->link_id_db[i].status = XRADIO_LINK_SOFT; -+ memcpy(map_link.mac_addr, priv->link_id_db[i].mac, ETH_ALEN); -+ spin_unlock_bh(&priv->ps_state_lock); -+ if (need_reset) { -+ WARN_ON(xrwl_unmap_link(priv, i + 1)); -+ } -+ map_link.link_id = i + 1; -+ WARN_ON(wsm_map_link(hw_priv, &map_link, priv->if_id)); -+ next_gc = min(next_gc, XRADIO_LINK_ID_GC_TIMEOUT); -+ spin_lock_bh(&priv->ps_state_lock); -+ } else if (priv->link_id_db[i].status == XRADIO_LINK_SOFT) { -+ ttl = priv->link_id_db[i].timestamp - now + XRADIO_LINK_ID_GC_TIMEOUT; -+ if (ttl <= 0) { -+ need_reset = true; -+ priv->link_id_db[i].status = XRADIO_LINK_OFF; -+ priv->link_id_map &= ~mask; -+ priv->sta_asleep_mask &= ~mask; -+ priv->pspoll_mask &= ~mask; -+ memset(map_link.mac_addr, 0, ETH_ALEN); -+ spin_unlock_bh(&priv->ps_state_lock); -+ WARN_ON(xrwl_unmap_link(priv, i + 1)); -+ spin_lock_bh(&priv->ps_state_lock); -+ } else { -+ next_gc = min_t(unsigned long, next_gc, ttl); -+ } -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ } else if (priv->link_id_db[i].status == XRADIO_LINK_RESET || -+ priv->link_id_db[i].status == XRADIO_LINK_RESET_REMAP) { -+ int status = priv->link_id_db[i].status; -+ priv->link_id_db[i].status = XRADIO_LINK_OFF; -+ priv->link_id_db[i].timestamp = now; -+ spin_unlock_bh(&priv->ps_state_lock); -+ WARN_ON(xrwl_unmap_link(priv, i + 1)); -+ if (status == XRADIO_LINK_RESET_REMAP) { -+ memcpy(map_link.mac_addr, priv->link_id_db[i].mac, ETH_ALEN); -+ map_link.link_id = i + 1; -+ WARN_ON(wsm_map_link(hw_priv, &map_link, priv->if_id)); -+ next_gc = min(next_gc, XRADIO_LINK_ID_GC_TIMEOUT); -+ priv->link_id_db[i].status = priv->link_id_db[i].prev_status; -+ } -+ spin_lock_bh(&priv->ps_state_lock); -+#endif -+ } -+ if (need_reset) { -+ skb_queue_purge(&priv->link_id_db[i].rx_queue); -+ ap_printk(XRADIO_DBG_NIY, "STA removed, link_id: %d\n", i + 1); -+ } -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ if (next_gc != -1) -+ queue_delayed_work(hw_priv->workqueue, &priv->link_id_gc_work, next_gc); -+ wsm_unlock_tx(hw_priv); -+} -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+#if 0 -+void xradio_notify_noa(struct xradio_vif *priv, int delay) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct cfg80211_p2p_ps p2p_ps = {0}; -+ struct wsm_p2p_ps_modeinfo *modeinfo; -+ modeinfo = &priv->p2p_ps_modeinfo; -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP) -+ return; -+ -+ if (delay) -+ msleep(delay); -+ -+ if (!WARN_ON(wsm_get_p2p_ps_modeinfo(hw_priv, modeinfo))) { -+#if defined(CONFIG_XRADIO_DEBUG) -+ print_hex_dump_bytes("[AP] p2p_get_ps_modeinfo: ", DUMP_PREFIX_NONE, -+ (u8 *)modeinfo, sizeof(*modeinfo)); -+#endif /* CONFIG_XRADIO_DEBUG */ -+ p2p_ps.opp_ps = !!(modeinfo->oppPsCTWindow & BIT(7)); -+ p2p_ps.ctwindow = modeinfo->oppPsCTWindow & (~BIT(7)); -+ p2p_ps.count = modeinfo->count; -+ p2p_ps.start = __le32_to_cpu(modeinfo->startTime); -+ p2p_ps.duration = __le32_to_cpu(modeinfo->duration); -+ p2p_ps.interval = __le32_to_cpu(modeinfo->interval); -+ p2p_ps.index = modeinfo->reserved; -+ -+ ieee80211_p2p_noa_notify(priv->vif, &p2p_ps, GFP_KERNEL); -+ } -+} -+#endif -+#endif -+int xrwl_unmap_link(struct xradio_vif *priv, int link_id) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int ret = 0; -+ -+ if (is_hardware_xradio(hw_priv)) { -+ struct wsm_map_link maplink = { -+ .link_id = link_id, -+ .unmap = true, -+ }; -+ if (link_id) -+ memcpy(&maplink.mac_addr[0], priv->link_id_db[link_id - 1].mac, ETH_ALEN); -+ return wsm_map_link(hw_priv, &maplink, priv->if_id); -+ } else { -+ struct wsm_reset reset = { -+ .link_id = link_id, -+ .reset_statistics = true, -+ }; -+ ret = wsm_reset(hw_priv, &reset, priv->if_id); -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ return ret; -+ } -+} -+#ifdef AP_HT_CAP_UPDATE -+void xradio_ht_oper_update_work(struct work_struct *work) -+{ -+ struct sk_buff *skb; -+ struct ieee80211_mgmt *mgmt; -+ u8 *ht_oper, *ies; -+ u32 ies_len; -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, ht_oper_update_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_update_ie update_ie = { -+ .what = WSM_UPDATE_IE_BEACON, -+ .count = 1, -+ }; -+ -+ skb = ieee80211_beacon_get(priv->hw, priv->vif); -+ if (WARN_ON(!skb)) -+ return; -+ -+ mgmt = (void *)skb->data; -+ ies = mgmt->u.beacon.variable; -+ ies_len = skb->len - (u32)(ies - (u8 *)mgmt); -+ ht_oper= (u8 *)cfg80211_find_ie( WLAN_EID_HT_OPERATION, ies, ies_len); -+ if(ht_oper && priv->ht_oper == HT_INFO_MASK) { -+ ht_oper[HT_INFO_OFFSET] |= 0x11; -+ update_ie.ies = ht_oper; -+ update_ie.length = HT_INFO_IE_LEN; -+ WARN_ON(wsm_update_ie(hw_priv, &update_ie, priv->if_id)); -+ } -+ dev_kfree_skb(skb); -+} -+#endif -diff --git a/drivers/net/wireless/xradio/ap.h b/drivers/net/wireless/xradio/ap.h -new file mode 100644 -index 0000000..9d55fb8 ---- /dev/null -+++ b/drivers/net/wireless/xradio/ap.h -@@ -0,0 +1,63 @@ -+/* -+ * STA and AP APIs for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef AP_H_INCLUDED -+#define AP_H_INCLUDED -+ -+#define XRADIO_NOA_NOTIFICATION_DELAY 10 -+ -+#ifdef AP_HT_CAP_UPDATE -+#define HT_INFO_OFFSET 4 -+#define HT_INFO_MASK 0x0011 -+#define HT_INFO_IE_LEN 22 -+#endif -+ -+int xradio_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, -+ bool set); -+int xradio_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta); -+int xradio_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta); -+void xradio_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, -+ enum sta_notify_cmd notify_cmd, -+ struct ieee80211_sta *sta); -+void xradio_bss_info_changed(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ struct ieee80211_bss_conf *info, -+ u32 changed); -+int xradio_ampdu_action(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_ampdu_params *params); -+/* enum ieee80211_ampdu_mlme_action action, -+ struct ieee80211_sta *sta, u16 tid, u16 *ssn, -+ u8 buf_size);*/ -+ -+void xradio_suspend_resume(struct xradio_vif *priv, -+ struct wsm_suspend_resume *arg); -+void xradio_set_tim_work(struct work_struct *work); -+void xradio_set_cts_work(struct work_struct *work); -+void xradio_multicast_start_work(struct work_struct *work); -+void xradio_multicast_stop_work(struct work_struct *work); -+void xradio_mcast_timeout(struct timer_list *t); -+int xradio_find_link_id(struct xradio_vif *priv, const u8 *mac); -+int xradio_alloc_link_id(struct xradio_vif *priv, const u8 *mac); -+void xradio_link_id_work(struct work_struct *work); -+void xradio_link_id_gc_work(struct work_struct *work); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+/*in linux3.4 mac,it does't have the noa pass*/ -+//void xradio_notify_noa(struct xradio_vif *priv, int delay); -+#endif -+int xrwl_unmap_link(struct xradio_vif *priv, int link_id); -+#ifdef AP_HT_CAP_UPDATE -+void xradio_ht_oper_update_work(struct work_struct *work); -+#endif -+ -+#endif -diff --git a/drivers/net/wireless/xradio/bh.c b/drivers/net/wireless/xradio/bh.c -new file mode 100644 -index 0000000..7666329 ---- /dev/null -+++ b/drivers/net/wireless/xradio/bh.c -@@ -0,0 +1,836 @@ -+/* -+ * Data Transmission thread implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include "xradio.h" -+#include "bh.h" -+#include "hwio.h" -+#include "wsm.h" -+#include "sdio.h" -+ -+/* TODO: Verify these numbers with WSM specification. */ -+#define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4) -+/* an SPI message cannot be bigger than (2"12-1)*2 bytes -+ * "*2" to cvt to bytes */ -+#define MAX_SZ_RD_WR_BUFFERS (DOWNLOAD_BLOCK_SIZE_WR*2) -+#define PIGGYBACK_CTRL_REG (2) -+#define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG) -+ -+/* Suspend state privates */ -+enum xradio_bh_pm_state { -+ XRADIO_BH_RESUMED = 0, -+ XRADIO_BH_SUSPEND, -+ XRADIO_BH_SUSPENDED, -+ XRADIO_BH_RESUME, -+}; -+typedef int (*xradio_wsm_handler)(struct xradio_common *hw_priv, u8 *data, size_t size); -+ -+#ifdef MCAST_FWDING -+int wsm_release_buffer_to_fw(struct xradio_vif *priv, int count); -+#endif -+static int xradio_bh(void *arg); -+ -+int xradio_register_bh(struct xradio_common *hw_priv) -+{ -+ int ret = 0; -+ -+ atomic_set(&hw_priv->bh_tx, 0); -+ atomic_set(&hw_priv->bh_term, 0); -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUMED); -+ hw_priv->buf_id_tx = 0; -+ hw_priv->buf_id_rx = 0; -+ init_waitqueue_head(&hw_priv->bh_wq); -+ init_waitqueue_head(&hw_priv->bh_evt_wq); -+ -+ hw_priv->bh_thread = kthread_run(&xradio_bh, hw_priv, XRADIO_BH_THREAD); -+ if (IS_ERR(hw_priv->bh_thread)) { -+ ret = PTR_ERR(hw_priv->bh_thread); -+ hw_priv->bh_thread = NULL; -+ } -+ -+ return ret; -+} -+ -+void xradio_unregister_bh(struct xradio_common *hw_priv) -+{ -+ struct task_struct *thread = hw_priv->bh_thread; -+ -+ if (WARN_ON(!thread)) -+ return; -+ -+ hw_priv->bh_thread = NULL; -+ kthread_stop(thread); -+#ifdef HAS_PUT_TASK_STRUCT -+ put_task_struct(thread); -+#endif -+ dev_dbg(hw_priv->pdev, "Unregister success.\n"); -+} -+ -+void xradio_irq_handler(struct xradio_common *hw_priv) -+{ -+ xradio_bh_wakeup(hw_priv); -+} -+ -+void xradio_bh_wakeup(struct xradio_common *hw_priv) -+{ -+ atomic_set(&hw_priv->bh_tx, 1); -+ wake_up(&hw_priv->bh_wq); -+} -+ -+int xradio_bh_suspend(struct xradio_common *hw_priv) -+{ -+#ifdef MCAST_FWDING -+ int i =0; -+ struct xradio_vif *priv = NULL; -+#endif -+ -+ if (hw_priv->bh_error) { -+ return -EINVAL; -+ } -+ -+#ifdef MCAST_FWDING -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ if ( (priv->multicast_filter.enable) -+ && (priv->join_status == XRADIO_JOIN_STATUS_AP) ) { -+ wsm_release_buffer_to_fw(priv, -+ (hw_priv->wsm_caps.numInpChBufs - 1)); -+ break; -+ } -+ } -+#endif -+ -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_SUSPEND); -+ wake_up(&hw_priv->bh_wq); -+ return wait_event_timeout(hw_priv->bh_evt_wq, (hw_priv->bh_error || -+ XRADIO_BH_SUSPENDED == atomic_read(&hw_priv->bh_suspend)), -+ 1 * HZ)? 0 : -ETIMEDOUT; -+} -+ -+int xradio_bh_resume(struct xradio_common *hw_priv) -+{ -+#ifdef MCAST_FWDING -+ int ret; -+ int i =0; -+ struct xradio_vif *priv =NULL; -+#endif -+ -+ -+ if (hw_priv->bh_error) { -+ return -EINVAL; -+ } -+ -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUME); -+ wake_up(&hw_priv->bh_wq); -+ -+#ifdef MCAST_FWDING -+ ret = wait_event_timeout(hw_priv->bh_evt_wq, (hw_priv->bh_error || -+ XRADIO_BH_RESUMED == atomic_read(&hw_priv->bh_suspend)) -+ ,1 * HZ)? 0 : -ETIMEDOUT; -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ if ((priv->join_status == XRADIO_JOIN_STATUS_AP) && -+ (priv->multicast_filter.enable)) { -+ u8 count = 0; -+ WARN_ON(wsm_request_buffer_request(priv, &count)); -+ dev_dbg(hw_priv->pdev, "Reclaim Buff %d \n",count); -+ break; -+ } -+ } -+ -+ return ret; -+#else -+ return wait_event_timeout(hw_priv->bh_evt_wq,hw_priv->bh_error || -+ (XRADIO_BH_RESUMED == atomic_read(&hw_priv->bh_suspend)), -+ 1 * HZ) ? 0 : -ETIMEDOUT; -+#endif -+ -+} -+ -+static inline void wsm_alloc_tx_buffer(struct xradio_common *hw_priv) -+{ -+ ++hw_priv->hw_bufs_used; -+} -+ -+int wsm_release_tx_buffer(struct xradio_common *hw_priv, int count) -+{ -+ int ret = 0; -+ int hw_bufs_used = hw_priv->hw_bufs_used; -+ -+ hw_priv->hw_bufs_used -= count; -+ if (WARN_ON(hw_priv->hw_bufs_used < 0)) { -+ /* Tx data patch stops when all but one hw buffers are used. -+ So, re-start tx path in case we find hw_bufs_used equals -+ numInputChBufs - 1. -+ */ -+ dev_err(hw_priv->pdev, "hw_bufs_used=%d, count=%d.\n", -+ hw_priv->hw_bufs_used, count); -+ ret = -1; -+ } else if (hw_bufs_used >= (hw_priv->wsm_caps.numInpChBufs - 1)) -+ ret = 1; -+ if (!hw_priv->hw_bufs_used) -+ wake_up(&hw_priv->bh_evt_wq); -+ return ret; -+} -+ -+int wsm_release_vif_tx_buffer(struct xradio_common *hw_priv, int if_id, int count) -+{ -+ int ret = 0; -+ -+ hw_priv->hw_bufs_used_vif[if_id] -= count; -+ if (!hw_priv->hw_bufs_used_vif[if_id]) -+ wake_up(&hw_priv->bh_evt_wq); -+ -+ if (WARN_ON(hw_priv->hw_bufs_used_vif[if_id] < 0)) -+ ret = -1; -+ return ret; -+} -+#ifdef MCAST_FWDING -+int wsm_release_buffer_to_fw(struct xradio_vif *priv, int count) -+{ -+ int i; -+ u8 flags; -+ struct wsm_buf *buf; -+ size_t buf_len; -+ struct wsm_hdr *wsm; -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP) { -+ return 0; -+ } -+ dev_dbg(hw_priv->pdev, "Rel buffer to FW %d, %d\n", count, hw_priv->hw_bufs_used); -+ -+ for (i = 0; i < count; i++) { -+ if ((hw_priv->hw_bufs_used + 1) < hw_priv->wsm_caps.numInpChBufs) { -+ flags = i ? 0: 0x1; -+ -+ wsm_alloc_tx_buffer(hw_priv); -+ buf = &hw_priv->wsm_release_buf[i]; -+ buf_len = buf->data - buf->begin; -+ -+ /* Add sequence number */ -+ wsm = (struct wsm_hdr *)buf->begin; -+ BUG_ON(buf_len < sizeof(*wsm)); -+ -+ wsm->id &= __cpu_to_le32(~WSM_TX_SEQ(WSM_TX_SEQ_MAX)); -+ wsm->id |= cpu_to_le32(WSM_TX_SEQ(hw_priv->wsm_tx_seq)); -+ -+ dev_dbg(hw_priv->pdev, "REL %d\n", hw_priv->wsm_tx_seq); -+ if (WARN_ON(xradio_data_write(hw_priv, buf->begin, buf_len))) { -+ break; -+ } -+ hw_priv->buf_released = 1; -+ hw_priv->wsm_tx_seq = (hw_priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; -+ } else -+ break; -+ } -+ -+ if (i == count) { -+ return 0; -+ } -+ -+ /* Should not be here */ -+ dev_dbg(hw_priv->pdev, "Error, Less HW buf %d,%d.\n", -+ hw_priv->hw_bufs_used, hw_priv->wsm_caps.numInpChBufs); -+ WARN_ON(1); -+ return -1; -+} -+#endif -+ -+/* reserve a packet for the case dev_alloc_skb failed in bh.*/ -+int xradio_init_resv_skb(struct xradio_common *hw_priv) -+{ -+ int len = (SDIO_BLOCK_SIZE<<2) + WSM_TX_EXTRA_HEADROOM + \ -+ 8 + 12; /* TKIP IV + ICV and MIC */ -+ -+ hw_priv->skb_reserved = dev_alloc_skb(len); -+ if (hw_priv->skb_reserved) { -+ hw_priv->skb_resv_len = len; -+ } else { -+ dev_warn(hw_priv->pdev, "xr_alloc_skb failed(%d)\n", len); -+ } -+ return 0; -+} -+ -+void xradio_deinit_resv_skb(struct xradio_common *hw_priv) -+{ -+ if (hw_priv->skb_reserved) { -+ dev_kfree_skb(hw_priv->skb_reserved); -+ hw_priv->skb_reserved = NULL; -+ hw_priv->skb_resv_len = 0; -+ } -+} -+ -+int xradio_realloc_resv_skb(struct xradio_common *hw_priv, -+ struct sk_buff *skb) -+{ -+ if (!hw_priv->skb_reserved && hw_priv->skb_resv_len) { -+ hw_priv->skb_reserved = dev_alloc_skb(hw_priv->skb_resv_len); -+ if (!hw_priv->skb_reserved) { -+ hw_priv->skb_reserved = skb; -+ dev_warn(hw_priv->pdev, "xr_alloc_skb failed(%d)\n", -+ hw_priv->skb_resv_len); -+ return -1; -+ } -+ } -+ return 0; /* realloc sbk success, deliver to upper.*/ -+} -+ -+static inline struct sk_buff *xradio_get_resv_skb(struct xradio_common *hw_priv, -+ size_t len) -+{ struct sk_buff *skb = NULL; -+ if (hw_priv->skb_reserved && len <= hw_priv->skb_resv_len) { -+ skb = hw_priv->skb_reserved; -+ hw_priv->skb_reserved = NULL; -+ } -+ return skb; -+} -+ -+static inline int xradio_put_resv_skb(struct xradio_common *hw_priv, -+ struct sk_buff *skb) -+{ -+ if (!hw_priv->skb_reserved && hw_priv->skb_resv_len) { -+ hw_priv->skb_reserved = skb; -+ return 0; -+ } -+ return 1; /* sbk not put to reserve*/ -+} -+ -+static struct sk_buff *xradio_get_skb(struct xradio_common *hw_priv, size_t len) -+{ -+ struct sk_buff *skb = NULL; -+ size_t alloc_len = (len > SDIO_BLOCK_SIZE) ? len : SDIO_BLOCK_SIZE; -+ -+ /* TKIP IV + TKIP ICV and MIC - Piggyback.*/ -+ alloc_len += WSM_TX_EXTRA_HEADROOM + 8 + 12- 2; -+ if (len > SDIO_BLOCK_SIZE || !hw_priv->skb_cache) { -+ skb = dev_alloc_skb(alloc_len); -+ /* In AP mode RXed SKB can be looped back as a broadcast. -+ * Here we reserve enough space for headers. */ -+ if (skb) { -+ skb_reserve(skb, WSM_TX_EXTRA_HEADROOM + 8 /* TKIP IV */ -+ - WSM_RX_EXTRA_HEADROOM); -+ } else { -+ skb = xradio_get_resv_skb(hw_priv, alloc_len); -+ if (skb) { -+ dev_dbg(hw_priv->pdev, "get skb_reserved(%d)!\n", alloc_len); -+ skb_reserve(skb, WSM_TX_EXTRA_HEADROOM + 8 /* TKIP IV */ -+ - WSM_RX_EXTRA_HEADROOM); -+ } else { -+ dev_dbg(hw_priv->pdev, "xr_alloc_skb failed(%d)!\n", alloc_len); -+ } -+ } -+ } else { -+ skb = hw_priv->skb_cache; -+ hw_priv->skb_cache = NULL; -+ } -+ return skb; -+} -+ -+static void xradio_put_skb(struct xradio_common *hw_priv, struct sk_buff *skb) -+{ -+ if (hw_priv->skb_cache) -+ dev_kfree_skb(skb); -+ else -+ hw_priv->skb_cache = skb; -+} -+ -+static int xradio_bh_read_ctrl_reg(struct xradio_common *hw_priv, -+ u16 *ctrl_reg) -+{ -+ int ret; -+ ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, ctrl_reg); -+ if (ret) { -+ ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, ctrl_reg); -+ if (ret) { -+ hw_priv->bh_error = 1; -+ dev_err(hw_priv->pdev, "Failed to read control register.\n"); -+ } -+ } -+ -+ return ret; -+} -+ -+static int xradio_device_wakeup(struct xradio_common *hw_priv) -+{ -+ u16 ctrl_reg; -+ int ret, i=0; -+ -+ /* To force the device to be always-on, the host sets WLAN_UP to 1 */ -+ ret = xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, HIF_CTRL_WUP_BIT); -+ if (WARN_ON(ret)) -+ return ret; -+ -+ ret = xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg); -+ if (WARN_ON(ret)) -+ return ret; -+ -+ /* If the device returns WLAN_RDY as 1, the device is active and will -+ * remain active. */ -+ while (!(ctrl_reg & HIF_CTRL_RDY_BIT) && i < 500) { -+ ret = xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg); -+ msleep(1); -+ i++; -+ } -+ if (unlikely(i >= 500)) { -+ dev_err(hw_priv->pdev, "Device cannot wakeup.\n"); -+ return -1; -+ } else if (unlikely(i >= 50)) -+ dev_warn(hw_priv->pdev, "Device wakeup time=%dms.\n", i); -+ dev_dbg(hw_priv->pdev, "Device awake, t=%dms.\n", i); -+ return 1; -+} -+ -+/* Must be called from BH thraed. */ -+void xradio_enable_powersave(struct xradio_vif *priv, -+ bool enable) -+{ -+ priv->powersave_enabled = enable; -+} -+ -+static void xradio_bh_rx_dump(struct device *dev, u8 *data, size_t len){ -+#ifdef DEBUG -+ static const char *msgnames[0xffff] = { -+ // 0x4?? is a sync response to a command -+ [0x0404] = "tx confirm", -+ [0x0406] = "mib confirm", -+ [0x0407] = "scan started", -+ [0x0409] = "configuration confirm", -+ [0x040a] = "reset confirm", -+ [0x040b] = "join confirm", -+ [0x040c] = "key added", -+ [0x040d] = "key removed", -+ [0x0410] = "pm confirm", -+ [0x0411] = "set bss params", -+ [0x0412] = "tx queue params", -+ [0x0413] = "edca confirm", -+ [0x0417] = "start confirm", -+ [0x041b] = "update ie confirm", -+ [0x041c] = "map link confirm", -+ // 0x8?? seem to be async responses or events -+ [0x0801] = "firmware startup complete", -+ [0x0804] = "rx", -+ [0x0805] = "event", -+ [0x0806] = "scan complete", -+ [0x0810] = "set pm indication" -+ }; -+ -+ u16 msgid, ifid; -+ u16 *p = (u16 *)data; -+ msgid = (*(p + 1)) & 0xC3F; -+ ifid = (*(p + 1)) >> 6; -+ ifid &= 0xF; -+ const char *msgname = msgnames[msgid]; -+ if(msgid == 0x804 && ifid == 2){ -+ msgname = "scan result"; -+ } -+ -+ dev_dbg(dev, "vif %d: sdio rx, msgid %s(0x%.4X) len %d\n", -+ ifid, msgname, msgid, *p); -+// print_hex_dump_bytes("<-- ", DUMP_PREFIX_NONE, -+// data, min(len, (size_t) 64)); -+#endif -+} -+ -+#define READLEN(ctrl) ((ctrl & HIF_CTRL_NEXT_LEN_MASK) << 1) //read_len=ctrl_reg*2. -+ -+static int xradio_bh_rx_availlen(struct xradio_common *hw_priv){ -+ u16 ctrl_reg = 0; -+ if (xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg)) { -+ return -EIO; -+ } -+ return READLEN(ctrl_reg); -+} -+ -+static int xradio_bh_rx(struct xradio_common *hw_priv, u16* nextlen) { -+ size_t read_len = 0; -+ struct sk_buff *skb_rx = NULL; -+ struct wsm_hdr *wsm; -+ size_t wsm_len; -+ int wsm_id; -+ u8 wsm_seq; -+ size_t alloc_len; -+ u8 *data; -+ int ret; -+ -+ read_len = *nextlen > 0 ? *nextlen : xradio_bh_rx_availlen(hw_priv); -+ if(read_len <= 0) -+ return read_len; -+ -+ if (read_len < sizeof(struct wsm_hdr) || (read_len > EFFECTIVE_BUF_SIZE)) { -+ dev_err(hw_priv->pdev, "Invalid read len: %d", read_len); -+ return -1; -+ } -+ -+ /* Add SIZE of PIGGYBACK reg (CONTROL Reg) -+ * to the NEXT Message length + 2 Bytes for SKB */ -+ read_len = read_len + 2; -+ -+ alloc_len = sdio_align_len(hw_priv, read_len); -+ /* Check if not exceeding XRADIO capabilities */ -+ if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) { -+ dev_err(hw_priv->pdev, "Read aligned len: %d\n", alloc_len); -+ } -+ -+ /* Get skb buffer. */ -+ skb_rx = xradio_get_skb(hw_priv, alloc_len); -+ if (!skb_rx) { -+ dev_err(hw_priv->pdev, "xradio_get_skb failed.\n"); -+ return -ENOMEM; -+ } -+ skb_trim(skb_rx, 0); -+ skb_put(skb_rx, read_len); -+ data = skb_rx->data; -+ if (!data) { -+ dev_err(hw_priv->pdev, "skb data is NULL.\n"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ /* Read data from device. */ -+ if (xradio_data_read(hw_priv, data, alloc_len)) { -+ ret = -EIO; -+ goto out; -+ } -+ -+ /* the ctrl register is appened to the end of the wsm frame -+ * so we can use this to avoid reading the control register -+ * again for the next read .. but if this is invalid we'll -+ * do an invalid read and the firmware will crash so this -+ * probably needs some sort of validation */ -+ *nextlen = READLEN(__le16_to_cpu(((__le16 *) data)[(alloc_len >> 1) - 1])); -+ -+ /* check wsm length. */ -+ wsm = (struct wsm_hdr *) data; -+ wsm_len = __le32_to_cpu(wsm->len); -+ -+ if (WARN_ON(wsm_len > read_len)) { -+ dev_err(hw_priv->pdev, "wsm is bigger than data read, read %d but frame is %d\n", -+ read_len, wsm_len); -+ ret = -1; -+ goto out; -+ } -+ -+ /* dump rx data. */ -+ xradio_bh_rx_dump(hw_priv->pdev, data, wsm_len); -+ -+ /* extract wsm id and seq. */ -+ wsm_id = __le32_to_cpu(wsm->id) & 0xFFF; -+ wsm_seq = (__le32_to_cpu(wsm->id) >> 13) & 7; -+ skb_trim(skb_rx, wsm_len); -+ -+ /* process exceptions. */ -+ if (wsm_id == 0) { -+ printk("wtf?\n"); -+ ret = 0; -+ goto out; -+ } else if (unlikely(wsm_id == 0x0800)) { -+ dev_err(hw_priv->pdev, "firmware exception!\n"); -+ wsm_handle_exception(hw_priv, &data[sizeof(*wsm)], -+ wsm_len - sizeof(*wsm)); -+ ret = -1; -+ goto out; -+ } -+ -+ hw_priv->wsm_rx_seq = (wsm_seq + 1) & 7; -+ -+ /* Process tx frames confirm. */ -+ if (wsm_id & 0x0400) { -+ if (wsm_release_tx_buffer(hw_priv, 1) < 0) { -+ dev_err(hw_priv->pdev, "tx buffer < 0.\n"); -+ ret = -1; -+ goto out; -+ } -+ } -+ -+ /* WSM processing frames. */ -+ if (wsm_handle_rx(hw_priv, wsm_id, wsm, &skb_rx)) { -+ dev_err(hw_priv->pdev, "wsm_handle_rx failed.\n"); -+ ret = -1; -+ goto out; -+ } -+ -+ ret = 1; -+ -+out: -+ /* Reclaim the SKB buffer */ -+ if (skb_rx) { -+ if (xradio_put_resv_skb(hw_priv, skb_rx)) -+ xradio_put_skb(hw_priv, skb_rx); -+ } -+ -+ return ret; -+} -+ -+static void xradio_bh_tx_dump(struct device *dev, u8 *data, size_t len){ -+#ifdef DEBUG -+ static const char *msgnames[0xffff] = { -+ [0x0004] = "tx", -+ [0x0006] = "MIB", -+ [0x0007] = "start scan", -+ [0x0009] = "configure", -+ [0x000A] = "reset", -+ [0x000B] = "join", -+ [0x000C] = "add key", -+ [0x000D] = "remove key", -+ [0x0010] = "set pm", -+ [0x0011] = "set bss params", -+ [0x0012] = "set tx queue params", -+ [0x0013] = "set edca", -+ [0x0017] = "start", -+ [0x001b] = "update ie", -+ [0x001c] = "map link", -+ }; -+ static const char *mibnames[0xffff] = { -+ [0x0003] = "DOT11_SLOT_TIME", -+ [0x1002] = "TEMPLATE_FRAME", -+ [0x1003] = "RX_FILTER", -+ [0x1004] = "BEACON_FILTER_TABLE", -+ [0x1005] = "BEACON_FILTER_ENABLE", -+ [0x1006] = "OPERATIONAL POWER MODE", -+ [0x1007] = "BEACON_WAKEUP_PERIOD", -+ [0x1009] = "RCPI_RSSI_THRESHOLD", -+ [0x1010] = "SET_ASSOCIATION_MODE", -+ [0x100e] = "BLOCK_ACK_POLICY", -+ [0x100f] = "OVERRIDE_INTERNAL_TX_RATE", -+ [0x1013] = "SET_UAPSD_INFORMATION", -+ [0x1016] = "SET_TX_RATE_RETRY_POLICY", -+ [0x1020] = "PROTECTED_MGMT_POLICY", -+ [0x1021] = "SET_HT_PROTECTION", -+ [0x1024] = "USE_MULTI_TX_CONF", -+ [0x1025] = "KEEP_ALIVE_PERIOD", -+ [0x1026] = "DISABLE_BSSID_FILTER", -+ [0x1035] = "SET_INACTIVITY", -+ }; -+ -+ u16 msgid, ifid, mib; -+ u16 *p = (u16 *)data; -+ msgid = (*(p + 1)) & 0x3F; -+ ifid = (*(p + 1)) >> 6; -+ ifid &= 0xF; -+ mib = *(p + 2); -+ -+ WARN_ON(msgnames[msgid] == NULL); -+ -+ if (msgid == 0x0006) { -+ dev_dbg(dev, "vif %d: sdio tx, msgid %s(0x%.4X) len %d MIB %s(0x%.4X)\n", -+ ifid, msgnames[msgid], msgid,*p, mibnames[mib], mib); -+ } else { -+ dev_dbg(dev, "vif %d: sdio tx, msgid %s(0x%.4X) len %d\n", ifid, msgnames[msgid], msgid, *p); -+ } -+ -+// print_hex_dump_bytes("--> ", DUMP_PREFIX_NONE, data, -+// min(len, (size_t) 64)); -+#endif -+} -+ -+static int xradio_bh_tx(struct xradio_common *hw_priv){ -+ int txavailable; -+ int txburst; -+ int vif_selected; -+ struct wsm_hdr *wsm; -+ size_t tx_len; -+ int ret; -+ u8 *data; -+ -+ BUG_ON(hw_priv->hw_bufs_used > hw_priv->wsm_caps.numInpChBufs); -+ txavailable = hw_priv->wsm_caps.numInpChBufs - hw_priv->hw_bufs_used; -+ if (txavailable) { -+ /* Wake up the devices */ -+ if (hw_priv->device_can_sleep) { -+ ret = xradio_device_wakeup(hw_priv); -+ if (WARN_ON(ret < 0)) { -+ return -1; -+ } else if (ret) { -+ hw_priv->device_can_sleep = false; -+ } else { /* Wait for "awake" interrupt */ -+ dev_dbg(hw_priv->pdev, -+ "need to wait for device to wake before doing tx\n"); -+ return 0; -+ } -+ } -+ /* Increase Tx buffer*/ -+ wsm_alloc_tx_buffer(hw_priv); -+ -+ /* Get data to send and send it. */ -+ ret = wsm_get_tx(hw_priv, &data, &tx_len, &txburst, &vif_selected); -+ if (ret <= 0) { -+ wsm_release_tx_buffer(hw_priv, 1); -+ if (WARN_ON(ret < 0)) { -+ dev_err(hw_priv->pdev, "wsm_get_tx=%d.\n", ret); -+ return -ENOMEM; -+ } else { -+ return 0; -+ } -+ } else { -+ wsm = (struct wsm_hdr *) data; -+ BUG_ON(tx_len < sizeof(*wsm)); -+ BUG_ON(__le32_to_cpu(wsm->len) != tx_len); -+ -+ /* Align tx length and check it. */ -+ if (tx_len <= 8) -+ tx_len = 16; -+ tx_len = sdio_align_len(hw_priv, tx_len); -+ -+ /* Check if not exceeding XRADIO capabilities */ -+ if (tx_len > EFFECTIVE_BUF_SIZE) { -+ dev_warn(hw_priv->pdev, "Write aligned len: %d\n", tx_len); -+ } -+ -+ /* Make sequence number. */ -+ wsm->id &= __cpu_to_le32(~WSM_TX_SEQ(WSM_TX_SEQ_MAX)); -+ wsm->id |= cpu_to_le32(WSM_TX_SEQ(hw_priv->wsm_tx_seq)); -+ -+ /* Send the data to devices. */ -+ if (WARN_ON(xradio_data_write(hw_priv, data, tx_len))) { -+ wsm_release_tx_buffer(hw_priv, 1); -+ dev_err(hw_priv->pdev, "xradio_data_write failed\n"); -+ return -EIO; -+ } -+ -+ xradio_bh_tx_dump(hw_priv->pdev, data, tx_len); -+ -+ /* Process after data have sent. */ -+ if (vif_selected != -1) { -+ hw_priv->hw_bufs_used_vif[vif_selected]++; -+ } -+ wsm_txed(hw_priv, data); -+ hw_priv->wsm_tx_seq = (hw_priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; -+ -+ return 1; -+ } -+ } else -+ return 0; -+} -+ -+static int xradio_bh_exchange(struct xradio_common *hw_priv) { -+ int rxdone; -+ int txdone; -+ u16 nextlen = 0; -+ -+ /* query stuck frames in firmware. */ -+ if (atomic_xchg(&hw_priv->query_cnt, 0)) { -+ if (schedule_work(&hw_priv->query_work) <= 0) -+ atomic_add(1, &hw_priv->query_cnt); -+ } -+ -+ /* keep doing tx and rx until they both stop or we are told -+ * to terminate */ -+ do { -+ txdone = xradio_bh_tx(hw_priv); -+ if (txdone < 0) { -+ break; -+ } -+ rxdone = xradio_bh_rx(hw_priv, &nextlen); -+ if (rxdone < 0) { -+ break; -+ } -+ } while ((txdone > 0 || rxdone > 0) && !kthread_should_stop()); -+ return 0; -+} -+ -+static int xradio_bh(void *arg) -+{ -+ struct xradio_common *hw_priv = arg; -+ int term, suspend; -+ int wake = 0; -+ long timeout; -+ long status; -+ -+ for (;;) { -+ timeout = HZ / 30; -+ -+ // wait for something to happen or a timeout -+ status = wait_event_interruptible_timeout(hw_priv->bh_wq, ( { -+ wake = atomic_xchg(&hw_priv->bh_tx, 0); -+ term = kthread_should_stop(); -+ suspend = atomic_read(&hw_priv->bh_suspend); -+ (wake || term || suspend);}), timeout); -+ -+ if (wake) { -+ if(xradio_bh_exchange(hw_priv) < 0){ -+ break; -+ } -+ } else if (term) { -+ dev_dbg(hw_priv->pdev, "xradio_bh exit!\n"); -+ break; -+ } else if (status < 0) { -+ dev_err(hw_priv->pdev, "bh_error=%d, status=%ld\n", -+ hw_priv->bh_error, status); -+ break; -+ } else if (!status) { -+ /* check if there is data waiting but we missed the interrupt*/ -+ if (xradio_bh_rx_availlen(hw_priv) > 0) { -+ dev_warn(hw_priv->pdev, "missed interrupt!\n"); -+ if(xradio_bh_exchange(hw_priv) < 0){ -+ break; -+ } -+ } -+ /* There are some frames to be confirmed. */ -+ else if (hw_priv->hw_bufs_used) { -+ long timeout = 0; -+ bool pending = 0; -+ dev_dbg(hw_priv->pdev, "Need confirm:%d!\n", -+ hw_priv->hw_bufs_used); -+ /* Check if frame transmission is timed out. */ -+ pending = xradio_query_txpkt_timeout(hw_priv, XRWL_ALL_IFS, -+ hw_priv->pending_frame_id, &timeout); -+ /* There are some frames confirm time out. */ -+ if (pending && timeout < 0) { -+ dev_err(hw_priv->pdev, "query_txpkt_timeout:%ld!\n", -+ timeout); -+ break; -+ } -+ } //else if (!txpending){ -+ //if (hw_priv->powersave_enabled && !hw_priv->device_can_sleep && !atomic_read(&hw_priv->recent_scan)) { -+ // /* Device is idle, we can go to sleep. */ -+ // dev_dbg(hw_priv->pdev, "Device idle(timeout), can sleep.\n"); -+ // WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, 0)); -+ // hw_priv->device_can_sleep = true; -+ //} -+ //continue; -+ //} -+ } else if (suspend) { -+ dev_dbg(hw_priv->pdev, "Host suspend request.\n"); -+ /* Check powersave setting again. */ -+ if (hw_priv->powersave_enabled) { -+ dev_dbg(hw_priv->pdev, -+ "Device idle(host suspend), can sleep.\n"); -+ WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, 0)); -+ hw_priv->device_can_sleep = true; -+ } -+ -+ /* bh thread go to suspend. */ -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_SUSPENDED); -+ wake_up(&hw_priv->bh_evt_wq); -+ status = wait_event_interruptible(hw_priv->bh_wq, -+ XRADIO_BH_RESUME == atomic_read(&hw_priv->bh_suspend)); -+ -+ if (status < 0) { -+ dev_err(hw_priv->pdev, "Failed to wait for resume: %ld.\n", -+ status); -+ break; -+ } -+ dev_dbg(hw_priv->pdev, "Host resume.\n"); -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUMED); -+ wake_up(&hw_priv->bh_evt_wq); -+ } -+ } /* for (;;)*/ -+ -+ dev_err(hw_priv->pdev, "bh thread exiting\n"); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/xradio/bh.h b/drivers/net/wireless/xradio/bh.h -new file mode 100644 -index 0000000..ca9187e ---- /dev/null -+++ b/drivers/net/wireless/xradio/bh.h -@@ -0,0 +1,36 @@ -+/* -+ * Data Transmission thread for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_BH_H -+#define XRADIO_BH_H -+ -+#define XRADIO_BH_THREAD "xradio_bh" -+ -+/* extern */ struct xradio_common; -+ -+#define SDIO_BLOCK_SIZE (528) -+ -+int xradio_register_bh(struct xradio_common *hw_priv); -+void xradio_unregister_bh(struct xradio_common *hw_priv); -+void xradio_irq_handler(struct xradio_common *hw_priv); -+void xradio_bh_wakeup(struct xradio_common *hw_priv); -+int xradio_bh_suspend(struct xradio_common *hw_priv); -+int xradio_bh_resume(struct xradio_common *hw_priv); -+/* Must be called from BH thread. */ -+void xradio_enable_powersave(struct xradio_vif *priv, bool enable); -+int wsm_release_tx_buffer(struct xradio_common *hw_priv, int count); -+int wsm_release_vif_tx_buffer(struct xradio_common *hw_priv, int if_id, -+ int count); -+int xradio_init_resv_skb(struct xradio_common *hw_priv); -+void xradio_deinit_resv_skb(struct xradio_common *hw_priv); -+int xradio_realloc_resv_skb(struct xradio_common *hw_priv, -+ struct sk_buff *skb); -+#endif /* XRADIO_BH_H */ -diff --git a/drivers/net/wireless/xradio/common.h b/drivers/net/wireless/xradio/common.h -new file mode 100644 -index 0000000..1ce23de ---- /dev/null -+++ b/drivers/net/wireless/xradio/common.h -@@ -0,0 +1,101 @@ -+/* -+ * Common interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_COMMON_H -+#define XRADIO_COMMON_H -+ -+/******************************************************* -+ interfaces for parse frame protocol info. -+********************************************************/ -+#define LLC_LEN 8 -+#define LLC_TYPE_OFF 6 //Ether type offset -+#define IP_PROTO_OFF 9 //protocol offset -+#define IP_S_ADD_OFF 12 -+#define IP_D_ADD_OFF 16 -+#define UDP_LEN 8 -+//DHCP -+#define DHCP_BOOTP_C 68 -+#define DHCP_BOOTP_S 67 -+#define UDP_BOOTP_LEN 236 //exclude "Options:64" -+#define BOOTP_OPS_LEN 64 -+#define DHCP_MAGIC 0x63825363 -+#define DHCP_DISCOVER 0x01 -+#define DHCP_OFFER 0x02 -+#define DHCP_REQUEST 0x03 -+#define DHCP_DECLINE 0x04 -+#define DHCP_ACK 0x05 -+#define DHCP_NACK 0x06 -+#define DHCP_RELEASE 0x07 -+ -+//LLC layer. -+static inline bool is_SNAP(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data) == 0xAAAA && llc_data[2] == 0x03); //0xAA, 0xAA, 0x03. -+} -+ -+static inline bool is_STP(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data) == 0xAAAA && llc_data[2] == 0x03); //0x42, 0x42, 0x03. -+} -+ -+//IP/IPV6/ARP layer... -+static inline bool is_ip(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_IP)); //0x0800 -+} -+static inline bool is_ipv6(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_IPV6)); //0x08dd -+} -+static inline bool is_arp(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_ARP)); //0x0806 -+} -+static inline bool is_8021x(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_PAE)); //0x888E -+} -+ -+//TCP/UDP layer... -+static inline bool is_tcp(u8* llc_data) -+{ -+ return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_TCP); // -+} -+ -+static inline bool is_udp(u8* llc_data) -+{ -+ return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_UDP); // -+} -+ -+static inline bool is_icmp(u8* llc_data) -+{ -+ return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_ICMP); // -+} -+ -+static inline bool is_igmp(u8* llc_data) -+{ -+ return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_IGMP); // -+} -+ -+static inline bool is_dhcp(u8* llc_data) -+{ -+ u8* ip_hdr = llc_data+LLC_LEN; -+ if(!is_ip(llc_data)) -+ return (bool)0; -+ if(ip_hdr[IP_PROTO_OFF] == IPPROTO_UDP) { -+ u8* udp_hdr = ip_hdr+((ip_hdr[0]&0xf)<<2); //ihl:words -+ return (bool)((((udp_hdr[0]<<8)|udp_hdr[1]) == DHCP_BOOTP_C) || //DHCP client -+ (((udp_hdr[0]<<8)|udp_hdr[1]) == DHCP_BOOTP_S)); //DHCP server -+ } -+ return (bool)0; -+} -+ -+#endif //XRADIO_COMMON_H -diff --git a/drivers/net/wireless/xradio/debug.h b/drivers/net/wireless/xradio/debug.h -new file mode 100644 -index 0000000..30a59f3 ---- /dev/null -+++ b/drivers/net/wireless/xradio/debug.h -@@ -0,0 +1,22 @@ -+/* -+ * DebugFS code for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef XRADIO_DEBUG_H_INCLUDED -+#define XRADIO_DEBUG_H_INCLUDED -+ -+#define xradio_dbg(level, ...) -+#define txrx_printk(level, ...) -+#define wsm_printk(level, ...) -+#define sta_printk(level, ...) -+#define scan_printk(level, ...) -+#define ap_printk(level, ...) -+#define pm_printk(level, ...) -+ -+#endif /* XRADIO_DEBUG_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/fwio.c b/drivers/net/wireless/xradio/fwio.c -new file mode 100644 -index 0000000..cfb45eb ---- /dev/null -+++ b/drivers/net/wireless/xradio/fwio.c -@@ -0,0 +1,560 @@ -+/* -+ * Firmware I/O implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "fwio.h" -+#include "hwio.h" -+#include "bh.h" -+#include "sdio.h" -+ -+/* Macroses are local. */ -+#define APB_WRITE(reg, val) \ -+ do { \ -+ ret = xradio_apb_write_32(hw_priv, APB_ADDR(reg), (val)); \ -+ if (ret < 0) { \ -+ dev_err(hw_priv->pdev, \ -+ "%s: can't write %s at line %d.\n", \ -+ __func__, #reg, __LINE__); \ -+ goto error; \ -+ } \ -+ } while (0) -+#define APB_READ(reg, val) \ -+ do { \ -+ ret = xradio_apb_read_32(hw_priv, APB_ADDR(reg), &(val)); \ -+ if (ret < 0) { \ -+ dev_err(hw_priv->pdev, \ -+ "%s: can't read %s at line %d.\n", \ -+ __func__, #reg, __LINE__); \ -+ goto error; \ -+ } \ -+ } while (0) -+#define REG_WRITE(reg, val) \ -+ do { \ -+ ret = xradio_reg_write_32(hw_priv, (reg), (val)); \ -+ if (ret < 0) { \ -+ dev_err(hw_priv->pdev, \ -+ "%s: can't write %s at line %d.\n", \ -+ __func__, #reg, __LINE__); \ -+ goto error; \ -+ } \ -+ } while (0) -+#define REG_READ(reg, val) \ -+ do { \ -+ ret = xradio_reg_read_32(hw_priv, (reg), &(val)); \ -+ if (ret < 0) { \ -+ dev_err(hw_priv->pdev, \ -+ "%s: can't read %s at line %d.\n", \ -+ __func__, #reg, __LINE__); \ -+ goto error; \ -+ } \ -+ } while (0) -+ -+ -+static int xradio_get_hw_type(u32 config_reg_val, int *major_revision) -+{ -+ int hw_type = -1; -+ u32 hif_type = (config_reg_val >> 24) & 0x4; -+ //u32 hif_vers = (config_reg_val >> 31) & 0x1; -+ -+ /* Check if we have XRADIO*/ -+ if (hif_type == 0x4) { -+ *major_revision = 0x4; -+ hw_type = HIF_HW_TYPE_XRADIO; -+ } else { -+ //hw type unknown. -+ *major_revision = 0x0; -+ } -+ return hw_type; -+} -+ -+/* -+ * This function is called to Parse the SDD file -+ * to extract some informations -+ */ -+static int xradio_parse_sdd(struct xradio_common *hw_priv, u32 *dpll) -+{ -+ int ret = 0; -+ const char *sdd_path = NULL; -+ struct xradio_sdd *pElement = NULL; -+ int parsedLength = 0; -+ -+ BUG_ON(hw_priv->sdd != NULL); -+ -+ /* select and load sdd file depend on hardware version. */ -+ switch (hw_priv->hw_revision) { -+ case XR819_HW_REV0: -+ sdd_path = XR819_SDD_FILE; -+ break; -+ default: -+ dev_dbg(hw_priv->pdev, "unknown hardware version.\n"); -+ return ret; -+ } -+ -+ ret = request_firmware(&hw_priv->sdd, sdd_path, hw_priv->pdev); -+ if (unlikely(ret)) { -+ dev_dbg(hw_priv->pdev, "can't load sdd file %s.\n", -+ sdd_path); -+ return ret; -+ } -+ -+ //parse SDD config. -+ hw_priv->is_BT_Present = false; -+ pElement = (struct xradio_sdd *)hw_priv->sdd->data; -+ parsedLength += (FIELD_OFFSET(struct xradio_sdd, data) + pElement->length); -+ pElement = FIND_NEXT_ELT(pElement); -+ -+ while (parsedLength < hw_priv->sdd->size) { -+ switch (pElement->id) { -+ case SDD_PTA_CFG_ELT_ID: -+ hw_priv->conf_listen_interval = (*((u16 *)pElement->data+1) >> 7) & 0x1F; -+ hw_priv->is_BT_Present = true; -+ xradio_dbg(XRADIO_DBG_NIY, "PTA element found.Listen Interval %d\n", -+ hw_priv->conf_listen_interval); -+ break; -+ case SDD_REFERENCE_FREQUENCY_ELT_ID: -+ switch(*((uint16_t*)pElement->data)) { -+ case 0x32C8: -+ *dpll = 0x1D89D241; -+ break; -+ case 0x3E80: -+ *dpll = 0x1E1; -+ break; -+ case 0x41A0: -+ *dpll = 0x124931C1; -+ break; -+ case 0x4B00: -+ *dpll = 0x191; -+ break; -+ case 0x5DC0: -+ *dpll = 0x141; -+ break; -+ case 0x6590: -+ *dpll = 0x0EC4F121; -+ break; -+ case 0x8340: -+ *dpll = 0x92490E1; -+ break; -+ case 0x9600: -+ *dpll = 0x100010C1; -+ break; -+ case 0x9C40: -+ *dpll = 0xC1; -+ break; -+ case 0xBB80: -+ *dpll = 0xA1; -+ break; -+ case 0xCB20: -+ *dpll = 0x7627091; -+ break; -+ default: -+ *dpll = DPLL_INIT_VAL_XRADIO; -+ xradio_dbg(XRADIO_DBG_WARN, "Unknown Reference clock frequency." -+ "Use default DPLL value=0x%08x.", DPLL_INIT_VAL_XRADIO); -+ break; -+ } -+ default: -+ break; -+ } -+ parsedLength += (FIELD_OFFSET(struct xradio_sdd, data) + pElement->length); -+ pElement = FIND_NEXT_ELT(pElement); -+ } -+ -+ dev_dbg(hw_priv->pdev, "sdd size=%d parse len=%d.\n", -+ hw_priv->sdd->size, parsedLength); -+ -+ // -+ if (hw_priv->is_BT_Present == false) { -+ hw_priv->conf_listen_interval = 0; -+ xradio_dbg(XRADIO_DBG_NIY, "PTA element NOT found.\n"); -+ } -+ return ret; -+} -+ -+static int xradio_firmware(struct xradio_common *hw_priv) -+{ -+ int ret, block, num_blocks; -+ unsigned i; -+ u32 val32; -+ u32 put = 0, get = 0; -+ u8 *buf = NULL; -+ const char *fw_path; -+ const struct firmware *firmware = NULL; -+ -+ switch (hw_priv->hw_revision) { -+ case XR819_HW_REV0: -+ fw_path = XR819_FIRMWARE; -+ break; -+ default: -+ dev_dbg(hw_priv->pdev, "invalid silicon revision %d.\n", -+ hw_priv->hw_revision); -+ return -EINVAL; -+ } -+ /* Initialize common registers */ -+ APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, DOWNLOAD_ARE_YOU_HERE); -+ APB_WRITE(DOWNLOAD_PUT_REG, 0); -+ APB_WRITE(DOWNLOAD_GET_REG, 0); -+ APB_WRITE(DOWNLOAD_STATUS_REG, DOWNLOAD_PENDING); -+ APB_WRITE(DOWNLOAD_FLAGS_REG, 0); -+ -+ /* Release CPU from RESET */ -+ REG_READ(HIF_CONFIG_REG_ID, val32); -+ val32 &= ~HIF_CONFIG_CPU_RESET_BIT; -+ REG_WRITE(HIF_CONFIG_REG_ID, val32); -+ -+ /* Enable Clock */ -+ val32 &= ~HIF_CONFIG_CPU_CLK_DIS_BIT; -+ REG_WRITE(HIF_CONFIG_REG_ID, val32); -+ -+ /* Load a firmware file */ -+ ret = request_firmware(&firmware, fw_path, hw_priv->pdev); -+ if (ret) { -+ dev_dbg(hw_priv->pdev, "can't load firmware file %s.\n", -+ fw_path); -+ goto error; -+ } -+ BUG_ON(!firmware->data); -+ -+ buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL); -+ if (!buf) { -+ dev_dbg(hw_priv->pdev, "can't allocate firmware buffer.\n"); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ /* Check if the bootloader is ready */ -+ for (i = 0; i < 100; i++/*= 1 + i / 2*/) { -+ APB_READ(DOWNLOAD_IMAGE_SIZE_REG, val32); -+ if (val32 == DOWNLOAD_I_AM_HERE) -+ break; -+ mdelay(10); -+ } /* End of for loop */ -+ if (val32 != DOWNLOAD_I_AM_HERE) { -+ dev_dbg(hw_priv->pdev, "bootloader is not ready.\n"); -+ ret = -ETIMEDOUT; -+ goto error; -+ } -+ -+ /* Calculcate number of download blocks */ -+ num_blocks = (firmware->size - 1) / DOWNLOAD_BLOCK_SIZE + 1; -+ -+ /* Updating the length in Download Ctrl Area */ -+ val32 = firmware->size; /* Explicit cast from size_t to u32 */ -+ APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32); -+ -+ /* Firmware downloading loop */ -+ for (block = 0; block < num_blocks ; block++) { -+ size_t tx_size; -+ size_t block_size; -+ -+ /* check the download status */ -+ APB_READ(DOWNLOAD_STATUS_REG, val32); -+ if (val32 != DOWNLOAD_PENDING) { -+ dev_dbg(hw_priv->pdev, "bootloader reported error %d.\n", -+ val32); -+ ret = -EIO; -+ goto error; -+ } -+ -+ /* loop until put - get <= 24K */ -+ for (i = 0; i < 100; i++) { -+ APB_READ(DOWNLOAD_GET_REG, get); -+ if ((put - get) <= (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) -+ break; -+ mdelay(i); -+ } -+ -+ if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { -+ dev_dbg(hw_priv->pdev, "Timeout waiting for FIFO.\n"); -+ ret = -ETIMEDOUT; -+ goto error; -+ } -+ -+ /* calculate the block size */ -+ tx_size = block_size = min((size_t)(firmware->size - put), (size_t)DOWNLOAD_BLOCK_SIZE); -+ memcpy(buf, &firmware->data[put], block_size); -+ -+ if (block_size < DOWNLOAD_BLOCK_SIZE) { -+ memset(&buf[block_size], 0, DOWNLOAD_BLOCK_SIZE - block_size); -+ tx_size = DOWNLOAD_BLOCK_SIZE; -+ } -+ -+ /* send the block to sram */ -+ ret = xradio_apb_write(hw_priv, APB_ADDR(DOWNLOAD_FIFO_OFFSET + (put & (DOWNLOAD_FIFO_SIZE - 1))), -+ buf, tx_size); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "%s: can't write block at line %d.\n", __func__, __LINE__); -+ goto error; -+ } -+ -+ /* update the put register */ -+ put += block_size; -+ APB_WRITE(DOWNLOAD_PUT_REG, put); -+ } /* End of firmware download loop */ -+ -+ /* Wait for the download completion */ -+ for (i = 0; i < 300; i += 1 + i / 2) { -+ APB_READ(DOWNLOAD_STATUS_REG, val32); -+ if (val32 != DOWNLOAD_PENDING) -+ break; -+ mdelay(i); -+ } -+ if (val32 != DOWNLOAD_SUCCESS) { -+ dev_dbg(hw_priv->pdev, "wait for download completion failed. " \ -+ "Read: 0x%.8X\n", val32); -+ ret = -ETIMEDOUT; -+ goto error; -+ } else { -+ dev_dbg(hw_priv->pdev, "Firmware completed.\n"); -+ ret = 0; -+ } -+ -+error: -+ if(buf) -+ kfree(buf); -+ if (firmware) { -+ release_firmware(firmware); -+ } -+ return ret; -+} -+ -+static int xradio_bootloader(struct xradio_common *hw_priv) -+{ -+ const char *bl_path = XR819_BOOTLOADER; -+ u32 addr = AHB_MEMORY_ADDRESS; -+ int ret; -+ u32 i; -+ u32 *data; -+ const struct firmware *bootloader; -+ -+ /* Load a bootloader file */ -+ ret = request_firmware(&bootloader, bl_path, hw_priv->pdev); -+ if (ret) { -+ dev_dbg(hw_priv->pdev, "can't load bootloader file %s.\n", -+ bl_path); -+ goto error; -+ } -+ -+ /* Down bootloader. */ -+ data = (u32 *)bootloader->data; -+ for(i = 0; i < (bootloader->size)/4; i++, addr+=4) { -+ REG_WRITE(HIF_SRAM_BASE_ADDR_REG_ID, addr); -+ REG_WRITE(HIF_AHB_DPORT_REG_ID,data[i]); -+ } -+ dev_dbg(hw_priv->pdev, "Bootloader complete\n"); -+ -+error: -+ if(bootloader) { -+ release_firmware(bootloader); -+ } -+ return ret; -+} -+ -+bool test_retry = false; -+int xradio_load_firmware(struct xradio_common *hw_priv) -+{ -+ int ret; -+ int i; -+ u32 val32; -+ u16 val16; -+ u32 dpll = 0; -+ int major_revision; -+ -+ /* Read CONFIG Register Value - We will read 32 bits */ -+ ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't read config register, err=%d.\n", -+ ret); -+ return ret; -+ } -+ -+ //check hardware type and revision. -+ hw_priv->hw_type = xradio_get_hw_type(val32, &major_revision); -+ switch (hw_priv->hw_type) { -+ case HIF_HW_TYPE_XRADIO: -+ dev_dbg(hw_priv->pdev, "HW_TYPE_XRADIO detected.\n"); -+ break; -+ default: -+ dev_dbg(hw_priv->pdev, "Unknown hardware: %d.\n", -+ hw_priv->hw_type); -+ return -ENOTSUPP; -+ } -+ if (major_revision == 4) { -+ hw_priv->hw_revision = XR819_HW_REV0; -+ dev_dbg(hw_priv->pdev, "XRADIO_HW_REV 1.0 detected.\n"); -+ } else { -+ dev_dbg(hw_priv->pdev, "Unsupported major revision %d.\n", -+ major_revision); -+ return -ENOTSUPP; -+ } -+ -+ //load sdd file, and get config from it. -+ ret = xradio_parse_sdd(hw_priv, &dpll); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ //set dpll initial value and check. -+ ret = xradio_reg_write_32(hw_priv, HIF_TSET_GEN_R_W_REG_ID, dpll); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't write DPLL register.\n"); -+ goto out; -+ } -+ msleep(5); -+ ret = xradio_reg_read_32(hw_priv, HIF_TSET_GEN_R_W_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't read DPLL register.\n"); -+ goto out; -+ } -+ if (val32 != dpll) { -+ dev_dbg(hw_priv->pdev, "unable to initialise " \ -+ "DPLL register. Wrote 0x%.8X, read 0x%.8X.\n", -+ dpll, val32); -+ ret = -EIO; -+ goto out; -+ } -+ -+ /* Set wakeup bit in device */ -+ ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, &val16); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "set_wakeup: can't read control register.\n"); -+ goto out; -+ } -+ ret = xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, val16 | HIF_CTRL_WUP_BIT); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "set_wakeup: can't write control register.\n"); -+ goto out; -+ } -+ -+ /* Wait for wakeup */ -+ for (i = 0 ; i < 300 ; i += 1 + i / 2) { -+ ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, &val16); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "Wait_for_wakeup: " -+ "can't read control register.\n"); -+ goto out; -+ } -+ if (val16 & HIF_CTRL_RDY_BIT) { -+ break; -+ } -+ msleep(i); -+ } -+ if ((val16 & HIF_CTRL_RDY_BIT) == 0) { -+ dev_dbg(hw_priv->pdev, "Wait for wakeup:" -+ "device is not responding.\n"); -+ ret = -ETIMEDOUT; -+ goto out; -+ } else { -+ dev_dbg(hw_priv->pdev, "WLAN device is ready.\n"); -+ } -+ -+ /* Checking for access mode and download firmware. */ -+ ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "check_access_mode: " -+ "can't read config register.\n"); -+ goto out; -+ } -+ if (val32 & HIF_CONFIG_ACCESS_MODE_BIT) { -+ /* Down bootloader. */ -+ ret = xradio_bootloader(hw_priv); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't download bootloader.\n"); -+ goto out; -+ } -+ /* Down firmware. */ -+ ret = xradio_firmware(hw_priv); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't download firmware.\n"); -+ goto out; -+ } -+ } else { -+ dev_dbg(hw_priv->pdev, "check_access_mode: " -+ "device is already in QUEUE mode.\n"); -+ /* TODO: verify this branch. Do we need something to do? */ -+ } -+ -+ if (HIF_HW_TYPE_XRADIO == hw_priv->hw_type) { -+ /* If device is XRADIO the IRQ enable/disable bits -+ * are in CONFIG register */ -+ ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "enable_irq: can't read " \ -+ "config register.\n"); -+ goto unsubscribe; -+ } -+ ret = xradio_reg_write_32(hw_priv, HIF_CONFIG_REG_ID, -+ val32 | HIF_CONF_IRQ_RDY_ENABLE); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "enable_irq: can't write " \ -+ "config register.\n"); -+ goto unsubscribe; -+ } -+ } else { -+ /* If device is XRADIO the IRQ enable/disable bits -+ * are in CONTROL register */ -+ /* Enable device interrupts - Both DATA_RDY and WLAN_RDY */ -+ ret = xradio_reg_read_16(hw_priv, HIF_CONFIG_REG_ID, &val16); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "enable_irq: can't read " \ -+ "control register.\n"); -+ goto unsubscribe; -+ } -+ ret = xradio_reg_write_16(hw_priv, HIF_CONFIG_REG_ID, -+ val16 | HIF_CTRL_IRQ_RDY_ENABLE); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "enable_irq: can't write " \ -+ "control register.\n"); -+ goto unsubscribe; -+ } -+ -+ } -+ -+ /* Configure device for MESSSAGE MODE */ -+ ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "set_mode: can't read config register.\n"); -+ goto unsubscribe; -+ } -+ ret = xradio_reg_write_32(hw_priv, HIF_CONFIG_REG_ID, -+ val32 & ~HIF_CONFIG_ACCESS_MODE_BIT); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "set_mode: can't write config register.\n"); -+ goto unsubscribe; -+ } -+ -+ /* Unless we read the CONFIG Register we are -+ * not able to get an interrupt */ -+ mdelay(10); -+ xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ return 0; -+ -+unsubscribe: -+out: -+ if (hw_priv->sdd) { -+ release_firmware(hw_priv->sdd); -+ hw_priv->sdd = NULL; -+ } -+ return ret; -+} -+ -+int xradio_dev_deinit(struct xradio_common *hw_priv) -+{ -+ if (hw_priv->sdd) { -+ release_firmware(hw_priv->sdd); -+ hw_priv->sdd = NULL; -+ } -+ return 0; -+} -diff --git a/drivers/net/wireless/xradio/fwio.h b/drivers/net/wireless/xradio/fwio.h -new file mode 100644 -index 0000000..b5efeb1 ---- /dev/null -+++ b/drivers/net/wireless/xradio/fwio.h -@@ -0,0 +1,33 @@ -+/* -+ * Firmware APIs for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef FWIO_H_INCLUDED -+#define FWIO_H_INCLUDED -+ -+#define XR819_HW_REV0 (8190) -+#define XR819_BOOTLOADER ("xr819/boot_xr819.bin") -+#define XR819_FIRMWARE ("xr819/fw_xr819.bin") -+#define XR819_SDD_FILE ("xr819/sdd_xr819.bin") -+ -+#define SDD_PTA_CFG_ELT_ID 0xEB -+#define SDD_REFERENCE_FREQUENCY_ELT_ID 0xC5 -+#define FIELD_OFFSET(type, field) ((u8 *)&((type *)0)->field - (u8 *)0) -+#define FIND_NEXT_ELT(e) (struct xradio_sdd *)((u8 *)&e->data + e->length) -+struct xradio_sdd { -+ u8 id; -+ u8 length; -+ u8 data[]; -+}; -+ -+struct xradio_common; -+int xradio_load_firmware(struct xradio_common *hw_priv); -+int xradio_dev_deinit(struct xradio_common *hw_priv); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/ht.c b/drivers/net/wireless/xradio/ht.c -new file mode 100644 -index 0000000..a9b3630 ---- /dev/null -+++ b/drivers/net/wireless/xradio/ht.c -@@ -0,0 +1,86 @@ -+#include -+ -+#include "xradio.h" -+#include "sta.h" -+ -+#define AG_RATE_INDEX 6 //11a/g rate for important short frames in 5G. -+ -+#ifdef AP_HT_COMPAT_FIX -+#define AP_COMPAT_THRESHOLD 2000 -+#define AP_COMPAT_MIN_CNT 200 -+u8 ap_compat_bssid[ETH_ALEN] = {0}; -+int xradio_apcompat_detect(struct xradio_vif *priv, u8 rx_rate) -+{ -+ if (rx_rate < AG_RATE_INDEX) { -+ priv->ht_compat_cnt++; -+ txrx_printk(XRADIO_DBG_MSG,"%s:rate=%d.\n", __func__, rx_rate); -+ } else { -+ priv->ht_compat_det |= 1; -+ priv->ht_compat_cnt = 0; -+ txrx_printk(XRADIO_DBG_NIY,"%s:HT compat detect\n", __func__); -+ return 0; -+ } -+ -+ /* Enhance compatibility with some illegal APs.*/ -+ if (priv->ht_compat_cnt > AP_COMPAT_THRESHOLD || -+ (priv->ht_compat_cnt > AP_COMPAT_MIN_CNT && -+ priv->bssid[0] == 0xC8 && -+ priv->bssid[1] == 0x3A && -+ priv->bssid[2] == 0x35)) { -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ memcpy(ap_compat_bssid, priv->bssid, ETH_ALEN); -+ wms_send_disassoc_to_self(hw_priv, priv); -+ txrx_printk(XRADIO_DBG_WARN, "%s:SSID=%s, BSSID=" \ -+ "%02x:%02x:%02x:%02x:%02x:%02x\n", __func__, priv->ssid, -+ ap_compat_bssid[0], ap_compat_bssid[1], -+ ap_compat_bssid[2], ap_compat_bssid[3], -+ ap_compat_bssid[4], ap_compat_bssid[5]); -+ return 1; -+ } -+ return 0; -+} -+ -+void xradio_remove_ht_ie(struct xradio_vif *priv, struct sk_buff *skb) -+{ -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -+ u8 *ies = NULL; -+ size_t ies_len = 0; -+ u8 *ht_ie = NULL; -+ -+ if (!mgmt || memcmp(ap_compat_bssid, mgmt->bssid, ETH_ALEN)) -+ return; -+ -+ if (ieee80211_is_probe_resp(mgmt->frame_control)) -+ ies = mgmt->u.probe_resp.variable; -+ else if (ieee80211_is_beacon(mgmt->frame_control)) -+ ies = mgmt->u.beacon.variable; -+ else if (ieee80211_is_assoc_resp(mgmt->frame_control)) -+ ies = mgmt->u.assoc_resp.variable; -+ else if (ieee80211_is_assoc_req(mgmt->frame_control)) -+ ies = mgmt->u.assoc_req.variable; -+ else -+ return; -+ -+ ies_len = skb->len - (ies - (u8 *)(skb->data)); -+ ht_ie = (u8 *)xradio_get_ie(ies, ies_len, WLAN_EID_HT_CAPABILITY); -+ if (ht_ie) { -+ u8 ht_len = *(ht_ie + 1) + 2; -+ u8 move_len = (ies + ies_len) - (ht_ie + ht_len); -+ memmove(ht_ie, (ht_ie + ht_len), move_len); -+ skb_trim(skb, skb->len - ht_len); -+ ies_len = skb->len - (ies - (u8 *)(skb->data)); -+ ht_ie = (u8 *)xradio_get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); -+ if (ht_ie) { -+ ht_len = *(ht_ie + 1) + 2; -+ move_len = (ies + ies_len) - (ht_ie + ht_len); -+ memmove(ht_ie, (ht_ie + ht_len), move_len); -+ skb_trim(skb, skb->len - ht_len); -+ } -+ } -+ txrx_printk(XRADIO_DBG_WARN, "%s: BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n", -+ __func__, -+ mgmt->bssid[0], mgmt->bssid[1], -+ mgmt->bssid[2], mgmt->bssid[3], -+ mgmt->bssid[4], mgmt->bssid[5]); -+} -+#endif //AP_HT_COMPAT_FIX -\ No newline at end of file -diff --git a/drivers/net/wireless/xradio/ht.h b/drivers/net/wireless/xradio/ht.h -new file mode 100644 -index 0000000..346b425 ---- /dev/null -+++ b/drivers/net/wireless/xradio/ht.h -@@ -0,0 +1,44 @@ -+/* -+ * HT-related code for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef XRADIO_HT_H_INCLUDED -+#define XRADIO_HT_H_INCLUDED -+ -+#include -+ -+struct xradio_ht_oper { -+ struct ieee80211_sta_ht_cap ht_cap; -+ enum nl80211_channel_type channel_type; -+ u16 operation_mode; -+}; -+ -+static inline int xradio_is_ht(const struct xradio_ht_oper *ht_oper) -+{ -+ return ht_oper->channel_type != NL80211_CHAN_NO_HT; -+} -+ -+static inline int xradio_ht_greenfield(const struct xradio_ht_oper *ht_oper) -+{ -+ return (xradio_is_ht(ht_oper) && -+ (ht_oper->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && -+ !(ht_oper->operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)); -+} -+ -+static inline int xradio_ht_ampdu_density(const struct xradio_ht_oper *ht_oper) -+{ -+ if (!xradio_is_ht(ht_oper)) -+ return 0; -+ return ht_oper->ht_cap.ampdu_density; -+} -+ -+int xradio_apcompat_detect(struct xradio_vif *priv, u8 rx_rate); -+void xradio_remove_ht_ie(struct xradio_vif *priv, struct sk_buff *skb); -+ -+#endif /* XRADIO_HT_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/hwio.c b/drivers/net/wireless/xradio/hwio.c -new file mode 100644 -index 0000000..b813333 ---- /dev/null -+++ b/drivers/net/wireless/xradio/hwio.c -@@ -0,0 +1,280 @@ -+/* -+ * Hardware I/O implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+ -+#include "xradio.h" -+#include "hwio.h" -+#include "sdio.h" -+ -+#define CHECK_ADDR_LEN 1 -+ -+ /* Sdio addr is 4*spi_addr */ -+#define SPI_REG_ADDR_TO_SDIO(spi_reg_addr) ((spi_reg_addr) << 2) -+#define SDIO_ADDR17BIT(buf_id, mpf, rfu, reg_id_ofs) \ -+ ((((buf_id) & 0x1F) << 7) \ -+ | (((mpf) & 1) << 6) \ -+ | (((rfu) & 1) << 5) \ -+ | (((reg_id_ofs) & 0x1F) << 0)) -+#define MAX_RETRY 3 -+ -+ -+static int __xradio_read(struct xradio_common *hw_priv, u16 addr, -+ void *buf, size_t buf_len, int buf_id) -+{ -+ u16 addr_sdio; -+ u32 sdio_reg_addr_17bit ; -+ -+#if (CHECK_ADDR_LEN) -+ /* Check if buffer is aligned to 4 byte boundary */ -+ if (WARN_ON(((unsigned long)buf & 3) && (buf_len > 4))) { -+ dev_dbg(hw_priv->pdev, "buffer is not aligned.\n"); -+ return -EINVAL; -+ } -+#endif -+ -+ /* Convert to SDIO Register Address */ -+ addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); -+ sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); -+ return sdio_data_read(hw_priv, -+ sdio_reg_addr_17bit, -+ buf, buf_len); -+} -+ -+static int __xradio_write(struct xradio_common *hw_priv, u16 addr, -+ const void *buf, size_t buf_len, int buf_id) -+{ -+ u16 addr_sdio; -+ u32 sdio_reg_addr_17bit ; -+ -+#if (CHECK_ADDR_LEN) -+ /* Check if buffer is aligned to 4 byte boundary */ -+ if (WARN_ON(((unsigned long)buf & 3) && (buf_len > 4))) { -+ dev_err(hw_priv->pdev, "buffer is not aligned.\n"); -+ return -EINVAL; -+ } -+#endif -+ -+ /* Convert to SDIO Register Address */ -+ addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); -+ sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); -+ -+ return sdio_data_write(hw_priv, -+ sdio_reg_addr_17bit, -+ buf, buf_len); -+} -+ -+static inline int __xradio_read_reg32(struct xradio_common *hw_priv, -+ u16 addr, u32 *val) -+{ -+ return __xradio_read(hw_priv, addr, val, sizeof(val), 0); -+} -+ -+static inline int __xradio_write_reg32(struct xradio_common *hw_priv, -+ u16 addr, u32 val) -+{ -+ return __xradio_write(hw_priv, addr, &val, sizeof(val), 0); -+} -+ -+int xradio_reg_read(struct xradio_common *hw_priv, u16 addr, -+ void *buf, size_t buf_len) -+{ -+ int ret; -+ sdio_lock(hw_priv); -+ ret = __xradio_read(hw_priv, addr, buf, buf_len, 0); -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_reg_write(struct xradio_common *hw_priv, u16 addr, -+ const void *buf, size_t buf_len) -+{ -+ int ret; -+ sdio_lock(hw_priv); -+ ret = __xradio_write(hw_priv, addr, buf, buf_len, 0); -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_data_read(struct xradio_common *hw_priv, void *buf, size_t buf_len) -+{ -+ int ret, retry = 1; -+ sdio_lock(hw_priv); -+ { -+ int buf_id_rx = hw_priv->buf_id_rx; -+ while (retry <= MAX_RETRY) { -+ ret = __xradio_read(hw_priv, HIF_IN_OUT_QUEUE_REG_ID, buf, -+ buf_len, buf_id_rx + 1); -+ if (!ret) { -+ buf_id_rx = (buf_id_rx + 1) & 3; -+ hw_priv->buf_id_rx = buf_id_rx; -+ break; -+ } else { -+ //~dgp this retrying stuff is silly as it can crash the fw if there is nothing to read -+ dev_err(hw_priv->pdev, "data read error :%d - attempt %d of %d\n", ret, retry, MAX_RETRY); -+ retry++; -+ mdelay(1); -+ } -+ } -+ } -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_data_write(struct xradio_common *hw_priv, const void *buf, -+ size_t buf_len) -+{ -+ int ret, retry = 1; -+ sdio_lock(hw_priv); -+ { -+ int buf_id_tx = hw_priv->buf_id_tx; -+ while (retry <= MAX_RETRY) { -+ ret = __xradio_write(hw_priv, HIF_IN_OUT_QUEUE_REG_ID, buf, -+ buf_len, buf_id_tx); -+ if (!ret) { -+ buf_id_tx = (buf_id_tx + 1) & 31; -+ hw_priv->buf_id_tx = buf_id_tx; -+ break; -+ } else { -+ dev_err(hw_priv->pdev, "data write error :%d - attempt %d - %d\n", ret, retry, MAX_RETRY); -+ retry++; -+ mdelay(1); -+ } -+ } -+ } -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_indirect_read(struct xradio_common *hw_priv, u32 addr, void *buf, -+ size_t buf_len, u32 prefetch, u16 port_addr) -+{ -+ u32 val32 = 0; -+ int i, ret; -+ -+ if ((buf_len / 2) >= 0x1000) { -+ dev_err(hw_priv->pdev, "Can't read more than 0xfff words.\n"); -+ return -EINVAL; -+ goto out; -+ } -+ -+ sdio_lock(hw_priv); -+ /* Write address */ -+ ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write address register.\n"); -+ goto out; -+ } -+ -+ /* Read CONFIG Register Value - We will read 32 bits */ -+ ret = __xradio_read_reg32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't read config register.\n"); -+ goto out; -+ } -+ -+ /* Set PREFETCH bit */ -+ ret = __xradio_write_reg32(hw_priv, HIF_CONFIG_REG_ID, val32 | prefetch); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write prefetch bit.\n"); -+ goto out; -+ } -+ -+ /* Check for PRE-FETCH bit to be cleared */ -+ for (i = 0; i < 20; i++) { -+ ret = __xradio_read_reg32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't check prefetch bit.\n"); -+ goto out; -+ } -+ if (!(val32 & prefetch)) -+ break; -+ mdelay(i); -+ } -+ -+ if (val32 & prefetch) { -+ dev_err(hw_priv->pdev, "Prefetch bit is not cleared.\n"); -+ goto out; -+ } -+ -+ /* Read data port */ -+ ret = __xradio_read(hw_priv, port_addr, buf, buf_len, 0); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't read data port.\n"); -+ goto out; -+ } -+ -+out: -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_apb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, -+ size_t buf_len) -+{ -+ int ret; -+ -+ if ((buf_len / 2) >= 0x1000) { -+ dev_err(hw_priv->pdev, "Can't wrire more than 0xfff words.\n"); -+ return -EINVAL; -+ } -+ -+ sdio_lock(hw_priv); -+ -+ /* Write address */ -+ ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write address register.\n"); -+ goto out; -+ } -+ -+ /* Write data port */ -+ ret = __xradio_write(hw_priv, HIF_SRAM_DPORT_REG_ID, buf, buf_len, 0); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write data port.\n"); -+ goto out; -+ } -+ -+out: -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_ahb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, -+ size_t buf_len) -+{ -+ int ret; -+ -+ if ((buf_len / 2) >= 0x1000) { -+ dev_err(hw_priv->pdev, "Can't wrire more than 0xfff words.\n"); -+ return -EINVAL; -+ } -+ -+ sdio_lock(hw_priv); -+ -+ /* Write address */ -+ ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write address register.\n"); -+ goto out; -+ } -+ -+ /* Write data port */ -+ ret = __xradio_write(hw_priv, HIF_AHB_DPORT_REG_ID, buf, buf_len, 0); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write data port.\n"); -+ goto out; -+ } -+ -+out: -+ sdio_unlock(hw_priv); -+ return ret; -+} -diff --git a/drivers/net/wireless/xradio/hwio.h b/drivers/net/wireless/xradio/hwio.h -new file mode 100644 -index 0000000..531c2b8 ---- /dev/null -+++ b/drivers/net/wireless/xradio/hwio.h -@@ -0,0 +1,229 @@ -+/* -+ * hardware interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_HWIO_H_INCLUDED -+#define XRADIO_HWIO_H_INCLUDED -+ -+/* extern */ struct xradio_common; -+ -+/* DPLL initial values */ -+#define DPLL_INIT_VAL_XRADIO (0x0EC4F121) -+ -+/* Hardware Type Definitions */ -+#define HIF_HW_TYPE_XRADIO (1) -+ -+ -+/* boot loader start address in SRAM */ -+#define DOWNLOAD_BOOT_LOADER_OFFSET (0x00000000) -+/* 32K, 0x4000 to 0xDFFF */ -+#define DOWNLOAD_FIFO_OFFSET (0x00004000) -+/* 32K */ -+#define DOWNLOAD_FIFO_SIZE (0x00008000) -+/* 128 bytes, 0xFF80 to 0xFFFF */ -+#define DOWNLOAD_CTRL_OFFSET (0x0000FF80) -+#define DOWNLOAD_CTRL_DATA_DWORDS (32-6) -+ -+/* Download control area */ -+struct download_cntl_t { -+ /* size of whole firmware file (including Cheksum), host init */ -+ u32 ImageSize; -+ /* downloading flags */ -+ u32 Flags; -+ /* No. of bytes put into the download, init & updated by host */ -+ u32 Put; -+ /* last traced program counter, last ARM reg_pc */ -+ u32 TracePc; -+ /* No. of bytes read from the download, host init, device updates */ -+ u32 Get; -+ /* r0, boot losader status, host init to pending, device updates */ -+ u32 Status; -+ /* Extra debug info, r1 to r14 if status=r0=DOWNLOAD_EXCEPTION */ -+ u32 DebugData[DOWNLOAD_CTRL_DATA_DWORDS]; -+}; -+ -+#define DOWNLOAD_IMAGE_SIZE_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, ImageSize)) -+#define DOWNLOAD_FLAGS_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Flags)) -+#define DOWNLOAD_PUT_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Put)) -+#define DOWNLOAD_TRACE_PC_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, TracePc)) -+#define DOWNLOAD_GET_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Get)) -+#define DOWNLOAD_STATUS_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Status)) -+#define DOWNLOAD_DEBUG_DATA_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, DebugData)) -+ -+#define DOWNLOAD_DEBUG_DATA_LEN (108) -+#define DOWNLOAD_BLOCK_SIZE (1024) -+ -+/* For boot loader detection */ -+#define DOWNLOAD_ARE_YOU_HERE (0x87654321) -+#define DOWNLOAD_I_AM_HERE (0x12345678) -+ -+/* Download error code */ -+#define DOWNLOAD_PENDING (0xFFFFFFFF) -+#define DOWNLOAD_SUCCESS (0) -+#define DOWNLOAD_EXCEPTION (1) -+#define DOWNLOAD_ERR_MEM_1 (2) -+#define DOWNLOAD_ERR_MEM_2 (3) -+#define DOWNLOAD_ERR_SOFTWARE (4) -+#define DOWNLOAD_ERR_FILE_SIZE (5) -+#define DOWNLOAD_ERR_CHECKSUM (6) -+#define DOWNLOAD_ERR_OVERFLOW (7) -+#define DOWNLOAD_ERR_IMAGE (8) -+#define DOWNLOAD_ERR_HOST (9) -+#define DOWNLOAD_ERR_ABORT (10) -+ -+#define SYS_BASE_ADDR_SILICON (0) -+#define AHB_MEMORY_ADDRESS (SYS_BASE_ADDR_SILICON + 0x08000000) -+#define PAC_BASE_ADDRESS_SILICON (SYS_BASE_ADDR_SILICON + 0x09000000) -+#define PAC_SHARED_MEMORY_SILICON (PAC_BASE_ADDRESS_SILICON) -+#define APB_ADDR(addr) (PAC_SHARED_MEMORY_SILICON + (addr)) -+ -+/* *************************************************************** -+*Device register definitions -+*************************************************************** */ -+/* WBF - SPI Register Addresses */ -+#define HIF_ADDR_ID_BASE (0x0000) -+/* 16/32 bits */ -+#define HIF_CONFIG_REG_ID (0x0000) -+/* 16/32 bits */ -+#define HIF_CONTROL_REG_ID (0x0001) -+/* 16 bits, Q mode W/R */ -+#define HIF_IN_OUT_QUEUE_REG_ID (0x0002) -+/* 32 bits, AHB bus R/W */ -+#define HIF_AHB_DPORT_REG_ID (0x0003) -+/* 16/32 bits */ -+#define HIF_SRAM_BASE_ADDR_REG_ID (0x0004) -+/* 32 bits, APB bus R/W */ -+#define HIF_SRAM_DPORT_REG_ID (0x0005) -+/* 32 bits, t_settle/general */ -+#define HIF_TSET_GEN_R_W_REG_ID (0x0006) -+/* 16 bits, Q mode read, no length */ -+#define HIF_FRAME_OUT_REG_ID (0x0007) -+#define HIF_ADDR_ID_MAX (HIF_FRAME_OUT_REG_ID) -+ -+/* WBF - Control register bit set */ -+/* next o/p length, bit 11 to 0 */ -+#define HIF_CTRL_NEXT_LEN_MASK (0x0FFF) -+#define HIF_CTRL_WUP_BIT (BIT(12)) -+#define HIF_CTRL_RDY_BIT (BIT(13)) -+#define HIF_CTRL_IRQ_ENABLE (BIT(14)) -+#define HIF_CTRL_RDY_ENABLE (BIT(15)) -+#define HIF_CTRL_IRQ_RDY_ENABLE (BIT(14)|BIT(15)) -+ -+/* SPI Config register bit set */ -+#define HIF_CONFIG_FRAME_BIT (BIT(2)) -+#define HIF_CONFIG_WORD_MODE_BITS (BIT(3)|BIT(4)) -+#define HIF_CONFIG_WORD_MODE_1 (BIT(3)) -+#define HIF_CONFIG_WORD_MODE_2 (BIT(4)) -+#define HIF_CONFIG_ERROR_0_BIT (BIT(5)) -+#define HIF_CONFIG_ERROR_1_BIT (BIT(6)) -+#define HIF_CONFIG_ERROR_2_BIT (BIT(7)) -+/* TBD: Sure??? */ -+#define HIF_CONFIG_CSN_FRAME_BIT (BIT(7)) -+#define HIF_CONFIG_ERROR_3_BIT (BIT(8)) -+#define HIF_CONFIG_ERROR_4_BIT (BIT(9)) -+/* QueueM */ -+#define HIF_CONFIG_ACCESS_MODE_BIT (BIT(10)) -+/* AHB bus */ -+#define HIF_CONFIG_AHB_PFETCH_BIT (BIT(11)) -+#define HIF_CONFIG_CPU_CLK_DIS_BIT (BIT(12)) -+/* APB bus */ -+#define HIF_CONFIG_PFETCH_BIT (BIT(13)) -+/* cpu reset */ -+#define HIF_CONFIG_CPU_RESET_BIT (BIT(14)) -+#define HIF_CONFIG_CLEAR_INT_BIT (BIT(15)) -+ -+/* For XRADIO the IRQ Enable and Ready Bits are in CONFIG register */ -+#define HIF_CONF_IRQ_RDY_ENABLE (BIT(16)|BIT(17)) -+ -+int xradio_data_read(struct xradio_common *hw_priv, void *buf, size_t buf_len); -+int xradio_data_write(struct xradio_common *hw_priv, const void *buf, size_t buf_len); -+int xradio_reg_read(struct xradio_common *hw_priv, u16 addr, void *buf, size_t buf_len); -+int xradio_reg_write(struct xradio_common *hw_priv, u16 addr, const void *buf, size_t buf_len); -+int xradio_indirect_read(struct xradio_common *hw_priv, u32 addr, void *buf, -+ size_t buf_len, u32 prefetch, u16 port_addr); -+int xradio_apb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, size_t buf_len); -+int xradio_ahb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, size_t buf_len); -+ -+ -+static inline int xradio_reg_read_16(struct xradio_common *hw_priv, -+ u16 addr, u16 *val) -+{ -+ int ret = 0; -+ u32 bigVal = 0; -+ ret = xradio_reg_read(hw_priv, addr, &bigVal, sizeof(bigVal)); -+ *val = (u16)bigVal; -+ return ret; -+} -+ -+static inline int xradio_reg_write_16(struct xradio_common *hw_priv, -+ u16 addr, u16 val) -+{ -+ u32 bigVal = (u32)val; -+ return xradio_reg_write(hw_priv, addr, &bigVal, sizeof(bigVal)); -+} -+ -+static inline int xradio_reg_read_32(struct xradio_common *hw_priv, -+ u16 addr, u32 *val) -+{ -+ return xradio_reg_read(hw_priv, addr, val, sizeof(val)); -+} -+ -+static inline int xradio_reg_write_32(struct xradio_common *hw_priv, -+ u16 addr, u32 val) -+{ -+ return xradio_reg_write(hw_priv, addr, &val, sizeof(val)); -+} -+ -+static inline int xradio_apb_read(struct xradio_common *hw_priv, u32 addr, -+ void *buf, size_t buf_len) -+{ -+ return xradio_indirect_read(hw_priv, addr, buf, buf_len, HIF_CONFIG_PFETCH_BIT, -+ HIF_SRAM_DPORT_REG_ID); -+} -+ -+static inline int xradio_ahb_read(struct xradio_common *hw_priv, u32 addr, -+ void *buf, size_t buf_len) -+{ -+ return xradio_indirect_read(hw_priv, addr, buf, buf_len, HIF_CONFIG_AHB_PFETCH_BIT, -+ HIF_AHB_DPORT_REG_ID); -+} -+ -+static inline int xradio_apb_read_32(struct xradio_common *hw_priv, -+ u32 addr, u32 *val) -+{ -+ return xradio_apb_read(hw_priv, addr, val, sizeof(val)); -+} -+ -+static inline int xradio_apb_write_32(struct xradio_common *hw_priv, -+ u32 addr, u32 val) -+{ -+ return xradio_apb_write(hw_priv, addr, &val, sizeof(val)); -+} -+ -+static inline int xradio_ahb_read_32(struct xradio_common *hw_priv, -+ u32 addr, u32 *val) -+{ -+ return xradio_ahb_read(hw_priv, addr, val, sizeof(val)); -+} -+ -+static inline int xradio_ahb_write_32(struct xradio_common *hw_priv, -+ u32 addr, u32 val) -+{ -+ return xradio_ahb_write(hw_priv, addr, &val, sizeof(val)); -+} -+ -+#endif /* XRADIO_HWIO_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/keys.c b/drivers/net/wireless/xradio/keys.c -new file mode 100644 -index 0000000..20050e1 ---- /dev/null -+++ b/drivers/net/wireless/xradio/keys.c -@@ -0,0 +1,193 @@ -+#include -+ -+#include "xradio.h" -+#include "sta.h" -+#include "keys.h" -+ -+int xradio_alloc_key(struct xradio_common *hw_priv) -+{ -+ int idx; -+ -+ idx = ffs(~hw_priv->key_map) - 1; -+ if (idx < 0 || idx > WSM_KEY_MAX_INDEX) -+ return -1; -+ -+ hw_priv->key_map |= BIT(idx); -+ hw_priv->keys[idx].entryIndex = idx; -+ return idx; -+} -+ -+void xradio_free_key(struct xradio_common *hw_priv, int idx) -+{ -+ BUG_ON(!(hw_priv->key_map & BIT(idx))); -+ memset(&hw_priv->keys[idx], 0, sizeof(hw_priv->keys[idx])); -+ hw_priv->key_map &= ~BIT(idx); -+} -+ -+void xradio_free_keys(struct xradio_common *hw_priv) -+{ -+ memset(&hw_priv->keys, 0, sizeof(hw_priv->keys)); -+ hw_priv->key_map = 0; -+} -+ -+int xradio_upload_keys(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int idx, ret = 0; -+ -+ -+ for (idx = 0; idx <= WSM_KEY_MAX_IDX; ++idx) -+ if (hw_priv->key_map & BIT(idx)) { -+ ret = wsm_add_key(hw_priv, &hw_priv->keys[idx], priv->if_id); -+ if (ret < 0) -+ break; -+ } -+ return ret; -+} -+ -+int xradio_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, -+ struct ieee80211_vif *vif, struct ieee80211_sta *sta, -+ struct ieee80211_key_conf *key) -+{ -+#ifdef XRADIO_DISABLE_HW_CRYPTO -+ wiphy_info(dev->wiphy, "hw crypto is disabled, ignoring key request\n"); -+ return -EOPNOTSUPP; -+#else -+ int ret = -EOPNOTSUPP; -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ -+ wiphy_dbg(dev->wiphy, "vif %d: set_key cmd %d\n", priv->if_id, (int) cmd); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ if (cmd == SET_KEY) { -+ u8 *peer_addr = NULL; -+ int pairwise = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ? 1 : 0; -+ int idx = xradio_alloc_key(hw_priv); -+ struct wsm_add_key *wsm_key = &hw_priv->keys[idx]; -+ -+ if (idx < 0) { -+ wiphy_err(dev->wiphy, "xradio_alloc_key failed!\n"); -+ ret = -EINVAL; -+ goto finally; -+ } -+ -+ BUG_ON(pairwise && !sta); -+ if (sta) -+ peer_addr = sta->addr; -+ -+ key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; -+ -+ priv->cipherType = key->cipher; -+ switch (key->cipher) { -+ case WLAN_CIPHER_SUITE_WEP40: -+ case WLAN_CIPHER_SUITE_WEP104: -+ if (key->keylen > 16) { -+ xradio_free_key(hw_priv, idx); -+ wiphy_err(dev->wiphy, "keylen too long=%d!\n", key->keylen); -+ ret = -EINVAL; -+ goto finally; -+ } -+ -+ if (pairwise) { -+ wsm_key->type = WSM_KEY_TYPE_WEP_PAIRWISE; -+ memcpy(wsm_key->wepPairwiseKey.peerAddress, peer_addr, ETH_ALEN); -+ memcpy(wsm_key->wepPairwiseKey.keyData, &key->key[0], key->keylen); -+ wsm_key->wepPairwiseKey.keyLength = key->keylen; -+ } else { -+ wsm_key->type = WSM_KEY_TYPE_WEP_DEFAULT; -+ memcpy(wsm_key->wepGroupKey.keyData, &key->key[0], key->keylen); -+ wsm_key->wepGroupKey.keyLength = key->keylen; -+ wsm_key->wepGroupKey.keyId = key->keyidx; -+ } -+ break; -+ case WLAN_CIPHER_SUITE_TKIP: -+ if (pairwise) { -+ wsm_key->type = WSM_KEY_TYPE_TKIP_PAIRWISE; -+ memcpy(wsm_key->tkipPairwiseKey.peerAddress, peer_addr, ETH_ALEN); -+ memcpy(wsm_key->tkipPairwiseKey.tkipKeyData, &key->key[0], 16); -+ memcpy(wsm_key->tkipPairwiseKey.txMicKey, &key->key[16], 8); -+ memcpy(wsm_key->tkipPairwiseKey.rxMicKey, &key->key[24], 8); -+ } else { -+ size_t mic_offset = (priv->mode == NL80211_IFTYPE_AP) ? 16 : 24; -+ wsm_key->type = WSM_KEY_TYPE_TKIP_GROUP; -+ memcpy(wsm_key->tkipGroupKey.tkipKeyData,&key->key[0], 16); -+ memcpy(wsm_key->tkipGroupKey.rxMicKey, &key->key[mic_offset], 8); -+ -+ /* TODO: Where can I find TKIP SEQ? */ -+ memset(wsm_key->tkipGroupKey.rxSeqCounter, 0, 8); -+ wsm_key->tkipGroupKey.keyId = key->keyidx; -+ } -+ break; -+ case WLAN_CIPHER_SUITE_CCMP: -+ if (pairwise) { -+ wsm_key->type = WSM_KEY_TYPE_AES_PAIRWISE; -+ memcpy(wsm_key->aesPairwiseKey.peerAddress, peer_addr, ETH_ALEN); -+ memcpy(wsm_key->aesPairwiseKey.aesKeyData, &key->key[0], 16); -+ wiphy_debug(dev->wiphy, "CCMP_PAIRWISE keylen=%d!\n", -+ key->keylen); -+ } else { -+ wsm_key->type = WSM_KEY_TYPE_AES_GROUP; -+ memcpy(wsm_key->aesGroupKey.aesKeyData, &key->key[0], 16); -+ /* TODO: Where can I find AES SEQ? */ -+ memset(wsm_key->aesGroupKey.rxSeqCounter, 0, 8); -+ wsm_key->aesGroupKey.keyId = key->keyidx; -+ } -+ break; -+#ifdef CONFIG_XRADIO_WAPI_SUPPORT -+ case WLAN_CIPHER_SUITE_SMS4: -+ if (pairwise) { -+ wsm_key->type = WSM_KEY_TYPE_WAPI_PAIRWISE; -+ memcpy(wsm_key->wapiPairwiseKey.peerAddress, peer_addr, ETH_ALEN); -+ memcpy(wsm_key->wapiPairwiseKey.wapiKeyData, &key->key[0], 16); -+ memcpy(wsm_key->wapiPairwiseKey.micKeyData, &key->key[16], 16); -+ wsm_key->wapiPairwiseKey.keyId = key->keyidx; -+ sta_printk(XRADIO_DBG_NIY,"%s: WAPI_PAIRWISE keylen=%d!\n", -+ __func__, key->keylen); -+ } else { -+ wsm_key->type = WSM_KEY_TYPE_WAPI_GROUP; -+ memcpy(wsm_key->wapiGroupKey.wapiKeyData, &key->key[0], 16); -+ memcpy(wsm_key->wapiGroupKey.micKeyData, &key->key[16], 16); -+ wsm_key->wapiGroupKey.keyId = key->keyidx; -+ sta_printk(XRADIO_DBG_NIY,"%s: WAPI_GROUP keylen=%d!\n", -+ __func__, key->keylen); -+ } -+ break; -+#endif /* CONFIG_XRADIO_WAPI_SUPPORT */ -+ default: -+ wiphy_err(dev->wiphy, "key->cipher unknown(%d)!\n", key->cipher); -+ xradio_free_key(hw_priv, idx); -+ ret = -EOPNOTSUPP; -+ goto finally; -+ } -+ ret = WARN_ON(wsm_add_key(hw_priv, wsm_key, priv->if_id)); -+ if (!ret) -+ key->hw_key_idx = idx; -+ else -+ xradio_free_key(hw_priv, idx); -+ -+ if (!ret && (pairwise || wsm_key->type == WSM_KEY_TYPE_WEP_DEFAULT) && -+ (priv->filter4.enable & 0x2)) -+ xradio_set_arpreply(dev, vif); -+ } else if (cmd == DISABLE_KEY) { -+ struct wsm_remove_key wsm_key = { -+ .entryIndex = key->hw_key_idx, -+ }; -+ -+ if (wsm_key.entryIndex > WSM_KEY_MAX_IDX) { -+ ret = -EINVAL; -+ goto finally; -+ } -+ -+ xradio_free_key(hw_priv, wsm_key.entryIndex); -+ ret = wsm_remove_key(hw_priv, &wsm_key, priv->if_id); -+ } else { -+ wiphy_err(dev->wiphy, "Unsupported command\n"); -+ } -+ -+finally: -+ mutex_unlock(&hw_priv->conf_mutex); -+ return ret; -+#endif // XRADIO_DISABLE_HW_CRYPTO -+} -diff --git a/drivers/net/wireless/xradio/keys.h b/drivers/net/wireless/xradio/keys.h -new file mode 100644 -index 0000000..23c5880 ---- /dev/null -+++ b/drivers/net/wireless/xradio/keys.h -@@ -0,0 +1,12 @@ -+#ifndef __KEYS_H_ -+#define __KEYS_H_INCLUDED -+ -+int xradio_alloc_key(struct xradio_common *hw_priv); -+void xradio_free_key(struct xradio_common *hw_priv, int idx); -+void xradio_free_keys(struct xradio_common *hw_priv); -+int xradio_upload_keys(struct xradio_vif *priv); -+int xradio_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, -+ struct ieee80211_vif *vif, struct ieee80211_sta *sta, -+ struct ieee80211_key_conf *key); -+ -+#endif -\ No newline at end of file -diff --git a/drivers/net/wireless/xradio/main.c b/drivers/net/wireless/xradio/main.c -new file mode 100644 -index 0000000..346710c ---- /dev/null -+++ b/drivers/net/wireless/xradio/main.c -@@ -0,0 +1,609 @@ -+/* -+ * Main code of XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "fwio.h" -+#include "hwio.h" -+#include "bh.h" -+#include "sta.h" -+#include "ap.h" -+#include "keys.h" -+#include "scan.h" -+#include "pm.h" -+#include "sdio.h" -+ -+/* TODO: use rates and channels from the device */ -+#define RATETAB_ENT(_rate, _rateid, _flags) \ -+ { \ -+ .bitrate = (_rate), \ -+ .hw_value = (_rateid), \ -+ .flags = (_flags), \ -+ } -+ -+static struct ieee80211_rate xradio_rates[] = { -+ RATETAB_ENT(10, 0, 0), -+ RATETAB_ENT(20, 1, 0), -+ RATETAB_ENT(55, 2, 0), -+ RATETAB_ENT(110, 3, 0), -+ RATETAB_ENT(60, 6, 0), -+ RATETAB_ENT(90, 7, 0), -+ RATETAB_ENT(120, 8, 0), -+ RATETAB_ENT(180, 9, 0), -+ RATETAB_ENT(240, 10, 0), -+ RATETAB_ENT(360, 11, 0), -+ RATETAB_ENT(480, 12, 0), -+ RATETAB_ENT(540, 13, 0), -+}; -+ -+static struct ieee80211_rate xradio_mcs_rates[] = { -+ RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS), -+}; -+ -+#define xradio_g_rates (xradio_rates + 0) -+#define xradio_a_rates (xradio_rates + 4) -+#define xradio_n_rates (xradio_mcs_rates) -+ -+#define xradio_g_rates_size (ARRAY_SIZE(xradio_rates)) -+#define xradio_a_rates_size (ARRAY_SIZE(xradio_rates) - 4) -+#define xradio_n_rates_size (ARRAY_SIZE(xradio_mcs_rates)) -+ -+#define CHAN2G(_channel, _freq, _flags) { \ -+ .band = NL80211_BAND_2GHZ, \ -+ .center_freq = (_freq), \ -+ .hw_value = (_channel), \ -+ .flags = (_flags), \ -+ .max_antenna_gain = 0, \ -+ .max_power = 30, \ -+} -+ -+#define CHAN5G(_channel, _flags) { \ -+ .band = NL80211_BAND_5GHZ, \ -+ .center_freq = 5000 + (5 * (_channel)), \ -+ .hw_value = (_channel), \ -+ .flags = (_flags), \ -+ .max_antenna_gain = 0, \ -+ .max_power = 30, \ -+} -+ -+static struct ieee80211_channel xradio_2ghz_chantable[] = { -+ CHAN2G(1, 2412, 0), -+ CHAN2G(2, 2417, 0), -+ CHAN2G(3, 2422, 0), -+ CHAN2G(4, 2427, 0), -+ CHAN2G(5, 2432, 0), -+ CHAN2G(6, 2437, 0), -+ CHAN2G(7, 2442, 0), -+ CHAN2G(8, 2447, 0), -+ CHAN2G(9, 2452, 0), -+ CHAN2G(10, 2457, 0), -+ CHAN2G(11, 2462, 0), -+ CHAN2G(12, 2467, 0), -+ CHAN2G(13, 2472, 0), -+ CHAN2G(14, 2484, 0), -+}; -+ -+static struct ieee80211_supported_band xradio_band_2ghz = { -+ .channels = xradio_2ghz_chantable, -+ .n_channels = ARRAY_SIZE(xradio_2ghz_chantable), -+ .bitrates = xradio_g_rates, -+ .n_bitrates = xradio_g_rates_size, -+ .ht_cap = { -+ .cap = IEEE80211_HT_CAP_GRN_FLD | -+ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), -+ .ht_supported = 1, -+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_32K, -+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, -+ .mcs = { -+ .rx_mask[0] = 0xFF, -+ .rx_highest = __cpu_to_le16(0x41), -+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, -+ }, -+ }, -+}; -+ -+static const unsigned long xradio_ttl[] = { -+ 1 * HZ, /* VO */ -+ 2 * HZ, /* VI */ -+ 5 * HZ, /* BE */ -+ 10 * HZ /* BK */ -+}; -+ -+static const struct ieee80211_ops xradio_ops = { -+ .start = xradio_start, -+ .stop = xradio_stop, -+ .add_interface = xradio_add_interface, -+ .remove_interface = xradio_remove_interface, -+ .change_interface = xradio_change_interface, -+ .tx = xradio_tx, -+ .hw_scan = xradio_hw_scan, -+#ifdef ROAM_OFFLOAD -+ .sched_scan_start = xradio_hw_sched_scan_start, -+ .sched_scan_stop = xradio_hw_sched_scan_stop, -+#endif /*ROAM_OFFLOAD*/ -+ .set_tim = xradio_set_tim, -+ .sta_notify = xradio_sta_notify, -+ .sta_add = xradio_sta_add, -+ .sta_remove = xradio_sta_remove, -+ .set_key = xradio_set_key, -+ .set_rts_threshold = xradio_set_rts_threshold, -+ .config = xradio_config, -+ .bss_info_changed = xradio_bss_info_changed, -+ .prepare_multicast = xradio_prepare_multicast, -+ .configure_filter = xradio_configure_filter, -+ .conf_tx = xradio_conf_tx, -+ .get_stats = xradio_get_stats, -+ .ampdu_action = xradio_ampdu_action, -+ .flush = xradio_flush, -+#ifdef CONFIG_PM -+ .suspend = xradio_wow_suspend, -+ .resume = xradio_wow_resume, -+#endif /* CONFIG_PM */ -+ /* Intentionally not offloaded: */ -+ /*.channel_switch = xradio_channel_switch, */ -+ .remain_on_channel = xradio_remain_on_channel, -+ .cancel_remain_on_channel = xradio_cancel_remain_on_channel, -+}; -+ -+ -+/*************************************** functions ***************************************/ -+ -+static void xradio_set_ifce_comb(struct xradio_common *hw_priv, -+ struct ieee80211_hw *hw) -+{ -+ hw_priv->if_limits1[0].max = 1; -+ -+ hw_priv->if_limits1[0].types = BIT(NL80211_IFTYPE_STATION); -+ hw_priv->if_limits1[1].max = 1; -+ hw_priv->if_limits1[1].types = BIT(NL80211_IFTYPE_AP); -+ -+ hw_priv->if_limits2[0].max = 2; -+ hw_priv->if_limits2[0].types = BIT(NL80211_IFTYPE_STATION); -+ -+ hw_priv->if_limits3[0].max = 1; -+ -+ hw_priv->if_limits3[0].types = BIT(NL80211_IFTYPE_STATION); -+ hw_priv->if_limits3[1].max = 1; -+ hw_priv->if_limits3[1].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | -+ BIT(NL80211_IFTYPE_P2P_GO); -+ -+ /* TODO:COMBO: mac80211 doesn't yet support more than 1 -+ * different channel */ -+ hw_priv->if_combs[0].num_different_channels = 1; -+ hw_priv->if_combs[0].max_interfaces = 2; -+ hw_priv->if_combs[0].limits = hw_priv->if_limits1; -+ hw_priv->if_combs[0].n_limits = 2; -+ -+ hw_priv->if_combs[1].num_different_channels = 1; -+ -+ hw_priv->if_combs[1].max_interfaces = 2; -+ hw_priv->if_combs[1].limits = hw_priv->if_limits2; -+ hw_priv->if_combs[1].n_limits = 1; -+ -+ hw_priv->if_combs[2].num_different_channels = 1; -+ hw_priv->if_combs[2].max_interfaces = 2; -+ hw_priv->if_combs[2].limits = hw_priv->if_limits3; -+ hw_priv->if_combs[2].n_limits = 2; -+ -+ hw->wiphy->iface_combinations = &hw_priv->if_combs[0]; -+ hw->wiphy->n_iface_combinations = 3; -+} -+ -+struct ieee80211_hw *xradio_init_common(size_t hw_priv_data_len) -+{ -+ int i; -+ struct ieee80211_hw *hw; -+ struct xradio_common *hw_priv; -+ struct ieee80211_supported_band *sband; -+ int band; -+ -+ /* Alloc ieee_802.11 hw and xradio_common struct. */ -+ hw = ieee80211_alloc_hw(hw_priv_data_len, &xradio_ops); -+ if (!hw) -+ return NULL; -+ hw_priv = hw->priv; -+ memset(hw_priv, 0, sizeof(*hw_priv)); -+ -+ /* Initialize members of hw_priv. */ -+ hw_priv->hw = hw; -+ hw_priv->if_id_slot = 0; -+ hw_priv->roc_if_id = -1; -+ atomic_set(&hw_priv->num_vifs, 0); -+ /* initial rates and channels TODO: fetch from FW */ -+ hw_priv->rates = xradio_rates; -+ hw_priv->mcs_rates = xradio_n_rates; -+#ifdef ROAM_OFFLOAD -+ hw_priv->auto_scanning = 0; -+ hw_priv->frame_rcvd = 0; -+ hw_priv->num_scanchannels = 0; -+ hw_priv->num_2g_channels = 0; -+ hw_priv->num_5g_channels = 0; -+#endif /*ROAM_OFFLOAD*/ -+#ifdef AP_AGGREGATE_FW_FIX -+ /* Enable block ACK for 4 TID (BE,VI,VI,VO). */ -+ hw_priv->ba_tid_mask = 0xB1; /*due to HW limitations*/ -+#else -+ /* Enable block ACK for every TID but voice. */ -+ hw_priv->ba_tid_mask = 0x3F; -+#endif -+ hw_priv->noise = -94; -+ /* hw_priv->beacon_req_id = cpu_to_le32(0); */ -+ -+ /* Initialize members of ieee80211_hw, it works in UMAC. */ -+ hw->sta_data_size = sizeof(struct xradio_sta_priv); -+ hw->vif_data_size = sizeof(struct xradio_vif); -+ -+ ieee80211_hw_set(hw, SIGNAL_DBM); -+ ieee80211_hw_set(hw, SUPPORTS_PS); -+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); -+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); -+ ieee80211_hw_set(hw, CONNECTION_MONITOR); -+ -+/* hw->flags = IEEE80211_HW_SIGNAL_DBM | -+ IEEE80211_HW_SUPPORTS_PS | -+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS | -+ IEEE80211_HW_REPORTS_TX_ACK_STATUS | -+ IEEE80211_HW_CONNECTION_MONITOR;*/ -+ //IEEE80211_HW_SUPPORTS_CQM_RSSI | -+ /* Aggregation is fully controlled by firmware. -+ * Do not need any support from the mac80211 stack */ -+ /* IEEE80211_HW_AMPDU_AGGREGATION | */ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //IEEE80211_HW_SUPPORTS_P2P_PS | -+ //IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS | -+ // IEEE80211_HW_SUPPORTS_CQM_TX_FAIL | -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ //IEEE80211_HW_BEACON_FILTER; -+ -+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -+ BIT(NL80211_IFTYPE_ADHOC) | -+ BIT(NL80211_IFTYPE_AP) | -+ BIT(NL80211_IFTYPE_MESH_POINT) | -+ BIT(NL80211_IFTYPE_P2P_CLIENT) | -+ BIT(NL80211_IFTYPE_P2P_GO); -+ -+ /* Support only for limited wowlan functionalities */ -+ /* TODO by Icenowy: RESTORE THIS */ -+/* hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT; -+ hw->wiphy->wowlan.n_patterns = 0;*/ -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ /* fix the problem that driver can not set pro-resp template frame to fw */ -+ hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; -+ -+#if defined(CONFIG_XRADIO_DISABLE_BEACON_HINTS) -+ hw->wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; -+#endif -+ hw->wiphy->n_addresses = XRWL_MAX_VIFS; -+ hw->wiphy->addresses = hw_priv->addresses; -+ hw->wiphy->max_remain_on_channel_duration = 500; -+ hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + -+ 8 /* TKIP IV */ + -+ 12 /* TKIP ICV and MIC */; -+ hw->wiphy->bands[NL80211_BAND_2GHZ] = &xradio_band_2ghz; -+ hw->queues = AC_QUEUE_NUM; -+ hw->max_rates = MAX_RATES_STAGE; -+ hw->max_rate_tries = MAX_RATES_RETRY; -+ /* Channel params have to be cleared before registering wiphy again */ -+ for (band = 0; band < NUM_NL80211_BANDS; band++) { -+ sband = hw->wiphy->bands[band]; -+ if (!sband) -+ continue; -+ for (i = 0; i < sband->n_channels; i++) { -+ sband->channels[i].flags = 0; -+ sband->channels[i].max_antenna_gain = 0; -+ sband->channels[i].max_power = 30; -+ } -+ } -+ /* hw_priv->channel init value is the local->oper_channel init value;when transplanting,take care */ -+ for (band = 0; band < NUM_NL80211_BANDS; band++) { -+ sband = hw->wiphy->bands[band]; -+ if (!sband) -+ continue; -+ if(!hw_priv->channel){ -+ hw_priv->channel = &sband->channels[2]; -+ } -+ } -+ hw->wiphy->max_scan_ssids = WSM_SCAN_MAX_NUM_OF_SSIDS; -+ hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; -+ SET_IEEE80211_PERM_ADDR(hw, hw_priv->addresses[0].addr); -+ -+ /* Initialize locks. */ -+ spin_lock_init(&hw_priv->vif_list_lock); -+ mutex_init(&hw_priv->wsm_cmd_mux); -+ mutex_init(&hw_priv->conf_mutex); -+ mutex_init(&hw_priv->wsm_oper_lock); -+ atomic_set(&hw_priv->tx_lock, 0); -+ sema_init(&hw_priv->tx_lock_sem, 1); -+ -+ hw_priv->workqueue = create_singlethread_workqueue(XRADIO_WORKQUEUE); -+ sema_init(&hw_priv->scan.lock, 1); -+ sema_init(&hw_priv->scan.status_lock,1); -+ INIT_WORK(&hw_priv->scan.work, xradio_scan_work); -+#ifdef ROAM_OFFLOAD -+ INIT_WORK(&hw_priv->scan.swork, xradio_sched_scan_work); -+#endif /*ROAM_OFFLOAD*/ -+ INIT_DELAYED_WORK(&hw_priv->scan.probe_work, xradio_probe_work); -+ INIT_DELAYED_WORK(&hw_priv->scan.timeout, xradio_scan_timeout); -+ INIT_DELAYED_WORK(&hw_priv->rem_chan_timeout, xradio_rem_chan_timeout); -+ INIT_WORK(&hw_priv->tx_policy_upload_work, tx_policy_upload_work); -+ atomic_set(&hw_priv->upload_count, 0); -+ memset(&hw_priv->connet_time, 0, sizeof(hw_priv->connet_time)); -+ -+ spin_lock_init(&hw_priv->event_queue_lock); -+ INIT_LIST_HEAD(&hw_priv->event_queue); -+ INIT_WORK(&hw_priv->event_handler, xradio_event_handler); -+ INIT_WORK(&hw_priv->ba_work, xradio_ba_work); -+ spin_lock_init(&hw_priv->ba_lock); -+ timer_setup(&hw_priv->ba_timer, xradio_ba_timer, 0); -+ -+ if (unlikely(xradio_queue_stats_init(&hw_priv->tx_queue_stats, -+ WLAN_LINK_ID_MAX,xradio_skb_dtor, hw_priv))) { -+ ieee80211_free_hw(hw); -+ return NULL; -+ } -+ for (i = 0; i < AC_QUEUE_NUM; ++i) { -+ if (unlikely(xradio_queue_init(&hw_priv->tx_queue[i], -+ &hw_priv->tx_queue_stats, i, XRWL_MAX_QUEUE_SZ, xradio_ttl[i]))) { -+ for (; i > 0; i--) -+ xradio_queue_deinit(&hw_priv->tx_queue[i - 1]); -+ xradio_queue_stats_deinit(&hw_priv->tx_queue_stats); -+ ieee80211_free_hw(hw); -+ return NULL; -+ } -+ } -+ -+ init_waitqueue_head(&hw_priv->channel_switch_done); -+ init_waitqueue_head(&hw_priv->wsm_cmd_wq); -+ init_waitqueue_head(&hw_priv->wsm_startup_done); -+ init_waitqueue_head(&hw_priv->offchannel_wq); -+ hw_priv->wsm_caps.firmwareReady = 0; -+ hw_priv->driver_ready = 0; -+ hw_priv->offchannel_done = 0; -+ wsm_buf_init(&hw_priv->wsm_cmd_buf); -+ spin_lock_init(&hw_priv->wsm_cmd.lock); -+ tx_policy_init(hw_priv); -+ xradio_init_resv_skb(hw_priv); -+ /* add for setting short_frame_max_tx_count(mean wdev->retry_short) to drv,init the max_rate_tries */ -+ spin_lock_bh(&hw_priv->tx_policy_cache.lock); -+ hw_priv->long_frame_max_tx_count = hw->conf.long_frame_max_tx_count; -+ hw_priv->short_frame_max_tx_count = -+ (hw->conf.short_frame_max_tx_count< 0x0F) ? -+ hw->conf.short_frame_max_tx_count : 0x0F; -+ hw_priv->hw->max_rate_tries = hw->conf.short_frame_max_tx_count; -+ spin_unlock_bh(&hw_priv->tx_policy_cache.lock); -+ -+ for (i = 0; i < XRWL_MAX_VIFS; i++) -+ hw_priv->hw_bufs_used_vif[i] = 0; -+ -+#ifdef MCAST_FWDING -+ for (i = 0; i < WSM_MAX_BUF; i++) -+ wsm_init_release_buffer_request(hw_priv, i); -+ hw_priv->buf_released = 0; -+#endif -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ -+ hw_priv->query_packetID = 0; -+ atomic_set(&hw_priv->query_cnt, 0); -+ INIT_WORK(&hw_priv->query_work, wsm_query_work); -+ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+ atomic_set(&hw_priv->suspend_state, XRADIO_RESUME); -+#endif -+ -+ xradio_set_ifce_comb(hw_priv, hw_priv->hw); -+ -+ return hw; -+} -+ -+void xradio_free_common(struct ieee80211_hw *dev) -+{ -+ int i; -+ struct xradio_common *hw_priv = dev->priv; -+ -+ cancel_work_sync(&hw_priv->query_work); -+ del_timer_sync(&hw_priv->ba_timer); -+ mutex_destroy(&hw_priv->wsm_oper_lock); -+ mutex_destroy(&hw_priv->conf_mutex); -+ mutex_destroy(&hw_priv->wsm_cmd_mux); -+ wsm_buf_deinit(&hw_priv->wsm_cmd_buf); -+ flush_workqueue(hw_priv->workqueue); -+ destroy_workqueue(hw_priv->workqueue); -+ hw_priv->workqueue = NULL; -+ -+ xradio_deinit_resv_skb(hw_priv); -+ if (hw_priv->skb_cache) { -+ dev_kfree_skb(hw_priv->skb_cache); -+ hw_priv->skb_cache = NULL; -+ } -+ -+ for (i = 0; i < 4; ++i) -+ xradio_queue_deinit(&hw_priv->tx_queue[i]); -+ xradio_queue_stats_deinit(&hw_priv->tx_queue_stats); -+ -+ for (i = 0; i < XRWL_MAX_VIFS; i++) { -+ kfree(hw_priv->vif_list[i]); -+ hw_priv->vif_list[i] = NULL; -+ } -+ -+//fixed memory leakage by yangfh -+#ifdef MCAST_FWDING -+ wsm_deinit_release_buffer(hw_priv); -+#endif -+ /* unsigned int i; */ -+ ieee80211_free_hw(dev); -+} -+ -+int xradio_register_common(struct ieee80211_hw *dev) -+{ -+ int err = 0; -+ struct xradio_common *hw_priv = dev->priv; -+ -+ SET_IEEE80211_DEV(dev, hw_priv->pdev); -+ err = ieee80211_register_hw(dev); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "Cannot register device (%d).\n", err); -+ return err; -+ } -+ dev_dbg(hw_priv->pdev, "is registered as '%s'\n", -+ wiphy_name(dev->wiphy)); -+ -+ hw_priv->driver_ready = 1; -+ wake_up(&hw_priv->wsm_startup_done); -+ return 0; -+} -+ -+void xradio_unregister_common(struct ieee80211_hw *dev) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ -+ if (wiphy_dev(dev->wiphy)) { -+ ieee80211_unregister_hw(dev); -+ SET_IEEE80211_DEV(dev, NULL); -+ } -+ hw_priv->driver_ready = 0; -+} -+ -+int xradio_core_init(struct sdio_func* func) -+{ -+ int err = -ENOMEM; -+ u16 ctrl_reg; -+ int if_id; -+ struct ieee80211_hw *dev; -+ struct xradio_common *hw_priv; -+ unsigned char randomaddr[ETH_ALEN]; -+ const unsigned char *addr = NULL; -+ -+ //init xradio_common -+ dev = xradio_init_common(sizeof(struct xradio_common)); -+ if (!dev) { -+ dev_dbg(&func->dev, "xradio_init_common failed\n"); -+ return err; -+ } -+ hw_priv = dev->priv; -+ hw_priv->pdev = &func->dev; -+ hw_priv->sdio_func = func; -+ sdio_set_drvdata(func, hw_priv); -+ -+ // fill in mac addresses -+ if (hw_priv->pdev->of_node) { -+ addr = of_get_mac_address(hw_priv->pdev->of_node); -+ } -+ if (!addr) { -+ dev_warn(hw_priv->pdev, "no mac address provided, using random\n"); -+ eth_random_addr(randomaddr); -+ addr = randomaddr; -+ } -+ memcpy(hw_priv->addresses[0].addr, addr, ETH_ALEN); -+ memcpy(hw_priv->addresses[1].addr, addr, ETH_ALEN); -+ hw_priv->addresses[1].addr[5] += 0x01; -+ -+ /*init pm and wakelock. */ -+#ifdef CONFIG_PM -+ err = xradio_pm_init(&hw_priv->pm_state, hw_priv); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "xradio_pm_init failed(%d).\n", err); -+ goto err2; -+ } -+#endif -+ /* Register bh thread*/ -+ err = xradio_register_bh(hw_priv); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "xradio_register_bh failed(%d).\n", err); -+ goto err3; -+ } -+ -+ /* Load firmware and register Interrupt Handler */ -+ err = xradio_load_firmware(hw_priv); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "xradio_load_firmware failed(%d).\n", err); -+ goto err4; -+ } -+ -+ /* Set sdio blocksize. */ -+ sdio_lock(hw_priv); -+ WARN_ON(sdio_set_blk_size(hw_priv, -+ SDIO_BLOCK_SIZE)); -+ sdio_unlock(hw_priv); -+ -+ if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, -+ hw_priv->wsm_caps.firmwareReady, 3*HZ) <= 0) { -+ -+ /* TODO: Needs to find how to reset device */ -+ /* in QUEUE mode properly. */ -+ dev_dbg(hw_priv->pdev, "Firmware Startup Timeout!\n"); -+ err = -ETIMEDOUT; -+ goto err5; -+ } -+ dev_dbg(hw_priv->pdev, "Firmware Startup Done.\n"); -+ -+ /* Keep device wake up. */ -+ WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, HIF_CTRL_WUP_BIT)); -+ if (xradio_reg_read_16(hw_priv,HIF_CONTROL_REG_ID, &ctrl_reg)) -+ WARN_ON(xradio_reg_read_16(hw_priv,HIF_CONTROL_REG_ID, &ctrl_reg)); -+ WARN_ON(!(ctrl_reg & HIF_CTRL_RDY_BIT)); -+ -+ /* Set device mode parameter. */ -+ for (if_id = 0; if_id < xrwl_get_nr_hw_ifaces(hw_priv); if_id++) { -+ /* Set low-power mode. */ -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, if_id)); -+ /* Enable multi-TX confirmation */ -+ WARN_ON(wsm_use_multi_tx_conf(hw_priv, true, if_id)); -+ } -+ -+ /* Register wireless net device. */ -+ err = xradio_register_common(dev); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "xradio_register_common failed(%d)!\n", err); -+ goto err5; -+ } -+ -+ return err; -+ -+err5: -+ xradio_dev_deinit(hw_priv); -+err4: -+ xradio_unregister_bh(hw_priv); -+err3: -+ xradio_pm_deinit(&hw_priv->pm_state); -+err2: -+/* err1: MRK: unused label*/ -+ xradio_free_common(dev); -+ return err; -+} -+ -+void xradio_core_deinit(struct sdio_func* func) -+{ -+ struct xradio_common* hw_priv = sdio_get_drvdata(func); -+ if (hw_priv) { -+ xradio_unregister_common(hw_priv->hw); -+ xradio_dev_deinit(hw_priv); -+ xradio_unregister_bh(hw_priv); -+ xradio_pm_deinit(&hw_priv->pm_state); -+ xradio_free_common(hw_priv->hw); -+ } -+ return; -+} -diff --git a/drivers/net/wireless/xradio/main.h b/drivers/net/wireless/xradio/main.h -new file mode 100644 -index 0000000..2238d75 ---- /dev/null -+++ b/drivers/net/wireless/xradio/main.h -@@ -0,0 +1,7 @@ -+#ifndef __XRADIO_MAIN_H -+#define __XRADIO_MAIN_H -+ -+int xradio_core_init(struct sdio_func* func); -+void xradio_core_deinit(struct sdio_func* func); -+ -+#endif -\ No newline at end of file -diff --git a/drivers/net/wireless/xradio/module.c b/drivers/net/wireless/xradio/module.c -new file mode 100644 -index 0000000..2a41c75 ---- /dev/null -+++ b/drivers/net/wireless/xradio/module.c -@@ -0,0 +1,27 @@ -+#include -+ -+#include "xradio.h" -+#include "debug.h" -+#include "sdio.h" -+ -+MODULE_AUTHOR("XRadioTech"); -+MODULE_DESCRIPTION("XRadioTech WLAN driver core"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("xradio_core"); -+ -+/* Init Module function -> Called by insmod */ -+static int __init xradio_core_entry(void) -+{ -+ int ret = 0; -+ ret = xradio_sdio_register(); -+ return ret; -+} -+ -+/* Called at Driver Unloading */ -+static void __exit xradio_core_exit(void) -+{ -+ xradio_sdio_unregister(); -+} -+ -+module_init(xradio_core_entry); -+module_exit(xradio_core_exit); -diff --git a/drivers/net/wireless/xradio/p2p.c b/drivers/net/wireless/xradio/p2p.c -new file mode 100644 -index 0000000..f32fb43 ---- /dev/null -+++ b/drivers/net/wireless/xradio/p2p.c -@@ -0,0 +1,62 @@ -+#include "xradio.h" -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+///w, TES_P2P_0002 WorkAround: -+///w, P2P GO Neg Process and P2P FIND may be collision. -+///w, When P2P Device is waiting for GO NEG CFM in 30ms, -+///w, P2P FIND may end with p2p listen, and then goes to p2p search. -+///w, Then xradio scan will occupy phy on other channel in 3+ seconds. -+///w, P2P Device will not be able to receive the GO NEG CFM. -+///w, We extend the roc period to remaind phy to receive GO NEG CFM as WorkAround. -+ -+s32 TES_P2P_0002_roc_dur; -+s32 TES_P2P_0002_roc_sec; -+s32 TES_P2P_0002_roc_usec; -+u32 TES_P2P_0002_packet_id; -+u32 TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; -+ -+void xradio_frame_monitor(struct xradio_common *hw_priv, struct sk_buff *skb, bool tx) { -+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -+ -+ u8 *action = (u8*)&mgmt->u.action.category; -+ u8 *category_code = &(action[0]); -+ u8 *action_code = &(action[1]); -+ u8 *oui = &(action[2]); -+ u8 *subtype = &(action[5]); -+ u8 *oui_subtype = &(action[6]); -+ -+ -+ if(ieee80211_is_action(frame->frame_control)) { -+ if( *category_code == WLAN_CATEGORY_PUBLIC) { -+ if (*action_code == 0x09) { -+ if((oui[0] == 0x50) && (oui[1] == 0x6F) && -+ (oui[2] == 0x9A) && (*subtype == 0x09)) { -+ if ( *oui_subtype == 0x01 ) { ///w, GO Negotiation Response -+ if((TES_P2P_0002_state == TES_P2P_0002_STATE_IDLE) && -+ (tx == true)) { ///w, p2p atturbute:status,id=0 -+ u8 *go_neg_resp_res = &(action[17]); -+ if (*go_neg_resp_res == 0x0) { -+ TES_P2P_0002_state = TES_P2P_0002_STATE_SEND_RESP; -+ txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_SEND_RESP]\n"); -+ } -+ } -+ } else if ( *oui_subtype == 0x02 ) { ///w, GO Negotiation Confirmation -+ if( tx == false ) { -+ TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; -+ txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_IDLE]" -+ "[GO Negotiation Confirmation]\n"); -+ } -+ } else if ( *oui_subtype == 0x08 ) { ///w, Provision Discovery Response -+ if(tx == false) { -+ TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; -+ txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_IDLE]" -+ "[Provision Discovery Response]\n"); -+ } -+ } -+ } -+ } -+ } -+ } -+} -+#endif -\ No newline at end of file -diff --git a/drivers/net/wireless/xradio/p2p.h b/drivers/net/wireless/xradio/p2p.h -new file mode 100644 -index 0000000..d86686b ---- /dev/null -+++ b/drivers/net/wireless/xradio/p2p.h -@@ -0,0 +1,6 @@ -+#ifndef XRADIO_P2P_H -+#define XRADIO_P2P_H -+ -+void xradio_frame_monitor(struct xradio_common *hw_priv, struct sk_buff *skb, bool tx); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/pm.c b/drivers/net/wireless/xradio/pm.c -new file mode 100644 -index 0000000..488c26c ---- /dev/null -+++ b/drivers/net/wireless/xradio/pm.c -@@ -0,0 +1,800 @@ -+/* -+ * PM implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include "xradio.h" -+#include "pm.h" -+#include "sta.h" -+#include "bh.h" -+#include "sdio.h" -+ -+#define XRADIO_BEACON_SKIPPING_MULTIPLIER 3 -+ -+struct xradio_udp_port_filter { -+ struct wsm_udp_port_filter_hdr hdr; -+ struct wsm_udp_port_filter dhcp; -+ struct wsm_udp_port_filter upnp; -+} __packed; -+ -+struct xradio_ether_type_filter { -+ struct wsm_ether_type_filter_hdr hdr; -+ struct wsm_ether_type_filter ip; -+ struct wsm_ether_type_filter pae; -+ struct wsm_ether_type_filter wapi; -+} __packed; -+ -+static struct xradio_udp_port_filter xradio_udp_port_filter_on = { -+ .hdr.nrFilters = 2, -+ .dhcp = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_OUT, -+ .portType = WSM_FILTER_PORT_TYPE_DST, -+ .udpPort = __cpu_to_le16(67), -+ }, -+ .upnp = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_OUT, -+ .portType = WSM_FILTER_PORT_TYPE_DST, -+ .udpPort = __cpu_to_le16(1900), -+ }, -+ /* Please add other known ports to be filtered out here and -+ * update nrFilters field in the header. -+ * Up to 4 filters are allowed. */ -+}; -+ -+static struct wsm_udp_port_filter_hdr xradio_udp_port_filter_off = { -+ .nrFilters = 0, -+}; -+ -+#ifndef ETH_P_WAPI -+#define ETH_P_WAPI 0x88B4 -+#endif -+ -+#ifdef TES_P2P_000B_DISABLE_EAPOL_FILTER -+/* TES_P2P_000B WorkAround: -+ * when the link keep 10min more or less(i am not sure), -+ * wpa_s session maybe expired, and want to update group key. -+ * it will use eapol frame(802.1x,0x888E). -+ * if driver suspend, and discard eapol frame, then session end. -+ * i don't know why original code discards eapol frame in suspend. -+ * but now make this filter disable as WorkAround. wzw */ -+static struct xradio_ether_type_filter xradio_ether_type_filter_on = { -+ .hdr.nrFilters = 1, -+/* .ip = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_IP), -+ },*/ -+/* .pae = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_PAE), -+ },*/ -+ .wapi = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_WAPI), -+ }, -+ /* Please add other known ether types to be filtered out here and -+ * update nrFilters field in the header. -+ * Up to 4 filters are allowed. */ -+}; -+#else -+static struct xradio_ether_type_filter xradio_ether_type_filter_on = { -+ .hdr.nrFilters = 2, -+/* .ip = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_IP), -+ },*/ -+ .pae = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_PAE), -+ }, -+ .wapi = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_WAPI), -+ }, -+ /* Please add other known ether types to be filtered out here and -+ * update nrFilters field in the header. -+ * Up to 4 filters are allowed. */ -+}; -+#endif -+ -+static struct wsm_ether_type_filter_hdr xradio_ether_type_filter_off = { -+ .nrFilters = 0, -+}; -+ -+static int xradio_suspend_late(struct device *dev); -+static void xradio_pm_release(struct device *dev); -+static int xradio_pm_probe(struct platform_device *pdev); -+static int __xradio_wow_suspend(struct xradio_vif *priv, -+ struct cfg80211_wowlan *wowlan); -+static int __xradio_wow_resume(struct xradio_vif *priv); -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+static int xradio_poweroff_suspend(struct xradio_common *hw_priv); -+static int xradio_poweroff_resume(struct xradio_common *hw_priv); -+#endif -+ -+ -+/* private */ -+struct xradio_suspend_state { -+ unsigned long bss_loss_tmo; -+ unsigned long connection_loss_tmo; -+ unsigned long join_tmo; -+ unsigned long direct_probe; -+ unsigned long link_id_gc; -+ bool beacon_skipping; -+}; -+ -+static const struct dev_pm_ops xradio_pm_ops = { -+ .suspend_noirq = xradio_suspend_late, -+}; -+ -+static struct platform_driver xradio_power_driver = { -+ .probe = xradio_pm_probe, -+ .driver = { -+ .name = XRADIO_PM_DEVICE, -+ .pm = &xradio_pm_ops, -+ }, -+}; -+ -+static int xradio_pm_init_common(struct xradio_pm_state *pm, -+ struct xradio_common *hw_priv) -+{ -+ int ret; -+ pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ -+ spin_lock_init(&pm->lock); -+ /* Register pm driver. */ -+ ret = platform_driver_register(&xradio_power_driver); -+ if (ret) { -+ pm_printk(XRADIO_DBG_ERROR, "%s:platform_driver_register failed(%d)!\n", -+ __FUNCTION__, ret); -+ return ret; -+ } -+ -+ /* Add pm device. */ -+ pm->pm_dev = platform_device_alloc(XRADIO_PM_DEVICE, 0); -+ if (!pm->pm_dev) { -+ pm_printk(XRADIO_DBG_ERROR, "%s:platform_device_alloc failed!\n", -+ __FUNCTION__); -+ platform_driver_unregister(&xradio_power_driver); -+ return -ENOMEM; -+ } -+ pm->pm_dev->dev.platform_data = hw_priv; -+ ret = platform_device_add(pm->pm_dev); -+ if (ret) { -+ pm_printk(XRADIO_DBG_ERROR, "%s:platform_device_add failed(%d)!\n", -+ __FUNCTION__, ret); -+ platform_driver_unregister(&xradio_power_driver); -+ kfree(pm->pm_dev); -+ pm->pm_dev = NULL; -+ } -+ -+ return ret; -+} -+ -+static void xradio_pm_deinit_common(struct xradio_pm_state *pm) -+{ -+ pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ platform_driver_unregister(&xradio_power_driver); -+ if (pm->pm_dev) { -+ pm->pm_dev->dev.platform_data = NULL; -+ platform_device_unregister(pm->pm_dev); /* kfree is already do */ -+ pm->pm_dev = NULL; -+ } -+} -+ -+#ifdef CONFIG_WAKELOCK -+ -+int xradio_pm_init(struct xradio_pm_state *pm, -+ struct xradio_common *hw_priv) -+{ -+ int ret = 0; -+ pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ -+ ret = xradio_pm_init_common(pm, hw_priv); -+ if (!ret) -+ wake_lock_init(&pm->wakelock, WAKE_LOCK_SUSPEND, XRADIO_WAKE_LOCK); -+ else -+ pm_printk(XRADIO_DBG_ERROR,"xradio_pm_init_common failed!\n"); -+ return ret; -+} -+ -+void xradio_pm_deinit(struct xradio_pm_state *pm) -+{ -+ pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ if (wake_lock_active(&pm->wakelock)) -+ wake_unlock(&pm->wakelock); -+ wake_lock_destroy(&pm->wakelock); -+ xradio_pm_deinit_common(pm); -+} -+ -+void xradio_pm_stay_awake(struct xradio_pm_state *pm, -+ unsigned long tmo) -+{ -+ long cur_tmo; -+ pm_printk(XRADIO_DBG_MSG,"%s\n", __FUNCTION__); -+ -+ spin_lock_bh(&pm->lock); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) -+ cur_tmo = pm->wakelock.ws.timer.expires - jiffies; -+#else -+ cur_tmo = pm->wakelock.expires - jiffies; -+#endif -+ if (!wake_lock_active(&pm->wakelock) || cur_tmo < (long)tmo) -+ wake_lock_timeout(&pm->wakelock, tmo); -+ spin_unlock_bh(&pm->lock); -+} -+void xradio_pm_lock_awake(struct xradio_pm_state *pm) -+{ -+ -+ spin_lock_bh(&pm->lock); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) -+ pm->expires_save = pm->wakelock.ws.timer.expires; -+#else -+ pm->expires_save = pm->wakelock.expires; -+#endif -+ wake_lock_timeout(&pm->wakelock, LONG_MAX); -+ spin_unlock_bh(&pm->lock); -+} -+void xradio_pm_unlock_awake(struct xradio_pm_state *pm) -+{ -+ -+ spin_lock_bh(&pm->lock); -+ pm->expires_save -= jiffies; -+ if (pm->expires_save) -+ wake_lock_timeout(&pm->wakelock, pm->expires_save); -+ else -+ wake_lock_timeout(&pm->wakelock, 1); -+ spin_unlock_bh(&pm->lock); -+} -+ -+#else /* CONFIG_WAKELOCK */ -+ -+static void xradio_pm_stay_awake_tmo(struct timer_list *t) -+{ -+ struct xradio_pm_state *pm = from_timer(pm, t, stay_awake); -+ (void)pm; -+} -+ -+int xradio_pm_init(struct xradio_pm_state *pm, -+ struct xradio_common *hw_priv) -+{ -+ int ret = 0; -+ pm_printk(XRADIO_DBG_MSG,"%s\n", __FUNCTION__); -+ -+ ret = xradio_pm_init_common(pm, hw_priv); -+ if (!ret) { -+ timer_setup(&pm->stay_awake, xradio_pm_stay_awake_tmo, 0); -+ } else -+ pm_printk(XRADIO_DBG_ERROR,"xradio_pm_init_common failed!\n"); -+ return ret; -+} -+ -+void xradio_pm_deinit(struct xradio_pm_state *pm) -+{ -+ del_timer_sync(&pm->stay_awake); -+ xradio_pm_deinit_common(pm); -+} -+ -+void xradio_pm_stay_awake(struct xradio_pm_state *pm, -+ unsigned long tmo) -+{ -+ long cur_tmo; -+ -+ spin_lock_bh(&pm->lock); -+ cur_tmo = pm->stay_awake.expires - jiffies; -+ if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo) -+ mod_timer(&pm->stay_awake, jiffies + tmo); -+ spin_unlock_bh(&pm->lock); -+} -+void xradio_pm_lock_awake(struct xradio_pm_state *pm) -+{ -+ -+ spin_lock_bh(&pm->lock); -+ pm->expires_save = pm->stay_awake.expires; -+ mod_timer(&pm->stay_awake, jiffies + LONG_MAX); -+ spin_unlock_bh(&pm->lock); -+} -+void xradio_pm_unlock_awake(struct xradio_pm_state *pm) -+{ -+ -+ spin_lock_bh(&pm->lock); -+ if (time_before(jiffies, pm->expires_save)) -+ mod_timer(&pm->stay_awake, pm->expires_save); -+ else -+ mod_timer(&pm->stay_awake, jiffies + 1); -+ spin_unlock_bh(&pm->lock); -+} -+#endif /* CONFIG_WAKELOCK */ -+ -+static long xradio_suspend_work(struct delayed_work *work) -+{ -+ int ret = cancel_delayed_work(work); -+ long tmo; -+ pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); -+ -+ if (ret > 0) { -+ /* Timer is pending */ -+ tmo = work->timer.expires - jiffies; -+ if (tmo < 0) -+ tmo = 0; -+ } else { -+ tmo = -1; -+ } -+ return tmo; -+} -+ -+static int xradio_resume_work(struct xradio_common *hw_priv, -+ struct delayed_work *work, -+ unsigned long tmo) -+{ -+ pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); -+ if ((long)tmo < 0) -+ return 1; -+ -+ return queue_delayed_work(hw_priv->workqueue, work, tmo); -+} -+ -+static int xradio_suspend_late(struct device *dev) -+{ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+ struct xradio_common *hw_priv = dev->platform_data; -+ -+ if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) { -+ return 0; /* we don't rx data when power down wifi.*/ -+ } -+#endif -+ -+ //if (atomic_read(&hw_priv->bh_rx)) { -+ // pm_printk(XRADIO_DBG_WARN, "%s: Suspend interrupted.\n", __func__); -+ // return -EAGAIN; -+ //} -+ return 0; -+} -+ -+static void xradio_pm_release(struct device *dev) -+{ -+ pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); -+} -+ -+static int xradio_pm_probe(struct platform_device *pdev) -+{ -+ pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); -+ pdev->dev.release = xradio_pm_release; -+ return 0; -+} -+ -+int xradio_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv; -+ int i, ret = 0; -+ -+ -+ if(hw_priv->bh_error) return -EBUSY; -+ WARN_ON(!atomic_read(&hw_priv->num_vifs)); -+ -+ if (work_pending(&hw_priv->query_work)) -+ return -EBUSY; -+ -+#ifdef ROAM_OFFLOAD -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ if((priv->vif->type == NL80211_IFTYPE_STATION) -+ && (priv->join_status == XRADIO_JOIN_STATUS_STA)) { -+ down(&hw_priv->scan.lock); -+ hw_priv->scan.if_id = priv->if_id; -+ xradio_sched_scan_work(&hw_priv->scan.swork); -+ } -+ } -+#endif /*ROAM_OFFLOAD*/ -+ -+ /* Do not suspend when datapath is not idle */ -+ if (hw_priv->tx_queue_stats.num_queued[0] + -+ hw_priv->tx_queue_stats.num_queued[1]) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of tx_queue is not empty.\n"); -+ return -EBUSY; -+ } -+ -+ /* Make sure there is no configuration requests in progress. */ -+ if (!mutex_trylock(&hw_priv->conf_mutex)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of configuration requests.\n"); -+ return -EBUSY; -+ } -+ -+ /* Make sure there is no wsm_oper_lock in progress. */ -+ if (!mutex_trylock(&hw_priv->wsm_oper_lock)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of wsm_oper_lock.\n"); -+ mutex_unlock(&hw_priv->conf_mutex); -+ return -EBUSY; -+ } -+ -+ /* Do not suspend when scanning or ROC*/ -+ if (down_trylock(&hw_priv->scan.lock)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of scan requests.\n"); -+ goto revert1; -+ } -+ -+ if (delayed_work_pending(&hw_priv->scan.probe_work)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of probe frames tx in progress.\n"); -+ goto revert2; -+ } -+ -+ /* Lock TX. */ -+ wsm_lock_tx_async(hw_priv); -+ -+ /* Wait to avoid possible race with bh code. -+ * But do not wait too long... */ -+ if (wait_event_timeout(hw_priv->bh_evt_wq, -+ !hw_priv->hw_bufs_used, HZ / 10) <= 0) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of there are frames not confirm.\n"); -+ goto revert3; -+ } -+ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+// if (STANDBY_WITH_POWER_OFF == standby_level) { -+ if (1) { -+ return xradio_poweroff_suspend(hw_priv); -+ } -+#endif -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ -+ ret = __xradio_wow_suspend(priv, wowlan); -+ if (ret) { -+ for (; i >= 0; i--) { -+ if (!hw_priv->vif_list[i]) -+ continue; -+ priv = (struct xradio_vif *)hw_priv->vif_list[i]->drv_priv; -+ __xradio_wow_resume(priv); -+ } -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of __xradio_wow_suspend failed!\n"); -+ goto revert3; -+ } -+ } -+ -+ /* Stop serving thread */ -+ if (xradio_bh_suspend(hw_priv)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of xradio_bh_suspend failed!\n"); -+ xradio_wow_resume(hw); -+ return -EBUSY; -+ } -+ -+ /* Enable IRQ wake */ -+ ret = sdio_pm(hw_priv, true); -+ if (ret) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend sbus pm failed\n"); -+ xradio_wow_resume(hw); -+ return -EBUSY; -+ } -+ -+ /* Force resume if event is coming from the device. */ -+ //if (atomic_read(&hw_priv->bh_rx)) { -+ // pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ // "because of recieved rx event!\n"); -+ // xradio_wow_resume(hw); -+ // return -EAGAIN; -+ //} -+ return 0; -+ -+revert3: -+ wsm_unlock_tx(hw_priv); -+revert2: -+ up(&hw_priv->scan.lock); -+revert1: -+ mutex_unlock(&hw_priv->conf_mutex); -+ mutex_unlock(&hw_priv->wsm_oper_lock); -+ return -EBUSY; -+} -+ -+static int __xradio_wow_suspend(struct xradio_vif *priv, -+ struct cfg80211_wowlan *wowlan) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif; -+ struct xradio_suspend_state *state; -+ int ret; -+#ifdef MCAST_FWDING -+ struct wsm_forwarding_offload fwdoffload = { -+ .fwenable = 0x1, -+ .flags = 0x1, -+ }; -+#endif -+ -+ -+ /* Do not suspend when join work is scheduled */ -+ if (work_pending(&priv->join_work)) { -+ pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " -+ "when join work is scheduled\n", __func__); -+ goto revert1; -+ } -+ -+ /* Set UDP filter */ -+ wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_on.hdr, -+ priv->if_id); -+ -+ /* Set ethernet frame type filter */ -+ wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_on.hdr, -+ priv->if_id); -+ -+ /* Set IP multicast filter */ -+ wsm_set_host_sleep(hw_priv, 1, priv->if_id); -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_keepalive_filter(priv, true)); -+ -+#ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE -+ /* Set Multicast Address Filter */ -+ if (priv->multicast_filter.numOfAddresses) { -+ priv->multicast_filter.enable = 1; -+ wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); -+ } -+ -+ /* Set Enable Broadcast Address Filter */ -+ priv->broadcast_filter.action_mode = 1; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ priv->broadcast_filter.address_mode = 3; -+ -+ xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); -+#endif -+ -+#ifdef MCAST_FWDING -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); -+#endif -+ -+ /* Allocate state */ -+ state = kzalloc(sizeof(struct xradio_suspend_state), GFP_KERNEL); -+ if (!state) { -+ pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " -+ "alloc xradio_suspend_state failed.\n", __func__); -+ goto revert2; -+ } -+ /* Store delayed work states. */ -+ state->bss_loss_tmo = xradio_suspend_work(&priv->bss_loss_work); -+ state->connection_loss_tmo = xradio_suspend_work(&priv->connection_loss_work); -+ state->join_tmo = xradio_suspend_work(&priv->join_timeout); -+ state->link_id_gc = xradio_suspend_work(&priv->link_id_gc_work); -+ -+ /* Enable beacon skipping */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA && -+ priv->join_dtim_period && !priv->has_multicast_subscription) { -+ state->beacon_skipping = true; -+ wsm_set_beacon_wakeup_period(hw_priv, priv->join_dtim_period, -+ XRADIO_BEACON_SKIPPING_MULTIPLIER * \ -+ priv->join_dtim_period, priv->if_id); -+ } -+ -+ ret = timer_pending(&priv->mcast_timeout); -+ if (ret) { -+ pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " -+ "mcast timeout timer_pending failed.\n", __func__); -+ goto revert3; -+ } -+ -+ /* Store suspend state */ -+ pm_state_vif->suspend_state = state; -+ -+ return 0; -+ -+revert3: -+ xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo); -+ xradio_resume_work(hw_priv, &priv->connection_loss_work, -+ state->connection_loss_tmo); -+ xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo); -+ xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc); -+ kfree(state); -+ -+revert2: -+ wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off, priv->if_id); -+ wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off, priv->if_id); -+ wsm_set_host_sleep(hw_priv, 0, priv->if_id); -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_keepalive_filter(priv, false)); -+ -+#ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE -+ /* Set Multicast Address Filter */ -+ if (priv->multicast_filter.numOfAddresses) { -+ priv->multicast_filter.enable = 0; -+ wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); -+ } -+ -+ /* Set Enable Broadcast Address Filter */ -+ priv->broadcast_filter.action_mode = 0; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ priv->broadcast_filter.address_mode = 0; -+ xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); -+#endif -+ -+#ifdef MCAST_FWDING -+ fwdoffload.flags = 0x0; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); -+#endif -+ -+revert1: -+ /* mutex_unlock(&hw_priv->conf_mutex); */ -+ return -EBUSY; -+} -+ -+int xradio_wow_resume(struct ieee80211_hw *hw) -+{ -+ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv; -+ int i, ret = 0; -+ -+ -+ WARN_ON(!atomic_read(&hw_priv->num_vifs)); -+ if(hw_priv->bh_error) return 0; -+ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+ if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) { -+ return xradio_poweroff_resume(hw_priv); -+ } -+#endif -+ -+ /* Disable IRQ wake */ -+ sdio_pm(hw_priv, false); -+ -+ up(&hw_priv->scan.lock); -+ -+ /* Resume BH thread */ -+ WARN_ON(xradio_bh_resume(hw_priv)); -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ ret = __xradio_wow_resume(priv); -+ if (ret) { -+ pm_printk(XRADIO_DBG_ERROR, "%s:__xradio_wow_resume failed!\n", __func__); -+ break; -+ } -+ } -+ -+ wsm_unlock_tx(hw_priv); -+ -+ /* Unlock configuration mutex */ -+ mutex_unlock(&hw_priv->conf_mutex); -+ mutex_unlock(&hw_priv->wsm_oper_lock); -+ -+ return ret; -+} -+ -+static int __xradio_wow_resume(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif; -+ struct xradio_suspend_state *state; -+#ifdef MCAST_FWDING -+ struct wsm_forwarding_offload fwdoffload = { -+ .fwenable = 0x1, -+ .flags = 0x0, -+ }; -+#endif -+ -+ -+ /* Restore suspend state */ -+ state = pm_state_vif->suspend_state; -+ pm_state_vif->suspend_state = NULL; -+ -+#ifdef ROAM_OFFLOAD -+ if((priv->vif->type == NL80211_IFTYPE_STATION) -+ && (priv->join_status == XRADIO_JOIN_STATUS_STA)) -+ xradio_hw_sched_scan_stop(hw_priv); -+#endif /*ROAM_OFFLOAD*/ -+ -+ if (state->beacon_skipping) { -+#ifdef XRADIO_USE_LONG_DTIM_PERIOD -+ int join_dtim_period_extend; -+ if (priv->join_dtim_period <= 3) { -+ join_dtim_period_extend = priv->join_dtim_period * 3; -+ } else if (priv->join_dtim_period <= 5) { -+ join_dtim_period_extend = priv->join_dtim_period * 2; -+ } else { -+ join_dtim_period_extend = priv->join_dtim_period; -+ } -+ wsm_set_beacon_wakeup_period(hw_priv, -+ ((priv->beacon_int * join_dtim_period_extend) > MAX_BEACON_SKIP_TIME_MS ? -+ 1 : join_dtim_period_extend) , 0, priv->if_id); -+#else -+ wsm_set_beacon_wakeup_period(hw_priv, priv->beacon_int * -+ (priv->join_dtim_period > MAX_BEACON_SKIP_TIME_MS ? 1 : priv->join_dtim_period), -+ 0, priv->if_id); -+#endif -+ state->beacon_skipping = false; -+ } -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_keepalive_filter(priv, false)); -+ -+#ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE -+ /* Set Multicast Address Filter */ -+ if (priv->multicast_filter.numOfAddresses) { -+ priv->multicast_filter.enable = 0; -+ wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); -+ } -+ /* Set Enable Broadcast Address Filter */ -+ priv->broadcast_filter.action_mode = 0; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ priv->broadcast_filter.address_mode = 0; -+ xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); -+#endif -+ -+#ifdef MCAST_FWDING -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); -+#endif -+ -+ /* Resume delayed work */ -+ xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo); -+ xradio_resume_work(hw_priv, &priv->connection_loss_work, -+ state->connection_loss_tmo); -+ xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo); -+ xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc); -+ -+ /* Remove UDP port filter */ -+ wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off, priv->if_id); -+ -+ /* Remove ethernet frame type filter */ -+ wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off, priv->if_id); -+ -+ /* Remove IP multicast filter */ -+ wsm_set_host_sleep(hw_priv, 0, priv->if_id); -+ /* Free memory */ -+ kfree(state); -+ -+ return 0; -+} -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+static int xradio_poweroff_suspend(struct xradio_common *hw_priv) -+{ -+ -+ //flush all work. -+ cancel_work_sync(&hw_priv->query_work); -+ flush_workqueue(hw_priv->workqueue); -+ /* Schedule hardware restart, ensure no cmds in progress.*/ -+ mutex_lock(&hw_priv->wsm_cmd_mux); -+ atomic_set(&hw_priv->suspend_state, XRADIO_POWEROFF_SUSP); -+ //hw_priv->hw_restart = true; -+ mutex_unlock(&hw_priv->wsm_cmd_mux); -+ /* Stop serving thread */ -+ if (xradio_bh_suspend(hw_priv)) { -+ pm_printk(XRADIO_DBG_WARN, "%s, xradio_bh_suspend failed!\n", __func__); -+ return -EBUSY; -+ } -+ -+ return 0; -+} -+ -+static int xradio_poweroff_resume(struct xradio_common *hw_priv) -+{ -+ -+ /* Revert locks */ -+ wsm_unlock_tx(hw_priv); -+ up(&hw_priv->scan.lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ mutex_unlock(&hw_priv->wsm_oper_lock); -+ //if (schedule_work(&hw_priv->hw_restart_work) <= 0) -+ // pm_printk(XRADIO_DBG_ERROR, "%s restart_work failed!\n", __func__); -+ return 0; -+} -+#endif -diff --git a/drivers/net/wireless/xradio/pm.h b/drivers/net/wireless/xradio/pm.h -new file mode 100644 -index 0000000..6443cbc ---- /dev/null -+++ b/drivers/net/wireless/xradio/pm.h -@@ -0,0 +1,64 @@ -+/* -+ * power management interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#ifndef PM_H_INCLUDED -+#define PM_H_INCLUDED -+ -+#ifdef CONFIG_WAKELOCK -+#include -+#endif -+ -+/* ******************************************************************** */ -+/* mac80211 API */ -+ -+#ifdef CONFIG_PM -+ -+#define XRADIO_PM_DEVICE "xradio_pm" -+#define XRADIO_WAKE_LOCK "xradio_wlan" -+ -+/* extern */ struct xradio_common; -+ /* private */ struct xradio_suspend_state; -+ -+struct xradio_pm_state { -+#ifdef CONFIG_WAKELOCK -+ struct wake_lock wakelock; -+#else -+ struct timer_list stay_awake; -+#endif -+ struct platform_device *pm_dev; -+ spinlock_t lock; -+ unsigned long expires_save; -+}; -+ -+struct xradio_pm_state_vif { -+ struct xradio_suspend_state *suspend_state; -+}; -+ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+enum suspend_state { -+ XRADIO_RESUME = 0, -+ XRADIO_CONNECT_SUSP, -+ XRADIO_DISCONNECT_SUSP, -+ XRADIO_POWEROFF_SUSP -+}; -+#endif -+int xradio_pm_init(struct xradio_pm_state *pm, struct xradio_common *priv); -+void xradio_pm_deinit(struct xradio_pm_state *pm); -+void xradio_pm_stay_awake(struct xradio_pm_state *pm, unsigned long tmo); -+void xradio_pm_lock_awake(struct xradio_pm_state *pm); -+void xradio_pm_unlock_awake(struct xradio_pm_state *pm); -+int xradio_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); -+int xradio_wow_resume(struct ieee80211_hw *hw); -+ -+#endif /* CONFIG_PM */ -+ -+#endif -diff --git a/drivers/net/wireless/xradio/queue.c b/drivers/net/wireless/xradio/queue.c -new file mode 100644 -index 0000000..e4b00ea ---- /dev/null -+++ b/drivers/net/wireless/xradio/queue.c -@@ -0,0 +1,820 @@ -+/* -+ * Queue implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include "xradio.h" -+#include "queue.h" -+ -+/* private */ struct xradio_queue_item -+{ -+ struct list_head head; -+ struct sk_buff *skb; -+ u32 packetID; -+ unsigned long queue_timestamp; -+ unsigned long xmit_timestamp; -+ struct xradio_txpriv txpriv; -+ u8 generation; -+ u8 pack_stk_wr; -+}; -+ -+static inline void __xradio_queue_lock(struct xradio_queue *queue) -+{ -+ struct xradio_queue_stats *stats = queue->stats; -+ if (queue->tx_locked_cnt++ == 0) { -+ txrx_printk(XRADIO_DBG_MSG, "[TX] Queue %d is locked.\n", -+ queue->queue_id); -+ ieee80211_stop_queue(stats->hw_priv->hw, queue->queue_id); -+ } -+} -+ -+static inline void __xradio_queue_unlock(struct xradio_queue *queue) -+{ -+ struct xradio_queue_stats *stats = queue->stats; -+ BUG_ON(!queue->tx_locked_cnt); -+ if (--queue->tx_locked_cnt == 0) { -+ txrx_printk(XRADIO_DBG_MSG, "[TX] Queue %d is unlocked.\n", -+ queue->queue_id); -+ ieee80211_wake_queue(stats->hw_priv->hw, queue->queue_id); -+ } -+} -+ -+static inline void xradio_queue_parse_id(u32 packetID, u8 *queue_generation, -+ u8 *queue_id, -+ u8 *item_generation, -+ u8 *item_id, -+ u8 *if_id, -+ u8 *link_id) -+{ -+ *item_id = (packetID >> 0) & 0xFF; -+ *item_generation = (packetID >> 8) & 0xFF; -+ *queue_id = (packetID >> 16) & 0xF; -+ *if_id = (packetID >> 20) & 0xF; -+ *link_id = (packetID >> 24) & 0xF; -+ *queue_generation = (packetID >> 28) & 0xF; -+} -+ -+static inline u32 xradio_queue_make_packet_id(u8 queue_generation, u8 queue_id, -+ u8 item_generation, u8 item_id, -+ u8 if_id, u8 link_id) -+{ -+ /*TODO:COMBO: Add interfaceID to the packetID */ -+ return ((u32)item_id << 0) | -+ ((u32)item_generation << 8) | -+ ((u32)queue_id << 16) | -+ ((u32)if_id << 20) | -+ ((u32)link_id << 24) | -+ ((u32)queue_generation << 28); -+} -+ -+static void xradio_queue_post_gc(struct xradio_queue_stats *stats, -+ struct list_head *gc_list) -+{ -+ struct xradio_queue_item *item; -+ -+ while (!list_empty(gc_list)) { -+ item = list_first_entry( -+ gc_list, struct xradio_queue_item, head); -+ list_del(&item->head); -+ stats->skb_dtor(stats->hw_priv, item->skb, &item->txpriv); -+ kfree(item); -+ } -+} -+ -+static void xradio_queue_register_post_gc(struct list_head *gc_list, -+ struct xradio_queue_item *item) -+{ -+ struct xradio_queue_item *gc_item; -+ gc_item = kmalloc(sizeof(struct xradio_queue_item), GFP_KERNEL); -+ BUG_ON(!gc_item); -+ memcpy(gc_item, item, sizeof(struct xradio_queue_item)); -+ list_add_tail(&gc_item->head, gc_list); -+} -+ -+static void __xradio_queue_gc(struct xradio_queue *queue, -+ struct list_head *head, -+ bool unlock) -+{ -+ struct xradio_queue_stats *stats = queue->stats; -+ struct xradio_queue_item *item = NULL; -+ //struct xradio_vif *priv; -+ int if_id; -+ bool wakeup_stats = false; -+ -+ while (!list_empty(&queue->queue)) { -+ struct xradio_txpriv *txpriv; -+ item = list_first_entry( -+ &queue->queue, struct xradio_queue_item, head); -+ if (time_before(jiffies, item->queue_timestamp+queue->ttl)) -+ break; -+ -+ txpriv = &item->txpriv; -+ if_id = txpriv->if_id; -+ --queue->num_queued; -+ --queue->num_queued_vif[if_id]; -+ --queue->link_map_cache[if_id][txpriv->link_id]; -+ spin_lock_bh(&stats->lock); -+ --stats->num_queued[if_id]; -+ if (!--stats->link_map_cache[if_id][txpriv->link_id]) -+ wakeup_stats = true; -+ spin_unlock_bh(&stats->lock); -+ //priv = xrwl_hwpriv_to_vifpriv(stats->hw_priv, if_id); -+ //if (priv) { -+ // xradio_debug_tx_ttl(priv); -+ // spin_unlock(&priv->vif_lock); -+ //} -+ xradio_queue_register_post_gc(head, item); -+ item->skb = NULL; -+ list_move_tail(&item->head, &queue->free_pool); -+ } -+ -+ if (wakeup_stats) -+ wake_up(&stats->wait_link_id_empty); -+ -+ //modified by yangfh for test WFD -+ if (queue->overfull) { -+ if (queue->num_queued <= ((stats->hw_priv->vif0_throttle + -+ stats->hw_priv->vif1_throttle+2)>>1)) { -+ queue->overfull = false; -+ if (unlock) { -+ __xradio_queue_unlock(queue); -+ } -+ } else if (item) { -+ unsigned long tmo = item->queue_timestamp + queue->ttl; -+ mod_timer(&queue->gc, tmo); -+ xradio_pm_stay_awake(&stats->hw_priv->pm_state, -+ tmo - jiffies); -+ } -+ } -+} -+ -+static void xradio_queue_gc(struct timer_list *t) -+{ -+ struct xradio_queue *queue = from_timer(queue, t, gc); -+ -+ LIST_HEAD(list); -+ -+ spin_lock_bh(&queue->lock); -+ __xradio_queue_gc(queue, &list, true); -+ spin_unlock_bh(&queue->lock); -+ xradio_queue_post_gc(queue->stats, &list); -+} -+ -+int xradio_queue_stats_init(struct xradio_queue_stats *stats, -+ size_t map_capacity, -+ xradio_queue_skb_dtor_t skb_dtor, -+ struct xradio_common *hw_priv) -+{ -+ int i; -+ -+ memset(stats, 0, sizeof(*stats)); -+ stats->map_capacity = map_capacity; -+ stats->skb_dtor = skb_dtor; -+ stats->hw_priv = hw_priv; -+ spin_lock_init(&stats->lock); -+ init_waitqueue_head(&stats->wait_link_id_empty); -+ for (i = 0; i < XRWL_MAX_VIFS; i++) { -+ stats->link_map_cache[i] = kzalloc(sizeof(int[map_capacity]), GFP_KERNEL); -+ if (!stats->link_map_cache[i]) { -+ for (; i >= 0; i--) -+ kfree(stats->link_map_cache[i]); -+ return -ENOMEM; -+ } -+ } -+ -+ return 0; -+} -+ -+int xradio_queue_init(struct xradio_queue *queue, -+ struct xradio_queue_stats *stats, -+ u8 queue_id, -+ size_t capacity, -+ unsigned long ttl) -+{ -+ int i; -+ -+ memset(queue, 0, sizeof(*queue)); -+ queue->stats = stats; -+ queue->capacity = capacity; -+ queue->queue_id = queue_id; -+ queue->ttl = ttl; -+ INIT_LIST_HEAD(&queue->queue); -+ INIT_LIST_HEAD(&queue->pending); -+ INIT_LIST_HEAD(&queue->free_pool); -+ spin_lock_init(&queue->lock); -+ timer_setup(&queue->gc, xradio_queue_gc, 0); -+ -+ queue->pool = kzalloc(sizeof(struct xradio_queue_item) * capacity, -+ GFP_KERNEL); -+ if (!queue->pool) -+ return -ENOMEM; -+ -+ for (i = 0; i < XRWL_MAX_VIFS; i++) { -+ queue->link_map_cache[i] = -+ kzalloc(sizeof(int[stats->map_capacity]), GFP_KERNEL); -+ if (!queue->link_map_cache[i]) { -+ for (; i >= 0; i--) -+ kfree(queue->link_map_cache[i]); -+ kfree(queue->pool); -+ queue->pool = NULL; -+ return -ENOMEM; -+ } -+ } -+ -+ for (i = 0; i < capacity; ++i) -+ list_add_tail(&queue->pool[i].head, &queue->free_pool); -+ -+ return 0; -+} -+ -+/* TODO:COMBO: Flush only a particular interface specific parts */ -+int xradio_queue_clear(struct xradio_queue *queue, int if_id) -+{ -+ int i, cnt, iter; -+ struct xradio_queue_stats *stats = queue->stats; -+ LIST_HEAD(gc_list); -+ -+ cnt = 0; -+ spin_lock_bh(&queue->lock); -+ queue->generation++; -+ queue->generation &= 0xf; -+ list_splice_tail_init(&queue->queue, &queue->pending); -+ while (!list_empty(&queue->pending)) { -+ struct xradio_queue_item *item = list_first_entry( -+ &queue->pending, struct xradio_queue_item, head); -+ WARN_ON(!item->skb); -+ if (XRWL_ALL_IFS == if_id || item->txpriv.if_id == if_id) { -+ xradio_queue_register_post_gc(&gc_list, item); -+ item->skb = NULL; -+ list_move_tail(&item->head, &queue->free_pool); -+ cnt++; -+ } -+ } -+ queue->num_queued -= cnt; -+ queue->num_pending = 0; -+ if (XRWL_ALL_IFS != if_id) { -+ queue->num_queued_vif[if_id] = 0; -+ queue->num_pending_vif[if_id] = 0; -+ } else { -+ for (iter = 0; iter < XRWL_MAX_VIFS; iter++) { -+ queue->num_queued_vif[iter] = 0; -+ queue->num_pending_vif[iter] = 0; -+ } -+ } -+ spin_lock_bh(&stats->lock); -+ if (XRWL_ALL_IFS != if_id) { -+ for (i = 0; i < stats->map_capacity; ++i) { -+ stats->num_queued[if_id] -= -+ queue->link_map_cache[if_id][i]; -+ stats->link_map_cache[if_id][i] -= -+ queue->link_map_cache[if_id][i]; -+ queue->link_map_cache[if_id][i] = 0; -+ } -+ } else { -+ for (iter = 0; iter < XRWL_MAX_VIFS; iter++) { -+ for (i = 0; i < stats->map_capacity; ++i) { -+ stats->num_queued[iter] -= -+ queue->link_map_cache[iter][i]; -+ stats->link_map_cache[iter][i] -= -+ queue->link_map_cache[iter][i]; -+ queue->link_map_cache[iter][i] = 0; -+ } -+ } -+ } -+ spin_unlock_bh(&stats->lock); -+ if (unlikely(queue->overfull)) { -+ queue->overfull = false; -+ __xradio_queue_unlock(queue); -+ } -+ spin_unlock_bh(&queue->lock); -+ wake_up(&stats->wait_link_id_empty); -+ xradio_queue_post_gc(stats, &gc_list); -+ return 0; -+} -+ -+void xradio_queue_stats_deinit(struct xradio_queue_stats *stats) -+{ -+ int i; -+ -+ for (i = 0; i < XRWL_MAX_VIFS ; i++) { -+ kfree(stats->link_map_cache[i]); -+ stats->link_map_cache[i] = NULL; -+ } -+} -+ -+void xradio_queue_deinit(struct xradio_queue *queue) -+{ -+ int i; -+ -+ xradio_queue_clear(queue, XRWL_ALL_IFS); -+ del_timer_sync(&queue->gc); -+ INIT_LIST_HEAD(&queue->free_pool); -+ kfree(queue->pool); -+ for (i = 0; i < XRWL_MAX_VIFS; i++) { -+ kfree(queue->link_map_cache[i]); -+ queue->link_map_cache[i] = NULL; -+ } -+ queue->pool = NULL; -+ queue->capacity = 0; -+} -+ -+size_t xradio_queue_get_num_queued(struct xradio_vif *priv, -+ struct xradio_queue *queue, -+ u32 link_id_map) -+{ -+ size_t ret; -+ int i, bit; -+ size_t map_capacity = queue->stats->map_capacity; -+ -+ if (!link_id_map) -+ return 0; -+ -+ spin_lock_bh(&queue->lock); -+ if (likely(link_id_map == (u32) -1)) { -+ ret = queue->num_queued_vif[priv->if_id] - -+ queue->num_pending_vif[priv->if_id]; -+ } else { -+ ret = 0; -+ for (i = 0, bit = 1; i < map_capacity; ++i, bit <<= 1) { -+ if (link_id_map & bit) -+ ret += -+ queue->link_map_cache[priv->if_id][i]; -+ } -+ } -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+int xradio_queue_put(struct xradio_queue *queue, struct sk_buff *skb, -+ struct xradio_txpriv *txpriv) -+{ -+ int ret = 0; -+ LIST_HEAD(gc_list); -+ struct xradio_queue_stats *stats = queue->stats; -+ /* TODO:COMBO: Add interface ID info to queue item */ -+ -+ if (txpriv->link_id >= queue->stats->map_capacity) -+ return -EINVAL; -+ -+ spin_lock_bh(&queue->lock); -+ if (!WARN_ON(list_empty(&queue->free_pool))) { -+ struct xradio_queue_item *item = list_first_entry( -+ &queue->free_pool, struct xradio_queue_item, head); -+ BUG_ON(item->skb); -+ -+ list_move_tail(&item->head, &queue->queue); -+ item->skb = skb; -+ item->txpriv = *txpriv; -+ item->generation = 1; /* avoid packet ID is 0.*/ -+ item->pack_stk_wr = 0; -+ item->packetID = xradio_queue_make_packet_id( -+ queue->generation, queue->queue_id, -+ item->generation, item - queue->pool, -+ txpriv->if_id, txpriv->raw_link_id); -+ item->queue_timestamp = jiffies; -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ if (TES_P2P_0002_state == TES_P2P_0002_STATE_SEND_RESP) { -+ TES_P2P_0002_packet_id = item->packetID; -+ TES_P2P_0002_state = TES_P2P_0002_STATE_GET_PKTID; -+ txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_GET_PKTID]\n"); -+ } -+#endif -+ -+ ++queue->num_queued; -+ ++queue->num_queued_vif[txpriv->if_id]; -+ ++queue->link_map_cache[txpriv->if_id][txpriv->link_id]; -+ -+ spin_lock_bh(&stats->lock); -+ ++stats->num_queued[txpriv->if_id]; -+ ++stats->link_map_cache[txpriv->if_id][txpriv->link_id]; -+ spin_unlock_bh(&stats->lock); -+ -+ /* -+ * TX may happen in parallel sometimes. -+ * Leave extra queue slots so we don't overflow. -+ */ -+ if (queue->overfull == false && -+ queue->num_queued >= -+ ((stats->hw_priv->vif0_throttle +stats->hw_priv->vif1_throttle) -+ - (num_present_cpus() - 1))) { -+ queue->overfull = true; -+ __xradio_queue_lock(queue); -+ mod_timer(&queue->gc, jiffies); -+ txrx_printk(XRADIO_DBG_NIY,"!lock queue\n"); -+ } -+ } else { -+ ret = -ENOENT; -+ } -+#if 0 -+ txrx_printk(XRADIO_DBG_ERROR, "queue_put queue %d, %d, %d\n", -+ queue->num_queued, -+ queue->link_map_cache[txpriv->if_id][txpriv->link_id], -+ queue->num_pending); -+ txrx_printk(XRADIO_DBG_ERROR, "queue_put stats %d, %d\n", stats->num_queued, -+ stats->link_map_cache[txpriv->if_id][txpriv->link_id]); -+#endif -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+int xradio_queue_get(struct xradio_queue *queue, -+ int if_id, -+ u32 link_id_map, -+ struct wsm_tx **tx, -+ struct ieee80211_tx_info **tx_info, -+ struct xradio_txpriv **txpriv) -+{ -+ int ret = -ENOENT; -+ struct xradio_queue_item *item; -+ struct xradio_queue_stats *stats = queue->stats; -+ bool wakeup_stats = false; -+ -+ spin_lock_bh(&queue->lock); -+ list_for_each_entry(item, &queue->queue, head) { -+ if ((item->txpriv.if_id == if_id) && -+ (link_id_map & BIT(item->txpriv.link_id))) { -+ ret = 0; -+ break; -+ } -+ } -+ -+ if (!WARN_ON(ret)) { -+ *tx = (struct wsm_tx *)item->skb->data; -+ *tx_info = IEEE80211_SKB_CB(item->skb); -+ *txpriv = &item->txpriv; -+ (*tx)->packetID = __cpu_to_le32(item->packetID); -+ list_move_tail(&item->head, &queue->pending); -+ ++queue->num_pending; -+ ++queue->num_pending_vif[item->txpriv.if_id]; -+ --queue->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]; -+ item->xmit_timestamp = jiffies; -+ -+ spin_lock_bh(&stats->lock); -+ --stats->num_queued[item->txpriv.if_id]; -+ if (!--stats->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]) -+ wakeup_stats = true; -+ -+ spin_unlock_bh(&stats->lock); -+#if 0 -+ txrx_printk(XRADIO_DBG_ERROR, "queue_get queue %d, %d, %d\n", -+ queue->num_queued, -+ queue->link_map_cache[item->txpriv.if_id][item->txpriv.link_id], -+ queue->num_pending); -+ txrx_printk(XRADIO_DBG_ERROR, "queue_get stats %d, %d\n", stats->num_queued, -+ stats->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]); -+#endif -+ } -+ spin_unlock_bh(&queue->lock); -+ if (wakeup_stats) -+ wake_up(&stats->wait_link_id_empty); -+ -+ return ret; -+} -+ -+int xradio_queue_requeue(struct xradio_queue *queue, u32 packetID, bool check) -+{ -+ int ret = 0; -+ u8 queue_generation, queue_id, item_generation, item_id, if_id, link_id; -+ struct xradio_queue_item *item; -+ struct xradio_queue_stats *stats = queue->stats; -+ -+ xradio_queue_parse_id(packetID, &queue_generation, &queue_id, -+ &item_generation, &item_id, &if_id, &link_id); -+ -+ item = &queue->pool[item_id]; -+ if (check && item->txpriv.offchannel_if_id == XRWL_GENERIC_IF_ID) { -+ txrx_printk(XRADIO_DBG_MSG, "Requeued frame dropped for " -+ "generic interface id.\n"); -+ xradio_queue_remove(queue, packetID); -+ return 0; -+ } -+ -+ if (!check) -+ item->txpriv.offchannel_if_id = XRWL_GENERIC_IF_ID; -+ -+ /*if_id = item->txpriv.if_id;*/ -+ -+ spin_lock_bh(&queue->lock); -+ BUG_ON(queue_id != queue->queue_id); -+ if (unlikely(queue_generation != queue->generation)) { -+ ret = -ENOENT; -+ } else if (unlikely(item_id >= (unsigned) queue->capacity)) { -+ WARN_ON(1); -+ ret = -EINVAL; -+ } else if (unlikely(item->generation != item_generation)) { -+ WARN_ON(1); -+ ret = -ENOENT; -+ } else { -+ --queue->num_pending; -+ --queue->num_pending_vif[if_id]; -+ ++queue->link_map_cache[if_id][item->txpriv.link_id]; -+ -+ spin_lock_bh(&stats->lock); -+ ++stats->num_queued[item->txpriv.if_id]; -+ ++stats->link_map_cache[if_id][item->txpriv.link_id]; -+ spin_unlock_bh(&stats->lock); -+ -+ item->generation = ++item_generation; -+ item->packetID = xradio_queue_make_packet_id( -+ queue_generation, queue_id, item_generation, item_id, -+ if_id, link_id); -+ list_move(&item->head, &queue->queue); -+#if 0 -+ txrx_printk(XRADIO_DBG_ERROR, "queue_requeue queue %d, %d, %d\n", -+ queue->num_queued, -+ queue->link_map_cache[if_id][item->txpriv.link_id], -+ queue->num_pending); -+ txrx_printk(XRADIO_DBG_ERROR, "queue_requeue stats %d, %d\n", -+ stats->num_queued, -+ stats->link_map_cache[if_id][item->txpriv.link_id]); -+#endif -+ } -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+int xradio_queue_requeue_all(struct xradio_queue *queue) -+{ -+ struct xradio_queue_stats *stats = queue->stats; -+ spin_lock_bh(&queue->lock); -+ while (!list_empty(&queue->pending)) { -+ struct xradio_queue_item *item = list_entry( -+ queue->pending.prev, struct xradio_queue_item, head); -+ -+ --queue->num_pending; -+ --queue->num_pending_vif[item->txpriv.if_id]; -+ ++queue->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]; -+ -+ spin_lock_bh(&stats->lock); -+ ++stats->num_queued[item->txpriv.if_id]; -+ ++stats->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]; -+ spin_unlock_bh(&stats->lock); -+ -+ ++item->generation; -+ item->packetID = xradio_queue_make_packet_id( -+ queue->generation, queue->queue_id, -+ item->generation, item - queue->pool, -+ item->txpriv.if_id, item->txpriv.raw_link_id); -+ list_move(&item->head, &queue->queue); -+ } -+ spin_unlock_bh(&queue->lock); -+ -+ return 0; -+} -+ -+int xradio_queue_remove(struct xradio_queue *queue, u32 packetID) -+{ -+ int ret = 0; -+ u8 queue_generation, queue_id, item_generation, item_id, if_id, link_id; -+ struct xradio_queue_item *item; -+ struct xradio_queue_stats *stats = queue->stats; -+ struct sk_buff *gc_skb = NULL; -+ struct xradio_txpriv gc_txpriv; -+ -+ xradio_queue_parse_id(packetID, &queue_generation, &queue_id, -+ &item_generation, &item_id, &if_id, &link_id); -+ -+ item = &queue->pool[item_id]; -+ -+ spin_lock_bh(&queue->lock); -+ BUG_ON(queue_id != queue->queue_id); -+ /*TODO:COMBO:Add check for interface ID also */ -+ if (unlikely(queue_generation != queue->generation)) { -+ ret = -ENOENT; -+ } else if (unlikely(item_id >= (unsigned) queue->capacity)) { -+ WARN_ON(1); -+ ret = -EINVAL; -+ } else if (unlikely(item->generation != item_generation)) { -+ WARN_ON(1); -+ ret = -ENOENT; -+ } else { -+ gc_txpriv = item->txpriv; -+ gc_skb = item->skb; -+ item->skb = NULL; -+ --queue->num_pending; -+ --queue->num_pending_vif[if_id]; -+ --queue->num_queued; -+ --queue->num_queued_vif[if_id]; -+ ++queue->num_sent; -+ ++item->generation; -+ -+ /* Do not use list_move_tail here, but list_move: -+ * try to utilize cache row. -+ */ -+ list_move(&item->head, &queue->free_pool); -+ -+ if (unlikely(queue->overfull) && -+ (queue->num_queued <= ((stats->hw_priv->vif0_throttle + stats->hw_priv->vif1_throttle + 2)>>1))) { -+ queue->overfull = false; -+ __xradio_queue_unlock(queue); -+ } -+ } -+ spin_unlock_bh(&queue->lock); -+ -+#if 0 -+ txrx_printk(XRADIO_DBG_ERROR, "queue_drop queue %d, %d, %d\n", -+ queue->num_queued, queue->link_map_cache[if_id][0], -+ queue->num_pending); -+ txrx_printk(XRADIO_DBG_ERROR, "queue_drop stats %d, %d\n", stats->num_queued, -+ stats->link_map_cache[if_id][0]); -+#endif -+ if (gc_skb) -+ stats->skb_dtor(stats->hw_priv, gc_skb, &gc_txpriv); -+ -+ return ret; -+} -+ -+int xradio_queue_get_skb(struct xradio_queue *queue, u32 packetID, -+ struct sk_buff **skb, -+ const struct xradio_txpriv **txpriv) -+{ -+ int ret = 0; -+ u8 queue_generation, queue_id, item_generation, item_id, if_id, link_id; -+ struct xradio_queue_item *item; -+ -+ xradio_queue_parse_id(packetID, &queue_generation, &queue_id, -+ &item_generation, &item_id, &if_id, &link_id); -+ -+ item = &queue->pool[item_id]; -+ -+ spin_lock_bh(&queue->lock); -+ BUG_ON(queue_id != queue->queue_id); -+ /* TODO:COMBO: Add check for interface ID here */ -+ if (unlikely(queue_generation != queue->generation)) { -+ ret = -ENOENT; -+ } else if (unlikely(item_id >= (unsigned) queue->capacity)) { -+ WARN_ON(1); -+ ret = -EINVAL; -+ } else if (unlikely(item->generation != item_generation)) { -+ WARN_ON(1); -+ ret = -ENOENT; -+ } else { -+ *skb = item->skb; -+ *txpriv = &item->txpriv; -+ } -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+void xradio_queue_lock(struct xradio_queue *queue) -+{ -+ spin_lock_bh(&queue->lock); -+ __xradio_queue_lock(queue); -+ spin_unlock_bh(&queue->lock); -+} -+ -+void xradio_queue_unlock(struct xradio_queue *queue) -+{ -+ spin_lock_bh(&queue->lock); -+ __xradio_queue_unlock(queue); -+ spin_unlock_bh(&queue->lock); -+} -+ -+bool xradio_queue_get_xmit_timestamp(struct xradio_queue *queue, -+ unsigned long *timestamp, int if_id, -+ u32 pending_frameID, u32 *Old_frame_ID) -+{ -+ struct xradio_queue_item *item; -+ bool ret; -+ -+ spin_lock_bh(&queue->lock); -+ ret = !list_empty(&queue->pending); -+ if (ret) { -+ list_for_each_entry(item, &queue->pending, head) { -+ if (((if_id == XRWL_GENERIC_IF_ID) || -+ (if_id == XRWL_ALL_IFS) || -+ (item->txpriv.if_id == if_id)) && -+ (item->packetID != pending_frameID)) { -+ if (time_before(item->xmit_timestamp, -+ *timestamp)) { -+ *timestamp = item->xmit_timestamp; -+ *Old_frame_ID = item->packetID; -+ } -+ } -+ } -+ } -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+bool xradio_queue_stats_is_empty(struct xradio_queue_stats *stats, -+ u32 link_id_map, int if_id) -+{ -+ bool empty = true; -+ -+ spin_lock_bh(&stats->lock); -+ if (link_id_map == (u32)-1) -+ empty = stats->num_queued[if_id] == 0; -+ else { -+ int i, if_id; -+ for (if_id = 0; if_id < XRWL_MAX_VIFS; if_id++) { -+ for (i = 0; i < stats->map_capacity; ++i) { -+ if (link_id_map & BIT(i)) { -+ if (stats->link_map_cache[if_id][i]) { -+ empty = false; -+ break; -+ } -+ } -+ } -+ } -+ } -+ spin_unlock_bh(&stats->lock); -+ -+ return empty; -+} -+ -+bool xradio_query_txpkt_timeout(struct xradio_common *hw_priv, int if_id, -+ u32 pending_pkt_id, long *timeout) -+{ -+ int i; -+ bool pending = false; -+ unsigned long timestamp = jiffies; -+ struct xradio_queue *queue = NULL; -+ struct xradio_queue_item *item = NULL; -+ struct xradio_queue *old_queue = NULL; -+ struct xradio_queue_item *old_item = NULL; -+ u8 pack_stk_wr = 0; -+ -+ /* Get oldest frame.*/ -+ for (i = 0; i < AC_QUEUE_NUM; ++i) { -+ queue = &hw_priv->tx_queue[i]; -+ spin_lock_bh(&queue->lock); -+ if (!list_empty(&queue->pending)) { -+ list_for_each_entry(item, &queue->pending, head) { -+ if (((if_id == XRWL_GENERIC_IF_ID) || -+ (if_id == XRWL_ALL_IFS) || -+ (item->txpriv.if_id == if_id)) && -+ (item->packetID != pending_pkt_id)) { -+ if (time_before(item->xmit_timestamp, timestamp)) { -+ timestamp = item->xmit_timestamp; -+ pack_stk_wr = item->pack_stk_wr; -+ old_queue = queue; -+ old_item = item; -+ } -+ } -+ } -+ pending = true; -+ } -+ spin_unlock_bh(&queue->lock); -+ } -+ if (!pending) -+ return false; -+ -+ /* Check if frame transmission is timed out. -+ * add (WSM_CMD_LAST_CHANCE_TIMEOUT>>1) for stuck workaround.*/ -+ *timeout = timestamp + WSM_CMD_LAST_CHANCE_TIMEOUT - jiffies; -+ if (unlikely(*timeout < 0) && !pack_stk_wr) { -+ struct ieee80211_hdr *frame = NULL; -+ const struct xradio_txpriv *txpriv = NULL; -+ u16 fctl = 0x0; -+ u32 len = 0x0; -+ u8 if_id = 0, link_id = 0, tid = 0; -+ -+ /* query the timeout frame. */ -+ spin_lock_bh(&old_queue->lock); -+ if (likely(old_item->skb && !hw_priv->query_packetID)) { -+ hw_priv->query_packetID = old_item->packetID; -+ old_item->pack_stk_wr = 1; -+ atomic_add(1, &hw_priv->query_cnt); -+ -+ /* Info of stuck frames for debug.*/ -+ txpriv = &old_item->txpriv; -+ frame = (struct ieee80211_hdr *)(&old_item->skb->data[txpriv->offset]); -+ fctl = frame->frame_control; -+ len = old_item->skb->len; -+ if_id = txpriv->if_id; -+ link_id = txpriv->link_id; -+ tid = txpriv->tid; -+ } -+ spin_unlock_bh(&old_queue->lock); -+ /* Dump Info of stuck frames. */ -+ if (frame) { -+ txrx_printk(XRADIO_DBG_ERROR, "TX confirm timeout(%ds).\n", -+ WSM_CMD_LAST_CHANCE_TIMEOUT/HZ); -+ txrx_printk(XRADIO_DBG_ERROR, "if=%d, linkid=%d, tid=%d, " \ -+ "old_packetID=0x%08x, fctl=0x%04x, len=%d, wr=%d\n", -+ if_id, link_id, tid, hw_priv->query_packetID, fctl, len, -+ pack_stk_wr); -+ } -+ /* Return half of timeout for query packet. */ -+ *timeout = (WSM_CMD_LAST_CHANCE_TIMEOUT>>1); -+ } else if (unlikely(pack_stk_wr)){ -+ *timeout = *timeout + (WSM_CMD_LAST_CHANCE_TIMEOUT>>1); -+ txrx_printk(XRADIO_DBG_MSG,"%s, wr and timeout=%ld\n", __func__, *timeout); -+ } -+ return pending; -+} -diff --git a/drivers/net/wireless/xradio/queue.h b/drivers/net/wireless/xradio/queue.h -new file mode 100644 -index 0000000..d6b64ce ---- /dev/null -+++ b/drivers/net/wireless/xradio/queue.h -@@ -0,0 +1,139 @@ -+/* -+ * queue operations for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#ifndef XRADIO_QUEUE_H_INCLUDED -+#define XRADIO_QUEUE_H_INCLUDED -+ -+/* private */ struct xradio_queue_item; -+ -+/* extern */ struct sk_buff; -+/* extern */ struct wsm_tx; -+/* extern */ struct xradio_common; -+/* extern */ struct xradio_vif; -+/* extern */ struct ieee80211_tx_queue_stats; -+/* extern */ struct xradio_txpriv; -+ -+/* forward */ struct xradio_queue_stats; -+ -+typedef void (*xradio_queue_skb_dtor_t)(struct xradio_common *priv, -+ struct sk_buff *skb, -+ const struct xradio_txpriv *txpriv); -+ -+struct xradio_queue { -+ struct xradio_queue_stats *stats; -+ size_t capacity; -+ size_t num_queued; -+ size_t num_queued_vif[XRWL_MAX_VIFS]; -+ size_t num_pending; -+ size_t num_pending_vif[XRWL_MAX_VIFS]; -+ size_t num_sent; -+ struct xradio_queue_item *pool; -+ struct list_head queue; -+ struct list_head free_pool; -+ struct list_head pending; -+ int tx_locked_cnt; -+ int *link_map_cache[XRWL_MAX_VIFS]; -+ bool overfull; -+ spinlock_t lock; -+ u8 queue_id; -+ u8 generation; -+ struct timer_list gc; -+ unsigned long ttl; -+}; -+ -+struct xradio_queue_stats { -+ spinlock_t lock; -+ int *link_map_cache[XRWL_MAX_VIFS]; -+ int num_queued[XRWL_MAX_VIFS]; -+ size_t map_capacity; -+ wait_queue_head_t wait_link_id_empty; -+ xradio_queue_skb_dtor_t skb_dtor; -+ struct xradio_common *hw_priv; -+}; -+ -+struct xradio_txpriv { -+ u8 link_id; -+ u8 raw_link_id; -+ u8 tid; -+ u8 rate_id; -+ u8 offset; -+ u8 if_id; -+ u8 offchannel_if_id; -+ u8 use_bg_rate; -+}; -+ -+int xradio_queue_stats_init(struct xradio_queue_stats *stats, -+ size_t map_capacity, -+ xradio_queue_skb_dtor_t skb_dtor, -+ struct xradio_common *priv); -+int xradio_queue_init(struct xradio_queue *queue, -+ struct xradio_queue_stats *stats, -+ u8 queue_id, -+ size_t capacity, -+ unsigned long ttl); -+int xradio_queue_clear(struct xradio_queue *queue, int if_id); -+void xradio_queue_stats_deinit(struct xradio_queue_stats *stats); -+void xradio_queue_deinit(struct xradio_queue *queue); -+ -+size_t xradio_queue_get_num_queued(struct xradio_vif *priv, -+ struct xradio_queue *queue, -+ u32 link_id_map); -+int xradio_queue_put(struct xradio_queue *queue, -+ struct sk_buff *skb, struct xradio_txpriv *txpriv); -+int xradio_queue_get(struct xradio_queue *queue, -+ int if_id, u32 link_id_map, -+ struct wsm_tx **tx, -+ struct ieee80211_tx_info **tx_info, -+ struct xradio_txpriv **txpriv); -+ -+int xradio_queue_requeue(struct xradio_queue *queue, u32 packetID, bool check); -+ -+int xradio_queue_requeue_all(struct xradio_queue *queue); -+int xradio_queue_remove(struct xradio_queue *queue, -+ u32 packetID); -+ -+int xradio_queue_get_skb(struct xradio_queue *queue, u32 packetID, -+ struct sk_buff **skb, -+ const struct xradio_txpriv **txpriv); -+void xradio_queue_lock(struct xradio_queue *queue); -+void xradio_queue_unlock(struct xradio_queue *queue); -+bool xradio_queue_get_xmit_timestamp(struct xradio_queue *queue, -+ unsigned long *timestamp, int if_id, -+ u32 pending_frameID, u32 *Old_frame_ID); -+bool xradio_query_txpkt_timeout(struct xradio_common *hw_priv, int if_id, -+ u32 pending_pkt_id, long *timeout); -+ -+ -+bool xradio_queue_stats_is_empty(struct xradio_queue_stats *stats, -+ u32 link_id_map, int if_id); -+ -+static inline u8 xradio_queue_get_queue_id(u32 packetID) -+{ -+ return (packetID >> 16) & 0xF; -+} -+ -+static inline u8 xradio_queue_get_if_id(u32 packetID) -+{ -+ return (packetID >> 20) & 0xF; -+} -+ -+static inline u8 xradio_queue_get_link_id(u32 packetID) -+{ -+ return (packetID >> 24) & 0xF; -+} -+ -+static inline u8 xradio_queue_get_generation(u32 packetID) -+{ -+ return (packetID >> 8) & 0xFF; -+} -+ -+#endif /* XRADIO_QUEUE_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/rx.c b/drivers/net/wireless/xradio/rx.c -new file mode 100644 -index 0000000..5a1ce60 ---- /dev/null -+++ b/drivers/net/wireless/xradio/rx.c -@@ -0,0 +1,414 @@ -+#include -+ -+#include "xradio.h" -+#include "rx.h" -+#include "ht.h" -+#include "p2p.h" -+#include "sta.h" -+#include "bh.h" -+#include "ap.h" -+ -+ // MRK: added copy of this tx.c function here for testing, renamed _rx -+ -+static void xradio_check_go_neg_conf_success_rx(struct xradio_common *hw_priv, -+ u8 *action) -+{ -+ if (action[2] == 0x50 && action[3] == 0x6F && action[4] == 0x9A && -+ action[5] == 0x09 && action[6] == 0x02) { -+ if(action[17] == 0) { -+ hw_priv->is_go_thru_go_neg = true; -+ } -+ else { -+ hw_priv->is_go_thru_go_neg = false; -+ } -+ } -+} -+ -+ -+static int xradio_handle_pspoll(struct xradio_vif *priv, -+ struct sk_buff *skb) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct ieee80211_sta *sta; -+ struct ieee80211_pspoll *pspoll = -+ (struct ieee80211_pspoll *) skb->data; -+ int link_id = 0; -+ u32 pspoll_mask = 0; -+ int drop = 1; -+ int i; -+ -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP) -+ goto done; -+ if (memcmp(priv->vif->addr, pspoll->bssid, ETH_ALEN)) -+ goto done; -+ -+ rcu_read_lock(); -+ sta = ieee80211_find_sta(priv->vif, pspoll->ta); -+ if (sta) { -+ struct xradio_sta_priv *sta_priv; -+ sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; -+ link_id = sta_priv->link_id; -+ pspoll_mask = BIT(sta_priv->link_id); -+ } -+ rcu_read_unlock(); -+ if (!link_id) -+ goto done; -+ -+ priv->pspoll_mask |= pspoll_mask; -+ drop = 0; -+ -+ /* Do not report pspols if data for given link id is -+ * queued already. */ -+ for (i = 0; i < 4; ++i) { -+ if (xradio_queue_get_num_queued(priv, -+ &hw_priv->tx_queue[i], -+ pspoll_mask)) { -+ xradio_bh_wakeup(hw_priv); -+ drop = 1; -+ break; -+ } -+ } -+ txrx_printk(XRADIO_DBG_NIY, "[RX] PSPOLL: %s\n", drop ? "local" : "fwd"); -+done: -+ return drop; -+} -+ -+ -+static void -+xradio_rx_h_ba_stat(struct xradio_vif *priv, -+ size_t hdrlen, size_t skb_len ) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_STA) -+ return; -+ if (!xradio_is_ht(&hw_priv->ht_oper)) -+ return; -+ if (!priv->setbssparams_done) -+ return; -+ -+ spin_lock_bh(&hw_priv->ba_lock); -+ hw_priv->ba_acc_rx += skb_len - hdrlen; -+ if (!(hw_priv->ba_cnt_rx || hw_priv->ba_cnt)) { -+ mod_timer(&hw_priv->ba_timer, -+ jiffies + XRADIO_BLOCK_ACK_INTERVAL); -+ } -+ hw_priv->ba_cnt_rx++; -+ spin_unlock_bh(&hw_priv->ba_lock); -+} -+ -+void xradio_rx_cb(struct xradio_vif *priv, -+ struct wsm_rx *arg, -+ struct sk_buff **skb_p) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct sk_buff *skb = *skb_p; -+ struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); -+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -+#endif -+ struct xradio_link_entry *entry = NULL; -+ unsigned long grace_period; -+ bool early_data = false; -+ size_t hdrlen = 0; -+ u8 parse_iv_len = 0; -+ -+ dev_dbg(hw_priv->pdev, "vif %d: rx, status %u flags 0x%.8x", -+ priv->if_id, arg->status, arg->flags); -+ if(ieee80211_is_deauth(frame->frame_control)) -+ dev_dbg(hw_priv->pdev, "vif %d: deauth\n", priv->if_id); -+ -+ hdr->flag = 0; -+ -+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { -+ /* STA is stopped. */ -+ goto drop; -+ } -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ xradio_frame_monitor(hw_priv,skb,false); -+#endif -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ if ((ieee80211_is_action(frame->frame_control)) -+ && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { -+ u8 *action = (u8*)&mgmt->u.action.category; -+ xradio_check_go_neg_conf_success_rx(hw_priv, action); -+ } -+#endif -+ -+ if (arg->link_id && (arg->link_id != XRADIO_LINK_ID_UNMAPPED) -+ && (arg->link_id <= XRADIO_MAX_STA_IN_AP_MODE)) { -+ entry = &priv->link_id_db[arg->link_id - 1]; -+ if (entry->status == XRADIO_LINK_SOFT && -+ ieee80211_is_data(frame->frame_control)) -+ early_data = true; -+ entry->timestamp = jiffies; -+ } -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ else if ((arg->link_id == XRADIO_LINK_ID_UNMAPPED) -+ && (priv->vif->p2p == WSM_START_MODE_P2P_GO) -+ && ieee80211_is_action(frame->frame_control) -+ && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { -+ txrx_printk(XRADIO_DBG_NIY, "[RX] Going to MAP&RESET link ID\n"); -+ -+ if (work_pending(&priv->linkid_reset_work)) -+ WARN_ON(1); -+ -+ memcpy(&priv->action_frame_sa[0], -+ ieee80211_get_SA(frame), ETH_ALEN); -+ priv->action_linkid = 0; -+ schedule_work(&priv->linkid_reset_work); -+ } -+ -+ if (arg->link_id && (arg->link_id != XRADIO_LINK_ID_UNMAPPED) -+ && (priv->vif->p2p == WSM_START_MODE_P2P_GO) -+ && ieee80211_is_action(frame->frame_control) -+ && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { -+ /* Link ID already exists for the ACTION frame. -+ * Reset and Remap */ -+ if (work_pending(&priv->linkid_reset_work)) -+ WARN_ON(1); -+ memcpy(&priv->action_frame_sa[0], -+ ieee80211_get_SA(frame), ETH_ALEN); -+ priv->action_linkid = arg->link_id; -+ schedule_work(&priv->linkid_reset_work); -+ } -+#endif -+ if (unlikely(arg->status)) { -+ if (arg->status == WSM_STATUS_MICFAILURE) { -+ dev_err(priv->hw_priv->pdev, "[RX] IF=%d, MIC failure.\n", -+ priv->if_id); -+ hdr->flag |= RX_FLAG_MMIC_ERROR; -+ } else if (arg->status == WSM_STATUS_NO_KEY_FOUND) { -+ dev_warn(priv->hw_priv->pdev, "received frame has no key status\n"); -+ goto drop; -+ } else { -+ dev_err(priv->hw_priv->pdev, "[RX] IF=%d, Receive failure: %d.\n", -+ priv->if_id, arg->status); -+ goto drop; -+ } -+ } -+ -+ if (skb->len < sizeof(struct ieee80211_pspoll)) { -+ dev_err(priv->hw_priv->pdev, "Malformed SDU rx'ed. " -+ "Size is lesser than IEEE header.\n"); -+ goto drop; -+ } -+ -+ if (unlikely(ieee80211_is_pspoll(frame->frame_control))) -+ if (xradio_handle_pspoll(priv, skb)) -+ goto drop; -+ -+ hdr->mactime = 0; /* Not supported by WSM */ -+ hdr->band = (arg->channelNumber > 14) ? -+ NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; -+ hdr->freq = ieee80211_channel_to_frequency( -+ arg->channelNumber, -+ hdr->band); -+ -+#ifdef AP_HT_COMPAT_FIX -+ if (!priv->ht_compat_det && priv->htcap && -+ ieee80211_is_data_qos(frame->frame_control)) { -+ if(xradio_apcompat_detect(priv, arg->rxedRate)) -+ goto drop; -+ } -+#endif -+ -+ if (arg->rxedRate >= 14) { -+ hdr->encoding = RX_ENC_HT; -+ hdr->rate_idx = arg->rxedRate - 14; -+ } else if (arg->rxedRate >= 4) { -+ if (hdr->band == NL80211_BAND_5GHZ) -+ hdr->rate_idx = arg->rxedRate - 6; -+ else -+ hdr->rate_idx = arg->rxedRate - 2; -+ } else { -+ hdr->rate_idx = arg->rxedRate; -+ } -+ -+ hdr->signal = (s8)arg->rcpiRssi; -+ hdr->antenna = 0; -+ -+ hdrlen = ieee80211_hdrlen(frame->frame_control); -+ -+ if (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { -+ size_t iv_len = 0, icv_len = 0; -+ -+ hdr->flag |= RX_FLAG_DECRYPTED; -+ -+ /* Oops... There is no fast way to ask mac80211 about -+ * IV/ICV lengths. Even defines are not exposed.*/ -+ switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { -+ case WSM_RX_STATUS_WEP: -+ iv_len = 4 /* WEP_IV_LEN */; -+ icv_len = 4 /* WEP_ICV_LEN */; -+ break; -+ case WSM_RX_STATUS_TKIP: -+ iv_len = 8 /* TKIP_IV_LEN */; -+ icv_len = 4 /* TKIP_ICV_LEN */ -+ + 8 /*MICHAEL_MIC_LEN*/; -+ break; -+ case WSM_RX_STATUS_AES: -+ iv_len = 8 /* CCMP_HDR_LEN */; -+ icv_len = 8 /* CCMP_MIC_LEN */; -+ break; -+ case WSM_RX_STATUS_WAPI: -+ iv_len = 18 /* WAPI_HDR_LEN */; -+ icv_len = 16 /* WAPI_MIC_LEN */; -+ hdr->flag |= RX_FLAG_IV_STRIPPED; -+ break; -+ default: -+ WARN_ON("Unknown encryption type"); -+ goto drop; -+ } -+ -+ /* Firmware strips ICV in case of MIC failure. */ -+ if (arg->status == WSM_STATUS_MICFAILURE) { -+ icv_len = 0; -+ hdr->flag |= RX_FLAG_IV_STRIPPED; -+ } -+ -+ if (skb->len < hdrlen + iv_len + icv_len) { -+ dev_err(priv->hw_priv->pdev, "Mailformed SDU rx'ed. " -+ "Size is lesser than crypto headers.\n"); -+ goto drop; -+ } -+ -+ if (WSM_RX_STATUS_ENCRYPTION(arg->flags) == -+ WSM_RX_STATUS_TKIP) { -+ /* Remove TKIP MIC 8 bytes*/ -+ memmove(skb->data + skb->len-icv_len, -+ skb->data + skb->len-icv_len+8, 4); -+ skb_trim(skb, skb->len - 8); -+ hdr->flag |= RX_FLAG_MMIC_STRIPPED; -+ } else if (unlikely(WSM_RX_STATUS_ENCRYPTION(arg->flags) == -+ WSM_RX_STATUS_WAPI)) { -+ /* Protocols not defined in mac80211 should be -+ stripped/crypted in driver/firmware */ -+ /* Remove IV, ICV and MIC */ -+ skb_trim(skb, skb->len - icv_len); -+ memmove(skb->data + iv_len, skb->data, hdrlen); -+ skb_pull(skb, iv_len); -+ } -+ parse_iv_len = iv_len; -+ } -+ -+ if (ieee80211_is_beacon(frame->frame_control) && -+ !arg->status && -+ !memcmp(ieee80211_get_SA(frame), priv->join_bssid,ETH_ALEN)) { -+ const u8 *tim_ie; -+ u8 *ies; -+ size_t ies_len; -+ priv->disable_beacon_filter = false; -+ queue_work(hw_priv->workqueue, &priv->update_filtering_work); -+ ies = ((struct ieee80211_mgmt *) -+ (skb->data))->u.beacon.variable; -+ ies_len = skb->len - (ies - (u8 *)(skb->data)); -+ -+ tim_ie = xradio_get_ie(ies, ies_len, WLAN_EID_TIM); -+ if (tim_ie) { -+ struct ieee80211_tim_ie *tim = -+ (struct ieee80211_tim_ie *)&tim_ie[2]; -+ -+ if (priv->join_dtim_period != tim->dtim_period) { -+ priv->join_dtim_period = tim->dtim_period; -+ queue_work(hw_priv->workqueue, -+ &priv->set_beacon_wakeup_period_work); -+ } -+ } -+ if (unlikely(priv->disable_beacon_filter)) { -+ priv->disable_beacon_filter = false; -+ queue_work(hw_priv->workqueue, -+ &priv->update_filtering_work); -+ } -+ } -+#ifdef AP_HT_CAP_UPDATE -+ if (priv->mode == NL80211_IFTYPE_AP && -+ ieee80211_is_beacon(frame->frame_control) && -+ ((priv->ht_oper&HT_INFO_MASK) != 0x0011) && -+ !arg->status){ -+ u8 *ies; -+ size_t ies_len; -+ const u8 *ht_cap; -+ ies = ((struct ieee80211_mgmt *)(skb->data))->u.beacon.variable; -+ ies_len = skb->len - (ies - (u8 *)(skb->data)); -+ ht_cap = xradio_get_ie(ies, ies_len, WLAN_EID_HT_CAPABILITY); -+ if(!ht_cap) { -+ priv->ht_oper |= 0x0011; -+ queue_work(hw_priv->workqueue, &priv->ht_oper_update_work); -+ } -+ } -+#endif -+ -+#ifdef AP_HT_COMPAT_FIX -+ if (ieee80211_is_mgmt(frame->frame_control) && -+ priv->if_id == 0 && !(priv->ht_compat_det & 0x10)) { -+ xradio_remove_ht_ie(priv, skb); -+ } -+#endif -+ -+#ifdef ROAM_OFFLOAD -+ if ((ieee80211_is_beacon(frame->frame_control)||ieee80211_is_probe_resp(frame->frame_control)) && -+ !arg->status ) { -+ if (hw_priv->auto_scanning && !atomic_read(&hw_priv->scan.in_progress)) -+ hw_priv->frame_rcvd = 1; -+ -+ if (!memcmp(ieee80211_get_SA(frame), priv->join_bssid, ETH_ALEN)) { -+ if (hw_priv->beacon) -+ dev_kfree_skb(hw_priv->beacon); -+ hw_priv->beacon = skb_copy(skb, GFP_ATOMIC); -+ if (!hw_priv->beacon) -+ txrx_printk(XRADIO_DBG_ERROR, "sched_scan: own beacon storing failed\n"); -+ } -+ } -+#endif /*ROAM_OFFLOAD*/ -+ -+ //don't delay scan before next connect, yangfh. -+ if (ieee80211_is_deauth(frame->frame_control) || -+ ieee80211_is_disassoc(frame->frame_control)) -+ hw_priv->connet_time[priv->if_id] = 0; -+ -+ /* Stay awake for 1sec. after frame is received to give -+ * userspace chance to react and acquire appropriate -+ * wakelock. */ -+ if (ieee80211_is_auth(frame->frame_control)) -+ grace_period = 5 * HZ; -+ else if (ieee80211_is_deauth(frame->frame_control)) -+ grace_period = 5 * HZ; -+ else -+ grace_period = HZ; -+ -+ if (ieee80211_is_data(frame->frame_control)) -+ xradio_rx_h_ba_stat(priv, hdrlen, skb->len); -+ -+ xradio_pm_stay_awake(&hw_priv->pm_state, grace_period); -+ -+ if(xradio_realloc_resv_skb(hw_priv, *skb_p)) { -+ *skb_p = NULL; -+ return; -+ } -+ /* Try to a packet for the case dev_alloc_skb failed in bh.*/ -+ if (unlikely(early_data)) { -+ spin_lock_bh(&priv->ps_state_lock); -+ /* Double-check status with lock held */ -+ if (entry->status == XRADIO_LINK_SOFT) { -+ skb_queue_tail(&entry->rx_queue, skb); -+ dev_warn(priv->hw_priv->pdev, "***skb_queue_tail\n"); -+ } else -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ spin_unlock_bh(&priv->ps_state_lock); -+ } else { -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+ *skb_p = NULL; -+ -+ return; -+ -+drop: -+ dev_warn(priv->hw_priv->pdev, "dropped received frame\n"); -+ return; -+} -diff --git a/drivers/net/wireless/xradio/rx.h b/drivers/net/wireless/xradio/rx.h -new file mode 100644 -index 0000000..0c02b23 ---- /dev/null -+++ b/drivers/net/wireless/xradio/rx.h -@@ -0,0 +1,8 @@ -+#ifndef XRADIO_RX_H -+#define XRADIO_RX_H -+ -+void xradio_rx_cb(struct xradio_vif *priv, -+ struct wsm_rx *arg, -+ struct sk_buff **skb_p); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/scan.c b/drivers/net/wireless/xradio/scan.c -new file mode 100644 -index 0000000..a8829c0 ---- /dev/null -+++ b/drivers/net/wireless/xradio/scan.c -@@ -0,0 +1,897 @@ -+/* -+ * Scan implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include "xradio.h" -+#include "scan.h" -+#include "sta.h" -+#include "pm.h" -+ -+static void xradio_scan_restart_delayed(struct xradio_vif *priv); -+ -+static void xradio_remove_wps_p2p_ie(struct wsm_template_frame *frame) -+{ -+ u8 *ies; -+ u32 ies_len; -+ u32 ie_len; -+ u32 p2p_ie_len = 0; -+ u32 wps_ie_len = 0; -+ -+ -+ ies = &frame->skb->data[sizeof(struct ieee80211_hdr_3addr)]; -+ ies_len = frame->skb->len - sizeof(struct ieee80211_hdr_3addr); -+ while (ies_len >= 6) { -+ ie_len = ies[1] + 2; -+ ies_len -= ie_len; -+ if ((ies[0] == WLAN_EID_VENDOR_SPECIFIC) && -+ (ies[2] == 0x00 && ies[3] == 0x50 && -+ ies[4] == 0xf2 && ies[5] == 0x04)) { -+ wps_ie_len = ie_len; -+ memmove(ies, ies + ie_len, ies_len); -+ } else if ((ies[0] == WLAN_EID_VENDOR_SPECIFIC) && -+ (ies[2] == 0x50 && ies[3] == 0x6f && -+ ies[4] == 0x9a && ies[5] == 0x09)) { -+ p2p_ie_len = ie_len; -+ memmove(ies, ies + ie_len, ies_len); -+ } else { -+ ies += ie_len; -+ } -+ } -+ -+ if (p2p_ie_len || wps_ie_len) { -+ skb_trim(frame->skb, frame->skb->len - (p2p_ie_len + wps_ie_len)); -+ } -+} -+ -+static int xradio_scan_start(struct xradio_vif *priv, struct wsm_scan *scan) -+{ -+ int ret, i; -+#ifdef FPGA_SETUP -+ int tmo = 5000; -+#else -+ int tmo = 5000; -+#endif -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ -+ for (i = 0; i < scan->numOfChannels; ++i) -+ tmo += scan->ch[i].maxChannelTime + 10; -+ -+ atomic_set(&hw_priv->scan.in_progress, 1); -+ atomic_set(&hw_priv->recent_scan, 1); -+ xradio_pm_stay_awake(&hw_priv->pm_state, tmo * HZ / 1000); -+ ret = wsm_scan(hw_priv, scan, priv->if_id); -+ if (unlikely(ret)) { -+ scan_printk(XRADIO_DBG_WARN, "%s,wsm_scan failed!\n", __func__); -+ atomic_set(&hw_priv->scan.in_progress, 0); -+ xradio_scan_restart_delayed(priv); -+ } else { -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, -+ tmo * HZ / 1000); -+ } -+ return ret; -+} -+ -+#ifdef ROAM_OFFLOAD -+static int xradio_sched_scan_start(struct xradio_vif *priv, struct wsm_scan *scan) -+{ -+ int ret; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ -+ ret = wsm_scan(hw_priv, scan, priv->if_id); -+ if (unlikely(ret)) { -+ atomic_set(&hw_priv->scan.in_progress, 0); -+ scan_printk(XRADIO_DBG_WARN,"%s,wsm_scan failed!\n", __func__); -+ } -+ return ret; -+} -+#endif /*ROAM_OFFLOAD*/ -+ -+int xradio_hw_scan(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_scan_request *hw_req) -+{ -+ struct cfg80211_scan_request *req = &hw_req->req; -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, -+ }; -+ int i; -+ -+ /* Scan when P2P_GO corrupt firmware MiniAP mode */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ scan_printk(XRADIO_DBG_WARN,"%s, can't scan in AP mode!\n", __func__); -+ return -EOPNOTSUPP; -+ } -+ -+ if (hw_priv->bh_error) { -+ scan_printk(XRADIO_DBG_NIY, "Ignoring scan bh error occur!\n"); -+ return -EBUSY; -+ } -+ -+ if (work_pending(&priv->offchannel_work) || -+ (hw_priv->roc_if_id != -1)) { -+ scan_printk(XRADIO_DBG_WARN, "Offchannel work pending, " -+ "ignoring scan work %d\n", hw_priv->roc_if_id); -+ return -EBUSY; -+ } -+ -+ if (req->n_ssids == 1 && !req->ssids[0].ssid_len) -+ req->n_ssids = 0; -+ -+ scan_printk(XRADIO_DBG_NIY, "vif%d Scan request(%s-%dchs) for %d SSIDs.\n", -+ priv->if_id, (req->channels[0]->band==NL80211_BAND_2GHZ)?"2.4G":"5G", -+ req->n_channels, req->n_ssids); -+ -+ /*delay multiple ssids scan of vif0 for 3s when connnetting to a node*/ -+ if(hw_priv->connet_time[0] > 0 && req->n_ssids == 0 && priv->if_id == 0) { -+ long timeleft0 = hw_priv->connet_time[0] + SCAN_MAX_DELAY - jiffies; -+ if(jiffies >= hw_priv->connet_time[0] && timeleft0 > 0) { -+ scan_printk(XRADIO_DBG_NIY, "vif0 connetting, scan delay %ldms\n", -+ timeleft0*1000/HZ); -+ return -EBUSY; -+ } -+ hw_priv->connet_time[0] = 0; -+ } -+ -+ if (req->n_ssids > hw->wiphy->max_scan_ssids){ -+ scan_printk(XRADIO_DBG_ERROR, "%s: ssids is too much(%d)\n", -+ __func__, req->n_ssids); -+ return -EINVAL; -+ } -+ -+ /* TODO by Icenowy: so strange function call */ -+ frame.skb = ieee80211_probereq_get(hw, vif->addr, NULL, 0, 0); -+ if (!frame.skb) { -+ scan_printk(XRADIO_DBG_ERROR, "%s: ieee80211_probereq_get failed!\n", -+ __func__); -+ return -ENOMEM; -+ } -+ -+#ifdef ROAM_OFFLOAD -+ if (priv->join_status != XRADIO_JOIN_STATUS_STA) { -+ if (req->channels[0]->band == NL80211_BAND_2GHZ) -+ hw_priv->num_scanchannels = 0; -+ else -+ hw_priv->num_scanchannels = hw_priv->num_2g_channels; -+ -+ for (i=0; i < req->n_channels; i++) { -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].number = \ -+ req->channels[i]->hw_value; -+ if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR) { -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].minChannelTime = 50; -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].maxChannelTime = 110; -+ } -+ else { -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].minChannelTime = 10; -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].maxChannelTime = 40; -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].number |= \ -+ XRADIO_SCAN_TYPE_ACTIVE; -+ } -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].txPowerLevel = \ -+ req->channels[i]->max_power; -+ if (req->channels[0]->band == NL80211_BAND_5GHZ) -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].number |= \ -+ XRADIO_SCAN_BAND_5G; -+ } -+ if (req->channels[0]->band == NL80211_BAND_2GHZ) -+ hw_priv->num_2g_channels = req->n_channels; -+ else -+ hw_priv->num_5g_channels = req->n_channels; -+ } -+ hw_priv->num_scanchannels = hw_priv->num_2g_channels + hw_priv->num_5g_channels; -+#endif /*ROAM_OFFLOAD*/ -+ -+ /* will be unlocked in xradio_scan_work() */ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ if (frame.skb) { -+ int ret = 0; -+ if (priv->if_id == 0) -+ xradio_remove_wps_p2p_ie(&frame); -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ if (ret) { -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+ dev_kfree_skb(frame.skb); -+ scan_printk(XRADIO_DBG_ERROR, "%s: wsm_set_template_frame failed: %d.\n", -+ __func__, ret); -+ return ret; -+ } -+ } -+ -+ wsm_vif_lock_tx(priv); -+ -+ BUG_ON(hw_priv->scan.req); -+ hw_priv->scan.req = req; -+ hw_priv->scan.n_ssids = 0; -+ hw_priv->scan.status = 0; -+ hw_priv->scan.begin = &req->channels[0]; -+ hw_priv->scan.curr = hw_priv->scan.begin; -+ hw_priv->scan.end = &req->channels[req->n_channels]; -+ hw_priv->scan.output_power = hw_priv->output_power; -+ hw_priv->scan.if_id = priv->if_id; -+ /* TODO:COMBO: Populate BIT4 in scanflags to decide on which MAC -+ * address the SCAN request will be sent */ -+ -+ for (i = 0; i < req->n_ssids; ++i) { -+ struct wsm_ssid *dst = &hw_priv->scan.ssids[hw_priv->scan.n_ssids]; -+ BUG_ON(req->ssids[i].ssid_len > sizeof(dst->ssid)); -+ memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); -+ dst->length = req->ssids[i].ssid_len; -+ ++hw_priv->scan.n_ssids; -+ } -+ -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ if (frame.skb) -+ dev_kfree_skb(frame.skb); -+ queue_work(hw_priv->workqueue, &hw_priv->scan.work); -+ -+ return 0; -+} -+ -+#ifdef ROAM_OFFLOAD -+int xradio_hw_sched_scan_start(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct cfg80211_sched_scan_request *req, -+ struct ieee80211_sched_scan_ies *ies) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, -+ }; -+ int i; -+ -+ -+ scan_printk(XRADIO_DBG_WARN, "Scheduled scan request-->.\n"); -+ if (!priv->vif) -+ return -EINVAL; -+ -+ /* Scan when P2P_GO corrupt firmware MiniAP mode */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ scan_printk(XRADIO_DBG_WARN,"%s, can't scan in AP mode!\n", __func__); -+ return -EOPNOTSUPP; -+ } -+ -+ scan_printk(XRADIO_DBG_WARN, "Scheduled scan: n_ssids %d, ssid[0].len = %d\n", -+ req->n_ssids, req->ssids[0].ssid_len); -+ if (req->n_ssids == 1 && !req->ssids[0].ssid_len) -+ req->n_ssids = 0; -+ -+ scan_printk(XRADIO_DBG_NIY, "[SCAN] Scan request for %d SSIDs.\n", -+ req->n_ssids); -+ -+ if (req->n_ssids > hw->wiphy->max_scan_ssids) [ -+ scan_printk(XRADIO_DBG_ERROR, "%s: ssids is too much(%d)\n", -+ __func__, req->n_ssids); -+ return -EINVAL; -+ } -+ -+ frame.skb = ieee80211_probereq_get(hw, priv->vif, NULL, 0, -+ ies->ie[0], ies->len[0]); -+ if (!frame.skb) { -+ scan_printk(XRADIO_DBG_ERROR, "%s: ieee80211_probereq_get failed!\n", -+ __func__); -+ return -ENOMEM; -+ } -+ -+ /* will be unlocked in xradio_scan_work() */ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ if (frame.skb) { -+ int ret; -+ if (priv->if_id == 0) -+ xradio_remove_wps_p2p_ie(&frame); -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ if (0 == ret) { -+ /* Host want to be the probe responder. */ -+ ret = wsm_set_probe_responder(priv, true); -+ } -+ if (ret) { -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+ dev_kfree_skb(frame.skb); -+ scan_printk(XRADIO_DBG_ERROR, "%s: wsm_set_probe_responder failed: %d.\n", -+ __func__, ret); -+ return ret; -+ } -+ } -+ -+ wsm_lock_tx(hw_priv); -+ BUG_ON(hw_priv->scan.req); -+ hw_priv->scan.sched_req = req; -+ hw_priv->scan.n_ssids = 0; -+ hw_priv->scan.status = 0; -+ hw_priv->scan.begin = &req->channels[0]; -+ hw_priv->scan.curr = hw_priv->scan.begin; -+ hw_priv->scan.end = &req->channels[req->n_channels]; -+ hw_priv->scan.output_power = hw_priv->output_power; -+ -+ for (i = 0; i < req->n_ssids; ++i) { -+ u8 j; -+ struct wsm_ssid *dst = &hw_priv->scan.ssids[hw_priv->scan.n_ssids]; -+ BUG_ON(req->ssids[i].ssid_len > sizeof(dst->ssid)); -+ memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); -+ dst->length = req->ssids[i].ssid_len; -+ ++hw_priv->scan.n_ssids; -+ scan_printk(XRADIO_DBG_NIY, "SSID %d\n",i); -+ for(j=0; jssids[i].ssid_len; j++) -+ scan_printk(XRADIO_DBG_NIY, "0x%x\n", req->ssids[i].ssid[j]); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ if (frame.skb) -+ dev_kfree_skb(frame.skb); -+ queue_work(hw_priv->workqueue, &hw_priv->scan.swork); -+ scan_printk(XRADIO_DBG_NIY, "<-- Scheduled scan request.\n"); -+ return 0; -+} -+#endif /*ROAM_OFFLOAD*/ -+ -+void xradio_scan_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = container_of(work, -+ struct xradio_common, -+ scan.work); -+ struct xradio_vif *priv; -+ struct ieee80211_channel **it; -+ struct wsm_scan scan = { -+ .scanType = WSM_SCAN_TYPE_FOREGROUND, -+ .scanFlags = 0, /* TODO:COMBO */ -+ //.scanFlags = WSM_SCAN_FLAG_SPLIT_METHOD, /* TODO:COMBO */ -+ }; -+ bool first_run; -+ int i; -+ const u32 ProbeRequestTime = 2; -+ const u32 ChannelRemainTime = 15; -+ u32 maxChannelTime; -+ struct cfg80211_scan_info scan_info; -+ -+ -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); -+ -+ /*TODO: COMBO: introduce locking so vif is not removed in meanwhile */ -+ if (!priv) { -+ scan_printk(XRADIO_DBG_WARN, "interface removed, " -+ "ignoring scan work\n"); -+ return; -+ } -+ -+ if (priv->if_id) -+ scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1; -+ else -+ scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1; -+ -+ /* No need to set WSM_SCAN_FLAG_FORCE_BACKGROUND in BSS_LOSS work. -+ * yangfh 2015-11-11 18:45:02 */ -+ //xradio_for_each_vif(hw_priv, vif, i) { -+ // if (!vif) -+ // continue; -+ // if (vif->bss_loss_status > XRADIO_BSS_LOSS_NONE) -+ // scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND; -+ //} -+ -+ first_run = (hw_priv->scan.begin == hw_priv->scan.curr && -+ hw_priv->scan.begin != hw_priv->scan.end); -+ if (first_run) { -+ /* Firmware gets crazy if scan request is sent -+ * when STA is joined but not yet associated. -+ * Force unjoin in this case. */ -+ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) -+ xradio_join_timeout(&priv->join_timeout.work); -+ } -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ if (first_run) { -+#if 0 -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA && -+ !(priv->powersave_mode.pmMode & WSM_PSM_PS)) { -+ struct wsm_set_pm pm = priv->powersave_mode; -+ pm.pmMode = WSM_PSM_PS; -+ xradio_set_pm(priv, &pm); -+ } else -+#endif -+ if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) { -+ /* FW bug: driver has to restart p2p-dev mode -+ * after scan */ -+ xradio_disable_listening(priv); -+ } -+ } -+ -+ if (!hw_priv->scan.req || (hw_priv->scan.curr == hw_priv->scan.end)) { -+ if (hw_priv->scan.output_power != hw_priv->output_power) { -+ /* TODO:COMBO: Change when mac80211 implementation -+ * is available for output power also */ -+ WARN_ON(wsm_set_output_power(hw_priv, hw_priv->output_power * 10, -+ priv->if_id)); -+ } -+ -+#if 0 -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA && -+ !(priv->powersave_mode.pmMode & WSM_PSM_PS)) -+ xradio_set_pm(priv, &priv->powersave_mode); -+#endif -+ -+ if (hw_priv->scan.status < 0) -+ scan_printk(XRADIO_DBG_ERROR, "Scan failed (%d).\n", hw_priv->scan.status); -+ else if (hw_priv->scan.req) -+ scan_printk(XRADIO_DBG_NIY, "Scan completed.\n"); -+ else -+ scan_printk(XRADIO_DBG_NIY, "Scan canceled.\n"); -+ -+ hw_priv->scan.req = NULL; -+ xradio_scan_restart_delayed(priv); -+ wsm_unlock_tx(hw_priv); -+ mutex_unlock(&hw_priv->conf_mutex); -+ memset(&scan_info, 0, sizeof(scan_info)); -+ scan_info.aborted = hw_priv->scan.status ? 1 : 0; -+ ieee80211_scan_completed(hw_priv->hw, &scan_info); -+ up(&hw_priv->scan.lock); -+ return; -+ -+ } else { -+ struct ieee80211_channel *first = *hw_priv->scan.curr; -+ for (it = hw_priv->scan.curr + 1, i = 1; -+ it != hw_priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; -+ ++it, ++i) { -+ if ((*it)->band != first->band) -+ break; -+ if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_NO_IR) -+ break; -+ if (!(first->flags & IEEE80211_CHAN_NO_IR) && -+ (*it)->max_power != first->max_power) -+ break; -+ } -+ scan.band = first->band; -+ -+ if (hw_priv->scan.req->no_cck) -+ scan.maxTransmitRate = WSM_TRANSMIT_RATE_6; -+ else -+ scan.maxTransmitRate = WSM_TRANSMIT_RATE_1; -+ -+ /* TODO: Is it optimal? */ -+ scan.numOfProbeRequests = (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; -+ -+ scan.numOfSSIDs = hw_priv->scan.n_ssids; -+ scan.ssids = &hw_priv->scan.ssids[0]; -+ scan.numOfChannels = it - hw_priv->scan.curr; -+ /* TODO: Is it optimal? */ -+ scan.probeDelay = 100; -+ /* It is not stated in WSM specification, however -+ * FW team says that driver may not use FG scan -+ * when joined. */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ scan.scanType = WSM_SCAN_TYPE_BACKGROUND; -+ scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; -+ } -+ scan.ch = kzalloc(sizeof(struct wsm_scan_ch[it - hw_priv->scan.curr]), GFP_KERNEL); -+ if (!scan.ch) { -+ hw_priv->scan.status = -ENOMEM; -+ scan_printk(XRADIO_DBG_ERROR, "xr_kzalloc wsm_scan_ch failed.\n"); -+ goto fail; -+ } -+ maxChannelTime = (scan.numOfSSIDs * scan.numOfProbeRequests *ProbeRequestTime) + -+ ChannelRemainTime; -+ maxChannelTime = (maxChannelTime < 35) ? 35 : maxChannelTime; -+ for (i = 0; i < scan.numOfChannels; ++i) { -+ scan.ch[i].number = hw_priv->scan.curr[i]->hw_value; -+ -+ -+ if (hw_priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) { -+ scan.ch[i].minChannelTime = 50; -+ scan.ch[i].maxChannelTime = 110; -+ } else { -+ scan.ch[i].minChannelTime = 15; -+ scan.ch[i].maxChannelTime = maxChannelTime; -+ } -+ -+ -+ } -+ -+ if (!(first->flags & IEEE80211_CHAN_NO_IR) && -+ hw_priv->scan.output_power != first->max_power) { -+ hw_priv->scan.output_power = first->max_power; -+ /* TODO:COMBO: Change after mac80211 implementation -+ * complete */ -+ WARN_ON(wsm_set_output_power(hw_priv, hw_priv->scan.output_power * 10, -+ priv->if_id)); -+ } -+ -+ down(&hw_priv->scan.status_lock); -+ hw_priv->scan.status = xradio_scan_start(priv, &scan); -+ -+ kfree(scan.ch); -+ if (WARN_ON(hw_priv->scan.status)) { -+ scan_printk(XRADIO_DBG_ERROR, "scan failed, status=%d.\n", -+ hw_priv->scan.status); -+ up(&hw_priv->scan.status_lock); -+ goto fail; -+ } -+ up(&hw_priv->scan.status_lock); -+ hw_priv->scan.curr = it; -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ return; -+ -+fail: -+ hw_priv->scan.curr = hw_priv->scan.end; -+ mutex_unlock(&hw_priv->conf_mutex); -+ queue_work(hw_priv->workqueue, &hw_priv->scan.work); -+ return; -+} -+ -+#ifdef ROAM_OFFLOAD -+void xradio_sched_scan_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = container_of(work, struct xradio_common, -+ scan.swork); -+ struct wsm_scan scan; -+ struct wsm_ssid scan_ssid; -+ int i; -+ struct xradio_vif *priv = NULL; -+ -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); -+ if (unlikely(!priv)) { -+ WARN_ON(1); -+ return; -+ } -+ -+ spin_unlock(&priv->vif_lock); -+ /* Firmware gets crazy if scan request is sent -+ * when STA is joined but not yet associated. -+ * Force unjoin in this case. */ -+ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) { -+ xradio_join_timeout(&priv->join_timeout.work); -+ } -+ mutex_lock(&hw_priv->conf_mutex); -+ hw_priv->auto_scanning = 1; -+ scan.band = 0; -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) -+ scan.scanType = 3; /* auto background */ -+ else -+ scan.scanType = 2; /* auto foreground */ -+ -+ scan.scanFlags = 0x01; /* bit 0 set => forced background scan */ -+ scan.maxTransmitRate = WSM_TRANSMIT_RATE_6; -+ scan.autoScanInterval = (0xba << 24)|(30 * 1024); /* 30 seconds, -70 rssi */ -+ scan.numOfProbeRequests = 1; -+ //scan.numOfChannels = 11; -+ scan.numOfChannels = hw_priv->num_scanchannels; -+ scan.numOfSSIDs = 1; -+ scan.probeDelay = 100; -+ scan_ssid.length = priv->ssid_length; -+ memcpy(scan_ssid.ssid, priv->ssid, priv->ssid_length); -+ scan.ssids = &scan_ssid; -+ -+ scan.ch = xr_kzalloc(sizeof(struct wsm_scan_ch[scan.numOfChannels]), false); -+ if (!scan.ch) { -+ scan_printk(XRADIO_DBG_ERROR, "xr_kzalloc wsm_scan_ch failed.\n"); -+ hw_priv->scan.status = -ENOMEM; -+ goto fail; -+ } -+ -+ for (i = 0; i < scan.numOfChannels; i++) { -+ scan.ch[i].number = hw_priv->scan_channels[i].number; -+ scan.ch[i].minChannelTime = hw_priv->scan_channels[i].minChannelTime; -+ scan.ch[i].maxChannelTime = hw_priv->scan_channels[i].maxChannelTime; -+ scan.ch[i].txPowerLevel = hw_priv->scan_channels[i].txPowerLevel; -+ } -+ -+#if 0 -+ for (i = 1; i <= scan.numOfChannels; i++) { -+ scan.ch[i-1].number = i; -+ scan.ch[i-1].minChannelTime = 10; -+ scan.ch[i-1].maxChannelTime = 40; -+ } -+#endif -+ -+ hw_priv->scan.status = xradio_sched_scan_start(priv, &scan); -+ kfree(scan.ch); -+ if (hw_priv->scan.status) { -+ scan_printk(XRADIO_DBG_ERROR, "scan failed, status=%d.\n", -+ hw_priv->scan.status); -+ goto fail; -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ return; -+ -+fail: -+ mutex_unlock(&hw_priv->conf_mutex); -+ queue_work(hw_priv->workqueue, &hw_priv->scan.swork); -+ return; -+} -+ -+void xradio_hw_sched_scan_stop(struct xradio_common *hw_priv) -+{ -+ struct xradio_vif *priv = NULL; -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv,hw_priv->scan.if_id); -+ if (unlikely(!priv)) -+ return; -+ -+ spin_unlock(&priv->vif_lock); -+ wsm_stop_scan(hw_priv, priv->if_id); -+ -+ return; -+} -+#endif /*ROAM_OFFLOAD*/ -+ -+ -+static void xradio_scan_restart_delayed(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ -+ if (priv->delayed_link_loss) { -+ int tmo = hw_priv->scan.direct_probe ? 0 : priv->cqm_beacon_loss_count; -+ -+ priv->delayed_link_loss = 0; -+ /* Restart beacon loss timer and requeue -+ BSS loss work. */ -+ scan_printk(XRADIO_DBG_WARN, "[CQM] Requeue BSS loss in %d " -+ "beacons.\n", tmo); -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ queue_delayed_work(hw_priv->workqueue, &priv->bss_loss_work, -+ tmo * HZ / 10); -+ -+ } -+ -+ /* FW bug: driver has to restart p2p-dev mode after scan. */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) { -+ /*xradio_enable_listening(priv);*/ -+ WARN_ON(1); -+ xradio_update_filtering(priv); -+ scan_printk(XRADIO_DBG_WARN, "driver has to restart " -+ "p2p-dev mode after scan"); -+ } -+ -+ if (atomic_xchg(&priv->delayed_unjoin, 0)) { -+ if (queue_work(hw_priv->workqueue, &priv->unjoin_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+} -+ -+static void xradio_scan_complete(struct xradio_common *hw_priv, int if_id) -+{ -+ struct xradio_vif *priv; -+ atomic_xchg(&hw_priv->recent_scan, 0); -+ -+ -+ if (hw_priv->scan.direct_probe) { -+ mutex_lock(&hw_priv->conf_mutex); -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, if_id); -+ if (priv) { -+ scan_printk(XRADIO_DBG_MSG, "Direct probe complete.\n"); -+ xradio_scan_restart_delayed(priv); -+ } else { -+ scan_printk(XRADIO_DBG_MSG, "Direct probe complete without interface!\n"); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ hw_priv->scan.direct_probe = 0; -+ up(&hw_priv->scan.lock); -+ wsm_unlock_tx(hw_priv); -+ } else { -+ xradio_scan_work(&hw_priv->scan.work); -+ } -+} -+ -+void xradio_scan_complete_cb(struct xradio_common *hw_priv, -+ struct wsm_scan_complete *arg) -+{ -+ struct xradio_vif *priv = xrwl_hwpriv_to_vifpriv(hw_priv, -+ hw_priv->scan.if_id); -+ -+ -+ if (unlikely(!priv)) -+ return; -+ -+#ifdef ROAM_OFFLOAD -+ if (hw_priv->auto_scanning) -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, 0); -+#endif /*ROAM_OFFLOAD*/ -+ -+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { -+ /* STA is stopped. */ -+ spin_unlock(&priv->vif_lock); -+ scan_printk(XRADIO_DBG_WARN, "%s: priv->mode UNSPECIFIED.\n", __func__); -+ return; -+ } -+ spin_unlock(&priv->vif_lock); -+ -+ /* -+ if(hw_priv->scan.status == -ETIMEDOUT) -+ scan_printk(XRADIO_DBG_WARN, "Scan timeout already occured. " -+ "Don't cancel work"); -+ if ((hw_priv->scan.status != -ETIMEDOUT) && -+ (cancel_delayed_work_sync(&hw_priv->scan.timeout) > 0)) { -+ hw_priv->scan.status = 1; -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, 0); -+ } -+ */ // should not involve status as a condition -+ -+ if (cancel_delayed_work_sync(&hw_priv->scan.timeout) > 0) { -+ down(&hw_priv->scan.status_lock); -+ hw_priv->scan.status = 1; -+ up(&hw_priv->scan.status_lock); -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, 0); -+ } -+} -+ -+void xradio_scan_timeout(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, scan.timeout.work); -+ -+ -+ if (likely(atomic_xchg(&hw_priv->scan.in_progress, 0))) { -+ if (hw_priv->scan.status > 0) -+ hw_priv->scan.status = 0; -+ else if (!hw_priv->scan.status) { -+ scan_printk(XRADIO_DBG_WARN, "Timeout waiting for scan " -+ "complete notification.\n"); -+ hw_priv->scan.status = -ETIMEDOUT; -+ hw_priv->scan.curr = hw_priv->scan.end; -+ WARN_ON(wsm_stop_scan(hw_priv, hw_priv->scan.if_id ? 1 : 0)); -+ } -+ xradio_scan_complete(hw_priv, hw_priv->scan.if_id); -+#ifdef ROAM_OFFLOAD -+ } else if (hw_priv->auto_scanning) { -+ hw_priv->auto_scanning = 0; -+ ieee80211_sched_scan_results(hw_priv->hw); -+#endif /*ROAM_OFFLOAD*/ -+ } -+} -+ -+void xradio_probe_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, scan.probe_work.work); -+ struct xradio_vif *priv; -+ u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queueId]; -+ const struct xradio_txpriv *txpriv; -+ struct wsm_tx *wsm; -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, -+ }; -+ struct wsm_ssid ssids[1] = {{ -+ .length = 0, -+ } }; -+ struct wsm_scan_ch ch[1] = {{ -+ .minChannelTime = 0, -+ .maxChannelTime = 10, -+ } }; -+ struct wsm_scan scan = { -+ .scanType = WSM_SCAN_TYPE_FOREGROUND, -+ .numOfProbeRequests = 1, -+ .probeDelay = 0, -+ .numOfChannels = 1, -+ .ssids = ssids, -+ .ch = ch, -+ }; -+ u8 *ies; -+ size_t ies_len; -+ int ret = 1; -+ scan_printk(XRADIO_DBG_MSG, "%s:Direct probe.\n", __func__); -+ -+ BUG_ON(queueId >= 4); -+ BUG_ON(!hw_priv->channel); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ if (unlikely(down_trylock(&hw_priv->scan.lock))) { -+ /* Scan is already in progress. Requeue self. */ -+ schedule(); -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.probe_work, -+ HZ / 10); -+ mutex_unlock(&hw_priv->conf_mutex); -+ return; -+ } -+ -+ if (xradio_queue_get_skb(queue, hw_priv->pending_frame_id, &frame.skb, &txpriv)) { -+ up(&hw_priv->scan.lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ wsm_unlock_tx(hw_priv); -+ scan_printk(XRADIO_DBG_ERROR, "%s:xradio_queue_get_skb error!\n", __func__); -+ return; -+ } -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, txpriv->if_id); -+ if (!priv) { -+ up(&hw_priv->scan.lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ scan_printk(XRADIO_DBG_ERROR, "%s:priv error!\n", __func__); -+ return; -+ } -+ wsm = (struct wsm_tx *)frame.skb->data; -+ scan.maxTransmitRate = wsm->maxTxRate; -+ scan.band = (hw_priv->channel->band == NL80211_BAND_5GHZ) ? -+ WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ scan.scanType = WSM_SCAN_TYPE_BACKGROUND; -+ scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; -+ if (priv->if_id) -+ scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1; -+ else -+ scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1; -+ } -+ -+ /* No need to set WSM_SCAN_FLAG_FORCE_BACKGROUND in BSS_LOSS work. -+ * yangfh 2015-11-11 18:45:02 */ -+ //xradio_for_each_vif(hw_priv, vif, i) { -+ // if (!vif) -+ // continue; -+ // if (vif->bss_loss_status > XRADIO_BSS_LOSS_NONE) -+ // scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND; -+ //} -+ -+ ch[0].number = hw_priv->channel->hw_value; -+ skb_pull(frame.skb, txpriv->offset); -+ ies = &frame.skb->data[sizeof(struct ieee80211_hdr_3addr)]; -+ ies_len = frame.skb->len - sizeof(struct ieee80211_hdr_3addr); -+ -+ if (ies_len) { -+ u8 *ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len); -+ if (ssidie && ssidie[1] && ssidie[1] <= sizeof(ssids[0].ssid)) { -+ u8 *nextie = &ssidie[2 + ssidie[1]]; -+ /* Remove SSID from the IE list. It has to be provided -+ * as a separate argument in xradio_scan_start call */ -+ -+ /* Store SSID localy */ -+ ssids[0].length = ssidie[1]; -+ memcpy(ssids[0].ssid, &ssidie[2], ssids[0].length); -+ scan.numOfSSIDs = 1; -+ -+ /* Remove SSID from IE list */ -+ ssidie[1] = 0; -+ memmove(&ssidie[2], nextie, &ies[ies_len] - nextie); -+ skb_trim(frame.skb, frame.skb->len - ssids[0].length); -+ } -+ } -+ -+ if (priv->if_id == 0) -+ xradio_remove_wps_p2p_ie(&frame); -+ -+ /* FW bug: driver has to restart p2p-dev mode after scan */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) { -+ WARN_ON(1); -+ /*xradio_disable_listening(priv);*/ -+ } -+ ret = WARN_ON(wsm_set_template_frame(hw_priv, &frame, -+ priv->if_id)); -+ -+ hw_priv->scan.direct_probe = 1; -+ hw_priv->scan.if_id = priv->if_id; -+ if (!ret) { -+ wsm_flush_tx(hw_priv); -+ ret = WARN_ON(xradio_scan_start(priv, &scan)); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ skb_push(frame.skb, txpriv->offset); -+ if (!ret) -+ IEEE80211_SKB_CB(frame.skb)->flags |= IEEE80211_TX_STAT_ACK; -+ -+ BUG_ON(xradio_queue_remove(queue, hw_priv->pending_frame_id)); -+ -+ if (ret) { -+ hw_priv->scan.direct_probe = 0; -+ up(&hw_priv->scan.lock); -+ wsm_unlock_tx(hw_priv); -+ } -+ -+ return; -+} -diff --git a/drivers/net/wireless/xradio/scan.h b/drivers/net/wireless/xradio/scan.h -new file mode 100644 -index 0000000..5c520ed ---- /dev/null -+++ b/drivers/net/wireless/xradio/scan.h -@@ -0,0 +1,71 @@ -+/* -+ * Scan interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#ifndef SCAN_H_INCLUDED -+#define SCAN_H_INCLUDED -+ -+#include -+#include "wsm.h" -+ -+/* external */ struct sk_buff; -+/* external */ struct cfg80211_scan_request; -+/* external */ struct ieee80211_channel; -+/* external */ struct ieee80211_hw; -+/* external */ struct work_struct; -+ -+#define SCAN_MAX_DELAY (3*HZ) //3s, add by yangfh for connect -+ -+struct xradio_scan { -+ struct semaphore lock; -+ struct work_struct work; -+#ifdef ROAM_OFFLOAD -+ struct work_struct swork; /* scheduled scan work */ -+ struct cfg80211_sched_scan_request *sched_req; -+#endif /*ROAM_OFFLOAD*/ -+ struct delayed_work timeout; -+ struct cfg80211_scan_request *req; -+ struct ieee80211_channel **begin; -+ struct ieee80211_channel **curr; -+ struct ieee80211_channel **end; -+ struct wsm_ssid ssids[WSM_SCAN_MAX_NUM_OF_SSIDS]; -+ int output_power; -+ int n_ssids; -+ //add by liwei, for h64 ping WS550 BUG -+ struct semaphore status_lock; -+ int status; -+ atomic_t in_progress; -+ /* Direct probe requests workaround */ -+ struct delayed_work probe_work; -+ int direct_probe; -+ u8 if_id; -+}; -+ -+int xradio_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_scan_request *req); -+#ifdef ROAM_OFFLOAD -+int xradio_hw_sched_scan_start(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct cfg80211_sched_scan_request *req, -+ struct ieee80211_sched_scan_ies *ies); -+void xradio_hw_sched_scan_stop(struct xradio_common *priv); -+void xradio_sched_scan_work(struct work_struct *work); -+#endif /*ROAM_OFFLOAD*/ -+void xradio_scan_work(struct work_struct *work); -+void xradio_scan_timeout(struct work_struct *work); -+void xradio_scan_complete_cb(struct xradio_common *priv, -+ struct wsm_scan_complete *arg); -+ -+/* ******************************************************************** */ -+/* Raw probe requests TX workaround */ -+void xradio_probe_work(struct work_struct *work); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/sdio.c b/drivers/net/wireless/xradio/sdio.c -new file mode 100644 -index 0000000..13d4eb5 ---- /dev/null -+++ b/drivers/net/wireless/xradio/sdio.c -@@ -0,0 +1,246 @@ -+/* -+ * SDIO driver for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "sdio.h" -+#include "main.h" -+ -+/* sdio vendor id and device id*/ -+#define SDIO_VENDOR_ID_XRADIO 0x0020 -+#define SDIO_DEVICE_ID_XRADIO 0x2281 -+static const struct sdio_device_id xradio_sdio_ids[] = { -+ { SDIO_DEVICE(SDIO_VENDOR_ID_XRADIO, SDIO_DEVICE_ID_XRADIO) }, -+ //{ SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) }, -+ { /* end: all zeroes */ }, -+}; -+ -+/* sbus_ops implemetation */ -+int sdio_data_read(struct xradio_common* self, unsigned int addr, -+ void *dst, int count) -+{ -+ int ret = sdio_memcpy_fromio(self->sdio_func, dst, addr, count); -+// printk("sdio_memcpy_fromio 0x%x:%d ret %d\n", addr, count, ret); -+// print_hex_dump_bytes("sdio read ", 0, dst, min(count,32)); -+ return ret; -+} -+ -+int sdio_data_write(struct xradio_common* self, unsigned int addr, -+ const void *src, int count) -+{ -+ int ret = sdio_memcpy_toio(self->sdio_func, addr, (void *)src, count); -+// printk("sdio_memcpy_toio 0x%x:%d ret %d\n", addr, count, ret); -+// print_hex_dump_bytes("sdio write", 0, src, min(count,32)); -+ return ret; -+} -+ -+void sdio_lock(struct xradio_common* self) -+{ -+ sdio_claim_host(self->sdio_func); -+} -+ -+void sdio_unlock(struct xradio_common *self) -+{ -+ sdio_release_host(self->sdio_func); -+} -+ -+size_t sdio_align_len(struct xradio_common *self, size_t size) -+{ -+ return sdio_align_size(self->sdio_func, size); -+} -+ -+int sdio_set_blk_size(struct xradio_common *self, size_t size) -+{ -+ return sdio_set_block_size(self->sdio_func, size); -+} -+ -+extern void xradio_irq_handler(struct xradio_common*); -+ -+static irqreturn_t sdio_irq_handler(int irq, void *dev_id) -+{ -+ struct sdio_func *func = (struct sdio_func*) dev_id; -+ struct xradio_common *self = sdio_get_drvdata(func); -+ if (self != NULL) -+ xradio_irq_handler(self); -+ return IRQ_HANDLED; -+} -+ -+static int sdio_enableint(struct sdio_func* func) -+{ -+ int ret = 0; -+ u8 cccr; -+ int func_num; -+ -+ sdio_claim_host(func); -+ -+ /* Hack to access Fuction-0 */ -+ func_num = func->num; -+ func->num = 0; -+ cccr = sdio_readb(func, SDIO_CCCR_IENx, &ret); -+ cccr |= BIT(0); /* Master interrupt enable ... */ -+ cccr |= BIT(func_num); /* ... for our function */ -+ sdio_writeb(func, cccr, SDIO_CCCR_IENx, &ret); -+ -+ /* Restore the WLAN function number */ -+ func->num = func_num; -+ -+ sdio_release_host(func); -+ -+ return ret; -+} -+ -+int sdio_pm(struct xradio_common *self, bool suspend) -+{ -+ int ret = 0; -+ if (suspend) { -+ /* Notify SDIO that XRADIO will remain powered during suspend */ -+ ret = sdio_set_host_pm_flags(self->sdio_func, MMC_PM_KEEP_POWER); -+ if (ret) -+ dev_dbg(&self->sdio_func->dev, "Error setting SDIO pm flags: %i\n", ret); -+ } -+ -+ return ret; -+} -+ -+static const struct of_device_id xradio_sdio_of_match_table[] = { -+ { .compatible = "xradio,xr819" }, -+ { } -+}; -+ -+static int xradio_probe_of(struct sdio_func *func) -+{ -+ struct device *dev = &func->dev; -+ struct device_node *np = dev->of_node; -+ const struct of_device_id *of_id; -+ int irq; -+ int ret; -+ -+ of_id = of_match_node(xradio_sdio_of_match_table, np); -+ if (!of_id) -+ return -ENODEV; -+ -+ //pdev_data->family = of_id->data; -+ -+ irq = irq_of_parse_and_map(np, 0); -+ if (!irq) { -+ dev_err(dev, "No irq in platform data\n"); -+ return -EINVAL; -+ } -+ -+ ret = devm_request_irq(dev, irq, sdio_irq_handler, 0, "xradio", func); -+ if (ret) { -+ dev_err(dev, "Failed to request irq_wakeup.\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* Probe Function to be called by SDIO stack when device is discovered */ -+static int sdio_probe(struct sdio_func *func, -+ const struct sdio_device_id *id) -+{ -+ dev_dbg(&func->dev, "XRadio Device:sdio clk=%d\n", -+ func->card->host->ios.clock); -+ dev_dbg(&func->dev, "sdio func->class=%x\n", func->class); -+ dev_dbg(&func->dev, "sdio_vendor: 0x%04x\n", func->vendor); -+ dev_dbg(&func->dev, "sdio_device: 0x%04x\n", func->device); -+ dev_dbg(&func->dev, "Function#: 0x%04x\n", func->num); -+ -+#if 0 //for odly and sdly debug. -+{ -+ u32 sdio_param = 0; -+ sdio_param = readl(__io_address(0x01c20088)); -+ sdio_param &= ~(0xf<<8); -+ sdio_param |= 3<<8; -+ sdio_param &= ~(0xf<<20); -+ sdio_param |= s_dly<<20; -+ writel(sdio_param, __io_address(0x01c20088)); -+ sbus_printk(XRADIO_DBG_ALWY, "%s: 0x01c20088=0x%08x\n", __func__, sdio_param); -+} -+#endif -+ -+ xradio_probe_of(func); -+ -+ func->card->quirks |= MMC_QUIRK_BROKEN_BYTE_MODE_512; -+ sdio_claim_host(func); -+ sdio_enable_func(func); -+ sdio_release_host(func); -+ -+ sdio_enableint(func); -+ -+ xradio_core_init(func); -+ -+ try_module_get(func->dev.driver->owner); -+ return 0; -+} -+/* Disconnect Function to be called by SDIO stack when -+ * device is disconnected */ -+static void sdio_remove(struct sdio_func *func) -+{ -+ sdio_claim_host(func); -+ sdio_disable_func(func); -+ sdio_release_host(func); -+ module_put(func->dev.driver->owner); -+} -+ -+static int sdio_suspend(struct device *dev) -+{ -+ int ret = 0; -+ /* -+ struct sdio_func *func = dev_to_sdio_func(dev); -+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); -+ if (ret) -+ sbus_printk(XRADIO_DBG_ERROR, "set MMC_PM_KEEP_POWER error\n"); -+ */ -+ return ret; -+} -+ -+static int sdio_resume(struct device *dev) -+{ -+ return 0; -+} -+ -+static const struct dev_pm_ops sdio_pm_ops = { -+ .suspend = sdio_suspend, -+ .resume = sdio_resume, -+}; -+ -+static struct sdio_driver sdio_driver = { -+ .name = "xradio_wlan", -+ .id_table = xradio_sdio_ids, -+ .probe = sdio_probe, -+ .remove = sdio_remove, -+ .drv = { -+ .owner = THIS_MODULE, -+ .pm = &sdio_pm_ops, -+ } -+}; -+ -+ -+int xradio_sdio_register(){ -+ return sdio_register_driver(&sdio_driver); -+} -+ -+void xradio_sdio_unregister(){ -+ sdio_unregister_driver(&sdio_driver); -+} -+ -+MODULE_DEVICE_TABLE(sdio, xradio_sdio_ids); -diff --git a/drivers/net/wireless/xradio/sdio.h b/drivers/net/wireless/xradio/sdio.h -new file mode 100644 -index 0000000..ea3c45a ---- /dev/null -+++ b/drivers/net/wireless/xradio/sdio.h -@@ -0,0 +1,17 @@ -+#ifndef __XRADIO_SDIO_H -+#define __XRADIO_SDIO_H -+ -+size_t sdio_align_len(struct xradio_common *self, size_t size); -+void sdio_lock(struct xradio_common *self); -+void sdio_unlock(struct xradio_common *self); -+int sdio_set_blk_size(struct xradio_common *self, size_t size); -+int sdio_data_read(struct xradio_common *self, unsigned int addr, void *dst, -+ int count); -+int sdio_data_write(struct xradio_common *self, unsigned int addr, const void *src, -+ int count); -+int sdio_pm(struct xradio_common *self, bool suspend); -+ -+int xradio_sdio_register(void); -+void xradio_sdio_unregister(void); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/sta.c b/drivers/net/wireless/xradio/sta.c -new file mode 100644 -index 0000000..5e9d8a2 ---- /dev/null -+++ b/drivers/net/wireless/xradio/sta.c -@@ -0,0 +1,2199 @@ -+/* -+ * STA APIs for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "sta.h" -+#include "ap.h" -+#include "keys.h" -+#include "fwio.h" -+#include "bh.h" -+#include "wsm.h" -+#ifdef ROAM_OFFLOAD -+#include -+#endif /*ROAM_OFFLOAD*/ -+ -+#include "net/mac80211.h" -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+#include -+#endif -+ -+#define WEP_ENCRYPT_HDR_SIZE 4 -+#define WEP_ENCRYPT_TAIL_SIZE 4 -+#define WPA_ENCRYPT_HDR_SIZE 8 -+#define WPA_ENCRYPT_TAIL_SIZE 12 -+#define WPA2_ENCRYPT_HDR_SIZE 8 -+#define WPA2_ENCRYPT_TAIL_SIZE 8 -+#define WAPI_ENCRYPT_HDR_SIZE 18 -+#define WAPI_ENCRYPT_TAIL_SIZE 16 -+#define MAX_ARP_REPLY_TEMPLATE_SIZE 120 -+ -+static inline void __xradio_free_event_queue(struct list_head *list) -+{ -+ while (!list_empty(list)) { -+ struct xradio_wsm_event *event = -+ list_first_entry(list, struct xradio_wsm_event,link); -+ list_del(&event->link); -+ kfree(event); -+ } -+} -+ -+static inline void __xradio_bf_configure(struct xradio_vif *priv) -+{ -+ priv->bf_table.numOfIEs = __cpu_to_le32(3); -+ priv->bf_table.entry[0].ieId = WLAN_EID_VENDOR_SPECIFIC; -+ priv->bf_table.entry[0].actionFlags = -+ WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED; -+ -+ priv->bf_table.entry[0].oui[0] = 0x50; -+ priv->bf_table.entry[0].oui[1] = 0x6F; -+ priv->bf_table.entry[0].oui[2] = 0x9A; -+ -+ priv->bf_table.entry[1].ieId = WLAN_EID_ERP_INFO; -+ priv->bf_table.entry[1].actionFlags = -+ WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED; -+ -+ priv->bf_table.entry[2].ieId = WLAN_EID_HT_OPERATION; -+ priv->bf_table.entry[2].actionFlags = -+ WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED; -+ -+ priv->bf_control.enabled = WSM_BEACON_FILTER_ENABLE; -+} -+ -+/* ******************************************************************** */ -+/* STA API */ -+ -+int xradio_start(struct ieee80211_hw *dev) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ int ret = 0; -+ -+ -+ if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, -+ hw_priv->driver_ready, 3*HZ) <= 0) { -+ wiphy_err(dev->wiphy, "driver is not ready!\n"); -+ return -ETIMEDOUT; -+ } -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ memcpy(hw_priv->mac_addr, dev->wiphy->perm_addr, ETH_ALEN); -+ hw_priv->softled_state = 0; -+ -+ ret = xradio_setup_mac(hw_priv); -+ if (WARN_ON(ret)) { -+ wiphy_err(dev->wiphy, "xradio_setup_mac failed(%d)\n", ret); -+ goto out; -+ } -+ -+out: -+ mutex_unlock(&hw_priv->conf_mutex); -+ return ret; -+} -+ -+void xradio_stop(struct ieee80211_hw *dev) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = NULL; -+ LIST_HEAD(list); -+ int i; -+ -+ wsm_lock_tx(hw_priv); -+ while (down_trylock(&hw_priv->scan.lock)) { -+ /* Scan is in progress. Force it to stop. */ -+ hw_priv->scan.req = NULL; -+ schedule(); -+ } -+ up(&hw_priv->scan.lock); -+ -+ cancel_delayed_work_sync(&hw_priv->scan.probe_work); -+ cancel_delayed_work_sync(&hw_priv->scan.timeout); -+ flush_workqueue(hw_priv->workqueue); -+ del_timer_sync(&hw_priv->ba_timer); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ hw_priv->softled_state = 0; -+ /* xradio_set_leds(hw_priv); */ -+ -+ spin_lock(&hw_priv->event_queue_lock); -+ list_splice_init(&hw_priv->event_queue, &list); -+ spin_unlock(&hw_priv->event_queue_lock); -+ __xradio_free_event_queue(&list); -+ -+ for (i = 0; i < 4; i++) -+ xradio_queue_clear(&hw_priv->tx_queue[i], XRWL_ALL_IFS); -+ -+ /* HACK! */ -+ if (atomic_xchg(&hw_priv->tx_lock, 1) != 1) -+ wiphy_debug(dev->wiphy, "TX is force-unlocked due to stop request.\n"); -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ priv->mode = NL80211_IFTYPE_UNSPECIFIED; -+ priv->listening = false; -+ priv->delayed_link_loss = 0; -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ cancel_delayed_work_sync(&priv->join_timeout); -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ cancel_delayed_work_sync(&priv->link_id_gc_work); -+ del_timer_sync(&priv->mcast_timeout); -+ } -+ -+ wsm_unlock_tx(hw_priv); -+ -+ mutex_unlock(&hw_priv->conf_mutex); -+} -+ -+int xradio_add_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif) -+{ -+ int ret; -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv; -+ struct xradio_vif **drv_priv = (void *)vif->drv_priv; -+ int i; -+ if (atomic_read(&hw_priv->num_vifs) >= XRWL_MAX_VIFS) -+ return -EOPNOTSUPP; -+ -+ if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, -+ hw_priv->driver_ready, 3*HZ) <= 0) { -+ wiphy_err(dev->wiphy, "driver is not ready!\n"); -+ return -ETIMEDOUT; -+ } -+ -+ /* fix the problem that when connected,then deauth */ -+ vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; -+ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; -+ -+ priv = xrwl_get_vif_from_ieee80211(vif); -+ atomic_set(&priv->enabled, 0); -+ -+ *drv_priv = priv; -+ /* __le32 auto_calibration_mode = __cpu_to_le32(1); */ -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ priv->mode = vif->type; -+ -+ spin_lock(&hw_priv->vif_list_lock); -+ if (atomic_read(&hw_priv->num_vifs) < XRWL_MAX_VIFS) { -+ for (i = 0; i < XRWL_MAX_VIFS; i++) -+ if (!memcmp(vif->addr, hw_priv->addresses[i].addr, ETH_ALEN)) -+ break; -+ if (i == XRWL_MAX_VIFS) { -+ spin_unlock(&hw_priv->vif_list_lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ return -EINVAL; -+ } -+ priv->if_id = i; -+ -+ hw_priv->if_id_slot |= BIT(priv->if_id); -+ priv->hw_priv = hw_priv; -+ priv->hw = dev; -+ priv->vif = vif; -+ hw_priv->vif_list[priv->if_id] = vif; -+ atomic_inc(&hw_priv->num_vifs); -+ } else { -+ spin_unlock(&hw_priv->vif_list_lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ return -EOPNOTSUPP; -+ } -+ spin_unlock(&hw_priv->vif_list_lock); -+ /* TODO:COMBO :Check if MAC address matches the one expected by FW */ -+ memcpy(hw_priv->mac_addr, vif->addr, ETH_ALEN); -+ -+ /* Enable auto-calibration */ -+ /* Exception in subsequent channel switch; disabled. -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE, -+ &auto_calibration_mode, sizeof(auto_calibration_mode))); -+ */ -+ wiphy_debug(dev->wiphy, "Interface ID:%d of type:%d added\n", priv->if_id, priv->mode); -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ xradio_vif_setup(priv); -+ -+ ret = WARN_ON(xradio_setup_mac_pvif(priv)); -+ -+ return ret; -+} -+ -+void xradio_remove_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct wsm_reset reset = { -+ .reset_statistics = true, -+ }; -+ int i; -+ bool is_htcapie = false; -+ struct xradio_vif *tmp_priv; -+ -+ wiphy_warn(dev->wiphy, "!!! vif_id=%d\n", priv->if_id); -+ atomic_set(&priv->enabled, 0); -+ down(&hw_priv->scan.lock); -+ if(priv->join_status == XRADIO_JOIN_STATUS_STA){ -+ if (atomic_xchg(&priv->delayed_unjoin, 0)) { -+ wsm_unlock_tx(hw_priv); -+ wiphy_err(dev->wiphy, "delayed_unjoin exist!\n"); -+ } -+ cancel_work_sync(&priv->unjoin_work); -+ wsm_lock_tx(hw_priv); -+ xradio_unjoin_work(&priv->unjoin_work); -+ } -+ mutex_lock(&hw_priv->conf_mutex); -+ xradio_tx_queues_lock(hw_priv); -+ wsm_lock_tx(hw_priv); -+ switch (priv->join_status) { -+ case XRADIO_JOIN_STATUS_AP: -+ for (i = 0; priv->link_id_map; ++i) { -+ if (priv->link_id_map & BIT(i)) { -+ xrwl_unmap_link(priv, i); -+ priv->link_id_map &= ~BIT(i); -+ } -+ } -+ memset(priv->link_id_db, 0, -+ sizeof(priv->link_id_db)); -+ priv->sta_asleep_mask = 0; -+ priv->enable_beacon = false; -+ priv->tx_multicast = false; -+ priv->aid0_bit_set = false; -+ priv->buffered_multicasts = false; -+ priv->pspoll_mask = 0; -+ reset.link_id = 0; -+ wsm_reset(hw_priv, &reset, priv->if_id); -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ xradio_for_each_vif(hw_priv, tmp_priv, i) { -+ if (!tmp_priv) -+ continue; -+ if ((tmp_priv->join_status == XRADIO_JOIN_STATUS_STA) && tmp_priv->htcap) -+ is_htcapie = true; -+ } -+ -+ if (is_htcapie) { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11N_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11N_THROTTLE; -+ sta_printk(XRADIO_DBG_NIY, "AP REMOVE HTCAP 11N %d\n",hw_priv->vif0_throttle); -+ } else { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ sta_printk(XRADIO_DBG_NIY, "AP REMOVE 11BG %d\n",hw_priv->vif0_throttle); -+ } -+ break; -+ case XRADIO_JOIN_STATUS_MONITOR: -+ xradio_disable_listening(priv); -+ break; -+ default: -+ break; -+ } -+ /* TODO:COMBO: Change Queue Module */ -+ __xradio_flush(hw_priv, false, priv->if_id); -+ -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ cancel_delayed_work_sync(&priv->link_id_gc_work); -+ cancel_delayed_work_sync(&priv->join_timeout); -+ cancel_delayed_work_sync(&priv->set_cts_work); -+ cancel_delayed_work_sync(&priv->pending_offchanneltx_work); -+ -+ del_timer_sync(&priv->mcast_timeout); -+ /* TODO:COMBO: May be reset of these variables "delayed_link_loss and -+ * join_status to default can be removed as dev_priv will be freed by -+ * mac80211 */ -+ priv->delayed_link_loss = 0; -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ wsm_unlock_tx(hw_priv); -+ -+ if ((priv->if_id ==1) && (priv->mode == NL80211_IFTYPE_AP -+ || priv->mode == NL80211_IFTYPE_P2P_GO)) { -+ hw_priv->is_go_thru_go_neg = false; -+ } -+ spin_lock(&hw_priv->vif_list_lock); -+ spin_lock(&priv->vif_lock); -+ hw_priv->vif_list[priv->if_id] = NULL; -+ hw_priv->if_id_slot &= (~BIT(priv->if_id)); -+ atomic_dec(&hw_priv->num_vifs); -+ if (atomic_read(&hw_priv->num_vifs) == 0) { -+ xradio_free_keys(hw_priv); -+ memset(hw_priv->mac_addr, 0, ETH_ALEN); -+ } -+ spin_unlock(&priv->vif_lock); -+ spin_unlock(&hw_priv->vif_list_lock); -+ priv->listening = false; -+ -+ xradio_tx_queues_unlock(hw_priv); -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ if (atomic_read(&hw_priv->num_vifs) == 0) -+ flush_workqueue(hw_priv->workqueue); -+ memset(priv, 0, sizeof(struct xradio_vif)); -+ up(&hw_priv->scan.lock); -+} -+ -+int xradio_change_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ enum nl80211_iftype new_type, -+ bool p2p) -+{ -+ int ret = 0; -+ wiphy_debug(dev->wiphy, "changing interface type; new type=%d(%d), p2p=%d(%d)\n", -+ new_type, vif->type, p2p, vif->p2p); -+ if (new_type != vif->type || vif->p2p != p2p) { -+ xradio_remove_interface(dev, vif); -+ vif->type = new_type; -+ vif->p2p = p2p; -+ ret = xradio_add_interface(dev, vif); -+ } -+ -+ return ret; -+} -+ -+int xradio_config(struct ieee80211_hw *dev, u32 changed) -+{ -+ int ret = 0; -+ struct xradio_common *hw_priv = dev->priv; -+ struct ieee80211_conf *conf = &dev->conf; -+ /* TODO:COMBO: adjust to multi vif interface -+ * IEEE80211_CONF_CHANGE_IDLE is still handled per xradio_vif*/ -+ int if_id = 0; -+ struct xradio_vif *priv; -+ -+ -+ if (changed & -+ (IEEE80211_CONF_CHANGE_MONITOR|IEEE80211_CONF_CHANGE_IDLE)) { -+ /* TBD: It looks like it's transparent -+ * there's a monitor interface present -- use this -+ * to determine for example whether to calculate -+ * timestamps for packets or not, do not use instead -+ * of filter flags! */ -+ wiphy_debug(dev->wiphy, "ignore IEEE80211_CONF_CHANGE_MONITOR (%d)" -+ "IEEE80211_CONF_CHANGE_IDLE (%d)\n", -+ (changed & IEEE80211_CONF_CHANGE_MONITOR) ? 1 : 0, -+ (changed & IEEE80211_CONF_CHANGE_IDLE) ? 1 : 0); -+ return ret; -+ } -+ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); -+ /* TODO: IEEE80211_CONF_CHANGE_QOS */ -+ /* TODO:COMBO:Change when support is available mac80211*/ -+ if (changed & IEEE80211_CONF_CHANGE_POWER) { -+ /*hw_priv->output_power = conf->power_level;*/ -+ hw_priv->output_power = 20; -+ wiphy_debug(dev->wiphy, "Config Tx power=%d, but real=%d\n", -+ conf->power_level, hw_priv->output_power); -+ WARN_ON(wsm_set_output_power(hw_priv, hw_priv->output_power * 10, if_id)); -+ } -+ -+ if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) && -+ (hw_priv->channel != conf->chandef.chan)) { -+ /* Switch Channel commented for CC Mode */ -+ struct ieee80211_channel *ch = conf->chandef.chan; -+ wiphy_debug(dev->wiphy, "Freq %d (wsm ch: %d).\n", -+ ch->center_freq, ch->hw_value); -+ /* Earlier there was a call to __xradio_flush(). -+ Removed as deemed unnecessary */ -+ hw_priv->channel = ch; -+ hw_priv->channel_changed = 1; -+ } -+ -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+ return ret; -+} -+ -+void xradio_update_filtering(struct xradio_vif *priv) -+{ -+ int ret; -+ bool bssid_filtering = !priv->rx_filter.bssid; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ static struct wsm_beacon_filter_control bf_disabled = { -+ .enabled = 0, -+ .bcn_count = 1, -+ }; -+ bool ap_mode = 0; -+ static struct wsm_beacon_filter_table bf_table_auto = { -+ .numOfIEs = __cpu_to_le32(2), -+ .entry[0].ieId = WLAN_EID_VENDOR_SPECIFIC, -+ .entry[0].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED, -+ .entry[0].oui[0] = 0x50, -+ .entry[0].oui[1] = 0x6F, -+ .entry[0].oui[2] = 0x9A, -+ -+ .entry[1].ieId = WLAN_EID_HT_OPERATION, -+ .entry[1].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED, -+ }; -+ static struct wsm_beacon_filter_control bf_auto = { -+ .enabled = WSM_BEACON_FILTER_ENABLE | -+ WSM_BEACON_FILTER_AUTO_ERP, -+ .bcn_count = 1, -+ }; -+ -+ -+ bf_auto.bcn_count = priv->bf_control.bcn_count; -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_PASSIVE) -+ return; -+ else if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) -+ bssid_filtering = false; -+ -+ if (priv->vif && (priv->vif->type == NL80211_IFTYPE_AP)) -+ ap_mode = true; -+ /* -+ * When acting as p2p client being connected to p2p GO, in order to -+ * receive frames from a different p2p device, turn off bssid filter. -+ * -+ * WARNING: FW dependency! -+ * This can only be used with FW WSM371 and its successors. -+ * In that FW version even with bssid filter turned off, -+ * device will block most of the unwanted frames. -+ */ -+ if (priv->vif && priv->vif->p2p) -+ bssid_filtering = false; -+ -+ ret = wsm_set_rx_filter(hw_priv, &priv->rx_filter, priv->if_id); -+ if (!ret && !ap_mode) { -+ if (priv->vif) { -+ if (priv->vif->p2p || NL80211_IFTYPE_STATION != priv->vif->type) -+ ret = wsm_set_beacon_filter_table(hw_priv, &priv->bf_table, priv->if_id); -+ else -+ ret = wsm_set_beacon_filter_table(hw_priv, &bf_table_auto, priv->if_id); -+ } else -+ WARN_ON(1); -+ } -+ if (!ret && !ap_mode) { -+ if (priv->disable_beacon_filter) -+ ret = wsm_beacon_filter_control(hw_priv, &bf_disabled, priv->if_id); -+ else { -+ if (priv->vif) { -+ if (priv->vif->p2p || NL80211_IFTYPE_STATION != priv->vif->type) -+ ret = wsm_beacon_filter_control(hw_priv, &priv->bf_control, -+ priv->if_id); -+ else -+ ret = wsm_beacon_filter_control(hw_priv, &bf_auto, priv->if_id); -+ } else -+ WARN_ON(1); -+ } -+ } -+ -+ if (!ret) -+ ret = wsm_set_bssid_filtering(hw_priv, bssid_filtering, priv->if_id); -+#if 0 -+ if (!ret) { -+ ret = wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); -+ } -+#endif -+ if (ret) -+ wiphy_debug(priv->hw_priv->hw->wiphy, "Update filtering failed: %d.\n", ret); -+ return; -+} -+ -+void xradio_update_filtering_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, -+ update_filtering_work); -+ -+ xradio_update_filtering(priv); -+} -+ -+void xradio_set_beacon_wakeup_period_work(struct work_struct *work) -+{ -+ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, set_beacon_wakeup_period_work); -+ -+ -+#ifdef XRADIO_USE_LONG_DTIM_PERIOD -+{ -+ int join_dtim_period_extend; -+ if (priv->join_dtim_period <= 3) { -+ join_dtim_period_extend = priv->join_dtim_period * 3; -+ } else if (priv->join_dtim_period <= 5) { -+ join_dtim_period_extend = priv->join_dtim_period * 2; -+ } else { -+ join_dtim_period_extend = priv->join_dtim_period; -+ } -+ WARN_ON(wsm_set_beacon_wakeup_period(priv->hw_priv, -+ priv->beacon_int * join_dtim_period_extend > -+ MAX_BEACON_SKIP_TIME_MS ? 1 : join_dtim_period_extend, -+ 0, priv->if_id)); -+} -+#else -+ WARN_ON(wsm_set_beacon_wakeup_period(priv->hw_priv, -+ priv->beacon_int * priv->join_dtim_period > -+ MAX_BEACON_SKIP_TIME_MS ? 1 :priv->join_dtim_period, -+ 0, priv->if_id)); -+#endif -+} -+ -+u64 xradio_prepare_multicast(struct ieee80211_hw *hw, -+ struct netdev_hw_addr_list *mc_list) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = NULL; -+ static u8 broadcast_ipv6[ETH_ALEN] = { -+ 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 -+ }; -+ static u8 broadcast_ipv4[ETH_ALEN] = { -+ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x01 -+ }; -+ -+ int i= 0; -+ xradio_for_each_vif(hw_priv,priv,i) { -+ struct netdev_hw_addr *ha = NULL; -+ int count = 0; -+ if ((!priv)) -+ continue; -+ -+ /* Disable multicast filtering */ -+ priv->has_multicast_subscription = false; -+ memset(&priv->multicast_filter, 0x00, sizeof(priv->multicast_filter)); -+ if (netdev_hw_addr_list_count(mc_list) > WSM_MAX_GRP_ADDRTABLE_ENTRIES) -+ return 0; -+ -+ /* Enable if requested */ -+ netdev_hw_addr_list_for_each(ha, mc_list) { -+ sta_printk(XRADIO_DBG_MSG, "multicast: %pM\n", ha->addr); -+ memcpy(&priv->multicast_filter.macAddress[count], ha->addr, ETH_ALEN); -+ if (memcmp(ha->addr, broadcast_ipv4, ETH_ALEN) && -+ memcmp(ha->addr, broadcast_ipv6, ETH_ALEN)) -+ priv->has_multicast_subscription = true; -+ count++; -+ } -+ if (count) { -+ priv->multicast_filter.enable = __cpu_to_le32(1); -+ priv->multicast_filter.numOfAddresses = __cpu_to_le32(count); -+ } -+ } -+ return netdev_hw_addr_list_count(mc_list); -+} -+ -+void xradio_configure_filter(struct ieee80211_hw *hw, -+ unsigned int changed_flags, -+ unsigned int *total_flags, -+ u64 multicast) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = NULL; -+ int i = 0; -+ -+ /* delete umac warning */ -+ if (hw_priv->vif_list[0] == NULL && hw_priv->vif_list[1] == NULL) -+ -+ *total_flags &= ~(1<<31); -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if(NULL == priv) -+ continue; -+ -+#if 0 -+ bool listening = !!(*total_flags & -+ (FIF_PROMISC_IN_BSS | -+ FIF_OTHER_BSS | -+ FIF_BCN_PRBRESP_PROMISC | -+ FIF_PROBE_REQ)); -+#endif -+ -+ *total_flags &= FIF_OTHER_BSS | -+ FIF_FCSFAIL | -+ FIF_BCN_PRBRESP_PROMISC | -+ FIF_PROBE_REQ; -+ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ priv->rx_filter.promiscuous = 0; -+ priv->rx_filter.bssid = (*total_flags & -+ (FIF_OTHER_BSS | FIF_PROBE_REQ)) ? 1 : 0; -+ priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0; -+ priv->bf_control.bcn_count = (*total_flags & -+ (FIF_BCN_PRBRESP_PROMISC | -+ FIF_PROBE_REQ)) ? 1 : 0; -+ -+ /*add for handle ap FIF_PROBE_REQ message,*/ -+ priv->rx_filter.promiscuous = 0; -+ priv->rx_filter.fcs = 0; -+ if(NL80211_IFTYPE_AP == priv->vif->type){ -+ priv->bf_control.bcn_count = 1; -+ priv->rx_filter.bssid = 1; -+ }else{ -+ priv->bf_control.bcn_count = 0; -+ priv->rx_filter.bssid = 0; -+ } -+#if 0 -+ if (priv->listening ^ listening) { -+ priv->listening = listening; -+ wsm_lock_tx(hw_priv); -+ xradio_update_listening(priv, listening); -+ wsm_unlock_tx(hw_priv); -+ } -+#endif -+ xradio_update_filtering(priv); -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+ } -+} -+ -+int xradio_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, -+ u16 queue, const struct ieee80211_tx_queue_params *params) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ int ret = 0; -+ /* To prevent re-applying PM request OID again and again*/ -+ bool old_uapsdFlags; -+ -+ wiphy_debug(dev->wiphy, "vif %d, configuring tx\n", priv->if_id); -+ -+ if (WARN_ON(!priv)) -+ return -EOPNOTSUPP; -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ if (queue < dev->queues) { -+ old_uapsdFlags = priv->uapsd_info.uapsdFlags; -+ -+ WSM_TX_QUEUE_SET(&priv->tx_queue_params, queue, 0, 0, 0); -+ ret = wsm_set_tx_queue_params(hw_priv, -+ &priv->tx_queue_params.params[queue], -+ queue, priv->if_id); -+ if (ret) { -+ wiphy_err(dev->wiphy, "wsm_set_tx_queue_params failed!\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ WSM_EDCA_SET(&priv->edca, queue, params->aifs, -+ params->cw_min, params->cw_max, -+ params->txop, 0xc8, params->uapsd); -+ /* sta role is not support the uapsd */ -+ if (priv->mode == NL80211_IFTYPE_STATION || -+ priv->mode == NL80211_IFTYPE_P2P_CLIENT) -+ priv->edca.params[queue].uapsdEnable = 0; -+ -+ ret = wsm_set_edca_params(hw_priv, &priv->edca, priv->if_id); -+ if (ret) { -+ wiphy_err(dev->wiphy, "wsm_set_edca_params failed!\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ if (priv->mode == NL80211_IFTYPE_STATION) { -+ ret = xradio_set_uapsd_param(priv, &priv->edca); -+ if (!ret && priv->setbssparams_done && -+ (priv->join_status == XRADIO_JOIN_STATUS_STA) && -+ (old_uapsdFlags != priv->uapsd_info.uapsdFlags)) -+ xradio_set_pm(priv, &priv->powersave_mode); -+ } -+ } else { -+ wiphy_err(dev->wiphy, "queue is to large!\n"); -+ ret = -EINVAL; -+ } -+ -+out: -+ mutex_unlock(&hw_priv->conf_mutex); -+ return ret; -+} -+ -+int xradio_get_stats(struct ieee80211_hw *dev, -+ struct ieee80211_low_level_stats *stats) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ -+ memcpy(stats, &hw_priv->stats, sizeof(*stats)); -+ return 0; -+} -+ -+/* -+int xradio_get_tx_stats(struct ieee80211_hw *dev, -+ struct ieee80211_tx_queue_stats *stats) -+{ -+ int i; -+ struct xradio_common *priv = dev->priv; -+ -+ for (i = 0; i < dev->queues; ++i) -+ xradio_queue_get_stats(&priv->tx_queue[i], &stats[i]); -+ -+ return 0; -+} -+*/ -+ -+int xradio_set_pm(struct xradio_vif *priv, const struct wsm_set_pm *arg) -+{ -+ struct wsm_set_pm pm = *arg; -+ -+ if (priv->uapsd_info.uapsdFlags != 0) -+ pm.pmMode &= ~WSM_PSM_FAST_PS_FLAG; -+ -+ if (memcmp(&pm, &priv->firmware_ps_mode, sizeof(struct wsm_set_pm))) { -+ priv->firmware_ps_mode = pm; -+ return wsm_set_pm(priv->hw_priv, &pm, priv->if_id); -+ } else { -+ return 0; -+ } -+} -+ -+void xradio_wep_key_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = container_of(work, struct xradio_vif , wep_key_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queueId]; -+ __le32 wep_default_key_id = __cpu_to_le32(priv->wep_default_key_id); -+ -+ -+ BUG_ON(queueId >= 4); -+ -+ sta_printk(XRADIO_DBG_MSG, "Setting default WEP key: %d\n", -+ priv->wep_default_key_id); -+ -+ wsm_flush_tx(hw_priv); -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, -+ &wep_default_key_id, sizeof(wep_default_key_id), -+ priv->if_id)); -+ -+ xradio_queue_requeue(queue, hw_priv->pending_frame_id, true); -+ -+ wsm_unlock_tx(hw_priv); -+} -+ -+int xradio_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ int ret = 0; -+ __le32 val32; -+ struct xradio_vif *priv = NULL; -+ int i =0; -+ int if_id; -+ -+ -+ xradio_for_each_vif(hw_priv,priv,i) { -+ if (!priv) -+ continue; -+ if_id = priv->if_id; -+ -+ if (value != (u32) -1) -+ val32 = __cpu_to_le32(value); -+ else -+ val32 = 0; /* disabled */ -+ -+ /* mutex_lock(&priv->conf_mutex); */ -+ ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_RTS_THRESHOLD, -+ &val32, sizeof(val32), if_id)); -+ /* mutex_unlock(&priv->conf_mutex); */ -+ } -+ return ret; -+} -+ -+/* TODO: COMBO: Flush only a particular interface specific parts */ -+int __xradio_flush(struct xradio_common *hw_priv, bool drop, int if_id) -+{ -+ int i, ret; -+ struct xradio_vif *priv = -+ __xrwl_hwpriv_to_vifpriv(hw_priv, if_id); -+ -+ -+ for (;;) { -+ /* TODO: correct flush handling is required when dev_stop. -+ * Temporary workaround: 2s -+ */ -+ if (drop) { -+ for (i = 0; i < 4; ++i) -+ xradio_queue_clear(&hw_priv->tx_queue[i],if_id); -+ } else if(!hw_priv->bh_error){ -+ ret = wait_event_timeout( -+ hw_priv->tx_queue_stats.wait_link_id_empty, -+ xradio_queue_stats_is_empty(&hw_priv->tx_queue_stats, -1, if_id), -+ 2 * HZ); -+ } else { //add by yangfh, don't wait when bh error -+ sta_printk(XRADIO_DBG_ERROR, " %s:bh_error occur.\n", __func__); -+ ret = -1; -+ break; -+ } -+ -+ if (!drop && unlikely(ret <= 0)) { -+ sta_printk(XRADIO_DBG_ERROR, " %s: timeout...\n", __func__); -+ ret = -ETIMEDOUT; -+ break; -+ } else { -+ ret = 0; -+ } -+ -+ wsm_vif_lock_tx(priv); -+ if (unlikely(!xradio_queue_stats_is_empty(&hw_priv->tx_queue_stats, -+ -1, if_id))) { -+ /* Highly unlekely: WSM requeued frames. */ -+ wsm_unlock_tx(hw_priv); -+ continue; -+ } -+ wsm_unlock_tx(hw_priv); -+ break; -+ } -+ return ret; -+} -+ -+void xradio_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) -+{ -+ //struct xradio_vif *priv = NULL; -+ struct xradio_common *hw_priv = hw->priv; -+ int i = 0; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ -+ /*TODO:COMBO: reenable this part of code when flush callback -+ * is implemented per vif */ -+ /*switch (hw_priv->mode) { -+ case NL80211_IFTYPE_MONITOR: -+ drop = true; -+ break; -+ case NL80211_IFTYPE_AP: -+ if (!hw_priv->enable_beacon) -+ drop = true; -+ break; -+ }*/ -+ -+ //if (!(hw_priv->if_id_slot & BIT(priv->if_id))) -+ // return; -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if(NULL == priv) -+ continue; -+ if ((hw_priv->if_id_slot & BIT(priv->if_id))) -+ __xradio_flush(hw_priv, drop, priv->if_id); -+ } -+ return; -+} -+ -+int xradio_remain_on_channel(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_channel *chan, -+ int duration, enum ieee80211_roc_type type) -+{ -+ int ret = 0; -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = NULL; -+ int i = 0; -+ int if_id; -+#ifdef TES_P2P_0002_ROC_RESTART -+ struct timeval TES_P2P_0002_tmval; -+#endif -+ -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ do_gettimeofday(&TES_P2P_0002_tmval); -+ TES_P2P_0002_roc_dur = (s32)duration; -+ TES_P2P_0002_roc_sec = (s32)TES_P2P_0002_tmval.tv_sec; -+ TES_P2P_0002_roc_usec = (s32)TES_P2P_0002_tmval.tv_usec; -+#endif -+ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if(NULL == priv) -+ continue; -+ if_id = priv->if_id; -+ -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "ROC IN %d ch %d\n", -+ priv->if_id, chan->hw_value); -+#endif -+ /* default only p2p interface if_id can remain on */ -+ if((priv->if_id == 0) || (priv->if_id == 1)) -+ continue; -+ hw_priv->roc_if_id = priv->if_id; -+ ret = WARN_ON(__xradio_flush(hw_priv, false, if_id)); -+ xradio_enable_listening(priv, chan); -+ -+ if (!ret) { -+ atomic_set(&hw_priv->remain_on_channel, 1); -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->rem_chan_timeout, -+ duration * HZ / 1000); -+ priv->join_status = XRADIO_JOIN_STATUS_MONITOR; -+ ieee80211_ready_on_channel(hw); -+ } else { -+ hw_priv->roc_if_id = -1; -+ up(&hw_priv->scan.lock); -+ } -+ -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "ROC OUT %d\n", priv->if_id); -+#endif -+ } -+ /* set the channel to supplied ieee80211_channel pointer, if it -+ is not set. This is to remove the crash while sending a probe res -+ in listen state. Later channel will updated on -+ IEEE80211_CONF_CHANGE_CHANNEL event*/ -+ if(!hw_priv->channel) { -+ hw_priv->channel = chan; -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ return ret; -+} -+ -+int xradio_cancel_remain_on_channel(struct ieee80211_hw *hw) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ -+ -+ sta_printk(XRADIO_DBG_NIY, "Cancel remain on channel\n"); -+#ifdef TES_P2P_0002_ROC_RESTART -+ if (TES_P2P_0002_state == TES_P2P_0002_STATE_GET_PKTID) { -+ TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; -+ sta_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_IDLE][Cancel ROC]\n"); -+ } -+#endif -+ -+ if (atomic_read(&hw_priv->remain_on_channel)) -+ cancel_delayed_work_sync(&hw_priv->rem_chan_timeout); -+ -+ if (atomic_read(&hw_priv->remain_on_channel)) -+ xradio_rem_chan_timeout(&hw_priv->rem_chan_timeout.work); -+ -+ return 0; -+} -+ -+/* ******************************************************************** */ -+/* WSM callbacks */ -+ -+void xradio_channel_switch_cb(struct xradio_common *hw_priv) -+{ -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_free_event_queue(struct xradio_common *hw_priv) -+{ -+ LIST_HEAD(list); -+ -+ -+ spin_lock(&hw_priv->event_queue_lock); -+ list_splice_init(&hw_priv->event_queue, &list); -+ spin_unlock(&hw_priv->event_queue_lock); -+ -+ __xradio_free_event_queue(&list); -+} -+ -+void xradio_event_handler(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, event_handler); -+ struct xradio_vif *priv; -+ struct xradio_wsm_event *event; -+ LIST_HEAD(list); -+ -+ -+ spin_lock(&hw_priv->event_queue_lock); -+ list_splice_init(&hw_priv->event_queue, &list); -+ spin_unlock(&hw_priv->event_queue_lock); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ list_for_each_entry(event, &list, link) { -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, event->if_id); -+ if (!priv) { -+ sta_printk(XRADIO_DBG_WARN, "[CQM] Event for non existing " -+ "interface, ignoring.\n"); -+ continue; -+ } -+ switch (event->evt.eventId) { -+ case WSM_EVENT_ERROR: -+ /* I even don't know what is it about.. */ -+ //STUB(); -+ break; -+ case WSM_EVENT_BSS_LOST: -+ { -+ spin_lock(&priv->bss_loss_lock); -+ if (priv->bss_loss_status > XRADIO_BSS_LOSS_NONE) { -+ spin_unlock(&priv->bss_loss_lock); -+ break; -+ } -+ priv->bss_loss_status = XRADIO_BSS_LOSS_CHECKING; -+ spin_unlock(&priv->bss_loss_lock); -+ sta_printk(XRADIO_DBG_WARN, "[CQM] BSS lost, Beacon miss=%d, event=%x.\n", -+ (event->evt.eventData>>8)&0xff, event->evt.eventData&0xff); -+ -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ if (!down_trylock(&hw_priv->scan.lock)) { -+ up(&hw_priv->scan.lock); -+ priv->delayed_link_loss = 0; -+ queue_delayed_work(hw_priv->workqueue, -+ &priv->bss_loss_work, HZ/10); //100ms -+ } else { -+ /* Scan is in progress. Delay reporting. */ -+ /* Scan complete will trigger bss_loss_work */ -+ priv->delayed_link_loss = 1; -+ /* Also we're starting watchdog. */ -+ queue_delayed_work(hw_priv->workqueue, -+ &priv->bss_loss_work, 10 * HZ); -+ } -+ break; -+ } -+ case WSM_EVENT_BSS_REGAINED: -+ { -+ sta_printk(XRADIO_DBG_WARN, "[CQM] BSS regained.\n"); -+ priv->delayed_link_loss = 0; -+ spin_lock(&priv->bss_loss_lock); -+ priv->bss_loss_status = XRADIO_BSS_LOSS_NONE; -+ spin_unlock(&priv->bss_loss_lock); -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ break; -+ } -+ case WSM_EVENT_RADAR_DETECTED: -+ //STUB(); -+ break; -+ case WSM_EVENT_RCPI_RSSI: -+ { -+ /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 -+ * RSSI = RCPI / 2 - 110 */ -+ int rcpiRssi = (int)(event->evt.eventData & 0xFF); -+ int cqm_evt; -+ if (priv->cqm_use_rssi) -+ rcpiRssi = (s8)rcpiRssi; -+ else -+ rcpiRssi = rcpiRssi / 2 - 110; -+ -+ cqm_evt = (rcpiRssi <= priv->cqm_rssi_thold) ? -+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : -+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; -+ sta_printk(XRADIO_DBG_NIY, "[CQM] RSSI event: %d", rcpiRssi); -+ ieee80211_cqm_rssi_notify(priv->vif, -+ cqm_evt, -+ 0, -+ GFP_KERNEL); -+ break; -+ } -+ case WSM_EVENT_BT_INACTIVE: -+ //STUB(); -+ break; -+ case WSM_EVENT_BT_ACTIVE: -+ //STUB(); -+ break; -+ case WSM_EVENT_INACTIVITY: -+ { -+ int link_id = ffs((u32)(event->evt.eventData)) - 1; -+ struct sk_buff *skb; -+ struct ieee80211_mgmt *deauth; -+ struct xradio_link_entry *entry = NULL; -+ -+ sta_printk(XRADIO_DBG_WARN, "Inactivity Event Recieved for " -+ "link_id %d\n", link_id); -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ break; -+ skb_reserve(skb, 64); -+ xrwl_unmap_link(priv, link_id); -+ deauth = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ WARN_ON(!deauth); -+ entry = &priv->link_id_db[link_id - 1]; -+ deauth->duration = 0; -+ memcpy(deauth->da, priv->vif->addr, ETH_ALEN); -+ memcpy(deauth->sa, entry->mac/*priv->link_id_db[i].mac*/, ETH_ALEN); -+ memcpy(deauth->bssid, priv->vif->addr, ETH_ALEN); -+ deauth->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | -+ IEEE80211_STYPE_DEAUTH | -+ IEEE80211_FCTL_TODS); -+ deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING; -+ deauth->seq_ctrl = 0; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ sta_printk(XRADIO_DBG_WARN, " Inactivity Deauth Frame sent for MAC SA %pM \t and DA %pM\n", deauth->sa, deauth->da); -+ queue_work(priv->hw_priv->workqueue, &priv->set_tim_work); -+ break; -+ } -+ case WSM_EVENT_PS_MODE_ERROR: -+ { -+ if (!priv->uapsd_info.uapsdFlags && -+ (priv->user_pm_mode != WSM_PSM_PS)) -+ { -+ struct wsm_set_pm pm = priv->powersave_mode; -+ int ret = 0; -+ -+ priv->powersave_mode.pmMode = WSM_PSM_ACTIVE; -+ ret = xradio_set_pm (priv, &priv->powersave_mode); -+ if(ret) -+ priv->powersave_mode = pm; -+ } -+ break; -+ } -+ } -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ __xradio_free_event_queue(&list); -+} -+ -+void xradio_bss_loss_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, bss_loss_work.work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int timeout; /* in beacons */ -+ -+ -+ timeout = priv->cqm_link_loss_count - priv->cqm_beacon_loss_count; -+ /* Skip the confimration procedure in P2P case */ -+ if (priv->vif->p2p) -+ goto report; -+ -+ spin_lock(&priv->bss_loss_lock); -+ if (priv->bss_loss_status == XRADIO_BSS_LOSS_CONFIRMING) { -+ //do loss report next time. -+ priv->bss_loss_status = XRADIO_BSS_LOSS_CONFIRMED; -+ spin_unlock(&priv->bss_loss_lock); -+ //wait for more 1s to loss confirm. -+ queue_delayed_work(hw_priv->workqueue, &priv->bss_loss_work, 1 * HZ); -+ return; -+ } else if (priv->bss_loss_status == XRADIO_BSS_LOSS_NONE) { -+ spin_unlock(&priv->bss_loss_lock); -+ //link is alive. -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ return; -+ } else if (priv->bss_loss_status == XRADIO_BSS_LOSS_CHECKING) { -+ /* it mean no confirming packets, just report loss. */ -+ } -+ spin_unlock(&priv->bss_loss_lock); -+ -+report: -+ if (priv->cqm_beacon_loss_count) { -+ sta_printk(XRADIO_DBG_WARN, "[CQM] Beacon loss.\n"); -+ if (timeout <= 0) -+ timeout = 0; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //ieee80211_cqm_beacon_miss_notify(priv->vif, GFP_KERNEL); -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ } else { -+ timeout = 0; -+ } -+ -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ queue_delayed_work(hw_priv->workqueue, &priv->connection_loss_work, -+ timeout * HZ / 10); -+ -+ spin_lock(&priv->bss_loss_lock); -+ priv->bss_loss_status = XRADIO_BSS_LOSS_NONE; -+ spin_unlock(&priv->bss_loss_lock); -+} -+ -+void xradio_connection_loss_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, connection_loss_work.work); -+ sta_printk(XRADIO_DBG_ERROR, "[CQM] if%d Reporting connection loss.\n", -+ priv->if_id); -+ ieee80211_connection_loss(priv->vif); -+} -+ -+void xradio_tx_failure_work(struct work_struct *work) -+{ -+ //struct xradio_vif *priv = -+ // container_of(work, struct xradio_vif, tx_failure_work); -+ sta_printk(XRADIO_DBG_WARN, "[CQM] Reporting TX failure.\n"); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //ieee80211_cqm_tx_fail_notify(priv->vif, GFP_KERNEL); -+#else /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ //(void)priv; -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+} -+ -+/* Internal API */ -+int xradio_setup_mac(struct xradio_common *hw_priv) -+{ -+ int ret = 0, if_id; -+ -+ -+ if (hw_priv->sdd) { -+ struct wsm_configuration cfg = { -+ .dot11StationId = &hw_priv->mac_addr[0], -+ .dpdData = hw_priv->sdd->data, -+ .dpdData_size = hw_priv->sdd->size, -+ }; -+ for (if_id = 0; if_id < xrwl_get_nr_hw_ifaces(hw_priv); -+ if_id++) { -+ /* Set low-power mode. */ -+ ret |= WARN_ON(wsm_configuration(hw_priv, &cfg, -+ if_id)); -+ } -+ /* wsm_configuration only once, so release it */ -+ release_firmware(hw_priv->sdd); -+ hw_priv->sdd = NULL; -+ } -+ -+ /* BUG:TX output power is not set untill config_xradio is called. -+ * This would lead to 0 power set in fw and would effect scan & p2p-find -+ * Setting to default value here from sdd which would be overwritten when -+ * we make connection to AP.This value is used only during scan & p2p-ops -+ * untill AP connection is made */ -+ /*BUG:TX output power: Hardcoding to 20dbm if CCX is not enabled*/ -+ /*TODO: This might change*/ -+ if (!hw_priv->output_power) -+ hw_priv->output_power=20; -+ sta_printk(XRADIO_DBG_MSG, "%s output power %d\n",__func__,hw_priv->output_power); -+ -+ return ret; -+} -+ -+void xradio_pending_offchanneltx_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, pending_offchanneltx_work.work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ -+ mutex_lock(&hw_priv->conf_mutex); -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "OFFCHAN PEND IN\n"); -+#endif -+ xradio_disable_listening(priv); -+ hw_priv->roc_if_id = -1; -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "OFFCHAN PEND OUT\n"); -+#endif -+ up(&hw_priv->scan.lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+} -+ -+void xradio_offchannel_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, offchannel_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queueId]; -+ -+ -+ BUG_ON(queueId >= 4); -+ BUG_ON(!hw_priv->channel); -+ -+ if (unlikely(down_trylock(&hw_priv->scan.lock))) { -+ int ret; -+ sta_printk(XRADIO_DBG_ERROR, "xradio_offchannel_work***** drop frame\n"); -+ ret = xradio_queue_remove(queue, hw_priv->pending_frame_id); -+ if (ret) -+ sta_printk(XRADIO_DBG_ERROR, "xradio_offchannel_work: " -+ "queue_remove failed %d\n", ret); -+ wsm_unlock_tx(hw_priv); -+ //workaround by yangfh -+ up(&hw_priv->scan.lock); -+ ieee80211_connection_loss(priv->vif); -+ sta_printk(XRADIO_DBG_ERROR,"lock %d\n", hw_priv->scan.lock.count); -+ -+ return; -+ } -+ mutex_lock(&hw_priv->conf_mutex); -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "OFFCHAN WORK IN %d\n", priv->if_id); -+#endif -+ hw_priv->roc_if_id = priv->if_id; -+ if (likely(!priv->join_status)) { -+ wsm_vif_flush_tx(priv); -+ xradio_enable_listening(priv, hw_priv->channel); -+ /* xradio_update_filtering(priv); */ -+ } -+ if (unlikely(!priv->join_status)) -+ xradio_queue_remove(queue, hw_priv->pending_frame_id); -+ else -+ xradio_queue_requeue(queue, hw_priv->pending_frame_id, false); -+ -+ queue_delayed_work(hw_priv->workqueue, -+ &priv->pending_offchanneltx_work, 204 * HZ/1000); -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "OFFCHAN WORK OUT %d\n", priv->if_id); -+#endif -+ mutex_unlock(&hw_priv->conf_mutex); -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_join_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, join_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queueId]; -+ const struct xradio_txpriv *txpriv = NULL; -+ struct sk_buff *skb = NULL; -+ const struct wsm_tx *wsm; -+ const struct ieee80211_hdr *frame; -+ const u8 *bssid; -+ struct cfg80211_bss *bss; -+ const u8 *ssidie; -+ const u8 *dtimie; -+ const struct ieee80211_tim_ie *tim = NULL; -+ struct wsm_protected_mgmt_policy mgmt_policy; -+ //struct wsm_reset reset = { -+ // .reset_statistics = true, -+ //}; -+ -+ -+ -+ BUG_ON(queueId >= 4); -+ if (xradio_queue_get_skb(queue, hw_priv->pending_frame_id, -+ &skb, &txpriv)) { -+ wsm_unlock_tx(hw_priv); -+ return; -+ } -+ wsm = (struct wsm_tx *)&skb->data[0]; -+ frame = (struct ieee80211_hdr *)&skb->data[txpriv->offset]; -+ bssid = &frame->addr1[0]; /* AP SSID in a 802.11 frame */ -+ -+ BUG_ON(!wsm); -+ BUG_ON(!hw_priv->channel); -+ -+ if (unlikely(priv->join_status)) { -+ sta_printk(XRADIO_DBG_WARN, "%s, pre join_status=%d.\n", -+ __func__, priv->join_status); -+ wsm_lock_tx(hw_priv); -+ xradio_unjoin_work(&priv->unjoin_work); -+ } -+ -+ cancel_delayed_work_sync(&priv->join_timeout); -+ -+ bss = cfg80211_get_bss(hw_priv->hw->wiphy, hw_priv->channel, -+ bssid, NULL, 0, 0, 0); -+ if (!bss) { -+ xradio_queue_remove(queue, hw_priv->pending_frame_id); -+ wsm_unlock_tx(hw_priv); -+ return; -+ } -+ ssidie = cfg80211_find_ie(WLAN_EID_SSID, -+ bss->ies->data, -+ bss->ies->len); -+ dtimie = cfg80211_find_ie(WLAN_EID_TIM, -+ bss->ies->data, -+ bss->ies->len); -+ if (dtimie) -+ tim = (struct ieee80211_tim_ie *)&dtimie[2]; -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ { -+ struct wsm_join join = { -+ .mode = (bss->capability & WLAN_CAPABILITY_IBSS) ? -+ WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, -+ /* default changed to LONG, by HuangLu, fix 2/5.5/11m tx fail*/ -+ .preambleType = WSM_JOIN_PREAMBLE_LONG, -+ .probeForJoin = 1, -+ /* dtimPeriod will be updated after association */ -+ .dtimPeriod = 1, -+ .beaconInterval = bss->beacon_interval, -+ }; -+ -+ if (priv->if_id) -+ join.flags |= WSM_FLAG_MAC_INSTANCE_1; -+ else -+ join.flags &= ~WSM_FLAG_MAC_INSTANCE_1; -+ -+ /* BT Coex related changes */ -+ if (hw_priv->is_BT_Present) { -+ if (((hw_priv->conf_listen_interval * 100) % -+ bss->beacon_interval) == 0) -+ priv->listen_interval = -+ ((hw_priv->conf_listen_interval * 100) / -+ bss->beacon_interval); -+ else -+ priv->listen_interval = -+ ((hw_priv->conf_listen_interval * 100) / -+ bss->beacon_interval + 1); -+ } -+ -+ if (tim && tim->dtim_period > 1) { -+ join.dtimPeriod = tim->dtim_period; -+ priv->join_dtim_period = tim->dtim_period; -+ } -+ priv->beacon_int = bss->beacon_interval; -+ sta_printk(XRADIO_DBG_NIY, "Join DTIM: %d, interval: %d\n", -+ join.dtimPeriod, priv->beacon_int); -+ -+ hw_priv->is_go_thru_go_neg = false; -+ join.channelNumber = hw_priv->channel->hw_value; -+ -+ /* basicRateSet will be updated after association. -+ Currently these values are hardcoded */ -+ if (hw_priv->channel->band == NL80211_BAND_5GHZ) { -+ join.band = WSM_PHY_BAND_5G; -+ join.basicRateSet = 64; /*6 mbps*/ -+ }else{ -+ join.band = WSM_PHY_BAND_2_4G; -+ join.basicRateSet = 7; /*1, 2, 5.5 mbps*/ -+ } -+ memcpy(&join.bssid[0], bssid, sizeof(join.bssid)); -+ memcpy(&priv->join_bssid[0], bssid, sizeof(priv->join_bssid)); -+ -+ if (ssidie) { -+ join.ssidLength = ssidie[1]; -+ if (WARN_ON(join.ssidLength > sizeof(join.ssid))) -+ join.ssidLength = sizeof(join.ssid); -+ memcpy(&join.ssid[0], &ssidie[2], join.ssidLength); -+ if(strstr(&join.ssid[0],"5.1.4")) -+ msleep(200); -+#ifdef ROAM_OFFLOAD -+ if((priv->vif->type == NL80211_IFTYPE_STATION)) { -+ priv->ssid_length = join.ssidLength; -+ memcpy(priv->ssid, &join.ssid[0], priv->ssid_length); -+ } -+#endif /*ROAM_OFFLOAD*/ -+ } -+ -+ if (priv->vif->p2p) { -+ join.flags |= WSM_JOIN_FLAGS_P2P_GO; -+ join.basicRateSet = -+ xradio_rate_mask_to_wsm(hw_priv, 0xFF0); -+ } -+ -+ wsm_flush_tx(hw_priv); -+ -+ /* Queue unjoin if not associated in 3 sec. */ -+ queue_delayed_work(hw_priv->workqueue, -+ &priv->join_timeout, 3 * HZ); -+ /*Stay Awake for Join Timeout*/ -+ xradio_pm_stay_awake(&hw_priv->pm_state, 3 * HZ); -+ -+ xradio_disable_listening(priv); -+ -+ //WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id)); -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ 0, hw_priv->ba_tid_mask, priv->if_id)); -+ spin_lock_bh(&hw_priv->ba_lock); -+ hw_priv->ba_ena = false; -+ hw_priv->ba_cnt = 0; -+ hw_priv->ba_acc = 0; -+ hw_priv->ba_hist = 0; -+ hw_priv->ba_cnt_rx = 0; -+ hw_priv->ba_acc_rx = 0; -+ spin_unlock_bh(&hw_priv->ba_lock); -+ -+ mgmt_policy.protectedMgmtEnable = 0; -+ mgmt_policy.unprotectedMgmtFramesAllowed = 1; -+ mgmt_policy.encryptionForAuthFrame = 1; -+ wsm_set_protected_mgmt_policy(hw_priv, &mgmt_policy, priv->if_id); -+ -+ if (wsm_join(hw_priv, &join, priv->if_id)) { -+ memset(&priv->join_bssid[0], -+ 0, sizeof(priv->join_bssid)); -+ xradio_queue_remove(queue, hw_priv->pending_frame_id); -+ cancel_delayed_work_sync(&priv->join_timeout); -+ } else { -+ /* Upload keys */ -+ xradio_queue_requeue(queue, hw_priv->pending_frame_id, -+ true); -+ priv->join_status = XRADIO_JOIN_STATUS_STA; -+ -+ /* Due to beacon filtering it is possible that the -+ * AP's beacon is not known for the mac80211 stack. -+ * Disable filtering temporary to make sure the stack -+ * receives at least one */ -+ priv->disable_beacon_filter = true; -+ -+ } -+ xradio_update_filtering(priv); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ cfg80211_put_bss(hw_priv->hw->wiphy,bss); -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_join_timeout(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, join_timeout.work); -+ sta_printk(XRADIO_DBG_WARN, "[WSM] Issue unjoin command (TMO).\n"); -+ wsm_lock_tx(priv->hw_priv); -+ xradio_unjoin_work(&priv->unjoin_work); -+} -+ -+void xradio_unjoin_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, unjoin_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ struct wsm_reset reset = { -+ .reset_statistics = true, -+ }; -+ bool is_htcapie = false; -+ int i; -+ struct xradio_vif *tmp_priv; -+ -+ //add by yangfh. -+ hw_priv->connet_time[priv->if_id] = 0; -+#ifdef AP_HT_COMPAT_FIX -+ priv->ht_compat_det &= ~1; -+ priv->ht_compat_cnt = 0; -+#endif -+ -+ del_timer_sync(&hw_priv->ba_timer); -+ mutex_lock(&hw_priv->conf_mutex); -+ if (unlikely(atomic_read(&hw_priv->scan.in_progress))) { -+ if (atomic_xchg(&priv->delayed_unjoin, 1)) { -+ sta_printk(XRADIO_DBG_NIY, -+ "%s: Delayed unjoin " -+ "is already scheduled.\n", -+ __func__); -+ wsm_unlock_tx(hw_priv); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ return; -+ } -+ -+ if (priv->join_status && -+ priv->join_status > XRADIO_JOIN_STATUS_STA) { -+ sta_printk(XRADIO_DBG_ERROR, -+ "%s: Unexpected: join status: %d\n", -+ __func__, priv->join_status); -+ BUG_ON(1); -+ } -+ if (priv->join_status) { -+ cancel_work_sync(&priv->update_filtering_work); -+ cancel_work_sync(&priv->set_beacon_wakeup_period_work); -+ memset(&priv->join_bssid[0], 0, sizeof(priv->join_bssid)); -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ -+ /* Unjoin is a reset. */ -+ wsm_flush_tx(hw_priv); -+ WARN_ON(wsm_keep_alive_period(hw_priv, 0, priv->if_id)); -+ WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id)); -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ WARN_ON(wsm_set_output_power(hw_priv, -+ hw_priv->output_power * 10, priv->if_id)); -+ priv->join_dtim_period = 0; -+ priv->cipherType = 0; -+ WARN_ON(xradio_setup_mac_pvif(priv)); -+ xradio_free_event_queue(hw_priv); -+ cancel_work_sync(&hw_priv->event_handler); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ 0, hw_priv->ba_tid_mask, priv->if_id)); -+ priv->disable_beacon_filter = false; -+ xradio_update_filtering(priv); -+ priv->setbssparams_done = false; -+ memset(&priv->association_mode, 0, -+ sizeof(priv->association_mode)); -+ memset(&priv->bss_params, 0, sizeof(priv->bss_params)); -+ memset(&priv->firmware_ps_mode, 0, -+ sizeof(priv->firmware_ps_mode)); -+ priv->htcap = false; -+ xradio_for_each_vif(hw_priv, tmp_priv, i) { -+ if (!tmp_priv) -+ continue; -+ if ((tmp_priv->join_status == XRADIO_JOIN_STATUS_STA) && tmp_priv->htcap) -+ is_htcapie = true; -+ } -+ -+ if (is_htcapie) { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11N_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11N_THROTTLE; -+ sta_printk(XRADIO_DBG_NIY, "UNJOIN HTCAP 11N %d\n",hw_priv->vif0_throttle); -+ } else { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ sta_printk(XRADIO_DBG_NIY, "UNJOIN 11BG %d\n",hw_priv->vif0_throttle); -+ } -+ sta_printk(XRADIO_DBG_NIY, "Unjoin.\n"); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ wsm_unlock_tx(hw_priv); -+} -+ -+int xradio_enable_listening(struct xradio_vif *priv, -+ struct ieee80211_channel *chan) -+{ -+ /* TODO:COMBO: Channel is common to HW currently in mac80211. -+ Change the code below once channel is made per VIF */ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_start start = { -+ .mode = WSM_START_MODE_P2P_DEV | (priv->if_id << 4), -+ .band = (chan->band == NL80211_BAND_5GHZ) ? -+ WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G, -+ .channelNumber = chan->hw_value, -+ .beaconInterval = 100, -+ .DTIMPeriod = 1, -+ .probeDelay = 0, -+ .basicRateSet = 0x0F, -+ }; -+ -+ -+ if(priv->if_id != 2) { -+ WARN_ON(priv->join_status > XRADIO_JOIN_STATUS_MONITOR); -+ return 0; -+ } -+ if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) -+ return 0; -+ if (priv->join_status == XRADIO_JOIN_STATUS_PASSIVE) -+ priv->join_status = XRADIO_JOIN_STATUS_MONITOR; -+ -+ WARN_ON(priv->join_status > XRADIO_JOIN_STATUS_MONITOR); -+ -+ return wsm_start(hw_priv, &start, XRWL_GENERIC_IF_ID); -+} -+ -+int xradio_disable_listening(struct xradio_vif *priv) -+{ -+ int ret; -+ struct wsm_reset reset = { -+ .reset_statistics = true, -+ }; -+ -+ -+ if(priv->if_id != 2) { -+ WARN_ON(priv->join_status > XRADIO_JOIN_STATUS_MONITOR); -+ return 0; -+ } -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ -+ WARN_ON(priv->join_status > XRADIO_JOIN_STATUS_MONITOR); -+ -+ if (priv->hw_priv->roc_if_id == -1) -+ return 0; -+ -+ ret = wsm_reset(priv->hw_priv, &reset, XRWL_GENERIC_IF_ID); -+ return ret; -+} -+ -+/* TODO:COMBO:UAPSD will be supported only on one interface */ -+int xradio_set_uapsd_param(struct xradio_vif *priv, -+ const struct wsm_edca_params *arg) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int ret; -+ u16 uapsdFlags = 0; -+ -+ -+ /* Here's the mapping AC [queue, bit] -+ VO [0,3], VI [1, 2], BE [2, 1], BK [3, 0]*/ -+ -+ if (arg->params[0].uapsdEnable) -+ uapsdFlags |= 1 << 3; -+ -+ if (arg->params[1].uapsdEnable) -+ uapsdFlags |= 1 << 2; -+ -+ if (arg->params[2].uapsdEnable) -+ uapsdFlags |= 1 << 1; -+ -+ if (arg->params[3].uapsdEnable) -+ uapsdFlags |= 1; -+ -+ /* Currently pseudo U-APSD operation is not supported, so setting -+ * MinAutoTriggerInterval, MaxAutoTriggerInterval and -+ * AutoTriggerStep to 0 */ -+ -+ priv->uapsd_info.uapsdFlags = cpu_to_le16(uapsdFlags); -+ priv->uapsd_info.minAutoTriggerInterval = 0; -+ priv->uapsd_info.maxAutoTriggerInterval = 0; -+ priv->uapsd_info.autoTriggerStep = 0; -+ -+ ret = wsm_set_uapsd_info(hw_priv, &priv->uapsd_info, -+ priv->if_id); -+ return ret; -+} -+ -+void xradio_ba_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, ba_work); -+ u8 tx_ba_tid_mask; -+ -+ -+ /* TODO:COMBO: reenable this part of code */ -+/* if (priv->join_status != XRADIO_JOIN_STATUS_STA) -+ return; -+ if (!priv->setbssparams_done) -+ return;*/ -+ -+ sta_printk(XRADIO_DBG_WARN, "BA work****\n"); -+ spin_lock_bh(&hw_priv->ba_lock); -+// tx_ba_tid_mask = hw_priv->ba_ena ? hw_priv->ba_tid_mask : 0; -+ tx_ba_tid_mask = hw_priv->ba_tid_mask; -+ spin_unlock_bh(&hw_priv->ba_lock); -+ -+ wsm_lock_tx(hw_priv); -+ -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ tx_ba_tid_mask, hw_priv->ba_tid_mask, -1)); /*TODO:COMBO*/ -+ -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_ba_timer(struct timer_list *t) -+{ -+ struct xradio_common *hw_priv = from_timer(hw_priv, t, ba_timer); -+ bool ba_ena; -+ -+ -+ spin_lock_bh(&hw_priv->ba_lock); -+ -+ if (atomic_read(&hw_priv->scan.in_progress)) { -+ hw_priv->ba_cnt = 0; -+ hw_priv->ba_acc = 0; -+ hw_priv->ba_cnt_rx = 0; -+ hw_priv->ba_acc_rx = 0; -+ goto skip_statistic_update; -+ } -+ -+ if (hw_priv->ba_cnt >= XRADIO_BLOCK_ACK_CNT && -+ (hw_priv->ba_acc / hw_priv->ba_cnt >= XRADIO_BLOCK_ACK_THLD || -+ (hw_priv->ba_cnt_rx >= XRADIO_BLOCK_ACK_CNT && -+ hw_priv->ba_acc_rx / hw_priv->ba_cnt_rx >= -+ XRADIO_BLOCK_ACK_THLD))) -+ ba_ena = true; -+ else -+ ba_ena = false; -+ -+ hw_priv->ba_cnt = 0; -+ hw_priv->ba_acc = 0; -+ hw_priv->ba_cnt_rx = 0; -+ hw_priv->ba_acc_rx = 0; -+ -+ if (ba_ena != hw_priv->ba_ena) { -+ if (ba_ena || ++hw_priv->ba_hist >= XRADIO_BLOCK_ACK_HIST) { -+ hw_priv->ba_ena = ba_ena; -+ hw_priv->ba_hist = 0; -+#if 0 -+ sta_printk(XRADIO_DBG_NIY, "%s block ACK:\n", -+ ba_ena ? "enable" : "disable"); -+ queue_work(hw_priv->workqueue, &hw_priv->ba_work); -+#endif -+ } -+ } else if (hw_priv->ba_hist) -+ --hw_priv->ba_hist; -+ -+skip_statistic_update: -+ spin_unlock_bh(&hw_priv->ba_lock); -+} -+ -+int xradio_vif_setup(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ int ret = 0; -+ -+ -+ //reset channel change flag, yangfh 2015-5-15 17:12:14 -+ hw_priv->channel_changed = 0; -+ /* Setup per vif workitems and locks */ -+ spin_lock_init(&priv->vif_lock); -+ INIT_WORK(&priv->join_work, xradio_join_work); -+ INIT_DELAYED_WORK(&priv->join_timeout, xradio_join_timeout); -+ INIT_WORK(&priv->unjoin_work, xradio_unjoin_work); -+ INIT_WORK(&priv->wep_key_work, xradio_wep_key_work); -+ INIT_WORK(&priv->offchannel_work, xradio_offchannel_work); -+ INIT_DELAYED_WORK(&priv->bss_loss_work, xradio_bss_loss_work); -+ INIT_DELAYED_WORK(&priv->connection_loss_work, xradio_connection_loss_work); -+ priv->bss_loss_status = XRADIO_BSS_LOSS_NONE; -+ spin_lock_init(&priv->bss_loss_lock); -+ INIT_WORK(&priv->tx_failure_work, xradio_tx_failure_work); -+ spin_lock_init(&priv->ps_state_lock); -+ INIT_DELAYED_WORK(&priv->set_cts_work, xradio_set_cts_work); -+ INIT_WORK(&priv->set_tim_work, xradio_set_tim_work); -+ INIT_WORK(&priv->multicast_start_work, xradio_multicast_start_work); -+ INIT_WORK(&priv->multicast_stop_work, xradio_multicast_stop_work); -+ INIT_WORK(&priv->link_id_work, xradio_link_id_work); -+ INIT_DELAYED_WORK(&priv->link_id_gc_work, xradio_link_id_gc_work); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ INIT_WORK(&priv->linkid_reset_work, xradio_link_id_reset); -+#endif -+ INIT_WORK(&priv->update_filtering_work, xradio_update_filtering_work); -+ INIT_DELAYED_WORK(&priv->pending_offchanneltx_work, -+ xradio_pending_offchanneltx_work); -+ INIT_WORK(&priv->set_beacon_wakeup_period_work, -+ xradio_set_beacon_wakeup_period_work); -+#ifdef AP_HT_CAP_UPDATE -+ INIT_WORK(&priv->ht_oper_update_work, xradio_ht_oper_update_work); -+#endif -+ timer_setup(&priv->mcast_timeout, xradio_mcast_timeout, 0); -+ priv->setbssparams_done = false; -+ priv->power_set_true = 0; -+ priv->user_power_set_true = 0; -+ priv->user_pm_mode = 0; -+ -+ /* Initialising the broadcast filter */ -+ memset(priv->broadcast_filter.MacAddr, 0xFF, ETH_ALEN); -+ priv->broadcast_filter.nummacaddr = 1; -+ priv->broadcast_filter.address_mode = 1; -+ priv->broadcast_filter.filter_mode = 1; -+ priv->htcap = false; -+#ifdef AP_HT_COMPAT_FIX -+ priv->ht_compat_det = 0; -+ priv->ht_compat_cnt = 0; -+#endif -+ -+ sta_printk(XRADIO_DBG_ALWY, "!!!%s: id=%d, type=%d, p2p=%d\n", -+ __func__, priv->if_id, priv->vif->type, priv->vif->p2p); -+ -+ atomic_set(&priv->enabled, 1); -+ -+ /* default EDCA */ -+ WSM_EDCA_SET(&priv->edca, 0, 0x0002, 0x0003, 0x0007, -+ 47, 0xc8, false); -+ WSM_EDCA_SET(&priv->edca, 1, 0x0002, 0x0007, 0x000f, -+ 94, 0xc8, false); -+ -+// if(priv->vif->p2p == true) { -+ WSM_EDCA_SET(&priv->edca, 2, 0x0002, 0x0003, 0x0007, -+ 0, 0xc8, false); -+ sta_printk(XRADIO_DBG_MSG, "EDCA params Best effort for sta/p2p is " \ -+ "aifs=%u, cw_min=%u, cw_max=%u \n", -+ priv->edca.params[2].aifns, priv->edca.params[2].cwMin, -+ priv->edca.params[2].cwMax); -+#if 0 -+ }else { -+ WSM_EDCA_SET(&priv->edca, 2, 0x0003, 0x000f, 0x03ff, -+ 0, 0xc8, false); -+ sta_printk(XRADIO_DBG_MSG, "EDCA params Best effort for sta is " \ -+ "aifs=%u, cw_min=%u, cw_max=%u \n", -+ priv->edca.params[2].aifns, priv->edca.params[2].cwMin, -+ priv->edca.params[2].cwMax); -+ } -+#endif -+ WSM_EDCA_SET(&priv->edca, 3, 0x0007, 0x000f, 0x03ff, -+ 0, 0xc8, false); -+ -+ ret = wsm_set_edca_params(hw_priv, &priv->edca, priv->if_id); -+ if (WARN_ON(ret)) -+ goto out; -+ -+ ret = xradio_set_uapsd_param(priv, &priv->edca); -+ if (WARN_ON(ret)) -+ goto out; -+ -+ memset(priv->bssid, ~0, ETH_ALEN); -+ priv->wep_default_key_id = -1; -+ priv->cipherType = 0; -+ priv->cqm_link_loss_count = XRADIO_LINK_LOSS_THOLD_DEF; -+ priv->cqm_beacon_loss_count = XRADIO_BSS_LOSS_THOLD_DEF; -+ -+ /* Temporary configuration - beacon filter table */ -+ __xradio_bf_configure(priv); -+ -+out: -+ return ret; -+} -+ -+int xradio_setup_mac_pvif(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ /* NOTE: There is a bug in FW: it reports signal -+ * as RSSI if RSSI subscription is enabled. -+ * It's not enough to set WSM_RCPI_RSSI_USE_RSSI. */ -+ /* NOTE2: RSSI based reports have been switched to RCPI, since -+ * FW has a bug and RSSI reported values are not stable, -+ * what can leads to signal level oscilations in user-end applications */ -+ struct wsm_rcpi_rssi_threshold threshold = { -+ .rssiRcpiMode = WSM_RCPI_RSSI_THRESHOLD_ENABLE | -+ WSM_RCPI_RSSI_DONT_USE_UPPER | -+ WSM_RCPI_RSSI_DONT_USE_LOWER, -+ .rollingAverageCount = 16, -+ }; -+ -+ -+ /* Remember the decission here to make sure, we will handle -+ * the RCPI/RSSI value correctly on WSM_EVENT_RCPI_RSS */ -+ if (threshold.rssiRcpiMode & WSM_RCPI_RSSI_USE_RSSI) -+ priv->cqm_use_rssi = true; -+ -+ -+ /* Configure RSSI/SCPI reporting as RSSI. */ -+ ret = wsm_set_rcpi_rssi_threshold(priv->hw_priv, &threshold, priv->if_id); -+ return ret; -+} -+ -+void xradio_rem_chan_timeout(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, rem_chan_timeout.work); -+ int ret, if_id; -+ struct xradio_vif *priv; -+ -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ if(TES_P2P_0002_state == TES_P2P_0002_STATE_GET_PKTID) { -+ sta_printk(XRADIO_DBG_WARN, "[Restart rem_chan_timeout:Timeout]\n"); -+ return; -+ } -+#endif -+ -+ if (atomic_read(&hw_priv->remain_on_channel) == 0) { -+ return; -+ } -+ ieee80211_remain_on_channel_expired(hw_priv->hw); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ if_id = hw_priv->roc_if_id; -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_ERROR, "ROC TO IN %d\n", if_id); -+#endif -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, if_id); -+ ret = WARN_ON(__xradio_flush(hw_priv, false, if_id)); -+ if (!ret) { -+ xradio_disable_listening(priv); -+ } -+ atomic_set(&hw_priv->remain_on_channel, 0); -+ hw_priv->roc_if_id = -1; -+ -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_ERROR, "ROC TO OUT %d\n", if_id); -+#endif -+ -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+} -+const u8 *xradio_get_ie(u8 *start, size_t len, u8 ie) -+{ -+ u8 *end, *pos; -+ -+ -+ pos = start; -+ if (pos == NULL) -+ return NULL; -+ end = pos + len; -+ -+ while (pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ if (pos[0] == ie) -+ return pos; -+ pos += 2 + pos[1]; -+ } -+ -+ return NULL; -+} -+ -+/** -+ * xradio_set_macaddrfilter -called when tesmode command -+ * is for setting mac address filter -+ * -+ * @hw: the hardware -+ * @data: incoming data -+ * -+ * Returns: 0 on success or non zero value on failure -+ */ -+int xradio_set_macaddrfilter(struct xradio_common *hw_priv, struct xradio_vif *priv, u8 *data) -+{ -+ struct wsm_mac_addr_filter *mac_addr_filter = NULL; -+ struct wsm_mac_addr_info *addr_info = NULL; -+ u8 action_mode = 0, no_of_mac_addr = 0, i = 0; -+ int ret = 0; -+ u16 macaddrfiltersize = 0; -+ -+ -+ /* Retrieving Action Mode */ -+ action_mode = data[0]; -+ /* Retrieving number of address entries */ -+ no_of_mac_addr = data[1]; -+ -+ addr_info = (struct wsm_mac_addr_info *)&data[2]; -+ -+ /* Computing sizeof Mac addr filter */ -+ macaddrfiltersize = sizeof(*mac_addr_filter) + \ -+ (no_of_mac_addr * sizeof(struct wsm_mac_addr_info)); -+ -+ mac_addr_filter = kzalloc(macaddrfiltersize, GFP_KERNEL); -+ if (!mac_addr_filter) { -+ ret = -ENOMEM; -+ goto exit_p; -+ } -+ mac_addr_filter->action_mode = action_mode; -+ mac_addr_filter->numfilter = no_of_mac_addr; -+ -+ for (i = 0; i < no_of_mac_addr; i++) { -+ mac_addr_filter->macaddrfilter[i].address_mode = \ -+ addr_info[i].address_mode; -+ memcpy(mac_addr_filter->macaddrfilter[i].MacAddr, \ -+ addr_info[i].MacAddr , ETH_ALEN); -+ mac_addr_filter->macaddrfilter[i].filter_mode = \ -+ addr_info[i].filter_mode; -+ } -+ ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_MAC_ADDR_FILTER, \ -+ mac_addr_filter, macaddrfiltersize, priv->if_id)); -+ -+ kfree(mac_addr_filter); -+exit_p: -+ return ret; -+} -+ -+/** -+ * xradio_set_arpreply -called for creating and -+ * configuring arp response template frame -+ * -+ * @hw: the hardware -+ * -+ * Returns: 0 on success or non zero value on failure -+ */ -+int xradio_set_arpreply(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -+{ -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct xradio_common *hw_priv = (struct xradio_common *)hw->priv; -+ u32 framehdrlen, encrypthdr, encrypttailsize, framebdylen = 0; -+ bool encrypt = false; -+ int ret = 0; -+ u8 *template_frame = NULL; -+ struct ieee80211_hdr_3addr *dot11hdr = NULL; -+ struct ieee80211_snap_hdr *snaphdr = NULL; -+ struct arphdr *arp_hdr = NULL; -+ -+ -+ template_frame = kzalloc(MAX_ARP_REPLY_TEMPLATE_SIZE, GFP_KERNEL); -+ if (!template_frame) { -+ sta_printk(XRADIO_DBG_ERROR, "Template frame memory failed\n"); -+ ret = -ENOMEM; -+ goto exit_p; -+ } -+ dot11hdr = (struct ieee80211_hdr_3addr *)&template_frame[4]; -+ -+ framehdrlen = sizeof(*dot11hdr); -+ if ((priv->vif->type == NL80211_IFTYPE_AP) && priv->vif->p2p) -+ priv->cipherType = WLAN_CIPHER_SUITE_CCMP; -+ switch (priv->cipherType) { -+ -+ case WLAN_CIPHER_SUITE_WEP40: -+ case WLAN_CIPHER_SUITE_WEP104: -+ sta_printk(XRADIO_DBG_NIY, "WEP\n"); -+ encrypthdr = WEP_ENCRYPT_HDR_SIZE; -+ encrypttailsize = WEP_ENCRYPT_TAIL_SIZE; -+ encrypt = 1; -+ break; -+ -+ -+ case WLAN_CIPHER_SUITE_TKIP: -+ sta_printk(XRADIO_DBG_NIY, "WPA\n"); -+ encrypthdr = WPA_ENCRYPT_HDR_SIZE; -+ encrypttailsize = WPA_ENCRYPT_TAIL_SIZE; -+ encrypt = 1; -+ break; -+ -+ case WLAN_CIPHER_SUITE_CCMP: -+ sta_printk(XRADIO_DBG_NIY, "WPA2\n"); -+ encrypthdr = WPA2_ENCRYPT_HDR_SIZE; -+ encrypttailsize = WPA2_ENCRYPT_TAIL_SIZE; -+ encrypt = 1; -+ break; -+ -+ case WLAN_CIPHER_SUITE_SMS4: -+ sta_printk(XRADIO_DBG_NIY, "WAPI\n"); -+ encrypthdr = WAPI_ENCRYPT_HDR_SIZE; -+ encrypttailsize = WAPI_ENCRYPT_TAIL_SIZE; -+ encrypt = 1; -+ break; -+ -+ default: -+ encrypthdr = 0; -+ encrypttailsize = 0; -+ encrypt = 0; -+ break; -+ } -+ -+ framehdrlen += encrypthdr; -+ /* Filling the 802.11 Hdr */ -+ dot11hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA); -+ if (priv->vif->type == NL80211_IFTYPE_STATION) -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_TODS); -+ else -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_FROMDS); -+ -+ if (encrypt) -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_WEP); -+ -+ if (priv->vif->bss_conf.qos) { -+ sta_printk(XRADIO_DBG_NIY, "QOS Enabled\n"); -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_QOS_DATAGRP); -+ *(u16 *)(dot11hdr + 1) = 0x0; -+ framehdrlen += 2; -+ } else { -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_STYPE_DATA); -+ } -+ -+ memcpy(dot11hdr->addr1, priv->vif->bss_conf.bssid, ETH_ALEN); -+ memcpy(dot11hdr->addr2, priv->vif->addr, ETH_ALEN); -+ memcpy(dot11hdr->addr3, priv->vif->bss_conf.bssid, ETH_ALEN); -+ -+ /* Filling the LLC/SNAP Hdr */ -+ snaphdr = (struct ieee80211_snap_hdr *)((u8 *)dot11hdr + framehdrlen); -+ memcpy(snaphdr, (struct ieee80211_snap_hdr *)rfc1042_header, \ -+ sizeof(*snaphdr)); -+ *(u16 *)(++snaphdr) = cpu_to_be16(ETH_P_ARP); -+ /* Updating the framebdylen with snaphdr and LLC hdr size */ -+ framebdylen = sizeof(*snaphdr) + 2; -+ -+ /* Filling the ARP Reply Payload */ -+ arp_hdr = (struct arphdr *)((u8 *)dot11hdr + framehdrlen + framebdylen); -+ arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); -+ arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); -+ arp_hdr->ar_hln = ETH_ALEN; -+ arp_hdr->ar_pln = 4; -+ arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); -+ -+ /* Updating the frmbdylen with Arp Reply Hdr and Arp payload size(20) */ -+ framebdylen += sizeof(*arp_hdr) + 20; -+ -+ /* Updating the framebdylen with Encryption Tail Size */ -+ framebdylen += encrypttailsize; -+ -+ /* Filling the Template Frame Hdr */ -+ template_frame[0] = WSM_FRAME_TYPE_ARP_REPLY; /* Template frame type */ -+ template_frame[1] = 0xFF; /* Rate to be fixed */ -+ ((u16 *)&template_frame[2])[0] = framehdrlen + framebdylen; -+ -+ ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_TEMPLATE_FRAME, \ -+ template_frame, (framehdrlen+framebdylen+4), -+ priv->if_id)); -+ kfree(template_frame); -+exit_p: -+ return ret; -+} -+ -+#ifdef ROAM_OFFLOAD -+/** -+ * xradio_testmode_event -send asynchronous event -+ * to userspace -+ * -+ * @wiphy: the wiphy -+ * @msg_id: XR msg ID -+ * @data: data to be sent -+ * @len: data length -+ * @gfp: allocation flag -+ * -+ * Returns: 0 on success or non zero value on failure -+ */ -+int xradio_testmode_event(struct wiphy *wiphy, const u32 msg_id, -+ const void *data, int len, gfp_t gfp) -+{ -+ struct sk_buff *skb = NULL; -+ -+ -+ skb = cfg80211_testmode_alloc_event_skb(wiphy, -+ nla_total_size(len+sizeof(msg_id)), gfp); -+ -+ if (!skb) -+ return -ENOMEM; -+ -+ cfg80211_testmode_event(skb, gfp); -+ return 0; -+} -+#endif /*ROAM_OFFLOAD*/ -diff --git a/drivers/net/wireless/xradio/sta.h b/drivers/net/wireless/xradio/sta.h -new file mode 100644 -index 0000000..42ea2f6 ---- /dev/null -+++ b/drivers/net/wireless/xradio/sta.h -@@ -0,0 +1,122 @@ -+/* -+ * sta interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef STA_H_INCLUDED -+#define STA_H_INCLUDED -+ -+ -+#ifdef XRADIO_USE_LONG_KEEP_ALIVE_PERIOD -+#define XRADIO_KEEP_ALIVE_PERIOD (28) -+#else -+/*For Samsung, it is defined as 4*/ -+#define XRADIO_KEEP_ALIVE_PERIOD (4) -+#endif -+ -+#ifdef XRADIO_USE_LONG_DTIM_PERIOD -+#define XRADIO_BSS_LOSS_THOLD_DEF 30 -+#define XRADIO_LINK_LOSS_THOLD_DEF 50 -+#else -+#define XRADIO_BSS_LOSS_THOLD_DEF 20 -+#define XRADIO_LINK_LOSS_THOLD_DEF 40 -+#endif -+ -+/* ******************************************************************** */ -+/* mac80211 API */ -+ -+int xradio_start(struct ieee80211_hw *dev); -+void xradio_stop(struct ieee80211_hw *dev); -+int xradio_add_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif); -+void xradio_remove_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif); -+int xradio_change_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ enum nl80211_iftype new_type, -+ bool p2p); -+int xradio_config(struct ieee80211_hw *dev, u32 changed); -+int xradio_change_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ enum nl80211_iftype new_type, -+ bool p2p); -+void xradio_configure_filter(struct ieee80211_hw *dev, -+ unsigned int changed_flags, -+ unsigned int *total_flags, -+ u64 multicast); -+int xradio_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, -+ u16 queue, const struct ieee80211_tx_queue_params *params); -+int xradio_get_stats(struct ieee80211_hw *dev, -+ struct ieee80211_low_level_stats *stats); -+/* Not more a part of interface? -+int xradio_get_tx_stats(struct ieee80211_hw *dev, -+ struct ieee80211_tx_queue_stats *stats); -+*/ -+int xradio_set_rts_threshold(struct ieee80211_hw *hw, u32 value); -+ -+void xradio_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); -+ -+ -+int xradio_remain_on_channel(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_channel *chan, -+ int duration, enum ieee80211_roc_type type); -+int xradio_cancel_remain_on_channel(struct ieee80211_hw *hw); -+int xradio_set_arpreply(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -+u64 xradio_prepare_multicast(struct ieee80211_hw *hw, -+ struct netdev_hw_addr_list *mc_list); -+int xradio_set_pm(struct xradio_vif *priv, const struct wsm_set_pm *arg); -+void xradio_set_data_filter(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ void *data, -+ int len); -+ -+/* ******************************************************************** */ -+/* WSM callbacks */ -+ -+/* void xradio_set_pm_complete_cb(struct xradio_common *hw_priv, -+ struct wsm_set_pm_complete *arg); */ -+void xradio_channel_switch_cb(struct xradio_common *hw_priv); -+ -+/* ******************************************************************** */ -+/* WSM events */ -+ -+void xradio_free_event_queue(struct xradio_common *hw_priv); -+void xradio_event_handler(struct work_struct *work); -+void xradio_bss_loss_work(struct work_struct *work); -+void xradio_connection_loss_work(struct work_struct *work); -+void xradio_keep_alive_work(struct work_struct *work); -+void xradio_tx_failure_work(struct work_struct *work); -+ -+/* ******************************************************************** */ -+/* Internal API */ -+ -+int xradio_setup_mac(struct xradio_common *hw_priv); -+void xradio_join_work(struct work_struct *work); -+void xradio_join_timeout(struct work_struct *work); -+void xradio_unjoin_work(struct work_struct *work); -+void xradio_offchannel_work(struct work_struct *work); -+void xradio_wep_key_work(struct work_struct *work); -+void xradio_update_filtering(struct xradio_vif *priv); -+void xradio_update_filtering_work(struct work_struct *work); -+int __xradio_flush(struct xradio_common *hw_priv, bool drop, int if_id); -+void xradio_set_beacon_wakeup_period_work(struct work_struct *work); -+int xradio_enable_listening(struct xradio_vif *priv, struct ieee80211_channel *chan); -+int xradio_disable_listening(struct xradio_vif *priv); -+int xradio_set_uapsd_param(struct xradio_vif *priv, const struct wsm_edca_params *arg); -+void xradio_ba_work(struct work_struct *work); -+void xradio_ba_timer(struct timer_list *t); -+const u8 *xradio_get_ie(u8 *start, size_t len, u8 ie); -+int xradio_vif_setup(struct xradio_vif *priv); -+int xradio_setup_mac_pvif(struct xradio_vif *priv); -+void xradio_iterate_vifs(void *data, u8 *mac, struct ieee80211_vif *vif); -+void xradio_rem_chan_timeout(struct work_struct *work); -+int xradio_set_macaddrfilter(struct xradio_common *hw_priv, struct xradio_vif *priv, u8 *data); -+#ifdef ROAM_OFFLOAD -+int xradio_testmode_event(struct wiphy *wiphy, const u32 msg_id, -+ const void *data, int len, gfp_t gfp); -+#endif /*ROAM_OFFLOAD*/ -+#endif -diff --git a/drivers/net/wireless/xradio/tx.c b/drivers/net/wireless/xradio/tx.c -new file mode 100644 -index 0000000..72c04ef ---- /dev/null -+++ b/drivers/net/wireless/xradio/tx.c -@@ -0,0 +1,1455 @@ -+/* -+ * Datapath implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "wsm.h" -+#include "bh.h" -+#include "ap.h" -+#include "sta.h" -+#include "sdio.h" -+#include "common.h" -+#include "p2p.h" -+ -+#define B_RATE_INDEX 0 //11b rate for important short frames in 2.4G. -+#define AG_RATE_INDEX 6 //11a/g rate for important short frames in 5G. -+#define XRADIO_INVALID_RATE_ID (0xFF) -+ -+/* rate should fall quickly to avoid dropping frames by aps. -+ * Add by yangfh 2014-9-22 13:39:57 -+ */ -+#define HIGH_RATE_MAX_RETRY 7 -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+#include -+#endif -+ -+//for test yangfh -+extern u32 tx_retrylimit; -+extern u32 tx_over_limit; -+extern u32 tx_lower_limit; -+extern int retry_mis; -+ -+static const struct ieee80211_rate * -+xradio_get_tx_rate(const struct xradio_common *hw_priv, -+ const struct ieee80211_tx_rate *rate); -+ -+/* ******************************************************************** */ -+/* TX policy cache implementation */ -+ -+static void tx_policy_dump(struct tx_policy *policy) -+{ -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] " -+ "%.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X" -+ "%.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X" -+ "%.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X: %d\n", -+ policy->raw[0] & 0x0F, policy->raw[0] >> 4, -+ policy->raw[1] & 0x0F, policy->raw[1] >> 4, -+ policy->raw[2] & 0x0F, policy->raw[2] >> 4, -+ policy->raw[3] & 0x0F, policy->raw[3] >> 4, -+ policy->raw[4] & 0x0F, policy->raw[4] >> 4, -+ policy->raw[5] & 0x0F, policy->raw[5] >> 4, -+ policy->raw[6] & 0x0F, policy->raw[6] >> 4, -+ policy->raw[7] & 0x0F, policy->raw[7] >> 4, -+ policy->raw[8] & 0x0F, policy->raw[8] >> 4, -+ policy->raw[9] & 0x0F, policy->raw[9] >> 4, -+ policy->raw[10] & 0x0F, policy->raw[10] >> 4, -+ policy->raw[11] & 0x0F, policy->raw[11] >> 4, -+ policy->defined); -+} -+ -+static void xradio_check_go_neg_conf_success(struct xradio_common *hw_priv, -+ u8 *action) -+{ -+ if (action[2] == 0x50 && action[3] == 0x6F && action[4] == 0x9A && -+ action[5] == 0x09 && action[6] == 0x02) { -+ if(action[17] == 0) { -+ hw_priv->is_go_thru_go_neg = true; -+ } -+ else { -+ hw_priv->is_go_thru_go_neg = false; -+ } -+ } -+} -+ -+static void xradio_check_prov_desc_req(struct xradio_common *hw_priv, -+ u8 *action) -+{ -+ if (action[2] == 0x50 && action[3] == 0x6F && action[4] == 0x9A && -+ action[5] == 0x09 && action[6] == 0x07) { -+ hw_priv->is_go_thru_go_neg = false; -+ } -+} -+ -+//modified by yangfh -+static void tx_policy_build(const struct xradio_common *hw_priv, -+ /* [out] */ struct tx_policy *policy, -+ struct ieee80211_tx_rate *rates, size_t count) -+{ -+ int i, j; -+ struct ieee80211_rate * tmp_rate = NULL; -+ unsigned limit = hw_priv->short_frame_max_tx_count; -+ unsigned max_rates_cnt = count; -+ unsigned total = 0; -+ BUG_ON(rates[0].idx < 0); -+ memset(policy, 0, sizeof(*policy)); -+ -+ -+ txrx_printk(XRADIO_DBG_NIY,"============================"); -+#if 0 -+ //debug yangfh -+ for (i = 0; i < count; ++i) { -+ if(rates[i].idx>=0) { -+ tmp_rate = xradio_get_tx_rate(hw_priv, &rates[i]); -+ txrx_printk(XRADIO_DBG_NIY,"[TX policy] Org %d.%dMps=%d", -+ tmp_rate->bitrate/10, tmp_rate->bitrate%10, rates[i].count); -+ } -+ } -+ txrx_printk(XRADIO_DBG_NIY,"----------------------------"); -+#endif -+ -+ /* minstrel is buggy a little bit, so distille -+ * incoming rates first. -+ */ -+ /* Sort rates in descending order. */ -+ total = rates[0].count; -+ for (i = 1; i < count; ++i) { -+ if (rates[i].idx > rates[i-1].idx) { -+ rates[i].idx = rates[i-1].idx>0?(rates[i-1].idx-1):-1; -+ } -+ if (rates[i].idx < 0 || i>=limit) { -+ count = i; -+ break; -+ } else { -+ total += rates[i].count; -+ } -+ } -+ -+ /* Add lowest rate to the end when 11a/n. -+ * Don't apply in 11b/g because p2p unsupport 1Mbps. -+ * TODO: it's better to do this in rate control of mac80211. -+ */ -+ if (((rates[0].flags & IEEE80211_TX_RC_MCS) || -+ hw_priv->channel->band == NL80211_BAND_5GHZ) && -+ count < max_rates_cnt && rates[count-1].idx != 0) { -+ rates[count].idx = 0; -+ rates[count].count = rates[0].count; -+ rates[count].flags = rates[0].flags; -+ total += rates[count].count; -+ count++; -+ } -+ -+ /* adjust tx count to limit, rates should fall quickly -+ * and lower rates should be more retry, because reorder -+ * buffer of reciever will be timeout and clear probably. -+ */ -+ if (count < 2) { -+ rates[0].count = limit; -+ total = limit; -+ } else { -+ u8 end_retry = 0; //the retry should be add to last rate. -+ if (limit > HIGH_RATE_MAX_RETRY) { -+ end_retry = limit - HIGH_RATE_MAX_RETRY; -+ limit = HIGH_RATE_MAX_RETRY; -+ } -+ for (i = 0; (limit != total) && (i < 100); ++i) { //i<100 to avoid dead loop -+ j = i % count; -+ if(limit < total) { -+ total += (rates[j].count > 1? -1 : 0); -+ rates[j].count += (rates[j].count > 1? -1 : 0); -+ } else { -+ j = count - 1 - j; -+ if (rates[j].count > 0) { -+ total++; -+ rates[j].count++; -+ } -+ } -+ } -+ if (end_retry) { -+ rates[count-1].count += end_retry; -+ limit += end_retry; -+ } -+ } -+ -+ /* Eliminate duplicates. */ -+ total = rates[0].count; -+ for (i = 0, j = 1; j < count; ++j) { -+ if (rates[j].idx == rates[i].idx) { -+ rates[i].count += rates[j].count; -+ } else if (rates[j].idx > rates[i].idx) { -+ break; -+ } else { -+ ++i; -+ if (i != j) -+ rates[i] = rates[j]; -+ } -+ total += rates[j].count; -+ } -+ count = i + 1; -+ -+ /* Re-fill policy trying to keep every requested rate and with -+ * respect to the global max tx retransmission count. -+ */ -+ if (limit < count) -+ limit = count; -+ if (total > limit) { -+ for (i = 0; i < count; ++i) { -+ int left = count - i - 1; -+ if (rates[i].count > limit - left) -+ rates[i].count = limit - left; -+ limit -= rates[i].count; -+ } -+ } -+ -+ /* HACK!!! Device has problems (at least) switching from -+ * 54Mbps CTS to 1Mbps. This switch takes enormous amount -+ * of time (100-200 ms), leading to valuable throughput drop. -+ * As a workaround, additional g-rates are injected to the -+ * policy. -+ */ -+ if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) && -+ rates[0].idx > 4 && rates[0].count > 2 && -+ rates[1].idx < 2) { -+ /* ">> 1" is an equivalent of "/ 2", but faster */ -+ int mid_rate = (rates[0].idx + 4) >> 1; -+ -+ /* Decrease number of retries for the initial rate */ -+ rates[0].count -= 2; -+ -+ if (mid_rate != 4) { -+ /* Keep fallback rate at 1Mbps. */ -+ rates[3] = rates[1]; -+ -+ /* Inject 1 transmission on lowest g-rate */ -+ rates[2].idx = 4; -+ rates[2].count = 1; -+ rates[2].flags = rates[1].flags; -+ -+ /* Inject 1 transmission on mid-rate */ -+ rates[1].idx = mid_rate; -+ rates[1].count = 1; -+ -+ /* Fallback to 1 Mbps is a really bad thing, -+ * so let's try to increase probability of -+ * successful transmission on the lowest g rate -+ * even more */ -+ if (rates[0].count >= 3) { -+ --rates[0].count; -+ ++rates[2].count; -+ } -+ -+ /* Adjust amount of rates defined */ -+ count += 2; -+ } else { -+ /* Keep fallback rate at 1Mbps. */ -+ rates[2] = rates[1]; -+ -+ /* Inject 2 transmissions on lowest g-rate */ -+ rates[1].idx = 4; -+ rates[1].count = 2; -+ -+ /* Adjust amount of rates defined */ -+ count += 1; -+ } -+ } -+ -+ tmp_rate = (struct ieee80211_rate *)xradio_get_tx_rate(hw_priv, &rates[0]); -+ if(tmp_rate) -+ policy->defined = tmp_rate->hw_value + 1; -+ -+ for (i = 0; i < count; ++i) { -+ register unsigned rateid, off, shift, retries; -+ -+ tmp_rate = (struct ieee80211_rate *)xradio_get_tx_rate(hw_priv, &rates[i]); -+ if(tmp_rate) { -+ rateid = tmp_rate->hw_value; -+ } else { -+ break; -+ } -+ off = rateid >> 3; /* eq. rateid / 8 */ -+ shift = (rateid & 0x07) << 2; /* eq. (rateid % 8) * 4 */ -+ -+ retries = rates[i].count; -+ if (unlikely(retries > 0x0F)) -+ rates[i].count = retries = 0x0F; -+ policy->tbl[off] |= __cpu_to_le32(retries << shift); -+ policy->retry_count += retries; -+ txrx_printk(XRADIO_DBG_NIY,"[TX policy] %d.%dMps=%d", -+ tmp_rate->bitrate/10, tmp_rate->bitrate%10, retries); -+ } -+ -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] Dst Policy (%d): " \ -+ "%d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n", -+ count, -+ rates[0].idx, rates[0].count, -+ rates[1].idx, rates[1].count, -+ rates[2].idx, rates[2].count, -+ rates[3].idx, rates[3].count, -+ rates[4].idx, rates[4].count); -+} -+ -+static inline bool tx_policy_is_equal(const struct tx_policy *wanted, -+ const struct tx_policy *cached) -+{ -+ size_t count = wanted->defined >> 1; -+ -+ if (wanted->defined > cached->defined) -+ return false; -+ if (count) { -+ if (memcmp(wanted->raw, cached->raw, count)) -+ return false; -+ } -+ if (wanted->defined & 1) { -+ if ((wanted->raw[count] & 0x0F) != (cached->raw[count] & 0x0F)) -+ return false; -+ } -+ return true; -+} -+ -+static int tx_policy_find(struct tx_policy_cache *cache, -+ const struct tx_policy *wanted) -+{ -+ /* O(n) complexity. Not so good, but there's only 8 entries in -+ * the cache. -+ * Also lru helps to reduce search time. */ -+ struct tx_policy_cache_entry *it; -+ /* Search for policy in "used" list */ -+ list_for_each_entry(it, &cache->used, link) { -+ if (tx_policy_is_equal(wanted, &it->policy)) -+ return it - cache->cache; -+ } -+ /* Then - in "free list" */ -+ list_for_each_entry(it, &cache->free, link) { -+ if (tx_policy_is_equal(wanted, &it->policy)) -+ return it - cache->cache; -+ } -+ return -1; -+} -+ -+static inline void tx_policy_use(struct tx_policy_cache *cache, -+ struct tx_policy_cache_entry *entry) -+{ -+ ++entry->policy.usage_count; -+ list_move(&entry->link, &cache->used); -+} -+ -+static inline int tx_policy_release(struct tx_policy_cache *cache, -+ struct tx_policy_cache_entry *entry) -+{ -+ int ret = --entry->policy.usage_count; -+ if (!ret) -+ list_move(&entry->link, &cache->free); -+ return ret; -+} -+ -+/* ******************************************************************** */ -+/* External TX policy cache API */ -+ -+void tx_policy_init(struct xradio_common *hw_priv) -+{ -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ int i; -+ -+ memset(cache, 0, sizeof(*cache)); -+ -+ spin_lock_init(&cache->lock); -+ INIT_LIST_HEAD(&cache->used); -+ INIT_LIST_HEAD(&cache->free); -+ -+ for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) -+ list_add(&cache->cache[i].link, &cache->free); -+} -+ -+static int tx_policy_get(struct xradio_common *hw_priv, -+ struct ieee80211_tx_rate *rates, -+ u8 use_bg_rate, bool *renew) -+{ -+ int idx; -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ struct tx_policy wanted; -+ -+ -+ if(use_bg_rate) { -+ u8 rate = (u8)(use_bg_rate & 0x3f); -+ u8 shitf = ((rate&0x7)<<2); -+ u8 off = (rate>>3); -+ memset(&wanted, 0, sizeof(wanted)); -+ wanted.defined = rate + 1; -+ wanted.retry_count = (hw_priv->short_frame_max_tx_count&0xf); -+ wanted.tbl[off] = wanted.retry_count<lock); -+ idx = tx_policy_find(cache, &wanted); -+ if (idx >= 0) { -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] Used TX policy: %d\n", -+ idx); -+ *renew = false; -+ } else { -+ struct tx_policy_cache_entry *entry; -+ if (WARN_ON_ONCE(list_empty(&cache->free))) { -+ spin_unlock_bh(&cache->lock); -+ txrx_printk(XRADIO_DBG_ERROR, "[TX policy] no policy cache\n"); -+ return XRADIO_INVALID_RATE_ID; -+ } -+ /* If policy is not found create a new one -+ * using the oldest entry in "free" list */ -+ *renew = true; -+ entry = list_entry(cache->free.prev, -+ struct tx_policy_cache_entry, link); -+ entry->policy = wanted; -+ idx = entry - cache->cache; -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] New TX policy: %d\n", -+ idx); -+ tx_policy_dump(&entry->policy); -+ } -+ tx_policy_use(cache, &cache->cache[idx]); -+ if (unlikely(list_empty(&cache->free))) { -+ /* Lock TX queues. */ -+ txrx_printk(XRADIO_DBG_WARN, "[TX policy] policy cache used up\n"); -+ xradio_tx_queues_lock(hw_priv); -+ } -+ spin_unlock_bh(&cache->lock); -+ -+ return idx; -+} -+ -+static void tx_policy_put(struct xradio_common *hw_priv, int idx) -+{ -+ int usage, locked; -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ -+ spin_lock_bh(&cache->lock); -+ locked = list_empty(&cache->free); -+ usage = tx_policy_release(cache, &cache->cache[idx]); -+ if (unlikely(locked) && !usage) { -+ /* Unlock TX queues. */ -+ xradio_tx_queues_unlock(hw_priv); -+ } -+ spin_unlock_bh(&cache->lock); -+} -+ -+/* -+bool tx_policy_cache_full(struct xradio_common *hw_priv) -+{ -+ bool ret; -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ spin_lock_bh(&cache->lock); -+ ret = list_empty(&cache->free); -+ spin_unlock_bh(&cache->lock); -+ return ret; -+} -+*/ -+extern u32 policy_upload; -+extern u32 policy_num; -+static int tx_policy_upload(struct xradio_common *hw_priv) -+{ -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ int i; -+ struct wsm_set_tx_rate_retry_policy arg = { -+ .hdr = { -+ .numTxRatePolicies = 0, -+ } -+ }; -+ int if_id = 0; -+ -+ spin_lock_bh(&cache->lock); -+ /* Upload only modified entries. */ -+ for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) { -+ struct tx_policy *src = &cache->cache[i].policy; -+ if (src->retry_count && !src->uploaded) { -+ struct wsm_set_tx_rate_retry_policy_policy *dst = -+ &arg.tbl[arg.hdr.numTxRatePolicies]; -+ dst->policyIndex = i; -+ dst->shortRetryCount = hw_priv->short_frame_max_tx_count-1; -+ //only RTS need use longRetryCount, should be short_frame. -+ dst->longRetryCount = hw_priv->short_frame_max_tx_count-1; -+ -+ /* BIT(2) - Terminate retries when Tx rate retry policy -+ * finishes. -+ * BIT(3) - Count initial frame transmission as part of -+ * rate retry counting but not as a retry -+ * attempt */ -+ dst->policyFlags = BIT(2) | BIT(3); -+ memcpy(dst->rateCountIndices, src->tbl, -+ sizeof(dst->rateCountIndices)); -+ src->uploaded = 1; -+ ++arg.hdr.numTxRatePolicies; -+ } -+ } -+ spin_unlock_bh(&cache->lock); -+ atomic_set(&hw_priv->upload_count, 0); -+ -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] Upload %d policies\n", -+ arg.hdr.numTxRatePolicies); -+ -+ /*TODO: COMBO*/ -+ return wsm_set_tx_rate_retry_policy(hw_priv, &arg, if_id); -+} -+ -+void tx_policy_upload_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, tx_policy_upload_work); -+ -+ WARN_ON(tx_policy_upload(hw_priv)); -+ wsm_unlock_tx(hw_priv); -+} -+ -+/* ******************************************************************** */ -+/* xradio TX implementation */ -+ -+struct xradio_txinfo { -+ struct sk_buff *skb; -+ unsigned queue; -+ struct ieee80211_tx_info *tx_info; -+ const struct ieee80211_rate *rate; -+ struct ieee80211_hdr *hdr; -+ size_t hdrlen; -+ const u8 *da; -+ struct xradio_sta_priv *sta_priv; -+ struct xradio_txpriv txpriv; -+}; -+ -+u32 xradio_rate_mask_to_wsm(struct xradio_common *hw_priv, u32 rates) -+{ -+ u32 ret = 0; -+ int i; -+ u32 n_bitrates = -+ hw_priv->hw->wiphy->bands[hw_priv->channel->band]->n_bitrates; -+ struct ieee80211_rate * bitrates = -+ hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates; -+ -+ for (i = 0; i < n_bitrates; ++i) { -+ if (rates & BIT(i)) -+ ret |= BIT(bitrates[i].hw_value); -+ } -+ return ret; -+} -+ -+static const struct ieee80211_rate * -+xradio_get_tx_rate(const struct xradio_common *hw_priv, -+ const struct ieee80211_tx_rate *rate) -+{ -+ if (rate->idx < 0) -+ return NULL; -+ if (rate->flags & IEEE80211_TX_RC_MCS) -+ return &hw_priv->mcs_rates[rate->idx]; -+ return &hw_priv->hw->wiphy->bands[hw_priv->channel->band]-> -+ bitrates[rate->idx]; -+} -+ -+inline static s8 -+xradio_get_rate_idx(const struct xradio_common *hw_priv, u8 flag, u16 hw_value) -+{ -+ s16 ret = (s16)hw_value; -+ if(flag & IEEE80211_TX_RC_MCS) { //11n -+ if(hw_value <= hw_priv->mcs_rates[7].hw_value && -+ hw_value >= hw_priv->mcs_rates[0].hw_value) -+ ret -= hw_priv->mcs_rates[0].hw_value; -+ else -+ ret = -1; -+ } else { //11b/g -+ if(hw_value>5 && hw_valuemcs_rates[0].hw_value) { -+ ret -= hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates[0].hw_value; -+ if(hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates[0].hw_value<5) //11a -+ ret -= 2; -+ } else if(hw_value<4) { -+ ret -= hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates[0].hw_value; -+ } else { -+ ret = -1; -+ } -+ } -+ return (s8)ret; -+} -+ -+static int -+xradio_tx_h_calc_link_ids(struct xradio_vif *priv, -+ struct ieee80211_tx_control *control, -+ struct xradio_txinfo *t) -+{ -+ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ if ((t->tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || -+ (hw_priv->roc_if_id == priv->if_id)) -+ t->txpriv.offchannel_if_id = 2; -+ else -+ t->txpriv.offchannel_if_id = 0; -+ -+ if (likely(control->sta && t->sta_priv->link_id)) -+ t->txpriv.raw_link_id = -+ t->txpriv.link_id = -+ t->sta_priv->link_id; -+ else if (priv->mode != NL80211_IFTYPE_AP) -+ t->txpriv.raw_link_id = -+ t->txpriv.link_id = 0; -+ else if (is_multicast_ether_addr(t->da)) { -+ if (priv->enable_beacon) { -+ t->txpriv.raw_link_id = 0; -+ t->txpriv.link_id = priv->link_id_after_dtim; -+ } else { -+ t->txpriv.raw_link_id = 0; -+ t->txpriv.link_id = 0; -+ } -+ } else { -+ t->txpriv.link_id = -+ xradio_find_link_id(priv, t->da); -+ /* Do not assign valid link id for deauth/disassoc frame being -+ transmitted to an unassociated STA */ -+ if (!(t->txpriv.link_id) && -+ (ieee80211_is_deauth(t->hdr->frame_control) || -+ ieee80211_is_disassoc(t->hdr->frame_control))) { -+ t->txpriv.link_id = 0; -+ } else { -+ if (!t->txpriv.link_id) -+ t->txpriv.link_id = xradio_alloc_link_id(priv, t->da); -+ if (!t->txpriv.link_id) { -+ txrx_printk(XRADIO_DBG_ERROR, -+ "%s: No more link IDs available.\n", __func__); -+ return -ENOENT; -+ } -+ } -+ t->txpriv.raw_link_id = t->txpriv.link_id; -+ } -+ if (t->txpriv.raw_link_id) -+ priv->link_id_db[t->txpriv.raw_link_id - 1].timestamp = -+ jiffies; -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ if (control->sta && -+ (control->sta->uapsd_queues & BIT(t->queue))) -+ t->txpriv.link_id = priv->link_id_uapsd; -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ return 0; -+} -+ -+static void -+xradio_tx_h_pm(struct xradio_vif *priv, -+ struct xradio_txinfo *t) -+{ -+ if (unlikely(ieee80211_is_auth(t->hdr->frame_control))) { -+ u32 mask = ~BIT(t->txpriv.raw_link_id); -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->sta_asleep_mask &= mask; -+ priv->pspoll_mask &= mask; -+ spin_unlock_bh(&priv->ps_state_lock); -+ } -+} -+ -+static void -+xradio_tx_h_calc_tid(struct xradio_vif *priv, -+ struct xradio_txinfo *t) -+{ -+ if (ieee80211_is_data_qos(t->hdr->frame_control)) { -+ u8 *qos = ieee80211_get_qos_ctl(t->hdr); -+ t->txpriv.tid = qos[0] & IEEE80211_QOS_CTL_TID_MASK; -+ } else if (ieee80211_is_data(t->hdr->frame_control)) { -+ t->txpriv.tid = 0; -+ } -+} -+ -+/* IV/ICV injection. */ -+/* TODO: Quite unoptimal. It's better co modify mac80211 -+ * to reserve space for IV */ -+static int -+xradio_tx_h_crypt(struct xradio_vif *priv, -+ struct xradio_txinfo *t) -+{ -+ size_t iv_len; -+ size_t icv_len; -+ u8 *icv; -+ -+ if (!t->tx_info->control.hw_key || -+ !(t->hdr->frame_control & -+ __cpu_to_le32(IEEE80211_FCTL_PROTECTED))) -+ return 0; -+ -+ iv_len = t->tx_info->control.hw_key->iv_len; -+ icv_len = t->tx_info->control.hw_key->icv_len; -+ -+ if (t->tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) -+ icv_len += 8; /* MIC */ -+ -+ if (unlikely((skb_headroom(t->skb) + skb_tailroom(t->skb) < -+ iv_len + icv_len + WSM_TX_EXTRA_HEADROOM) || -+ (skb_headroom(t->skb) < -+ iv_len + WSM_TX_EXTRA_HEADROOM))) { -+ dev_dbg(priv->hw_priv->pdev, -+ "no space allocated for crypto headers.\n" -+ "headroom: %d, tailroom: %d, " -+ "req_headroom: %d, req_tailroom: %d\n" -+ "Please fix it in xradio_get_skb().\n", -+ skb_headroom(t->skb), skb_tailroom(t->skb), -+ iv_len + WSM_TX_EXTRA_HEADROOM, icv_len); -+ return -ENOMEM; -+ } else if (unlikely(skb_tailroom(t->skb) < icv_len)) { -+ size_t offset = icv_len - skb_tailroom(t->skb); -+ u8 *p; -+ dev_dbg(priv->hw_priv->pdev, -+ "Slowpath: tailroom is not big enough. " -+ "Req: %d, got: %d.\n", -+ icv_len, skb_tailroom(t->skb)); -+ -+ p = skb_push(t->skb, offset); -+ memmove(p, &p[offset], t->skb->len - offset); -+ skb_trim(t->skb, t->skb->len - offset); -+ } -+ /* ccmp pkt from umac to driver,it has iv room,,so ccmp pkt do not add iv room */ -+ if (t->tx_info->control.hw_key->cipher != WLAN_CIPHER_SUITE_CCMP){ -+ u8 *newhdr; -+ newhdr = skb_push(t->skb, iv_len); -+ memmove(newhdr, newhdr + iv_len, t->hdrlen); -+ t->hdr = (struct ieee80211_hdr *) newhdr; -+ } -+ t->hdrlen += iv_len; -+ icv = skb_put(t->skb, icv_len); -+ -+ return 0; -+} -+ -+static int -+xradio_tx_h_align(struct xradio_vif *priv, struct xradio_txinfo *t, -+ u8 *flags) -+{ -+ size_t offset = (size_t)t->skb->data & 3; -+ u8 *newhdr;//add by dingxh -+ -+ -+ if (!offset) -+ return 0; -+ -+ if (skb_headroom(t->skb) < offset) { -+ txrx_printk(XRADIO_DBG_ERROR, -+ "Bug: no space allocated " -+ "for DMA alignment.\n" -+ "headroom: %d\n", -+ skb_headroom(t->skb)); -+ return -ENOMEM; -+ } -+ //offset = 1or3 process add by dingxh -+ if (offset & 1) { -+ newhdr = skb_push(t->skb, offset); -+ memmove(newhdr, newhdr + offset, t->skb->len-offset); -+ skb_trim(t->skb, t->skb->len-offset); -+ t->hdr = (struct ieee80211_hdr *) newhdr; -+ return 0; -+ } -+ //add by dingxh -+ //offset=2 process -+ skb_push(t->skb, offset); -+ t->hdrlen += offset; -+ t->txpriv.offset += offset; -+ *flags |= WSM_TX_2BYTES_SHIFT; -+ return 0; -+} -+ -+static int -+xradio_tx_h_action(struct xradio_vif *priv, struct xradio_txinfo *t) -+{ -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)t->hdr; -+ -+ if (ieee80211_is_action(t->hdr->frame_control) && -+ mgmt->u.action.category == WLAN_CATEGORY_BACK) -+ return 1; -+ else -+ return 0; -+} -+ -+/* Add WSM header */ -+static struct wsm_tx * -+xradio_tx_h_wsm(struct xradio_vif *priv, struct xradio_txinfo *t) -+{ -+ struct wsm_tx *wsm; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ if (skb_headroom(t->skb) < sizeof(struct wsm_tx)) { -+ txrx_printk(XRADIO_DBG_ERROR, -+ "Bug: no space allocated " -+ "for WSM header.\n" -+ "headroom: %d\n", -+ skb_headroom(t->skb)); -+ return NULL; -+ } -+ -+ wsm = (struct wsm_tx *)skb_push(t->skb, sizeof(struct wsm_tx)); -+ t->txpriv.offset += sizeof(struct wsm_tx); -+ memset(wsm, 0, sizeof(*wsm)); -+ wsm->hdr.len = __cpu_to_le16(t->skb->len); -+ wsm->hdr.id = __cpu_to_le16(0x0004); -+ wsm->queueId = (t->txpriv.raw_link_id << 2) | wsm_queue_id_to_wsm(t->queue); -+ if (wsm->hdr.len > hw_priv->wsm_caps.sizeInpChBuf) { -+ txrx_printk(XRADIO_DBG_ERROR,"%s,msg length too big=%d\n", -+ __func__, wsm->hdr.len); -+ wsm = NULL; -+ } -+ -+ return wsm; -+} -+ -+/* BT Coex specific handling */ -+static void -+xradio_tx_h_bt(struct xradio_vif *priv, struct xradio_txinfo *t, struct wsm_tx *wsm) -+{ -+ u8 priority = 0; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ if (!hw_priv->is_BT_Present) -+ return; -+ -+ if (unlikely(ieee80211_is_nullfunc(t->hdr->frame_control))) -+ priority = WSM_EPTA_PRIORITY_MGT; -+ else if (ieee80211_is_data(t->hdr->frame_control)) { -+ /* Skip LLC SNAP header (+6) */ -+ u8 *payload = &t->skb->data[t->hdrlen]; -+ u16 *ethertype = (u16 *) &payload[6]; -+ if (unlikely(*ethertype == __be16_to_cpu(ETH_P_PAE))) -+ priority = WSM_EPTA_PRIORITY_EAPOL; -+ } else if (unlikely(ieee80211_is_assoc_req(t->hdr->frame_control) || -+ ieee80211_is_reassoc_req(t->hdr->frame_control))) { -+ struct ieee80211_mgmt *mgt_frame = -+ (struct ieee80211_mgmt *)t->hdr; -+ -+ if (mgt_frame->u.assoc_req.listen_interval < -+ priv->listen_interval) { -+ txrx_printk(XRADIO_DBG_MSG, -+ "Modified Listen Interval to %d from %d\n", -+ priv->listen_interval, -+ mgt_frame->u.assoc_req.listen_interval); -+ /* Replace listen interval derieved from -+ * the one read from SDD */ -+ mgt_frame->u.assoc_req.listen_interval = -+ priv->listen_interval; -+ } -+ } -+ -+ if (likely(!priority)) { -+ if (ieee80211_is_action(t->hdr->frame_control)) -+ priority = WSM_EPTA_PRIORITY_ACTION; -+ else if (ieee80211_is_mgmt(t->hdr->frame_control)) -+ priority = WSM_EPTA_PRIORITY_MGT; -+ else if ((wsm->queueId == WSM_QUEUE_VOICE)) -+ priority = WSM_EPTA_PRIORITY_VOICE; -+ else if ((wsm->queueId == WSM_QUEUE_VIDEO)) -+ priority = WSM_EPTA_PRIORITY_VIDEO; -+ else -+ priority = WSM_EPTA_PRIORITY_DATA; -+ } -+ -+ txrx_printk(XRADIO_DBG_MSG, "[TX] EPTA priority %d.\n", -+ priority); -+ -+ wsm->flags |= priority << 1; -+} -+ -+static int -+xradio_tx_h_rate_policy(struct xradio_common *hw_priv, struct xradio_txinfo *t, -+ struct wsm_tx *wsm) -+{ -+ bool tx_policy_renew = false; -+ struct xradio_vif *priv = -+ xrwl_get_vif_from_ieee80211(t->tx_info->control.vif); -+ -+ t->txpriv.rate_id = tx_policy_get(hw_priv, -+ t->tx_info->control.rates, t->txpriv.use_bg_rate, -+ &tx_policy_renew); -+ if (t->txpriv.rate_id == XRADIO_INVALID_RATE_ID) -+ return -EFAULT; -+ -+ wsm->flags |= t->txpriv.rate_id << 4; -+ t->rate = xradio_get_tx_rate(hw_priv, &t->tx_info->control.rates[0]); -+ if (t->txpriv.use_bg_rate) -+ wsm->maxTxRate = (u8)(t->txpriv.use_bg_rate & 0x3f); -+ else -+ wsm->maxTxRate = t->rate->hw_value; -+ -+ if (t->rate->flags & IEEE80211_TX_RC_MCS) { -+ if (priv->association_mode.greenfieldMode) -+ wsm->htTxParameters |= -+ __cpu_to_le32(WSM_HT_TX_GREENFIELD); -+ else -+ wsm->htTxParameters |= -+ __cpu_to_le32(WSM_HT_TX_MIXED); -+ } -+ -+ if (tx_policy_renew) { -+ txrx_printk(XRADIO_DBG_MSG, "[TX] TX policy renew.\n"); -+ /* It's not so optimal to stop TX queues every now and then. -+ * Maybe it's better to reimplement task scheduling with -+ * a counter. */ -+ /* xradio_tx_queues_lock(priv); */ -+ /* Definetly better. TODO. */ -+ if (atomic_add_return(1, &hw_priv->upload_count) == 1) { -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, -+ &hw_priv->tx_policy_upload_work) <= 0) { -+ atomic_set(&hw_priv->upload_count, 0); -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+ } -+ return 0; -+} -+ -+static bool -+xradio_tx_h_pm_state(struct xradio_vif *priv, struct xradio_txinfo *t) -+{ -+ int was_buffered = 1; -+ -+ -+ if (t->txpriv.link_id == priv->link_id_after_dtim && -+ !priv->buffered_multicasts) { -+ priv->buffered_multicasts = true; -+ if (priv->sta_asleep_mask) -+ queue_work(priv->hw_priv->workqueue, -+ &priv->multicast_start_work); -+ } -+ -+ if (t->txpriv.raw_link_id && t->txpriv.tid < XRADIO_MAX_TID) -+ was_buffered = priv->link_id_db[t->txpriv.raw_link_id - 1] -+ .buffered[t->txpriv.tid]++; -+ -+ return !was_buffered; -+} -+ -+static void -+xradio_tx_h_ba_stat(struct xradio_vif *priv, -+ struct xradio_txinfo *t) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_STA) -+ return; -+ if (!xradio_is_ht(&hw_priv->ht_oper)) -+ return; -+ if (!priv->setbssparams_done) -+ return; -+ if (!ieee80211_is_data(t->hdr->frame_control)) -+ return; -+ -+ spin_lock_bh(&hw_priv->ba_lock); -+ hw_priv->ba_acc += t->skb->len - t->hdrlen; -+ if (!(hw_priv->ba_cnt_rx || hw_priv->ba_cnt)) { -+ mod_timer(&hw_priv->ba_timer, -+ jiffies + XRADIO_BLOCK_ACK_INTERVAL); -+ } -+ hw_priv->ba_cnt++; -+ spin_unlock_bh(&hw_priv->ba_lock); -+} -+ -+static int -+xradio_tx_h_skb_pad(struct xradio_common *priv, -+ struct wsm_tx *wsm, -+ struct sk_buff *skb) -+{ -+ size_t len = __le16_to_cpu(wsm->hdr.len); -+ size_t padded_len = sdio_align_len(priv, len); -+ -+ -+ if (WARN_ON(skb_padto(skb, padded_len) != 0)) { -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+void xradio_tx(struct ieee80211_hw *dev, struct ieee80211_tx_control *control, struct sk_buff *skb) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_txinfo t = { -+ .skb = skb, -+ .queue = skb_get_queue_mapping(skb), -+ .tx_info = IEEE80211_SKB_CB(skb), -+ .hdr = (struct ieee80211_hdr *)skb->data, -+ .txpriv.tid = XRADIO_MAX_TID, -+ .txpriv.rate_id = XRADIO_INVALID_RATE_ID, -+ .txpriv.use_bg_rate = 0, -+ }; -+ struct ieee80211_sta *sta; -+ struct wsm_tx *wsm; -+ bool tid_update = 0; -+ u8 flags = 0; -+ int ret = 0; -+ struct xradio_vif *priv; -+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -+ -+ if (!skb->data) -+ BUG_ON(1); -+ -+ if (!(t.tx_info->control.vif)) { -+ ret = __LINE__; -+ goto drop; -+ } -+ priv = xrwl_get_vif_from_ieee80211(t.tx_info->control.vif); -+ if (!priv) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ if (atomic_read(&priv->enabled) == 0) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ //dhcp and 80211 frames are important, use b/g rate and delay scan. -+ //it can make sense, such as accelerate connect. -+ if (ieee80211_is_auth(frame->frame_control)) { -+ hw_priv->connet_time[priv->if_id] = jiffies; -+ } else if (ieee80211_is_data_present(frame->frame_control)) { -+ /* since Umac had already alloc IV space in ccmp skb, so we need to add this iv_len as the new offset to LLC */ -+ u8* llc = NULL; -+ if(t.tx_info->control.hw_key && -+ (t.hdr->frame_control & __cpu_to_le32(IEEE80211_FCTL_PROTECTED)) && -+ (t.tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP)) -+ llc = skb->data+ieee80211_hdrlen(frame->frame_control) + t.tx_info->control.hw_key->iv_len; -+ else -+ llc = skb->data+ieee80211_hdrlen(frame->frame_control); -+ if (is_dhcp(llc) || is_8021x(llc)) { -+ t.txpriv.use_bg_rate = -+ hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates[0].hw_value; -+ if (priv->vif->p2p) -+ t.txpriv.use_bg_rate = AG_RATE_INDEX; -+ t.txpriv.use_bg_rate |= 0x80; -+ } -+ if (t.txpriv.use_bg_rate){ -+ hw_priv->connet_time[priv->if_id] = jiffies; -+ } -+ } else if (ieee80211_is_deauth(frame->frame_control) || -+ ieee80211_is_disassoc(frame->frame_control)) { -+ hw_priv->connet_time[priv->if_id] = 0; -+ } -+ -+#ifdef AP_HT_COMPAT_FIX -+ if (ieee80211_is_assoc_req(frame->frame_control) && -+ priv->if_id == 0 && !(priv->ht_compat_det & 0x10)) { -+ xradio_remove_ht_ie(priv, skb); -+ } -+#endif -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ xradio_frame_monitor(hw_priv,skb,true); -+#endif -+ -+ if (ieee80211_is_action(frame->frame_control) && -+ mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { -+ u8 *action = (u8*)&mgmt->u.action.category; -+ xradio_check_go_neg_conf_success(hw_priv, action); -+ xradio_check_prov_desc_req(hw_priv, action); -+ } -+ -+ t.txpriv.if_id = priv->if_id; -+ t.hdrlen = ieee80211_hdrlen(t.hdr->frame_control); -+ t.da = ieee80211_get_DA(t.hdr); -+ t.sta_priv = -+ (struct xradio_sta_priv *)&control->sta->drv_priv; -+ -+ if (WARN_ON(t.queue >= 4)) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ //spin_lock_bh(&hw_priv->tx_queue[t.queue].lock); -+ //if ((priv->if_id == 0) && -+ // (hw_priv->tx_queue[t.queue].num_queued_vif[0] >= -+ // hw_priv->vif0_throttle)) { -+ // spin_unlock_bh(&hw_priv->tx_queue[t.queue].lock); -+ // -+ // ret = __LINE__; -+ // goto drop; -+ //} else if ((priv->if_id == 1) && -+ // (hw_priv->tx_queue[t.queue].num_queued_vif[1] >= -+ // hw_priv->vif1_throttle)) { -+ // spin_unlock_bh(&hw_priv->tx_queue[t.queue].lock); -+ // -+ // ret = __LINE__; -+ // goto drop; -+ //} -+ //spin_unlock_bh(&hw_priv->tx_queue[t.queue].lock); -+ -+ ret = xradio_tx_h_calc_link_ids(priv, control, &t); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ dev_dbg(hw_priv->pdev, "vif %d: tx, %d bytes queue %d, link_id %d(%d).\n", -+ priv->if_id, skb->len, t.queue, t.txpriv.link_id, t.txpriv.raw_link_id); -+ if(ieee80211_is_assoc_resp(frame->frame_control)){ -+ dev_dbg(hw_priv->pdev, "vif %d: association response\n", priv->if_id); -+ } -+ -+ xradio_tx_h_pm(priv, &t); -+ xradio_tx_h_calc_tid(priv, &t); -+ ret = xradio_tx_h_crypt(priv, &t); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ ret = xradio_tx_h_align(priv, &t, &flags); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ ret = xradio_tx_h_action(priv, &t); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ wsm = xradio_tx_h_wsm(priv, &t); -+ if (!wsm) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ wsm->flags |= flags; -+ xradio_tx_h_bt(priv, &t, wsm); -+ ret = xradio_tx_h_rate_policy(hw_priv, &t, wsm); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ ret = xradio_tx_h_skb_pad(hw_priv, wsm, skb); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ rcu_read_lock(); -+ sta = rcu_dereference(control->sta); -+ -+ xradio_tx_h_ba_stat(priv, &t); -+ spin_lock_bh(&priv->ps_state_lock); -+ { -+ tid_update = xradio_tx_h_pm_state(priv, &t); -+ BUG_ON(xradio_queue_put(&hw_priv->tx_queue[t.queue], -+ t.skb, &t.txpriv)); -+#ifdef ROC_DEBUG -+ txrx_printk(XRADIO_DBG_ERROR, "QPUT %x, %pM, if_id - %d\n", -+ t.hdr->frame_control, t.da, priv->if_id); -+#endif -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ if (tid_update && sta) -+ ieee80211_sta_set_buffered(sta, -+ t.txpriv.tid, true); -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ -+ rcu_read_unlock(); -+ -+ xradio_bh_wakeup(hw_priv); -+ -+ return; -+ -+drop: -+ dev_dbg(hw_priv->pdev, "dropped tx at line %d, fctl=0x%04x.\n", ret, frame->frame_control); -+ xradio_skb_dtor(hw_priv, skb, &t.txpriv); -+ return; -+} -+ -+void xradio_tx_confirm_cb(struct xradio_common *hw_priv, -+ struct wsm_tx_confirm *arg) -+{ -+ u8 queue_id = xradio_queue_get_queue_id(arg->packetID); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queue_id]; -+ struct sk_buff *skb; -+ const struct xradio_txpriv *txpriv; -+ struct xradio_vif *priv; -+ u32 feedback_retry = 0; -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, arg->if_id); -+ if (unlikely(!priv)) -+ return; -+ -+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { -+ /* STA is stopped. */ -+ spin_unlock(&priv->vif_lock); -+ return; -+ } -+ -+ if (WARN_ON(queue_id >= 4)) { -+ spin_unlock(&priv->vif_lock); -+ return; -+ } -+ -+ dev_dbg(hw_priv->pdev, "vif %d: tx confirm status=%d, retry=%d, lastRate=%d\n", -+ priv->if_id, arg->status, arg->ackFailures, arg->txedRate); -+ -+ if ((arg->status == WSM_REQUEUE) && -+ (arg->flags & WSM_TX_STATUS_REQUEUE)) { -+ /* "Requeue" means "implicit suspend" */ -+ struct wsm_suspend_resume suspend = { -+ .link_id = arg->link_id, -+ .stop = 1, -+ .multicast = !arg->link_id, -+ .if_id = arg->if_id, -+ }; -+ xradio_suspend_resume(priv, &suspend); -+ txrx_printk(XRADIO_DBG_WARN, "Requeue for link_id %d (try %d)." -+ " STAs asleep: 0x%.8X\n", -+ arg->link_id, -+ xradio_queue_get_generation(arg->packetID) + 1, -+ priv->sta_asleep_mask); -+ -+ WARN_ON(xradio_queue_requeue(queue, -+ arg->packetID, true)); -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ if (!arg->link_id) { -+ priv->buffered_multicasts = true; -+ if (priv->sta_asleep_mask) { -+ queue_work(hw_priv->workqueue, -+ &priv->multicast_start_work); -+ } -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ spin_unlock(&priv->vif_lock); -+ } else if (!WARN_ON(xradio_queue_get_skb( -+ queue, arg->packetID, &skb, &txpriv))) { -+ struct ieee80211_tx_info *tx = IEEE80211_SKB_CB(skb); -+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)&skb->data[txpriv->offset]; -+ int tx_count = arg->ackFailures; -+ u8 ht_flags = 0; -+ int i; -+ -+ //yangfh add to reset if_0 in firmware when STA-unjoined, -+ //fix the errors when switch APs in combo mode. -+ if (unlikely(ieee80211_is_disassoc(frame->frame_control) || -+ ieee80211_is_deauth(frame->frame_control))) { -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ wms_send_deauth_to_self(hw_priv, priv); -+ /* Shedule unjoin work */ -+ txrx_printk(XRADIO_DBG_WARN, "Issue unjoin command(TX) by self.\n"); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->unjoin_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+ -+ if (priv->association_mode.greenfieldMode) -+ ht_flags |= IEEE80211_TX_RC_GREEN_FIELD; -+ -+ //bss loss confirm. -+ if (unlikely(priv->bss_loss_status == XRADIO_BSS_LOSS_CONFIRMING && -+ priv->bss_loss_confirm_id == arg->packetID)) { -+ spin_lock(&priv->bss_loss_lock); -+ priv->bss_loss_status = arg->status? -+ XRADIO_BSS_LOSS_CONFIRMED : XRADIO_BSS_LOSS_NONE; -+ spin_unlock(&priv->bss_loss_lock); -+ } -+ -+ if (likely(!arg->status)) { -+ tx->flags |= IEEE80211_TX_STAT_ACK; -+ priv->cqm_tx_failure_count = 0; -+ ++tx_count; -+ -+ if (arg->flags & WSM_TX_STATUS_AGGREGATION) { -+ /* Do not report aggregation to mac80211: -+ * it confuses minstrel a lot. */ -+ /* tx->flags |= IEEE80211_TX_STAT_AMPDU; */ -+ } -+ } else { -+ /* TODO: Update TX failure counters */ -+ if (unlikely(priv->cqm_tx_failure_thold && -+ (++priv->cqm_tx_failure_count > -+ priv->cqm_tx_failure_thold))) { -+ priv->cqm_tx_failure_thold = 0; -+ queue_work(hw_priv->workqueue, -+ &priv->tx_failure_work); -+ } -+ if (tx_count) -+ ++tx_count; -+ } -+ spin_unlock(&priv->vif_lock); -+ -+ tx->status.ampdu_len = 1; -+ tx->status.ampdu_ack_len = 1; -+ -+ txrx_printk(XRADIO_DBG_NIY,"feedback:%08x, %08x, %08x.\n", -+ arg->rate_try[2], arg->rate_try[1], arg->rate_try[0]); -+ if(txpriv->use_bg_rate) { //bg rates -+ tx->status.rates[0].count = arg->ackFailures+1; -+ tx->status.rates[0].idx = 0; -+ tx->status.rates[1].idx = -1; -+ tx->status.rates[2].idx = -1; -+ tx->status.rates[3].idx = -1; -+ } else { -+ int j; -+ s8 txed_idx; -+ register u8 rate_num=0, shift=0, retries=0; -+ u8 flag = tx->status.rates[0].flags; -+ -+ //get retry rate idx. -+ for(i=2; i>=0;i--) { -+ if(arg->rate_try[i]) { -+ for(j=7; j>=0;j--) { -+ shift = j<<2; -+ retries = (arg->rate_try[i]>>shift)&0xf; -+ if(retries) { -+ feedback_retry += retries; -+ txed_idx = xradio_get_rate_idx(hw_priv,flag,((i<<3)+j)); -+ txrx_printk(XRADIO_DBG_NIY, "rate_num=%d, hw=%d, idx=%d, " -+ "retries=%d, flag=%d", rate_num, ((i<<3)+j), -+ txed_idx, retries, flag); -+ if(likely(txed_idx>=0)) { -+ tx->status.rates[rate_num].idx = txed_idx; -+ tx->status.rates[rate_num].count = retries; -+ if (tx->status.rates[rate_num].flags & IEEE80211_TX_RC_MCS) -+ tx->status.rates[rate_num].flags |= ht_flags; -+ rate_num++; -+ if(rate_num>=IEEE80211_TX_MAX_RATES) { -+ i = -1; -+ break; -+ } -+ } -+ } -+ } -+ } -+ } -+ //clear other rate. -+ for (i=rate_num; i < IEEE80211_TX_MAX_RATES; ++i) { -+ tx->status.rates[i].count = 0; -+ tx->status.rates[i].idx = -1; -+ } -+ //get successful rate idx. -+ if(!arg->status) { -+ txed_idx = xradio_get_rate_idx(hw_priv, flag, arg->txedRate); -+ if(rate_num == 0) { -+ tx->status.rates[0].idx = txed_idx; -+ tx->status.rates[0].count = 1; -+ } else if(rate_num <= IEEE80211_TX_MAX_RATES){ -+ --rate_num; -+ if(txed_idx == tx->status.rates[rate_num].idx) { -+ tx->status.rates[rate_num].count += 1; -+ } else if(rate_num<(IEEE80211_TX_MAX_RATES-1)){ -+ ++rate_num; -+ tx->status.rates[rate_num].idx = txed_idx; -+ tx->status.rates[rate_num].count = 1; -+ } else if(txed_idx >=0) { -+ tx->status.rates[rate_num].idx = txed_idx; -+ tx->status.rates[rate_num].count = 1; -+ } -+ } -+ } -+ } -+ -+ dev_dbg(hw_priv->pdev, "[TX policy] Ack: " \ -+ "%d:%d, %d:%d, %d:%d, %d:%d\n", -+ tx->status.rates[0].idx, tx->status.rates[0].count, -+ tx->status.rates[1].idx, tx->status.rates[1].count, -+ tx->status.rates[2].idx, tx->status.rates[2].count, -+ tx->status.rates[3].idx, tx->status.rates[3].count); -+ -+ -+ xradio_queue_remove(queue, arg->packetID); -+ } -+} -+ -+static void xradio_notify_buffered_tx(struct xradio_vif *priv, -+ struct sk_buff *skb, int link_id, int tid) -+{ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ struct ieee80211_sta *sta; -+ struct ieee80211_hdr *hdr; -+ u8 *buffered; -+ u8 still_buffered = 0; -+ -+ -+ if (link_id && tid < XRADIO_MAX_TID) { -+ buffered = priv->link_id_db -+ [link_id - 1].buffered; -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ if (!WARN_ON(!buffered[tid])) -+ still_buffered = --buffered[tid]; -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+ if (!still_buffered && tid < XRADIO_MAX_TID) { -+ hdr = (struct ieee80211_hdr *) skb->data; -+ rcu_read_lock(); -+ sta = ieee80211_find_sta(priv->vif, hdr->addr1); -+ if (sta) -+ ieee80211_sta_set_buffered(sta, tid, false); -+ rcu_read_unlock(); -+ } -+ } -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+} -+ -+void xradio_skb_dtor(struct xradio_common *hw_priv, -+ struct sk_buff *skb, -+ const struct xradio_txpriv *txpriv) -+{ -+ struct xradio_vif *priv = -+ __xrwl_hwpriv_to_vifpriv(hw_priv, txpriv->if_id); -+ -+ -+ skb_pull(skb, txpriv->offset); -+ if (priv && txpriv->rate_id != XRADIO_INVALID_RATE_ID) { -+ xradio_notify_buffered_tx(priv, skb, -+ txpriv->raw_link_id, txpriv->tid); -+ tx_policy_put(hw_priv, txpriv->rate_id); -+ } -+ ieee80211_tx_status(hw_priv->hw, skb); -+} -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+/* Workaround for WFD test case 6.1.10 */ -+void xradio_link_id_reset(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, linkid_reset_work); -+ struct xradio_common *hw_priv = priv->hw_priv; -+ int temp_linkid; -+ -+ -+ if (!priv->action_linkid) { -+ /* In GO mode we can receive ACTION frames without a linkID */ -+ temp_linkid = xradio_alloc_link_id(priv, -+ &priv->action_frame_sa[0]); -+ WARN_ON(!temp_linkid); -+ if (temp_linkid) { -+ /* Make sure we execute the WQ */ -+ flush_workqueue(hw_priv->workqueue); -+ /* Release the link ID */ -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->link_id_db[temp_linkid - 1].prev_status = -+ priv->link_id_db[temp_linkid - 1].status; -+ priv->link_id_db[temp_linkid - 1].status = -+ XRADIO_LINK_RESET; -+ spin_unlock_bh(&priv->ps_state_lock); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, -+ &priv->link_id_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+ } else { -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->link_id_db[priv->action_linkid - 1].prev_status = -+ priv->link_id_db[priv->action_linkid - 1].status; -+ priv->link_id_db[priv->action_linkid - 1].status = -+ XRADIO_LINK_RESET_REMAP; -+ spin_unlock_bh(&priv->ps_state_lock); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->link_id_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ flush_workqueue(hw_priv->workqueue); -+ } -+} -+#endif -diff --git a/drivers/net/wireless/xradio/tx.h b/drivers/net/wireless/xradio/tx.h -new file mode 100644 -index 0000000..e08bb71 ---- /dev/null -+++ b/drivers/net/wireless/xradio/tx.h -@@ -0,0 +1,86 @@ -+/* -+ * txrx interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_TXRX_H -+#define XRADIO_TXRX_H -+ -+#include -+ -+/* extern */ struct ieee80211_hw; -+/* extern */ struct sk_buff; -+/* extern */ struct wsm_tx; -+/* extern */ struct wsm_rx; -+/* extern */ struct wsm_tx_confirm; -+/* extern */ struct xradio_txpriv; -+/* extern */ struct xradio_vif; -+ -+struct tx_policy { -+ union { -+ __le32 tbl[3]; -+ u8 raw[12]; -+ }; -+ u8 defined; /* TODO: u32 or u8, profile and select best */ -+ u8 usage_count; /* --// -- */ -+ u8 retry_count; /* --// -- */ -+ u8 uploaded; -+}; -+ -+struct tx_policy_cache_entry { -+ struct tx_policy policy; -+ struct list_head link; -+}; -+ -+#define TX_POLICY_CACHE_SIZE (8) -+struct tx_policy_cache { -+ struct tx_policy_cache_entry cache[TX_POLICY_CACHE_SIZE]; -+ struct list_head used; -+ struct list_head free; -+ spinlock_t lock; -+}; -+ -+/* ******************************************************************** */ -+/* TX policy cache */ -+/* Intention of TX policy cache is an overcomplicated WSM API. -+ * Device does not accept per-PDU tx retry sequence. -+ * It uses "tx retry policy id" instead, so driver code has to sync -+ * linux tx retry sequences with a retry policy table in the device. -+ */ -+void tx_policy_init(struct xradio_common *hw_priv); -+void tx_policy_upload_work(struct work_struct *work); -+ -+/* ******************************************************************** */ -+/* TX implementation */ -+ -+u32 xradio_rate_mask_to_wsm(struct xradio_common *hw_priv, -+ u32 rates); -+void xradio_tx(struct ieee80211_hw *dev, struct ieee80211_tx_control *control, struct sk_buff *skb); -+void xradio_skb_dtor(struct xradio_common *hw_priv, -+ struct sk_buff *skb, -+ const struct xradio_txpriv *txpriv); -+ -+/* ******************************************************************** */ -+/* WSM callbacks */ -+ -+void xradio_tx_confirm_cb(struct xradio_common *hw_priv, -+ struct wsm_tx_confirm *arg); -+ -+/* ******************************************************************** */ -+/* Timeout */ -+ -+void xradio_tx_timeout(struct work_struct *work); -+ -+/* ******************************************************************** */ -+/* Workaround for WFD test case 6.1.10 */ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+void xradio_link_id_reset(struct work_struct *work); -+#endif -+ -+#endif /* XRADIO_TXRX_H */ -diff --git a/drivers/net/wireless/xradio/wsm.c b/drivers/net/wireless/xradio/wsm.c -new file mode 100644 -index 0000000..3842116 ---- /dev/null -+++ b/drivers/net/wireless/xradio/wsm.c -@@ -0,0 +1,3004 @@ -+/* -+ * WSM host interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "wsm.h" -+#include "bh.h" -+#include "ap.h" -+#include "sta.h" -+#include "rx.h" -+ -+#define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */ -+#define WSM_CMD_JOIN_TIMEOUT (7 * HZ) /* Join timeout is 5 sec. in FW */ -+#define WSM_CMD_START_TIMEOUT (7 * HZ) -+#define WSM_CMD_RESET_TIMEOUT (3 * HZ) /* 2 sec. timeout was observed. */ -+#define WSM_CMD_DEFAULT_TIMEOUT (3 * HZ) -+#define WSM_SKIP(buf, size) \ -+ do { \ -+ if (unlikely((buf)->data + size > (buf)->end)) \ -+ goto underflow; \ -+ (buf)->data += size; \ -+ } while (0) -+ -+#define WSM_GET(buf, ptr, size) \ -+ do { \ -+ if (unlikely((buf)->data + size > (buf)->end)) \ -+ goto underflow; \ -+ memcpy(ptr, (buf)->data, size); \ -+ (buf)->data += size; \ -+ } while (0) -+ -+#define __WSM_GET(buf, type, cvt) \ -+ ({ \ -+ type val; \ -+ if (unlikely((buf)->data + sizeof(type) > (buf)->end)) \ -+ goto underflow; \ -+ val = cvt(*(type *)(buf)->data); \ -+ (buf)->data += sizeof(type); \ -+ val; \ -+ }) -+ -+#define WSM_GET8(buf) __WSM_GET(buf, u8, (u8)) -+#define WSM_GET16(buf) __WSM_GET(buf, u16, __le16_to_cpu) -+#define WSM_GET32(buf) __WSM_GET(buf, u32, __le32_to_cpu) -+ -+#define WSM_PUT(buf, ptr, size) \ -+ do { \ -+ if (unlikely((buf)->data + size > (buf)->end)) \ -+ if (unlikely(wsm_buf_reserve((buf), size))) \ -+ goto nomem; \ -+ memcpy((buf)->data, ptr, size); \ -+ (buf)->data += size; \ -+ } while (0) -+ -+#define __WSM_PUT(buf, val, type, cvt) \ -+ do { \ -+ if (unlikely((buf)->data + sizeof(type) > (buf)->end)) \ -+ if (unlikely(wsm_buf_reserve((buf), sizeof(type)))) \ -+ goto nomem; \ -+ *(type *)(buf)->data = cvt(val); \ -+ (buf)->data += sizeof(type); \ -+ } while (0) -+ -+#define WSM_PUT8(buf, val) __WSM_PUT(buf, val, u8, (u8)) -+#define WSM_PUT16(buf, val) __WSM_PUT(buf, val, u16, __cpu_to_le16) -+#define WSM_PUT32(buf, val) __WSM_PUT(buf, val, u32, __cpu_to_le32) -+ -+static void wsm_buf_reset(struct wsm_buf *buf); -+static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size); -+static int get_interface_id_scanning(struct xradio_common *hw_priv); -+ -+static int wsm_cmd_send(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, -+ void *arg, u16 cmd, long tmo, int if_id); -+ -+static struct xradio_vif -+ *wsm_get_interface_for_tx(struct xradio_common *hw_priv); -+ -+static inline void wsm_cmd_lock(struct xradio_common *hw_priv) -+{ -+ mutex_lock(&hw_priv->wsm_cmd_mux); -+} -+ -+static inline void wsm_cmd_unlock(struct xradio_common *hw_priv) -+{ -+ mutex_unlock(&hw_priv->wsm_cmd_mux); -+} -+ -+static inline void wsm_oper_lock(struct xradio_common *hw_priv) -+{ -+ mutex_lock(&hw_priv->wsm_oper_lock); -+} -+ -+static inline void wsm_oper_unlock(struct xradio_common *hw_priv) -+{ -+ mutex_unlock(&hw_priv->wsm_oper_lock); -+} -+ -+/* ******************************************************************** */ -+/* WSM API implementation */ -+ -+static int wsm_generic_confirm(struct xradio_common *hw_priv, -+ void *arg, -+ struct wsm_buf *buf) -+{ -+ u32 status = WSM_GET32(buf); -+ if (status != WSM_STATUS_SUCCESS) -+ return -EINVAL; -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+#ifdef XR_RRM//RadioResourceMeasurement -+static int wsm_start_measure_requset(struct xradio_common *hw_priv, -+ MEASUREMENT_PARAMETERS *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT(buf, arg, sizeof(*arg)); -+ ret = wsm_cmd_send(hw_priv, buf, arg, 0x000E, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+ nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+ -+} -+ -+int wsm_11k_measure_requset(struct xradio_common *hw_priv, -+ u8 measure_type, -+ u16 ChannelNum, -+ u16 Duration) -+{ -+ int ret; -+ u8 type, sub_type; -+ MEASUREMENT_PARAMETERS rrm_paras; -+ LMAC_MEAS_REQUEST *rrm_req = &rrm_paras.MeasurementRequest; -+// LMAC_MEAS_CHANNEL_LOAD_PARAMS *rrm_req = &rrm_paras.MeasurementRequest; -+ rrm_paras.TxPowerLevel = 0x11; -+ rrm_paras.DurationMandatory = 0x22; -+ rrm_paras.MeasurementRequestLength = 0x33; -+ -+ type = (measure_type&0xf0)>>4; -+ sub_type = measure_type&0xf; -+ rrm_paras.MeasurementType = type; -+// if (measure_type == ChannelLoadMeasurement) { -+ if (type == ChannelLoadMeasurement) { -+ rrm_req->ChannelLoadParams.Reserved = 0; -+ rrm_req->ChannelLoadParams.ChannelLoadCCA = sub_type; -+ rrm_req->ChannelLoadParams.ChannelNum = ChannelNum; -+ //valid when channelload measure, interval bettween request&start -+ rrm_req->ChannelLoadParams.RandomInterval = 0; -+ //unit:1TU=1024us -+ rrm_req->ChannelLoadParams.MeasurementDuration = Duration; -+ rrm_req->ChannelLoadParams.MeasurementStartTimel = 0; -+ rrm_req->ChannelLoadParams.MeasurementStartTimeh = 0; -+ } else if (type == NoiseHistrogramMeasurement) { -+ rrm_req->NoisHistogramParams.Reserved = 0; -+ rrm_req->NoisHistogramParams.IpiRpi = sub_type; -+ rrm_req->NoisHistogramParams.ChannelNum = ChannelNum; -+ rrm_req->NoisHistogramParams.RandomInterval = 0; -+ rrm_req->NoisHistogramParams.MeasurementDuration = Duration; -+ rrm_req->NoisHistogramParams.MeasurementStartTimel = 0; -+ rrm_req->NoisHistogramParams.MeasurementStartTimeh = 0; -+ } -+ ret = wsm_start_measure_requset(hw_priv, &rrm_paras, 0); -+ -+ return ret; -+} -+ -+ -+#endif//RadioResourceMeasurement -+int wsm_configuration(struct xradio_common *hw_priv, -+ struct wsm_configuration *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT32(buf, arg->dot11MaxTransmitMsduLifeTime); -+ WSM_PUT32(buf, arg->dot11MaxReceiveLifeTime); -+ WSM_PUT32(buf, arg->dot11RtsThreshold); -+ -+ /* DPD block. */ -+ WSM_PUT16(buf, arg->dpdData_size + 12); -+ WSM_PUT16(buf, 1); /* DPD version */ -+ WSM_PUT(buf, arg->dot11StationId, ETH_ALEN); -+ WSM_PUT16(buf, 5); /* DPD flags */ -+ WSM_PUT(buf, arg->dpdData, arg->dpdData_size); -+ -+ ret = wsm_cmd_send(hw_priv, buf, arg, 0x0009, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+static int wsm_configuration_confirm(struct xradio_common *hw_priv, -+ struct wsm_configuration *arg, -+ struct wsm_buf *buf) -+{ -+ int i; -+ int status; -+ -+ status = WSM_GET32(buf); -+ if (WARN_ON(status != WSM_STATUS_SUCCESS)) -+ return -EINVAL; -+ -+ WSM_GET(buf, arg->dot11StationId, ETH_ALEN); -+ arg->dot11FrequencyBandsSupported = WSM_GET8(buf); -+ WSM_SKIP(buf, 1); -+ arg->supportedRateMask = WSM_GET32(buf); -+ for (i = 0; i < 2; ++i) { -+ arg->txPowerRange[i].min_power_level = WSM_GET32(buf); -+ arg->txPowerRange[i].max_power_level = WSM_GET32(buf); -+ arg->txPowerRange[i].stepping = WSM_GET32(buf); -+ } -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+void wsm_query_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, query_work); -+ u8 ret[100] = {0}; -+ -+ -+ *(u32*)&ret[0] = hw_priv->query_packetID; -+ wsm_read_mib(hw_priv, WSM_MIB_ID_REQ_PKT_STATUS, (void*)&ret[0], sizeof(ret), 4); -+ if(!ret[4]) { -+ wsm_printk(XRADIO_DBG_ERROR,"QuerypktID=0x%08x, status=0x%x, retry=%d, flags=0x%x, PktDebug=0x%x\n" \ -+ "pktqueue=0x%x, ext1=%d, ext2=%d, ext3=%d, ext4=0x%x, ext5=0x%x\n", -+ *(u32*)&ret[0], ret[6], ret[7], *(u32*)&ret[8], *(u32*)&ret[12], -+ ret[44], ret[45], ret[46], ret[47], ret[48], ret[49]); -+ wsm_printk(XRADIO_DBG_ERROR,"interdebug=0x%x, 0x%x, 0x%x, Soure=0x%x, 0x%x, 0x%x\n" \ -+ "interuse=%d, external=%d, TxOutstanding=%d, QueueStatus=0x%x, BA0=0x%x, BA1=0x%x\n" \ -+ "ScanStatus=0x%x, scanNULL=0x%x, wr_state=0x%x,0x%x,0x%x,0x%x," \ -+ "wr_cnt=%d, %d, %d, %d\n", -+ *(u32*)&ret[16], *(u32*)&ret[20], *(u32*)&ret[24], ret[28], ret[29], ret[30], -+ ret[32], ret[33], ret[34], ret[35], *(u32*)&ret[36], *(u32*)&ret[40], -+ ret[50], ret[51], ret[52], ret[53], ret[54], ret[55], -+ *(u16*)&ret[56], *(u16*)&ret[58], *(u16*)&ret[60], *(u16*)&ret[62]); -+ } else { -+ ret[5] = 0; -+ wsm_printk(XRADIO_DBG_ERROR,"No req packid=0x%08x!\n", *(u32*)&ret[0]); -+ } -+ //hardware error occurs, try to restart wifi. -+ if(ret[5] & 0x4) { -+ wsm_printk(XRADIO_DBG_ERROR,"Hardware need to reset 0x%x.\n", ret[5]); -+ hw_priv->bh_error = 1; -+ wake_up(&hw_priv->bh_wq); -+ } -+ hw_priv->query_packetID = 0; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_reset(struct xradio_common *hw_priv, const struct wsm_reset *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ u16 cmd = 0x000A | WSM_TX_LINK_ID(arg->link_id); -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT32(buf, arg->reset_statistics ? 0 : 1); -+ ret = wsm_cmd_send(hw_priv, buf, NULL, cmd, WSM_CMD_RESET_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+struct wsm_mib { -+ u16 mibId; -+ void *buf; -+ size_t buf_size; -+}; -+ -+int wsm_read_mib(struct xradio_common *hw_priv, u16 mibId, void *_buf, -+ size_t buf_size, size_t arg_size) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ struct wsm_mib mib_buf = { -+ .mibId = mibId, -+ .buf = _buf, -+ .buf_size = buf_size, -+ }; -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT16(buf, mibId); -+ WSM_PUT16(buf, arg_size); -+ WSM_PUT(buf, _buf, arg_size); -+ -+ ret = wsm_cmd_send(hw_priv, buf, &mib_buf, 0x0005, WSM_CMD_TIMEOUT, -1); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+static int wsm_read_mib_confirm(struct xradio_common *hw_priv, -+ struct wsm_mib *arg, -+ struct wsm_buf *buf) -+{ -+ u16 size; -+ if (WARN_ON(WSM_GET32(buf) != WSM_STATUS_SUCCESS)) -+ return -EINVAL; -+ -+ if (WARN_ON(WSM_GET16(buf) != arg->mibId)) -+ return -EINVAL; -+ -+ size = WSM_GET16(buf); -+ if (size > arg->buf_size) -+ size = arg->buf_size; -+ -+ WSM_GET(buf, arg->buf, size); -+ arg->buf_size = size; -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_write_mib(struct xradio_common *hw_priv, u16 mibId, void *_buf, -+ size_t buf_size, int if_id) -+{ -+ int ret = 0; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ struct wsm_mib mib_buf = { -+ .mibId = mibId, -+ .buf = _buf, -+ .buf_size = buf_size, -+ }; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT16(buf, mibId); -+ WSM_PUT16(buf, buf_size); -+ WSM_PUT(buf, _buf, buf_size); -+ -+ ret = wsm_cmd_send(hw_priv, buf, &mib_buf, 0x0006, WSM_CMD_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+static int wsm_write_mib_confirm(struct xradio_common *hw_priv, -+ struct wsm_mib *arg, -+ struct wsm_buf *buf, -+ int interface_link_id) -+{ -+ int ret; -+ int i; -+ struct xradio_vif *priv; -+ ret = wsm_generic_confirm(hw_priv, arg, buf); -+ if (ret) -+ return ret; -+ -+ /*wsm_set_operational_mode confirm.*/ -+ if (arg->mibId == 0x1006) { -+ const char *p = arg->buf; -+ bool powersave_enabled = (p[0] & 0x0F) ? true : false; -+ -+ /* update vif PM status. */ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, interface_link_id); -+ if (priv) { -+ xradio_enable_powersave(priv, powersave_enabled); -+ spin_unlock(&priv->vif_lock); -+ } -+ -+ /* HW powersave base on vif except for generic vif. */ -+ spin_lock(&hw_priv->vif_list_lock); -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ powersave_enabled &= !!priv->powersave_enabled; -+ } -+ hw_priv->powersave_enabled = powersave_enabled; -+ spin_unlock(&hw_priv->vif_list_lock); -+ -+ } -+ return 0; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_scan(struct xradio_common *hw_priv, const struct wsm_scan *arg, -+ int if_id) -+{ -+ int i; -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ if (unlikely(arg->numOfChannels > 48)) -+ return -EINVAL; -+ -+ if (unlikely(arg->numOfSSIDs > WSM_SCAN_MAX_NUM_OF_SSIDS)) -+ return -EINVAL; -+ -+ if (unlikely(arg->band > 1)) -+ return -EINVAL; -+ -+ wsm_oper_lock(hw_priv); -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->band); -+ WSM_PUT8(buf, arg->scanType); -+ WSM_PUT8(buf, arg->scanFlags); -+ WSM_PUT8(buf, arg->maxTransmitRate); -+ WSM_PUT32(buf, arg->autoScanInterval); -+ WSM_PUT8(buf, arg->numOfProbeRequests); -+ WSM_PUT8(buf, arg->numOfChannels); -+ WSM_PUT8(buf, arg->numOfSSIDs); -+ WSM_PUT8(buf, arg->probeDelay); -+ -+ for (i = 0; i < arg->numOfChannels; ++i) { -+ WSM_PUT16(buf, arg->ch[i].number); -+ WSM_PUT16(buf, 0); -+ WSM_PUT32(buf, arg->ch[i].minChannelTime); -+ WSM_PUT32(buf, arg->ch[i].maxChannelTime); -+ WSM_PUT32(buf, 0); -+ } -+ -+ for (i = 0; i < arg->numOfSSIDs; ++i) { -+ WSM_PUT32(buf, arg->ssids[i].length); -+ WSM_PUT(buf, &arg->ssids[i].ssid[0], -+ sizeof(arg->ssids[i].ssid)); -+ } -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0007, WSM_CMD_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ if (ret) -+ wsm_oper_unlock(hw_priv); -+ -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ wsm_oper_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_stop_scan(struct xradio_common *hw_priv, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ wsm_cmd_lock(hw_priv); -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0008, WSM_CMD_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+} -+ -+ -+static int wsm_tx_confirm(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, -+ int interface_link_id) -+{ -+ struct wsm_tx_confirm tx_confirm; -+ -+ tx_confirm.packetID = WSM_GET32(buf); -+ tx_confirm.status = WSM_GET32(buf); -+ tx_confirm.txedRate = WSM_GET8(buf); -+ tx_confirm.ackFailures = WSM_GET8(buf); -+ tx_confirm.flags = WSM_GET16(buf); -+ tx_confirm.rate_try[0] = WSM_GET32(buf); -+ tx_confirm.rate_try[1] = WSM_GET32(buf); -+ tx_confirm.rate_try[2] = WSM_GET32(buf); -+ tx_confirm.mediaDelay = WSM_GET32(buf); -+ tx_confirm.txQueueDelay = WSM_GET32(buf); -+ -+ if (is_hardware_xradio(hw_priv)) { -+ /* TODO:COMBO:linkID will be stored in packetID*/ -+ /* TODO:COMBO: Extract traffic resumption map */ -+ tx_confirm.if_id = xradio_queue_get_if_id(tx_confirm.packetID); -+ tx_confirm.link_id = xradio_queue_get_link_id( -+ tx_confirm.packetID); -+ } else { -+ tx_confirm.link_id = interface_link_id; -+ tx_confirm.if_id = 0; -+ } -+ -+ wsm_release_vif_tx_buffer(hw_priv, tx_confirm.if_id, 1); -+ -+ xradio_tx_confirm_cb(hw_priv, &tx_confirm); -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+static int wsm_multi_tx_confirm(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, int interface_link_id) -+{ -+ struct xradio_vif *priv; -+ int ret; -+ int count; -+ int i; -+ -+ count = WSM_GET32(buf); -+ if (WARN_ON(count <= 0)) -+ return -EINVAL; -+ else if (count > 1) { -+ ret = wsm_release_tx_buffer(hw_priv, count - 1); -+ if (ret < 0) -+ return ret; -+ else if (ret > 0) -+ xradio_bh_wakeup(hw_priv); -+ } -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, interface_link_id); -+ if (priv) { -+ spin_unlock(&priv->vif_lock); -+ } -+ for (i = 0; i < count; ++i) { -+ ret = wsm_tx_confirm(hw_priv, buf, interface_link_id); -+ if (ret) -+ return ret; -+ } -+ return ret; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+/* ******************************************************************** */ -+ -+static int wsm_join_confirm(struct xradio_common *hw_priv, -+ struct wsm_join *arg, -+ struct wsm_buf *buf) -+{ -+ if (WSM_GET32(buf) != WSM_STATUS_SUCCESS) -+ return -EINVAL; -+ arg->minPowerLevel = WSM_GET32(buf); -+ arg->maxPowerLevel = WSM_GET32(buf); -+ -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+int wsm_join(struct xradio_common *hw_priv, struct wsm_join *arg, -+ int if_id) -+/*TODO: combo: make it work per vif.*/ -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_oper_lock(hw_priv); -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->mode); -+ WSM_PUT8(buf, arg->band); -+ WSM_PUT16(buf, arg->channelNumber); -+ WSM_PUT(buf, &arg->bssid[0], sizeof(arg->bssid)); -+ WSM_PUT16(buf, arg->atimWindow); -+ WSM_PUT8(buf, arg->preambleType); -+ WSM_PUT8(buf, arg->probeForJoin); -+ WSM_PUT8(buf, arg->dtimPeriod); -+ WSM_PUT8(buf, arg->flags); -+ WSM_PUT32(buf, arg->ssidLength); -+ WSM_PUT(buf, &arg->ssid[0], sizeof(arg->ssid)); -+ WSM_PUT32(buf, arg->beaconInterval); -+ WSM_PUT32(buf, arg->basicRateSet); -+ -+ hw_priv->tx_burst_idx = -1; -+ ret = wsm_cmd_send(hw_priv, buf, arg, 0x000B, WSM_CMD_JOIN_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ wsm_oper_unlock(hw_priv); /*confirm, not indcation.*/ -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ wsm_oper_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_set_bss_params(struct xradio_common *hw_priv, -+ const struct wsm_set_bss_params *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, 0); -+ WSM_PUT8(buf, arg->beaconLostCount); -+ WSM_PUT16(buf, arg->aid); -+ WSM_PUT32(buf, arg->operationalRateSet); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0011, WSM_CMD_TIMEOUT, -+ if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_add_key(struct xradio_common *hw_priv, const struct wsm_add_key *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT(buf, arg, sizeof(*arg)); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x000C, WSM_CMD_TIMEOUT, -+ if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_remove_key(struct xradio_common *hw_priv, -+ const struct wsm_remove_key *arg, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->entryIndex); -+ WSM_PUT8(buf, 0); -+ WSM_PUT16(buf, 0); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x000D, WSM_CMD_TIMEOUT, -+ if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_set_tx_queue_params(struct xradio_common *hw_priv, -+ const struct wsm_set_tx_queue_params *arg, -+ u8 id, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ u8 queue_id_to_wmm_aci[] = {3, 2, 0, 1}; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, queue_id_to_wmm_aci[id]); -+ WSM_PUT8(buf, 0); -+ WSM_PUT8(buf, arg->ackPolicy); -+ WSM_PUT8(buf, 0); -+ WSM_PUT32(buf, arg->maxTransmitLifetime); -+ WSM_PUT16(buf, arg->allowedMediumTime); -+ WSM_PUT16(buf, 0); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0012, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_set_edca_params(struct xradio_common *hw_priv, -+ const struct wsm_edca_params *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ /* Implemented according to specification. */ -+ -+ WSM_PUT16(buf, arg->params[3].cwMin); -+ WSM_PUT16(buf, arg->params[2].cwMin); -+ WSM_PUT16(buf, arg->params[1].cwMin); -+ WSM_PUT16(buf, arg->params[0].cwMin); -+ -+ WSM_PUT16(buf, arg->params[3].cwMax); -+ WSM_PUT16(buf, arg->params[2].cwMax); -+ WSM_PUT16(buf, arg->params[1].cwMax); -+ WSM_PUT16(buf, arg->params[0].cwMax); -+ -+ WSM_PUT8(buf, arg->params[3].aifns); -+ WSM_PUT8(buf, arg->params[2].aifns); -+ WSM_PUT8(buf, arg->params[1].aifns); -+ WSM_PUT8(buf, arg->params[0].aifns); -+ -+ WSM_PUT16(buf, arg->params[3].txOpLimit); -+ WSM_PUT16(buf, arg->params[2].txOpLimit); -+ WSM_PUT16(buf, arg->params[1].txOpLimit); -+ WSM_PUT16(buf, arg->params[0].txOpLimit); -+ -+ WSM_PUT32(buf, arg->params[3].maxReceiveLifetime); -+ WSM_PUT32(buf, arg->params[2].maxReceiveLifetime); -+ WSM_PUT32(buf, arg->params[1].maxReceiveLifetime); -+ WSM_PUT32(buf, arg->params[0].maxReceiveLifetime); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0013, WSM_CMD_TIMEOUT, if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_switch_channel(struct xradio_common *hw_priv, -+ const struct wsm_switch_channel *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_lock_tx(hw_priv); -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->channelMode); -+ WSM_PUT8(buf, arg->channelSwitchCount); -+ WSM_PUT16(buf, arg->newChannelNumber); -+ -+ hw_priv->channel_switch_in_progress = 1; -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0016, WSM_CMD_TIMEOUT, if_id); -+ wsm_cmd_unlock(hw_priv); -+ if (ret) { -+ wsm_unlock_tx(hw_priv); -+ hw_priv->channel_switch_in_progress = 0; -+ } -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ wsm_unlock_tx(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_set_pm(struct xradio_common *hw_priv, const struct wsm_set_pm *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_oper_lock(hw_priv); -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->pmMode); -+ WSM_PUT8(buf, arg->fastPsmIdlePeriod); -+ WSM_PUT8(buf, arg->apPsmChangePeriod); -+ WSM_PUT8(buf, arg->minAutoPsPollPeriod); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0010, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ if (ret) -+ wsm_oper_unlock(hw_priv); -+ -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ wsm_oper_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_start(struct xradio_common *hw_priv, const struct wsm_start *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->mode); -+ WSM_PUT8(buf, arg->band); -+ WSM_PUT16(buf, arg->channelNumber); -+ WSM_PUT32(buf, arg->CTWindow); -+ WSM_PUT32(buf, arg->beaconInterval); -+ WSM_PUT8(buf, arg->DTIMPeriod); -+ WSM_PUT8(buf, arg->preambleType); -+ WSM_PUT8(buf, arg->probeDelay); -+ WSM_PUT8(buf, arg->ssidLength); -+ WSM_PUT(buf, arg->ssid, sizeof(arg->ssid)); -+ WSM_PUT32(buf, arg->basicRateSet); -+ -+ hw_priv->tx_burst_idx = -1; -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0017, WSM_CMD_START_TIMEOUT, -+ if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+#if 0 -+/* This API is no longer present in WSC */ -+/* ******************************************************************** */ -+ -+int wsm_beacon_transmit(struct xradio_common *hw_priv, -+ const struct wsm_beacon_transmit *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT32(buf, arg->enableBeaconing ? 1 : 0); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0018, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+#endif -+ -+/* ******************************************************************** */ -+ -+int wsm_start_find(struct xradio_common *hw_priv, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0019, WSM_CMD_TIMEOUT, if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_stop_find(struct xradio_common *hw_priv, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x001A, WSM_CMD_TIMEOUT, if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_map_link(struct xradio_common *hw_priv, const struct wsm_map_link *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ u16 cmd = 0x001C; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT(buf, &arg->mac_addr[0], sizeof(arg->mac_addr)); -+ -+ if (is_hardware_xradio(hw_priv)) { -+ WSM_PUT8(buf, arg->unmap); -+ WSM_PUT8(buf, arg->link_id); -+ } else { -+ cmd |= WSM_TX_LINK_ID(arg->link_id); -+ WSM_PUT16(buf, 0); -+ } -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, cmd, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_update_ie(struct xradio_common *hw_priv, -+ const struct wsm_update_ie *arg, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT16(buf, arg->what); -+ WSM_PUT16(buf, arg->count); -+ WSM_PUT(buf, arg->ies, arg->length); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x001B, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+ -+} -+/* ******************************************************************** */ -+#ifdef MCAST_FWDING -+/* 3.66 */ -+static int wsm_give_buffer_confirm(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ wsm_printk(XRADIO_DBG_MSG, "HW Buf count %d\n", hw_priv->hw_bufs_used); -+ if (!hw_priv->hw_bufs_used) -+ wake_up(&hw_priv->bh_evt_wq); -+ -+ return 0; -+} -+ -+/* 3.65 */ -+int wsm_init_release_buffer_request(struct xradio_common *hw_priv, u8 index) -+{ -+ struct wsm_buf *buf = &hw_priv->wsm_release_buf[index]; -+ u16 cmd = 0x0022; /* Buffer Request */ -+ u8 flags; -+ size_t buf_len; -+ -+ wsm_buf_init(buf); -+ -+ flags = index ? 0: 0x1; -+ -+ WSM_PUT8(buf, flags); -+ WSM_PUT8(buf, 0); -+ WSM_PUT16(buf, 0); -+ -+ buf_len = buf->data - buf->begin; -+ -+ /* Fill HI message header */ -+ ((__le16 *)buf->begin)[0] = __cpu_to_le16(buf_len); -+ ((__le16 *)buf->begin)[1] = __cpu_to_le16(cmd); -+ -+ return 0; -+nomem: -+ return -ENOMEM; -+} -+ -+/* 3.65 fixed memory leakage by yangfh*/ -+int wsm_deinit_release_buffer(struct xradio_common *hw_priv) -+{ -+ struct wsm_buf *buf = NULL; -+ int i, err = 0; -+ -+ for (i = 0; i < WSM_MAX_BUF; i++) { -+ buf = &hw_priv->wsm_release_buf[i]; -+ if(likely(buf)) { -+ if(likely(buf->begin)) -+ kfree(buf->begin); -+ buf->begin = buf->data = buf->end = NULL; -+ } else { -+ err++; -+ } -+ } -+ if(err) wsm_printk(XRADIO_DBG_ERROR, "%s, NULL buf=%d!\n", __func__, err); -+ return 0; -+} -+ -+/* 3.68 */ -+static int wsm_request_buffer_confirm(struct xradio_vif *priv, -+ u8 *arg, -+ struct wsm_buf *buf) -+{ -+ u8 count; -+ u32 sta_asleep_mask = 0; -+ int i; -+ u32 mask = 0; -+ u32 change_mask = 0; -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ /* There is no status field in this message */ -+ sta_asleep_mask = WSM_GET32(buf); -+ count = WSM_GET8(buf); -+ count -= 1; /* Current workaround for FW issue */ -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ change_mask = (priv->sta_asleep_mask ^ sta_asleep_mask); -+ wsm_printk(XRADIO_DBG_MSG, "CM %x, HM %x, FWM %x\n", change_mask,priv->sta_asleep_mask, sta_asleep_mask); -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+ if (change_mask) { -+ struct ieee80211_sta *sta; -+ int ret = 0; -+ -+ -+ for (i = 0; i < MAX_STA_IN_AP_MODE ; ++i) { -+ -+ if(XRADIO_LINK_HARD != priv->link_id_db[i].status) -+ continue; -+ -+ mask = BIT(i + 1); -+ -+ /* If FW state and host state for this link are different then notify OMAC */ -+ if(change_mask & mask) { -+ wsm_printk(XRADIO_DBG_MSG, "PS State Changed %d for sta %pM\n", (sta_asleep_mask & mask) ? 1:0, priv->link_id_db[i].mac); -+ rcu_read_lock(); -+ sta = ieee80211_find_sta(priv->vif, priv->link_id_db[i].mac); -+ if (!sta) { -+ wsm_printk(XRADIO_DBG_MSG, "WRBC - could not find sta %pM\n", -+ priv->link_id_db[i].mac); -+ } else { -+ ret = ieee80211_sta_ps_transition_ni(sta, (sta_asleep_mask & mask) ? true: false); -+ wsm_printk(XRADIO_DBG_MSG, "PS State NOTIFIED %d\n", ret); -+ WARN_ON(ret); -+ } -+ rcu_read_unlock(); -+ } -+ } -+ /* Replace STA mask with one reported by FW */ -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->sta_asleep_mask = sta_asleep_mask; -+ spin_unlock_bh(&priv->ps_state_lock); -+ } -+ -+ wsm_printk(XRADIO_DBG_MSG, "WRBC - HW Buf count %d SleepMask %d\n", -+ hw_priv->hw_bufs_used, sta_asleep_mask); -+ hw_priv->buf_released = 0; -+ WARN_ON(count != (hw_priv->wsm_caps.numInpChBufs - 1)); -+ -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+/* 3.67 */ -+int wsm_request_buffer_request(struct xradio_vif *priv, -+ u8 *arg) -+{ -+ int ret; -+ struct wsm_buf *buf = &priv->hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(priv->hw_priv); -+ -+ WSM_PUT8(buf, (*arg)); -+ WSM_PUT8(buf, 0); -+ WSM_PUT16(buf, 0); -+ -+ ret = wsm_cmd_send(priv->hw_priv, buf, arg, 0x0023, WSM_CMD_JOIN_TIMEOUT,priv->if_id); -+ -+ wsm_cmd_unlock(priv->hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(priv->hw_priv); -+ return -ENOMEM; -+} -+ -+#endif -+ -+int wsm_set_keepalive_filter(struct xradio_vif *priv, bool enable) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ priv->rx_filter.keepalive = enable; -+ return wsm_set_rx_filter(hw_priv, &priv->rx_filter, priv->if_id); -+} -+ -+int wsm_set_probe_responder(struct xradio_vif *priv, bool enable) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ priv->rx_filter.probeResponder = enable; -+ return wsm_set_rx_filter(hw_priv, &priv->rx_filter, priv->if_id); -+} -+/* ******************************************************************** */ -+/* WSM indication events implementation */ -+ -+static int wsm_startup_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ u16 status; -+ static const char * const fw_types[] = { -+ "ETF", -+ "WFM", -+ "WSM", -+ "HI test", -+ "Platform test" -+ }; -+ -+ hw_priv->wsm_caps.numInpChBufs = WSM_GET16(buf); -+ hw_priv->wsm_caps.sizeInpChBuf = WSM_GET16(buf); -+ hw_priv->wsm_caps.hardwareId = WSM_GET16(buf); -+ hw_priv->wsm_caps.hardwareSubId = WSM_GET16(buf); -+ status = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareCap = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareType = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareApiVer = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareBuildNumber = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareVersion = WSM_GET16(buf); -+ WSM_GET(buf, &hw_priv->wsm_caps.fw_label[0], WSM_FW_LABEL); -+ hw_priv->wsm_caps.fw_label[WSM_FW_LABEL+1] = 0; /* Do not trust FW too much. */ -+ -+ if (WARN_ON(status)) -+ return -EINVAL; -+ -+ if (WARN_ON(hw_priv->wsm_caps.firmwareType > 4)) -+ return -EINVAL; -+ -+ dev_info(hw_priv->pdev, -+ " Input buffers: %d x %d bytes\n" -+ " Hardware: %d.%d\n" -+ " %s firmware ver: %d, build: %d," -+ " api: %d, cap: 0x%.4X\n", -+ hw_priv->wsm_caps.numInpChBufs, -+ hw_priv->wsm_caps.sizeInpChBuf, -+ hw_priv->wsm_caps.hardwareId, -+ hw_priv->wsm_caps.hardwareSubId, -+ fw_types[hw_priv->wsm_caps.firmwareType], -+ hw_priv->wsm_caps.firmwareVersion, -+ hw_priv->wsm_caps.firmwareBuildNumber, -+ hw_priv->wsm_caps.firmwareApiVer, -+ hw_priv->wsm_caps.firmwareCap); -+ -+ dev_info(hw_priv->pdev, "Firmware Label:%s\n", &hw_priv->wsm_caps.fw_label[0]); -+ -+ hw_priv->wsm_caps.firmwareReady = 1; -+ -+ wake_up(&hw_priv->wsm_startup_done); -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+//add by yangfh 2014-10-31 16:58:53 -+void wms_send_deauth_to_self(struct xradio_common *hw_priv, struct xradio_vif *priv) -+{ -+ struct sk_buff *skb = NULL; -+ struct ieee80211_mgmt *deauth = NULL; -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ int i = 0; -+ wsm_printk(XRADIO_DBG_WARN, "AP mode, send_deauth_to_self\n"); -+ for (i = 0; ilink_id_db[i].status == XRADIO_LINK_HARD) { -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ return; -+ skb_reserve(skb, 64); -+ deauth = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ if(!deauth) { -+ WARN_ON(1); -+ return; -+ } -+ deauth->frame_control = -+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); -+ deauth->duration = 0; -+ memcpy(deauth->da, priv->vif->addr, ETH_ALEN); -+ memcpy(deauth->sa, priv->link_id_db[i].mac, ETH_ALEN); -+ memcpy(deauth->bssid, priv->vif->addr, ETH_ALEN); -+ deauth->seq_ctrl = 0; -+ deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+ } -+ } else if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ wsm_printk(XRADIO_DBG_WARN, "STA mode, send_deauth_to_self\n"); -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ return; -+ skb_reserve(skb, 64); -+ deauth = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ if(!deauth) { -+ WARN_ON(1); -+ return; -+ } -+ deauth->frame_control = -+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); -+ deauth->duration = 0; -+ memcpy(deauth->da, priv->vif->addr, ETH_ALEN); -+ memcpy(deauth->sa, priv->join_bssid, ETH_ALEN); -+ memcpy(deauth->bssid, priv->join_bssid, ETH_ALEN); -+ deauth->seq_ctrl = 0; -+ deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+} -+ -+void wms_send_disassoc_to_self(struct xradio_common *hw_priv, struct xradio_vif *priv) -+{ -+ struct sk_buff *skb = NULL; -+ struct ieee80211_mgmt *disassoc = NULL; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ int i = 0; -+ wsm_printk(XRADIO_DBG_WARN, "AP mode, wms_send_disassoc_to_self\n"); -+ for (i = 0; ilink_id_db[i].status == XRADIO_LINK_HARD) { -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ return; -+ skb_reserve(skb, 64); -+ disassoc = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ if(!disassoc) { -+ WARN_ON(1); -+ return; -+ } -+ disassoc->frame_control = -+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DISASSOC); -+ disassoc->duration = 0; -+ memcpy(disassoc->da, priv->vif->addr, ETH_ALEN); -+ memcpy(disassoc->sa, priv->link_id_db[i].mac, ETH_ALEN); -+ memcpy(disassoc->bssid, priv->vif->addr, ETH_ALEN); -+ disassoc->seq_ctrl = 0; -+ disassoc->u.disassoc.reason_code = WLAN_REASON_DISASSOC_STA_HAS_LEFT; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+ } -+ } else if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ wsm_printk(XRADIO_DBG_WARN, "STA mode, wms_send_disassoc_to_self\n"); -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ return; -+ skb_reserve(skb, 64); -+ disassoc = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ if(!disassoc) { -+ WARN_ON(1); -+ return; -+ } -+ disassoc->frame_control = -+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DISASSOC); -+ disassoc->duration = 0; -+ memcpy(disassoc->da, priv->vif->addr, ETH_ALEN); -+ memcpy(disassoc->sa, priv->join_bssid, ETH_ALEN); -+ memcpy(disassoc->bssid, priv->join_bssid, ETH_ALEN); -+ disassoc->seq_ctrl = 0; -+ disassoc->u.disassoc.reason_code = WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+} -+ -+static int wsm_receive_indication(struct xradio_common *hw_priv, -+ int interface_link_id, -+ struct wsm_buf *buf, -+ struct sk_buff **skb_p) -+{ -+ struct xradio_vif *priv; -+ struct wsm_rx rx; -+ struct ieee80211_hdr *hdr; -+ size_t hdr_len; -+ -+ hw_priv->rx_timestamp = jiffies; -+ -+ rx.status = WSM_GET32(buf); -+ rx.channelNumber = WSM_GET16(buf); -+ rx.rxedRate = WSM_GET8(buf); -+ rx.rcpiRssi = WSM_GET8(buf); -+ rx.flags = WSM_GET32(buf); -+ -+ /* TODO:COMBO: Frames received from scanning are received -+ * with interface ID == 2 */ -+ if (is_hardware_xradio(hw_priv)) { -+ if (interface_link_id == XRWL_GENERIC_IF_ID) { -+ /* Frames received in response to SCAN -+ * Request */ -+ interface_link_id = -+ get_interface_id_scanning(hw_priv); -+ if (interface_link_id == -1) { -+ interface_link_id = hw_priv->roc_if_id; -+ } -+#ifdef ROAM_OFFLOAD -+ if (hw_priv->auto_scanning) { -+ interface_link_id = hw_priv->scan.if_id; -+ } -+#endif/*ROAM_OFFLOAD*/ -+ } -+ /* linkid (peer sta id is encoded in bit 25-28 of -+ flags field */ -+ rx.link_id = ((rx.flags & (0xf << 25)) >> 25); -+ rx.if_id = interface_link_id; -+ } else { -+ rx.link_id = interface_link_id; -+ rx.if_id = 0; -+ } -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, rx.if_id); -+ if (!priv) { -+ dev_dbg(hw_priv->pdev, "got frame on a vif we don't have, dropped\n"); -+ return 0; -+ } -+ //remove wsm hdr of skb -+ hdr_len = buf->data - buf->begin; -+ skb_pull(*skb_p, hdr_len); -+ -+ /* FW Workaround: Drop probe resp or -+ beacon when RSSI is 0 */ -+ hdr = (struct ieee80211_hdr *) (*skb_p)->data; -+ -+ if (!rx.rcpiRssi && -+ (ieee80211_is_probe_resp(hdr->frame_control) || -+ ieee80211_is_beacon(hdr->frame_control))) { -+ spin_unlock(&priv->vif_lock); -+ return 0; -+ } -+ -+ /* If no RSSI subscription has been made, -+ * convert RCPI to RSSI here */ -+ if (!priv->cqm_use_rssi) -+ rx.rcpiRssi = rx.rcpiRssi / 2 - 110; -+ -+ if (!rx.status && unlikely(ieee80211_is_deauth(hdr->frame_control))) { -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ /* Shedule unjoin work */ -+ dev_dbg(hw_priv->pdev, -+ "Issue unjoin command (RX).\n"); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, -+ &priv->unjoin_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+ xradio_rx_cb(priv, &rx, skb_p); -+ if (*skb_p) -+ skb_push(*skb_p, hdr_len); -+ spin_unlock(&priv->vif_lock); -+ -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+ -+static int wsm_event_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, -+ int interface_link_id) -+{ -+ int first; -+ struct xradio_wsm_event *event = NULL; -+ struct xradio_vif *priv; -+ -+ if (!is_hardware_xradio(hw_priv)) -+ interface_link_id = 0; -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, interface_link_id); -+ -+ if (unlikely(!priv)) { -+ dev_warn(hw_priv->pdev, "Event: %d(%d) for removed " -+ "interface, ignoring\n", __le32_to_cpu(WSM_GET32(buf)), -+ __le32_to_cpu(WSM_GET32(buf))); -+ return 0; -+ } -+ -+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { -+ /* STA is stopped. */ -+ return 0; -+ } -+ spin_unlock(&priv->vif_lock); -+ -+ event = kzalloc(sizeof(struct xradio_wsm_event), GFP_KERNEL); -+ if (event == NULL) { -+ dev_err(hw_priv->pdev, "xr_kzalloc failed!"); -+ return -EINVAL; -+ } -+ -+ event->evt.eventId = __le32_to_cpu(WSM_GET32(buf)); -+ event->evt.eventData = __le32_to_cpu(WSM_GET32(buf)); -+ event->if_id = interface_link_id; -+ -+ dev_dbg(hw_priv->pdev, "Event: %d(%d)\n", -+ event->evt.eventId, event->evt.eventData); -+ -+ spin_lock(&hw_priv->event_queue_lock); -+ first = list_empty(&hw_priv->event_queue); -+ list_add_tail(&event->link, &hw_priv->event_queue); -+ spin_unlock(&hw_priv->event_queue_lock); -+ -+ if (first) -+ queue_work(hw_priv->workqueue, &hw_priv->event_handler); -+ -+ return 0; -+ -+underflow: -+ kfree(event); -+ return -EINVAL; -+} -+ -+#define PRINT_11K_MEASRURE 1 -+static int wsm_measure_cmpl_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ MEASUREMENT_COMPLETE measure_cmpl; -+ u8 cca_chanload; -+ u32 buf_len = 0; -+ u32 *data; -+ -+ LMAC_MEAS_CHANNEL_LOAD_RESULTS *chanload_res; -+ LMAC_MEAS_NOISE_HISTOGRAM_RESULTS *noise_res; -+ WSM_GET(buf, &measure_cmpl, 12); -+ -+ switch (measure_cmpl.MeasurementType) { -+ case ChannelLoadMeasurement: -+ buf_len = sizeof(LMAC_MEAS_CHANNEL_LOAD_RESULTS); -+ break; -+ case NoiseHistrogramMeasurement: -+ buf_len = sizeof(LMAC_MEAS_NOISE_HISTOGRAM_RESULTS); -+ break; -+ case BeaconReport: -+ buf_len = sizeof(LMAC_MEAS_BEACON_RESULTS); -+ break; -+ case STAstatisticsReport: -+ buf_len = sizeof(LMAC_MEAS_STA_STATS_RESULTS); -+ break; -+ case LinkMeasurement: -+ buf_len = sizeof(LMAC_MEAS_LINK_MEASUREMENT_RESULTS); -+ break; -+ } -+ wsm_printk(XRADIO_DBG_ERROR, "[11K]buf_len = %d\n", buf_len); -+ WSM_GET(buf, &measure_cmpl.MeasurementReport, buf_len); -+ -+ data = (u32 *)(&measure_cmpl); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[0]=%08x\n", data[0]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[1]=%08x\n", data[1]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[2]=%08x\n", data[2]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[3]=%08x\n", data[3]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[4]=%08x\n", data[4]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[5]=%08x\n", data[5]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[6]=%08x\n", data[6]); -+ wsm_printk(XRADIO_DBG_ERROR, "[***HL***]MeasurementType=%0d\n", measure_cmpl.MeasurementType); -+ -+ if (measure_cmpl.Status == WSM_STATUS_SUCCESS){ -+ switch (measure_cmpl.MeasurementType) { -+ case ChannelLoadMeasurement: -+ chanload_res = &measure_cmpl.MeasurementReport.ChannelLoadResults; -+ cca_chanload = (chanload_res->ChannelLoadCCA == MEAS_CCA) ? -+ chanload_res->CCAbusyFraction : -+ chanload_res->ChannelLoad; -+ #ifdef PRINT_11K_MEASRURE -+ wsm_printk(XRADIO_DBG_ERROR, "[11K] ChannelLoadMeasurement Result:\n"\ -+ "ChannelLoadCCA = %d\n"\ -+ "ChannelNum = %d\n"\ -+ "Duration = %d\n"\ -+ "Fraction = %d\n", \ -+ chanload_res->ChannelLoadCCA,\ -+ chanload_res->ChannelNum,\ -+ chanload_res->MeasurementDuration,\ -+ cca_chanload -+ ); -+ #endif -+ break; -+ case NoiseHistrogramMeasurement: -+ noise_res = &measure_cmpl.MeasurementReport.NoiseHistogramResults; -+// IpiRpi = (noise_res->IpiRpi == MEAS_RPI) ? -+// chanload_res->CCAbusyFraction : -+// chanload_res->ChannelLoad; -+ #ifdef PRINT_11K_MEASRURE -+ wsm_printk(XRADIO_DBG_ERROR, "[11K] NoiseHistogramResults:\n"\ -+ "IpiRpi = %d\n"\ -+ "ChannelNum = %d\n"\ -+ "PI_0__Density = %d\n"\ -+ "PI_1__Density = %d\n"\ -+ "PI_2__Density = %d\n"\ -+ "PI_3__Density = %d\n"\ -+ "PI_4__Density = %d\n"\ -+ "PI_5__Density = %d\n"\ -+ "PI_6__Density = %d\n"\ -+ "PI_7__Density = %d\n"\ -+ "PI_8__Density = %d\n"\ -+ "PI_9__Density = %d\n"\ -+ "PI_10_Density = %d\n", \ -+ noise_res->IpiRpi,\ -+ noise_res->ChannelNum,\ -+ noise_res->PI_0_Density,\ -+ noise_res->PI_1_Density,\ -+ noise_res->PI_2_Density,\ -+ noise_res->PI_3_Density,\ -+ noise_res->PI_4_Density,\ -+ noise_res->PI_5_Density,\ -+ noise_res->PI_6_Density,\ -+ noise_res->PI_7_Density,\ -+ noise_res->PI_8_Density,\ -+ noise_res->PI_9_Density,\ -+ noise_res->PI_10_Density -+ ); -+ #endif -+ break; -+ case BeaconReport: -+ break; -+ case STAstatisticsReport: -+ break; -+ case LinkMeasurement: -+ break; -+ } -+ } else { -+ wsm_printk(XRADIO_DBG_ERROR, "11K Measure(type=%d) Fail\n", measure_cmpl.MeasurementType); -+ } -+ -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+/* TODO:COMBO:Make this perVIFF once mac80211 support is available */ -+static int wsm_channel_switch_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ wsm_unlock_tx(hw_priv); /* Re-enable datapath */ -+ WARN_ON(WSM_GET32(buf)); -+ -+ hw_priv->channel_switch_in_progress = 0; -+ wake_up(&hw_priv->channel_switch_done); -+ -+ -+ xradio_channel_switch_cb(hw_priv); -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+ -+static int wsm_set_pm_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ wsm_oper_unlock(hw_priv); -+ return 0; -+} -+ -+static int wsm_scan_complete_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ struct wsm_scan_complete arg; -+#ifdef ROAM_OFFLOAD -+ if(hw_priv->auto_scanning == 0) -+ wsm_oper_unlock(hw_priv); -+#else -+ wsm_oper_unlock(hw_priv); -+#endif /*ROAM_OFFLOAD*/ -+ -+ arg.status = WSM_GET32(buf); -+ arg.psm = WSM_GET8(buf); -+ arg.numChannels = WSM_GET8(buf); -+ xradio_scan_complete_cb(hw_priv, &arg); -+ -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+ -+static int wsm_find_complete_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ /* TODO: Implement me. */ -+ //STUB(); -+ return 0; -+} -+ -+static int wsm_suspend_resume_indication(struct xradio_common *hw_priv, -+ int interface_link_id, -+ struct wsm_buf *buf) -+{ -+ u32 flags; -+ struct wsm_suspend_resume arg; -+ struct xradio_vif *priv; -+ -+ if (is_hardware_xradio(hw_priv)) { -+ int i; -+ arg.if_id = interface_link_id; -+ /* TODO:COMBO: Extract bitmap from suspend-resume -+ * TX indication */ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ if (priv->join_status == -+ XRADIO_JOIN_STATUS_AP) { -+ arg.if_id = priv->if_id; -+ break; -+ } -+ arg.link_id = 0; -+ } -+ } else { -+ arg.if_id = 0; -+ arg.link_id = interface_link_id; -+ } -+ -+ flags = WSM_GET32(buf); -+ arg.stop = !(flags & 1); -+ arg.multicast = !!(flags & 8); -+ arg.queue = (flags >> 1) & 3; -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, arg.if_id); -+ if (unlikely(!priv)) { -+ wsm_printk(XRADIO_DBG_MSG, "suspend-resume indication" -+ " for removed interface!\n"); -+ return 0; -+ } -+ xradio_suspend_resume(priv, &arg); -+ spin_unlock(&priv->vif_lock); -+ -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+ -+ -+/* ******************************************************************** */ -+/* WSM TX */ -+ -+int wsm_cmd_send(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, -+ void *arg, u16 cmd, long tmo, int if_id) -+{ -+ size_t buf_len = buf->data - buf->begin; -+ int ret; -+ -+ if (cmd == 0x0006 || cmd == 0x0005) /* Write/Read MIB */ -+ wsm_printk(XRADIO_DBG_MSG, ">>> 0x%.4X [MIB: 0x%.4X] (%d)\n", -+ cmd, __le16_to_cpu(((__le16 *)buf->begin)[2]), -+ buf_len); -+ else -+ wsm_printk(XRADIO_DBG_MSG, ">>> 0x%.4X (%d)\n", cmd, buf_len); -+ -+ if (unlikely(hw_priv->bh_error)) { -+ wsm_buf_reset(buf); -+ wsm_printk(XRADIO_DBG_ERROR, "bh error!>>> 0x%.4X (%d)\n", cmd, buf_len); -+ return -ETIMEDOUT; -+ } -+ -+ /* Fill HI message header */ -+ /* BH will add sequence number */ -+ -+ /* TODO:COMBO: Add if_id from to the WSM header */ -+ /* if_id == -1 indicates that command is HW specific, -+ * eg. wsm_configuration which is called during driver initialzation -+ * (mac80211 .start callback called when first ifce is created. )*/ -+ -+ /* send hw specific commands on if 0 */ -+ if (if_id == -1) -+ if_id = 0; -+ -+ ((__le16 *)buf->begin)[0] = __cpu_to_le16(buf_len); -+ ((__le16 *)buf->begin)[1] = __cpu_to_le16(cmd | -+ ((is_hardware_xradio(hw_priv)) ? (if_id << 6) : 0)); -+ -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ BUG_ON(hw_priv->wsm_cmd.ptr); -+ hw_priv->wsm_cmd.done = 0; -+ hw_priv->wsm_cmd.ptr = buf->begin; -+ hw_priv->wsm_cmd.len = buf_len; -+ hw_priv->wsm_cmd.arg = arg; -+ hw_priv->wsm_cmd.cmd = cmd; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ -+ xradio_bh_wakeup(hw_priv); -+ -+ if (unlikely(hw_priv->bh_error)) { -+ /* Do not wait for timeout if BH is dead. Exit immediately. */ -+ ret = 0; -+ } else { -+ unsigned long wsm_cmd_max_tmo; -+ -+ /* Give start cmd a little more time */ -+ if (unlikely(tmo == WSM_CMD_START_TIMEOUT)) -+ wsm_cmd_max_tmo = WSM_CMD_START_TIMEOUT; -+ else -+ wsm_cmd_max_tmo = WSM_CMD_DEFAULT_TIMEOUT; -+ -+ /*Set max timeout.*/ -+ wsm_cmd_max_tmo = jiffies + wsm_cmd_max_tmo; -+ -+ /* Firmware prioritizes data traffic over control confirm. -+ * Loop below checks if data was RXed and increases timeout -+ * accordingly. */ -+ do { -+ /* It's safe to use unprotected access to wsm_cmd.done here */ -+ ret = wait_event_timeout(hw_priv->wsm_cmd_wq, hw_priv->wsm_cmd.done, tmo); -+ -+ /* check time since last rxed and max timeout.*/ -+ } while (!ret && -+ time_before_eq(jiffies, hw_priv->rx_timestamp+tmo) && -+ time_before(jiffies, wsm_cmd_max_tmo)); -+ -+ } -+ -+ if (unlikely(ret == 0)) { -+ u16 raceCheck; -+ -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ raceCheck = hw_priv->wsm_cmd.cmd; -+ hw_priv->wsm_cmd.arg = NULL; -+ hw_priv->wsm_cmd.ptr = NULL; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ -+ dev_err(hw_priv->pdev, "***CMD timeout!>>> 0x%.4X (%d), buf_use=%d, bh_state=%d\n", -+ cmd, buf_len, hw_priv->hw_bufs_used, hw_priv->bh_error); -+ /* Race condition check to make sure _confirm is not called -+ * after exit of _send */ -+ if (raceCheck == 0xFFFF) { -+ /* If wsm_handle_rx got stuck in _confirm we will hang -+ * system there. It's better than silently currupt -+ * stack or heap, isn't it? */ -+ BUG_ON(wait_event_timeout( -+ hw_priv->wsm_cmd_wq, -+ hw_priv->wsm_cmd.done, -+ WSM_CMD_LAST_CHANCE_TIMEOUT) <= 0); -+ } -+ -+ /* Kill BH thread to report the error to the top layer. */ -+ hw_priv->bh_error = 1; -+#ifdef BH_USE_SEMAPHORE -+ up(&hw_priv->bh_sem); -+#else -+ wake_up(&hw_priv->bh_wq); -+#endif -+ ret = -ETIMEDOUT; -+ } else { -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ BUG_ON(!hw_priv->wsm_cmd.done); -+ ret = hw_priv->wsm_cmd.ret; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ } -+ wsm_buf_reset(buf); -+ return ret; -+} -+ -+/* ******************************************************************** */ -+/* WSM TX port control */ -+ -+void wsm_lock_tx(struct xradio_common *hw_priv) -+{ -+ down(&hw_priv->tx_lock_sem); -+ atomic_add(1, &hw_priv->tx_lock); -+ /* always check event if wsm_vif_lock_tx.*/ -+ if (wsm_flush_tx(hw_priv)) -+ wsm_printk(XRADIO_DBG_MSG, "TX is locked.\n"); -+ up(&hw_priv->tx_lock_sem); -+} -+ -+void wsm_vif_lock_tx(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ down(&hw_priv->tx_lock_sem); -+ if (atomic_add_return(1, &hw_priv->tx_lock) == 1) { -+ if (wsm_vif_flush_tx(priv)) -+ wsm_printk(XRADIO_DBG_MSG, "TX is locked for" -+ " if_id %d.\n", priv->if_id); -+ } -+ up(&hw_priv->tx_lock_sem); -+} -+ -+void wsm_lock_tx_async(struct xradio_common *hw_priv) -+{ -+ if (atomic_add_return(1, &hw_priv->tx_lock) == 1) -+ wsm_printk(XRADIO_DBG_MSG, "TX is locked (async).\n"); -+} -+ -+bool wsm_flush_tx(struct xradio_common *hw_priv) -+{ -+ long timeout = WSM_CMD_LAST_CHANCE_TIMEOUT; -+ -+ /* Flush must be called with TX lock held. */ -+ BUG_ON(!atomic_read(&hw_priv->tx_lock)); -+ -+ /* First check if we really need to do something. -+ * It is safe to use unprotected access, as hw_bufs_used -+ * can only decrements. */ -+ if (!hw_priv->hw_bufs_used) -+ return true; -+ -+ if (hw_priv->bh_error) { -+ /* In case of failure do not wait for magic. */ -+ wsm_printk(XRADIO_DBG_ERROR, "Fatal error occured, " -+ "will not flush TX.\n"); -+ return false; -+ } else { -+ /* Get "oldest" frame, if any frames stuck in firmware, -+ query all of them until max timeout. */ -+ int num = hw_priv->hw_bufs_used + 1; -+ while (xradio_query_txpkt_timeout(hw_priv, XRWL_ALL_IFS, -+ 0xffffffff, &timeout)) { -+ if (timeout < 0 || !num) { -+ /* Hmmm... Not good. Frame had stuck in firmware. */ -+ wsm_printk(XRADIO_DBG_ERROR, -+ "%s:hw_bufs_used=%d, num=%d, timeout=%ld\n", -+ __func__, hw_priv->hw_bufs_used, num, timeout); -+ hw_priv->bh_error = 1; -+#ifdef BH_USE_SEMAPHORE -+ up(&hw_priv->bh_sem); -+#else -+ wake_up(&hw_priv->bh_wq); -+#endif -+ return false; -+ } else if (wait_event_timeout(hw_priv->bh_evt_wq, -+ !hw_priv->hw_bufs_used, timeout) > 0) { -+ return true; -+ } -+ --num; -+ } -+ if (hw_priv->hw_bufs_used) -+ wsm_printk(XRADIO_DBG_ERROR, "%s:No pengding, but hw_bufs_used=%d\n", -+ __func__, hw_priv->hw_bufs_used); -+ /* Ok, everything is flushed. */ -+ return true; -+ } -+} -+ -+bool wsm_vif_flush_tx(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ long timeout = WSM_CMD_LAST_CHANCE_TIMEOUT; -+ int if_id = priv->if_id; -+ -+ /* Flush must be called with TX lock held. */ -+ BUG_ON(!atomic_read(&hw_priv->tx_lock)); -+ -+ /* First check if we really need to do something. -+ * It is safe to use unprotected access, as hw_bufs_used -+ * can only decrements. */ -+ if (!hw_priv->hw_bufs_used_vif[if_id]) -+ return true; -+ -+ if (hw_priv->bh_error) { -+ /* In case of failure do not wait for magic. */ -+ wsm_printk(XRADIO_DBG_ERROR, "Fatal error occured, " -+ "will not flush TX.\n"); -+ return false; -+ } else { -+ /* Get "oldest" frame, if any frames stuck in firmware, -+ query all of them until max timeout. */ -+ int num = hw_priv->hw_bufs_used_vif[if_id] + 1; -+ while (xradio_query_txpkt_timeout(hw_priv, if_id, 0xffffffff, &timeout)) { -+ if (timeout < 0 || !num) { -+ /* Hmmm... Not good. Frame had stuck in firmware. */ -+ wsm_printk(XRADIO_DBG_ERROR, "%s: if_id=%d, hw_bufs_used_vif=%d, num=%d\n", -+ __func__, if_id, hw_priv->hw_bufs_used_vif[priv->if_id], -+ num); -+ hw_priv->bh_error = 1; -+ #ifdef BH_USE_SEMAPHORE -+ up(&hw_priv->bh_sem); -+ #else -+ wake_up(&hw_priv->bh_wq); -+ #endif -+ return false; -+ } else if (wait_event_timeout(hw_priv->bh_evt_wq, -+ !hw_priv->hw_bufs_used_vif[if_id], timeout) > 0) { -+ return true; -+ } -+ --num; -+ } -+ if (hw_priv->hw_bufs_used_vif[if_id]) -+ wsm_printk(XRADIO_DBG_ERROR, "%s:No pengding, but hw_bufs_used_vif=%d\n", -+ __func__, hw_priv->hw_bufs_used_vif[priv->if_id]); -+ /* Ok, everything is flushed. */ -+ return true; -+ } -+} -+ -+ -+void wsm_unlock_tx(struct xradio_common *hw_priv) -+{ -+ int tx_lock; -+ if (hw_priv->bh_error) -+ wsm_printk(XRADIO_DBG_ERROR, "bh_error=%d, wsm_unlock_tx is unsafe\n", -+ hw_priv->bh_error); -+ else { -+ tx_lock = atomic_sub_return(1, &hw_priv->tx_lock); -+ if (tx_lock < 0) { -+ BUG_ON(1); -+ } else if (tx_lock == 0) { -+ xradio_bh_wakeup(hw_priv); -+ wsm_printk(XRADIO_DBG_MSG, "TX is unlocked.\n"); -+ } -+ } -+} -+ -+/* ******************************************************************** */ -+/* WSM RX */ -+ -+int wsm_handle_exception(struct xradio_common *hw_priv, u8 *data, size_t len) -+{ -+ struct wsm_buf buf; -+ u32 reason; -+ u32 reg[18]; -+ char fname[48]; -+ int i = 0; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ struct xradio_vif *priv = NULL; -+#endif -+ -+ static const char * const reason_str[] = { -+ "undefined instruction", -+ "prefetch abort", -+ "data abort", -+ "unknown error", -+ }; -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ /* Send the event upwards on the FW exception */ -+ xradio_pm_stay_awake(&hw_priv->pm_state, 3*HZ); -+ -+ spin_lock(&hw_priv->vif_list_lock); -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ //ieee80211_driver_hang_notify(priv->vif, GFP_KERNEL); -+ } -+ spin_unlock(&hw_priv->vif_list_lock); -+#endif -+ -+ buf.begin = buf.data = data; -+ buf.end = &buf.begin[len]; -+ -+ reason = WSM_GET32(&buf); -+ for (i = 0; i < ARRAY_SIZE(reg); ++i) -+ reg[i] = WSM_GET32(&buf); -+ WSM_GET(&buf, fname, sizeof(fname)); -+ -+ if (reason < 4) { -+ dev_err(hw_priv->pdev, "Firmware exception: %s.\n", -+ reason_str[reason]); -+ } else { -+ dev_err(hw_priv->pdev, "Firmware assert at %.*s, line %d, reason=0x%x\n", -+ sizeof(fname), fname, reg[1], reg[2]); -+ } -+ -+ for (i = 0; i < 12; i += 4) { -+ dev_err(hw_priv->pdev, "Firmware:" \ -+ "R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X,\n", -+ i + 0, reg[i + 0], i + 1, reg[i + 1], -+ i + 2, reg[i + 2], i + 3, reg[i + 3]); -+ } -+ dev_err(hw_priv->pdev, "Firmware:" \ -+ "R12: 0x%.8X, SP: 0x%.8X, LR: 0x%.8X, PC: 0x%.8X,\n", -+ reg[i + 0], reg[i + 1], reg[i + 2], reg[i + 3]); -+ i += 4; -+ dev_err(hw_priv->pdev, "Firmware:CPSR: 0x%.8X, SPSR: 0x%.8X\n", -+ reg[i + 0], reg[i + 1]); -+ -+ return 0; -+ -+underflow: -+ dev_err(hw_priv->pdev, "Firmware exception.\n"); -+ print_hex_dump_bytes("Exception: ", DUMP_PREFIX_NONE, data, len); -+ return -EINVAL; -+} -+ -+static int wsm_debug_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ //for only one debug item. -+ u32 dbg_id, buf_data=0; -+ u16 dbg_buf_len; -+ u8 dbg_len; -+ u8 *dbg_buf; -+ dbg_id = WSM_GET32(buf); -+ -+ dbg_buf_len = buf->end - buf->data; -+ -+ if (dbg_id == 5) { -+ do { -+ dbg_buf_len = buf->end - buf->data; -+ dbg_len = WSM_GET8(buf); -+ if (dbg_len > dbg_buf_len - sizeof(dbg_len)) { -+ wsm_printk(XRADIO_DBG_ERROR, "[FW]dbg_len = %d\n", dbg_len); -+ wsm_printk(XRADIO_DBG_ERROR, "[FW]dbg_buf_len = %d\n", dbg_buf_len); -+ wsm_printk(XRADIO_DBG_ERROR, "[FW]debug ind err\n"); -+ //ret = -EINVAL; -+ //return ret; -+ -+ -+ break; -+ } -+ -+ dbg_buf = buf->data; -+ //print it; -+ wsm_printk(XRADIO_DBG_ALWY, "[FW-LOG] %s", dbg_buf); -+ // -+ buf->data += dbg_len; -+ -+ } while (buf->data < buf->end); -+ } else { -+ if (dbg_buf_len >= 4) { -+ buf_data = WSM_GET32(buf); -+ wsm_printk(XRADIO_DBG_ALWY, "[FW-DEBUG] DbgId = %d, data = %d", dbg_id, buf_data); -+ } else { -+ wsm_printk(XRADIO_DBG_ALWY, "[FW-DEBUG] DbgId = %d", dbg_id); -+ } -+ } -+ -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+int wsm_handle_rx(struct xradio_common *hw_priv, int id, -+ struct wsm_hdr *wsm, struct sk_buff **skb_p) -+{ -+ int ret = 0; -+ struct wsm_buf wsm_buf; -+ /* struct xradio_vif *priv = NULL; MRK: unused variable, see if 0 below */ -+ /* int i = 0; MRK: unused variable, see if 0 below */ -+ int interface_link_id = (id >> 6) & 0x0F; -+#ifdef ROAM_OFFLOAD -+#if 0 -+ struct xradio_vif *priv; -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, interface_link_id); -+ if (unlikely(!priv)) { -+ WARN_ON(1); -+ return 0; -+ } -+ spin_unlock(&priv->vif_lock); -+#endif -+#endif/*ROAM_OFFLOAD*/ -+ -+ /* Strip link id. */ -+ id &= ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); -+ -+ wsm_buf.begin = (u8 *)&wsm[0]; -+ wsm_buf.data = (u8 *)&wsm[1]; -+ wsm_buf.end = &wsm_buf.begin[__le32_to_cpu(wsm->len)]; -+ -+ wsm_printk(XRADIO_DBG_MSG, "<<< 0x%.4X (%d)\n", id, -+ wsm_buf.end - wsm_buf.begin); -+ -+#if defined(DGB_XRADIO_HWT) -+/***************************for HWT ********************************/ -+ if (id == 0x0424) { -+ u16 TestID = *(u16 *)(wsm_buf.data); -+ if (TestID == 1) //test frame confirm. -+ wsm_hwt_tx_confirm(hw_priv, &wsm_buf); -+ else { -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ hw_priv->wsm_cmd.ret = *((u16 *)(wsm_buf.data) + 1); -+ hw_priv->wsm_cmd.done = 1; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ wake_up(&hw_priv->wsm_cmd_wq); -+ wsm_printk(XRADIO_DBG_ALWY, "HWT TestID=0x%x Confirm ret=%d\n", -+ *(u16 *)(wsm_buf.data), hw_priv->wsm_cmd.ret); -+ } -+ return 0; -+ } else if (id == 0x0824) { -+ u16 TestID = *(u16 *)(wsm_buf.data); -+ switch (TestID) { -+ case 2: //recieve a test frame. -+ wsm_hwt_rx_frames(hw_priv, &wsm_buf); -+ break; -+ case 3: //enc test result. -+ wsm_hwt_enc_results(hw_priv, &wsm_buf); -+ break; -+ case 4: //mic test result. -+ wsm_hwt_mic_results(hw_priv, &wsm_buf); -+ break; -+ default: -+ wsm_printk(XRADIO_DBG_ERROR, "HWT ERROR Indication TestID=0x%x\n", TestID); -+ break; -+ } -+ return 0; -+ } -+/***************************for HWT ********************************/ -+#endif //DGB_XRADIO_HWT -+ -+ if (id == 0x404) { -+ ret = wsm_tx_confirm(hw_priv, &wsm_buf, interface_link_id); -+#ifdef MCAST_FWDING -+#if 1 -+ } else if (id == 0x422) { -+ ret = wsm_give_buffer_confirm(hw_priv, &wsm_buf); -+#endif -+#endif -+ -+ } else if (id == 0x41E) { -+ ret = wsm_multi_tx_confirm(hw_priv, &wsm_buf, -+ interface_link_id); -+ } else if (id & 0x0400) { -+ void *wsm_arg; -+ u16 wsm_cmd; -+ -+ /* Do not trust FW too much. Protection against repeated -+ * response and race condition removal (see above). */ -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ wsm_arg = hw_priv->wsm_cmd.arg; -+ wsm_cmd = hw_priv->wsm_cmd.cmd & -+ ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); -+ hw_priv->wsm_cmd.cmd = 0xFFFF; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ -+ if (WARN_ON((id & ~0x0400) != wsm_cmd)) { -+ /* Note that any non-zero is a fatal retcode. */ -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ switch (id) { -+ case 0x0409: -+ /* Note that wsm_arg can be NULL in case of timeout in -+ * wsm_cmd_send(). */ -+ if (likely(wsm_arg)) -+ ret = wsm_configuration_confirm(hw_priv, -+ wsm_arg, -+ &wsm_buf); -+ break; -+ case 0x0405: -+ if (likely(wsm_arg)) -+ ret = wsm_read_mib_confirm(hw_priv, wsm_arg, -+ &wsm_buf); -+ break; -+ case 0x0406: -+ if (likely(wsm_arg)) -+ ret = wsm_write_mib_confirm(hw_priv, wsm_arg, -+ &wsm_buf, -+ interface_link_id); -+ break; -+ case 0x040B: -+ if (likely(wsm_arg)) -+ ret = wsm_join_confirm(hw_priv, wsm_arg, &wsm_buf); -+ if (ret) -+ wsm_printk(XRADIO_DBG_WARN, "Join confirm Failed!\n"); -+ break; -+ case 0x040E: /* 11K measure*/ -+ if (likely(wsm_arg)) -+ ret = wsm_generic_confirm(hw_priv, wsm_arg, &wsm_buf); -+ if (ret) -+ wsm_printk(XRADIO_DBG_ERROR, "[***HL***]11K Confirm Error\n"); -+ -+ break; -+ -+#ifdef MCAST_FWDING -+ case 0x0423: /* req buffer cfm*/ -+ if (likely(wsm_arg)){ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (priv && (priv->join_status == XRADIO_JOIN_STATUS_AP)) -+ ret = wsm_request_buffer_confirm(priv, -+ wsm_arg, &wsm_buf); -+ } -+ } -+ break; -+#endif -+ case 0x0407: /* start-scan */ -+#ifdef ROAM_OFFLOAD -+ if (hw_priv->auto_scanning) { -+ if (atomic_read(&hw_priv->scan.in_progress)) { -+ hw_priv->auto_scanning = 0; -+ } -+ else { -+ wsm_oper_unlock(hw_priv); -+ up(&hw_priv->scan.lock); -+ } -+ } -+#endif /*ROAM_OFFLOAD*/ -+ case 0x0408: /* stop-scan */ -+ case 0x040A: /* wsm_reset */ -+ case 0x040C: /* add_key */ -+ case 0x040D: /* remove_key */ -+ case 0x0410: /* wsm_set_pm */ -+ case 0x0411: /* set_bss_params */ -+ case 0x0412: /* set_tx_queue_params */ -+ case 0x0413: /* set_edca_params */ -+ case 0x0416: /* switch_channel */ -+ case 0x0417: /* start */ -+ case 0x0418: /* beacon_transmit */ -+ case 0x0419: /* start_find */ -+ case 0x041A: /* stop_find */ -+ case 0x041B: /* update_ie */ -+ case 0x041C: /* map_link */ -+ WARN_ON(wsm_arg != NULL); -+ ret = wsm_generic_confirm(hw_priv, wsm_arg, &wsm_buf); -+ if (ret) -+ wsm_printk(XRADIO_DBG_ERROR, -+ "wsm_generic_confirm " -+ "failed for request 0x%.4X.\n", -+ id & ~0x0400); -+ break; -+ default: -+ BUG_ON(1); -+ } -+ -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ hw_priv->wsm_cmd.ret = ret; -+ hw_priv->wsm_cmd.done = 1; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ ret = 0; /* Error response from device should ne stop BH. */ -+ -+ wake_up(&hw_priv->wsm_cmd_wq); -+ } else if (id & 0x0800) { -+ switch (id) { -+ case 0x0801: -+ ret = wsm_startup_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x0804: -+ ret = wsm_receive_indication(hw_priv, interface_link_id, -+ &wsm_buf, skb_p); -+ break; -+ case 0x0805: -+ ret = wsm_event_indication(hw_priv, &wsm_buf, -+ interface_link_id); -+ break; -+ case 0x0807: -+ wsm_printk(XRADIO_DBG_ERROR, "[11K]wsm_measure_cmpl_indication\n"); -+// wsm_printk(XRADIO_DBG_ERROR, "[11K]wsm->len = %d\n",wsm->len); -+ -+ ret = wsm_measure_cmpl_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x080A: -+ ret = wsm_channel_switch_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x0809: -+ ret = wsm_set_pm_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x0806: -+#ifdef ROAM_OFFLOAD -+ if(hw_priv->auto_scanning && hw_priv->frame_rcvd) { -+ struct xradio_vif *priv; -+ hw_priv->frame_rcvd = 0; -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); -+ if (unlikely(!priv)) { -+ WARN_ON(1); -+ return 0; -+ } -+ spin_unlock(&priv->vif_lock); -+ if (hw_priv->beacon) { -+ struct wsm_scan_complete *scan_cmpl = \ -+ (struct wsm_scan_complete *) \ -+ ((u8 *)wsm + sizeof(struct wsm_hdr)); -+ struct ieee80211_rx_status *rhdr = \ -+ IEEE80211_SKB_RXCB(hw_priv->beacon); -+ rhdr->signal = (s8)scan_cmpl->reserved; -+ if (!priv->cqm_use_rssi) { -+ rhdr->signal = rhdr->signal / 2 - 110; -+ } -+ if (!hw_priv->beacon_bkp) -+ hw_priv->beacon_bkp = \ -+ skb_copy(hw_priv->beacon, GFP_ATOMIC); -+ ieee80211_rx_irqsafe(hw_priv->hw, hw_priv->beacon); -+ hw_priv->beacon = hw_priv->beacon_bkp; -+ -+ hw_priv->beacon_bkp = NULL; -+ } -+ wsm_printk(XRADIO_DBG_MSG, \ -+ "Send Testmode Event.\n"); -+ xradio_testmode_event(priv->hw->wiphy, -+ NL80211_CMD_NEW_SCAN_RESULTS, 0, -+ 0, GFP_KERNEL); -+ -+ } -+#endif /*ROAM_OFFLOAD*/ -+ ret = wsm_scan_complete_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x080B: -+ ret = wsm_find_complete_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x080C: -+ ret = wsm_suspend_resume_indication(hw_priv, -+ interface_link_id, &wsm_buf); -+ break; -+ case 0x080E: -+ wsm_printk(XRADIO_DBG_MSG, "wsm_debug_indication"); -+ ret = wsm_debug_indication(hw_priv, &wsm_buf); -+ break; -+ -+ default: -+ wsm_printk(XRADIO_DBG_ERROR, "unknown Indmsg ID=0x%04x,len=%d\n", -+ wsm->id, wsm->len); -+ break; -+ } -+ } else { -+ WARN_ON(1); -+ ret = -EINVAL; -+ } -+out: -+ return ret; -+} -+ -+static bool wsm_handle_tx_data(struct xradio_vif *priv, -+ const struct wsm_tx *wsm, -+ const struct ieee80211_tx_info *tx_info, -+ struct xradio_txpriv *txpriv, -+ struct xradio_queue *queue) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ bool handled = false; -+ const struct ieee80211_hdr *frame = -+ (struct ieee80211_hdr *) &((u8 *)wsm)[txpriv->offset]; -+ __le16 fctl = frame->frame_control; -+ enum { -+ doProbe, -+ doDrop, -+ doJoin, -+ doOffchannel, -+ doWep, -+ doTx, -+ } action = doTx; -+ -+ hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ frame = (struct ieee80211_hdr *) &((u8 *)wsm)[txpriv->offset]; -+ fctl = frame->frame_control; -+ -+ switch (priv->mode) { -+ case NL80211_IFTYPE_STATION: -+ if (unlikely(priv->bss_loss_status == XRADIO_BSS_LOSS_CHECKING && -+ priv->join_status == XRADIO_JOIN_STATUS_STA) && -+ ieee80211_is_data(fctl)) { -+ spin_lock(&priv->bss_loss_lock); -+ priv->bss_loss_confirm_id = wsm->packetID; -+ priv->bss_loss_status = XRADIO_BSS_LOSS_CONFIRMING; -+ spin_unlock(&priv->bss_loss_lock); -+ } else if (unlikely((priv->join_status <= XRADIO_JOIN_STATUS_MONITOR) || -+ memcmp(frame->addr1, priv->join_bssid,sizeof(priv->join_bssid)))) { -+ if (ieee80211_is_auth(fctl)) -+ action = doJoin; -+ else if ((ieee80211_is_deauth(fctl) || ieee80211_is_disassoc(fctl))&& -+ priv->join_status < XRADIO_JOIN_STATUS_MONITOR) -+ action = doDrop; //no need to send deauth when STA-unjoined, yangfh 2014-10-31 16:32:16. -+ else if (ieee80211_is_probe_req(fctl)) -+ action = doTx; -+ else if (memcmp(frame->addr1, priv->join_bssid, -+ sizeof(priv->join_bssid)) && -+ (priv->join_status == -+ XRADIO_JOIN_STATUS_STA) && -+ (ieee80211_is_data(fctl))) { -+ action = doDrop; -+ } -+ else if (priv->join_status >= -+ XRADIO_JOIN_STATUS_MONITOR) -+ action = doTx; -+ else if (get_interface_id_scanning(hw_priv) != -1) { -+ wsm_printk(XRADIO_DBG_WARN, "Scan ONGOING dropping" -+ " offchannel eligible frame.\n"); -+ action = doDrop; -+ } else { -+ if (ieee80211_is_probe_resp(fctl)) -+ action = doDrop; -+ else -+ action = doOffchannel; -+ wsm_printk(XRADIO_DBG_WARN, "Offchannel fctl=0x%04x", fctl); -+ } -+ } -+ break; -+ case NL80211_IFTYPE_AP: -+ if (unlikely(!priv->join_status)) -+ action = doDrop; -+ else if (unlikely(!(BIT(txpriv->raw_link_id) & -+ (BIT(0) | priv->link_id_map)))) { -+ wsm_printk(XRADIO_DBG_WARN, -+ "A frame with expired link id " -+ "is dropped.\n"); -+ action = doDrop; -+ } -+ if (xradio_queue_get_generation(wsm->packetID) > -+ XRADIO_MAX_REQUEUE_ATTEMPTS) { -+ /* HACK!!! WSM324 firmware has tendency to requeue -+ * multicast frames in a loop, causing performance -+ * drop and high power consumption of the driver. -+ * In this situation it is better just to drop -+ * the problematic frame. */ -+ wsm_printk(XRADIO_DBG_WARN, -+ "Too many attempts " -+ "to requeue a frame. " -+ "Frame is dropped, fctl=0x%04x.\n", fctl); -+ action = doDrop; -+ } -+ break; -+ case NL80211_IFTYPE_ADHOC: -+ case NL80211_IFTYPE_MESH_POINT: -+ //STUB(); -+ case NL80211_IFTYPE_MONITOR: -+ default: -+ action = doDrop; -+ break; -+ } -+ -+ if (action == doTx) { -+ if (unlikely(ieee80211_is_probe_req(fctl))) { -+ action = doProbe; -+ } else if ((fctl & __cpu_to_le32(IEEE80211_FCTL_PROTECTED)) && -+ tx_info->control.hw_key && -+ unlikely(tx_info->control.hw_key->keyidx != -+ priv->wep_default_key_id) && -+ (tx_info->control.hw_key->cipher == -+ WLAN_CIPHER_SUITE_WEP40 || -+ tx_info->control.hw_key->cipher == -+ WLAN_CIPHER_SUITE_WEP104)) { -+ action = doWep; -+ } -+ } -+ -+ switch (action) { -+ case doProbe: -+ { -+ /* An interesting FW "feature". Device filters -+ * probe responses. -+ * The easiest way to get it back is to convert -+ * probe request into WSM start_scan command. */ -+ wsm_printk(XRADIO_DBG_MSG, \ -+ "Convert probe request to scan.\n"); -+ wsm_lock_tx_async(hw_priv); -+ hw_priv->pending_frame_id = __le32_to_cpu(wsm->packetID); -+ queue_delayed_work(hw_priv->workqueue, -+ &hw_priv->scan.probe_work, 0); -+ handled = true; -+ } -+ break; -+ case doDrop: -+ { -+ /* See detailed description of "join" below. -+ * We are dropping everything except AUTH in non-joined mode. */ -+ wsm_printk(XRADIO_DBG_MSG, "Drop frame (0x%.4X).\n", fctl); -+ BUG_ON(xradio_queue_remove(queue, -+ __le32_to_cpu(wsm->packetID))); -+ handled = true; -+ } -+ break; -+ case doJoin: -+ { -+ /* p2p should disconnect when sta try to join a different channel AP, -+ * because no good performance in this case. -+ */ -+ struct xradio_vif *p2p_tmp_vif = __xrwl_hwpriv_to_vifpriv(hw_priv, 1); -+ if (priv->if_id == 0 && p2p_tmp_vif) { -+ if (p2p_tmp_vif->join_status >= XRADIO_JOIN_STATUS_STA && -+ hw_priv->channel_changed) { -+ wsm_printk(XRADIO_DBG_WARN, "combo with different channels, p2p disconnect.\n"); -+ wms_send_disassoc_to_self(hw_priv, p2p_tmp_vif); -+ } -+ } -+ -+ /* There is one more interesting "feature" -+ * in FW: it can't do RX/TX before "join". -+ * "Join" here is not an association, -+ * but just a syncronization between AP and STA. -+ * priv->join_status is used only in bh thread and does -+ * not require protection */ -+ wsm_printk(XRADIO_DBG_NIY, "Issue join command.\n"); -+ wsm_lock_tx_async(hw_priv); -+ hw_priv->pending_frame_id = __le32_to_cpu(wsm->packetID); -+ if (queue_work(hw_priv->workqueue, &priv->join_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ handled = true; -+ } -+ break; -+ case doOffchannel: -+ { -+ wsm_printk(XRADIO_DBG_MSG, "Offchannel TX request.\n"); -+ wsm_lock_tx_async(hw_priv); -+ hw_priv->pending_frame_id = __le32_to_cpu(wsm->packetID); -+ if (queue_work(hw_priv->workqueue, &priv->offchannel_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ handled = true; -+ } -+ break; -+ case doWep: -+ { -+ wsm_printk(XRADIO_DBG_MSG, "Issue set_default_wep_key.\n"); -+ wsm_lock_tx_async(hw_priv); -+ priv->wep_default_key_id = tx_info->control.hw_key->keyidx; -+ hw_priv->pending_frame_id = __le32_to_cpu(wsm->packetID); -+ if (queue_work(hw_priv->workqueue, &priv->wep_key_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ handled = true; -+ } -+ break; -+ case doTx: -+ { -+#if 0 -+ /* Kept for history. If you want to implement wsm->more, -+ * make sure you are able to send a frame after that. */ -+ wsm->more = (count > 1) ? 1 : 0; -+ if (wsm->more) { -+ /* HACK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -+ * It's undocumented in WSM spec, but XRADIO hangs -+ * if 'more' is set and no TX is performed due to TX -+ * buffers limitation. */ -+ if (priv->hw_bufs_used + 1 == -+ priv->wsm_caps.numInpChBufs) -+ wsm->more = 0; -+ } -+ -+ /* BUG!!! FIXME: we can't use 'more' at all: we don't know -+ * future. It could be a request from upper layer with TX lock -+ * requirements (scan, for example). If "more" is set device -+ * will not send data and wsm_tx_lock() will fail... -+ * It's not obvious how to fix this deadlock. Any ideas? -+ * As a workaround more is set to 0. */ -+ wsm->more = 0; -+#endif /* 0 */ -+ -+ if (ieee80211_is_deauth(fctl) && -+ priv->mode != NL80211_IFTYPE_AP) { -+ /* Shedule unjoin work */ -+ wsm_printk(XRADIO_DBG_WARN, "Issue unjoin command(TX).\n"); -+#if 0 -+ wsm->more = 0; -+#endif /* 0 */ -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->unjoin_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+ break; -+ } -+ return handled; -+} -+ -+static int xradio_get_prio_queue(struct xradio_vif *priv, -+ u32 link_id_map, int *total) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ static u32 urgent; -+ struct wsm_edca_queue_params *edca; -+ unsigned score, best = -1; -+ int winner = -1; -+ int queued; -+ int i; -+ urgent = BIT(priv->link_id_after_dtim) | BIT(priv->link_id_uapsd); -+ -+ /* search for a winner using edca params */ -+ for (i = 0; i < 4; ++i) { -+ queued = xradio_queue_get_num_queued(priv, -+ &hw_priv->tx_queue[i], -+ link_id_map); -+ if (!queued) -+ continue; -+ *total += queued; -+ edca = &priv->edca.params[i]; -+ score = ((edca->aifns + edca->cwMin) << 16) + -+ (edca->cwMax - edca->cwMin) * -+ (prandom_u32() & 0xFFFF); -+ if (score < best && (winner < 0 || i != 3)) { -+ best = score; -+ winner = i; -+ } -+ } -+ -+ /* override winner if bursting */ -+ if (winner >= 0 && hw_priv->tx_burst_idx >= 0 && -+ winner != hw_priv->tx_burst_idx && -+ !xradio_queue_get_num_queued(priv, -+ &hw_priv->tx_queue[winner], -+ link_id_map & urgent) && -+ xradio_queue_get_num_queued(priv, -+ &hw_priv->tx_queue[hw_priv->tx_burst_idx], -+ link_id_map)) -+ winner = hw_priv->tx_burst_idx; -+ -+ return winner; -+} -+ -+static int wsm_get_tx_queue_and_mask(struct xradio_vif *priv, -+ struct xradio_queue **queue_p, -+ u32 *tx_allowed_mask_p, -+ bool *more) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int idx; -+ u32 tx_allowed_mask; -+ int total = 0; -+ -+ /* Search for a queue with multicast frames buffered */ -+ if (priv->tx_multicast) { -+ tx_allowed_mask = BIT(priv->link_id_after_dtim); -+ idx = xradio_get_prio_queue(priv, -+ tx_allowed_mask, &total); -+ if (idx >= 0) { -+ *more = total > 1; -+ goto found; -+ } -+ } -+ -+ /* Search for unicast traffic */ -+ tx_allowed_mask = ~priv->sta_asleep_mask; -+ tx_allowed_mask |= BIT(priv->link_id_uapsd); -+ if (priv->sta_asleep_mask) { -+ tx_allowed_mask |= priv->pspoll_mask; -+ tx_allowed_mask &= ~BIT(priv->link_id_after_dtim); -+ } else { -+ tx_allowed_mask |= BIT(priv->link_id_after_dtim); -+ } -+ idx = xradio_get_prio_queue(priv, -+ tx_allowed_mask, &total); -+ if (idx < 0) -+ return -ENOENT; -+ -+found: -+ *queue_p = &hw_priv->tx_queue[idx]; -+ *tx_allowed_mask_p = tx_allowed_mask; -+ return 0; -+} -+ -+int wsm_get_tx(struct xradio_common *hw_priv, u8 **data, -+ size_t *tx_len, int *burst, int *vif_selected) -+{ -+ struct wsm_tx *wsm = NULL; -+ struct ieee80211_tx_info *tx_info; -+ struct xradio_queue *queue = NULL; -+ int queue_num; -+ u32 tx_allowed_mask = 0; -+ struct xradio_txpriv *txpriv = NULL; -+ /* -+ * Count was intended as an input for wsm->more flag. -+ * During implementation it was found that wsm->more -+ * is not usable, see details above. It is kept just -+ * in case you would like to try to implement it again. -+ */ -+ int count = 0; -+ int if_pending = 1; -+ -+ /* More is used only for broadcasts. */ -+ bool more = false; -+ -+ if (hw_priv->wsm_cmd.ptr) { -+ ++count; -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ BUG_ON(!hw_priv->wsm_cmd.ptr); -+ *data = hw_priv->wsm_cmd.ptr; -+ *tx_len = hw_priv->wsm_cmd.len; -+ *burst = 1; -+ *vif_selected = -1; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ } else { -+ for (;;) { -+ int ret; -+ struct xradio_vif *priv; -+#if 0 -+ int num_pending_vif0, num_pending_vif1; -+#endif -+ if (atomic_add_return(0, &hw_priv->tx_lock)) -+ break; -+ /* Keep one buffer reserved for commands. Note -+ that, hw_bufs_used has already been incremented -+ before reaching here. */ -+ if (hw_priv->hw_bufs_used >= -+ hw_priv->wsm_caps.numInpChBufs) -+ break; -+ priv = wsm_get_interface_for_tx(hw_priv); -+ /* go to next interface ID to select next packet */ -+ hw_priv->if_id_selected ^= 1; -+ -+ /* There might be no interface before add_interface -+ * call */ -+ if (!priv) { -+ if (if_pending) { -+ if_pending = 0; -+ continue; -+ } -+ break; -+ } -+ -+#if 0 -+ if (((priv->if_id == 0) && -+ (hw_priv->hw_bufs_used_vif[0] >= -+ XRWL_FW_VIF0_THROTTLE)) || -+ ((priv->if_id == 1) && -+ (hw_priv->hw_bufs_used_vif[1] >= -+ XRWL_FW_VIF1_THROTTLE))) { -+ spin_unlock(&priv->vif_lock); -+ if (if_pending) { -+ if_pending = 0; -+ continue; -+ } -+ break; -+ } -+#endif -+ -+ /* This can be removed probably: xradio_vif will not -+ * be in hw_priv->vif_list (as returned from -+ * wsm_get_interface_for_tx) until it's fully -+ * enabled, so statement above will take case of that*/ -+ if (!atomic_read(&priv->enabled)) { -+ spin_unlock(&priv->vif_lock); -+ break; -+ } -+ -+ /* TODO:COMBO: Find the next interface for which -+ * packet needs to be found */ -+ spin_lock_bh(&priv->ps_state_lock); -+ ret = wsm_get_tx_queue_and_mask(priv, &queue, -+ &tx_allowed_mask, &more); -+ queue_num = queue - hw_priv->tx_queue; -+ -+ if (priv->buffered_multicasts && -+ (ret || !more) && -+ (priv->tx_multicast || -+ !priv->sta_asleep_mask)) { -+ priv->buffered_multicasts = false; -+ if (priv->tx_multicast) { -+ priv->tx_multicast = false; -+ queue_work(hw_priv->workqueue, -+ &priv->multicast_stop_work); -+ } -+ } -+ -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+ if (ret) { -+ spin_unlock(&priv->vif_lock); -+ if (if_pending == 1) { -+ if_pending = 0; -+ continue; -+ } -+ break; -+ } -+ -+ if (xradio_queue_get(queue, -+ priv->if_id, -+ tx_allowed_mask, -+ &wsm, &tx_info, &txpriv)) { -+ spin_unlock(&priv->vif_lock); -+ if_pending = 0; -+ continue; -+ } -+ -+// #ifdef ROC_DEBUG -+// { -+// struct ieee80211_hdr *hdr = -+// (struct ieee80211_hdr *) -+// &((u8 *)wsm)[txpriv->offset]; -+// -+// wsm_printk(XRADIO_DBG_ERROR, "QGET-1 %x, off_id %d," -+// " if_id %d\n", -+// hdr->frame_control, -+// txpriv->offchannel_if_id, -+// priv->if_id); -+// } -+// #else -+// { -+// struct ieee80211_hdr *hdr = -+// (struct ieee80211_hdr *) -+// &((u8 *)wsm)[txpriv->offset]; -+// -+// wsm_printk(XRADIO_DBG_ERROR, "QGET-1 %x, off_id %d," -+// " if_id %d\n", -+// hdr->frame_control, -+// txpriv->raw_if_id, -+// priv->if_id); -+// } -+// #endif -+ -+ if (wsm_handle_tx_data(priv, wsm, -+ tx_info, txpriv, queue)) { -+ spin_unlock(&priv->vif_lock); -+ if_pending = 0; -+ continue; /* Handled by WSM */ -+ } -+ -+ wsm->hdr.id &= __cpu_to_le16( -+ ~WSM_TX_IF_ID(WSM_TX_IF_ID_MAX)); -+ if (txpriv->offchannel_if_id) -+ wsm->hdr.id |= cpu_to_le16( -+ WSM_TX_IF_ID(txpriv->offchannel_if_id)); -+ else -+ wsm->hdr.id |= cpu_to_le16( -+ WSM_TX_IF_ID(priv->if_id)); -+ -+ *vif_selected = priv->if_id; -+// #ifdef ROC_DEBUG -+// /* remand the roc debug. */ -+// { -+// struct ieee80211_hdr *hdr = -+// (struct ieee80211_hdr *) -+// &((u8 *)wsm)[txpriv->offset]; -+// -+// wsm_printk(XRADIO_DBG_ERROR, "QGET-2 %x, off_id %d," -+// " if_id %d\n", -+// hdr->frame_control, -+// txpriv->offchannel_if_id, -+// priv->if_id); -+// } -+// #else -+// { -+// struct ieee80211_hdr *hdr = -+// (struct ieee80211_hdr *) -+// &((u8 *)wsm)[txpriv->offset]; -+// -+// wsm_printk(XRADIO_DBG_ERROR, "QGET-2 %x, off_id %d," -+// " if_id %d\n", -+// hdr->frame_control, -+// txpriv->raw_if_id, -+// priv->if_id); -+// } -+// #endif -+ -+ priv->pspoll_mask &= ~BIT(txpriv->raw_link_id); -+ -+ *data = (u8 *)wsm; -+ *tx_len = __le16_to_cpu(wsm->hdr.len); -+ -+ /* allow bursting if txop is set */ -+ if (priv->edca.params[queue_num].txOpLimit) -+ *burst = min(*burst, -+ (int)xradio_queue_get_num_queued(priv, -+ queue, tx_allowed_mask) + 1); -+ else -+ *burst = 1; -+ -+ /* store index of bursting queue */ -+ if (*burst > 1) -+ hw_priv->tx_burst_idx = queue_num; -+ else -+ hw_priv->tx_burst_idx = -1; -+ -+ if (more) { -+ struct ieee80211_hdr *hdr = -+ (struct ieee80211_hdr *) -+ &((u8 *)wsm)[txpriv->offset]; -+ if(strstr(&priv->ssid[0], "6.1.12")) { -+ if(hdr->addr1[0] & 0x01 ) { -+ hdr->frame_control |= -+ cpu_to_le16(IEEE80211_FCTL_MOREDATA); -+ } -+ } -+ else { -+ /* more buffered multicast/broadcast frames -+ * ==> set MoreData flag in IEEE 802.11 header -+ * to inform PS STAs */ -+ hdr->frame_control |= -+ cpu_to_le16(IEEE80211_FCTL_MOREDATA); -+ } -+ } -+ wsm_printk(XRADIO_DBG_MSG, ">>> 0x%.4X (%d) %p %c\n", -+ 0x0004, *tx_len, *data, -+ wsm->more ? 'M' : ' '); -+ ++count; -+ spin_unlock(&priv->vif_lock); -+ break; -+ } -+ } -+ -+ return count; -+} -+ -+void wsm_txed(struct xradio_common *hw_priv, u8 *data) -+{ -+ if (data == hw_priv->wsm_cmd.ptr) { -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ hw_priv->wsm_cmd.ptr = NULL; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ } -+} -+ -+/* ******************************************************************** */ -+/* WSM buffer */ -+ -+void wsm_buf_init(struct wsm_buf *buf) -+{ -+ int size = (SDIO_BLOCK_SIZE<<1); //for sdd file big than SDIO_BLOCK_SIZE -+ BUG_ON(buf->begin); -+ buf->begin = kmalloc(size, GFP_KERNEL); -+ buf->end = buf->begin ? &buf->begin[size] : buf->begin; -+ wsm_buf_reset(buf); -+} -+ -+void wsm_buf_deinit(struct wsm_buf *buf) -+{ -+ if(buf->begin) -+ kfree(buf->begin); -+ buf->begin = buf->data = buf->end = NULL; -+} -+ -+static void wsm_buf_reset(struct wsm_buf *buf) -+{ -+ if (buf->begin) { -+ buf->data = &buf->begin[4]; -+ *(u32 *)buf->begin = 0; -+ } else -+ buf->data = buf->begin; -+} -+ -+static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size) -+{ -+ size_t pos = buf->data - buf->begin; -+ size_t size = pos + extra_size; -+ -+ -+ if (size & (SDIO_BLOCK_SIZE - 1)) { -+ size &= SDIO_BLOCK_SIZE; -+ size += SDIO_BLOCK_SIZE; -+ } -+ -+ buf->begin = krealloc(buf->begin, size, GFP_KERNEL); -+ if (buf->begin) { -+ buf->data = &buf->begin[pos]; -+ buf->end = &buf->begin[size]; -+ return 0; -+ } else { -+ buf->end = buf->data = buf->begin; -+ return -ENOMEM; -+ } -+} -+ -+static struct xradio_vif -+ *wsm_get_interface_for_tx(struct xradio_common *hw_priv) -+{ -+ struct xradio_vif *priv = NULL, *i_priv; -+ int i = hw_priv->if_id_selected; -+ -+ if ( 1 /*TODO:COMBO*/) { -+ spin_lock(&hw_priv->vif_list_lock); -+ i_priv = hw_priv->vif_list[i] ? -+ xrwl_get_vif_from_ieee80211(hw_priv->vif_list[i]) : NULL; -+ if (i_priv) { -+ priv = i_priv; -+ spin_lock(&priv->vif_lock); -+ } -+ /* TODO:COMBO: -+ * Find next interface based on TX bitmap announced by the FW -+ * Find next interface based on load balancing */ -+ spin_unlock(&hw_priv->vif_list_lock); -+ } else { -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, 0); -+ } -+ -+ return priv; -+} -+ -+static inline int get_interface_id_scanning(struct xradio_common *hw_priv) -+{ -+ if (hw_priv->scan.req || hw_priv->scan.direct_probe) -+ return hw_priv->scan.if_id; -+ else -+ return -1; -+} -diff --git a/drivers/net/wireless/xradio/wsm.h b/drivers/net/wireless/xradio/wsm.h -new file mode 100644 -index 0000000..8056abc ---- /dev/null -+++ b/drivers/net/wireless/xradio/wsm.h -@@ -0,0 +1,2354 @@ -+/* -+ * wsm interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_WSM_H_INCLUDED -+#define XRADIO_WSM_H_INCLUDED -+ -+#include -+ -+struct xradio_common; -+ -+/* Bands */ -+/* Radio band 2.412 -2.484 GHz. */ -+#define WSM_PHY_BAND_2_4G (0) -+ -+/* Radio band 4.9375-5.8250 GHz. */ -+#define WSM_PHY_BAND_5G (1) -+ -+/* Transmit rates */ -+/* 1 Mbps ERP-DSSS */ -+#define WSM_TRANSMIT_RATE_1 (0) -+ -+/* 2 Mbps ERP-DSSS */ -+#define WSM_TRANSMIT_RATE_2 (1) -+ -+/* 5.5 Mbps ERP-CCK, ERP-PBCC (Not supported) */ -+/* #define WSM_TRANSMIT_RATE_5 (2) */ -+ -+/* 11 Mbps ERP-CCK, ERP-PBCC (Not supported) */ -+/* #define WSM_TRANSMIT_RATE_11 (3) */ -+ -+/* 22 Mbps ERP-PBCC (Not supported) */ -+/* #define WSM_TRANSMIT_RATE_22 (4) */ -+ -+/* 33 Mbps ERP-PBCC (Not supported) */ -+/* #define WSM_TRANSMIT_RATE_33 (5) */ -+ -+/* 6 Mbps (3 Mbps) ERP-OFDM, BPSK coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_6 (6) -+ -+/* 9 Mbps (4.5 Mbps) ERP-OFDM, BPSK coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_9 (7) -+ -+/* 12 Mbps (6 Mbps) ERP-OFDM, QPSK coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_12 (8) -+ -+/* 18 Mbps (9 Mbps) ERP-OFDM, QPSK coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_18 (9) -+ -+/* 24 Mbps (12 Mbps) ERP-OFDM, 16QAM coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_24 (10) -+ -+/* 36 Mbps (18 Mbps) ERP-OFDM, 16QAM coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_36 (11) -+ -+/* 48 Mbps (24 Mbps) ERP-OFDM, 64QAM coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_48 (12) -+ -+/* 54 Mbps (27 Mbps) ERP-OFDM, 64QAM coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_54 (13) -+ -+/* 6.5 Mbps HT-OFDM, BPSK coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_HT_6 (14) -+ -+/* 13 Mbps HT-OFDM, QPSK coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_HT_13 (15) -+ -+/* 19.5 Mbps HT-OFDM, QPSK coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_HT_19 (16) -+ -+/* 26 Mbps HT-OFDM, 16QAM coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_HT_26 (17) -+ -+/* 39 Mbps HT-OFDM, 16QAM coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_HT_39 (18) -+ -+/* 52 Mbps HT-OFDM, 64QAM coding rate 2/3 */ -+#define WSM_TRANSMIT_RATE_HT_52 (19) -+ -+/* 58.5 Mbps HT-OFDM, 64QAM coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_HT_58 (20) -+ -+/* 65 Mbps HT-OFDM, 64QAM coding rate 5/6 */ -+#define WSM_TRANSMIT_RATE_HT_65 (21) -+ -+/* Scan types */ -+/* Foreground scan */ -+#define WSM_SCAN_TYPE_FOREGROUND (0) -+ -+/* Background scan */ -+#define WSM_SCAN_TYPE_BACKGROUND (1) -+ -+/* Auto scan */ -+#define WSM_SCAN_TYPE_AUTO (2) -+ -+/* Scan flags */ -+/* Forced background scan means if the station cannot */ -+/* enter the power-save mode, it shall force to perform a */ -+/* background scan. Only valid when ScanType is */ -+/* background scan. */ -+#define WSM_SCAN_FLAG_FORCE_BACKGROUND (BIT(0)) -+ -+/* The WLAN device scans one channel at a time so */ -+/* that disturbance to the data traffic is minimized. */ -+#define WSM_SCAN_FLAG_SPLIT_METHOD (BIT(1)) -+ -+/* Preamble Type. Long if not set. */ -+#define WSM_SCAN_FLAG_SHORT_PREAMBLE (BIT(2)) -+ -+/* 11n Tx Mode. Mixed if not set. */ -+#define WSM_SCAN_FLAG_11N_GREENFIELD (BIT(3)) -+ -+#define WSM_FLAG_MAC_INSTANCE_1 (BIT(4)) -+ -+#define WSM_FLAG_MAC_INSTANCE_0 (~(BIT(4))) -+ -+/* Scan constraints */ -+/* Maximum number of channels to be scanned. */ -+#define WSM_SCAN_MAX_NUM_OF_CHANNELS (48) -+ -+/* The maximum number of SSIDs that the device can scan for. */ -+#define WSM_SCAN_MAX_NUM_OF_SSIDS (2) -+ -+/* Power management modes */ -+/* 802.11 Active mode */ -+#define WSM_PSM_ACTIVE (0) -+ -+/* 802.11 PS mode */ -+#define WSM_PSM_PS BIT(0) -+ -+/* Fast Power Save bit */ -+#define WSM_PSM_FAST_PS_FLAG BIT(7) -+ -+/* Dynamic aka Fast power save */ -+#define WSM_PSM_FAST_PS (BIT(0) | BIT(7)) -+ -+/* Undetermined */ -+/* Note : Undetermined status is reported when the */ -+/* NULL data frame used to advertise the PM mode to */ -+/* the AP at Pre or Post Background Scan is not Acknowledged */ -+#define WSM_PSM_UNKNOWN BIT(1) -+ -+/* Queue IDs */ -+/* best effort/legacy */ -+#define WSM_QUEUE_BEST_EFFORT (0) -+ -+/* background */ -+#define WSM_QUEUE_BACKGROUND (1) -+ -+/* video */ -+#define WSM_QUEUE_VIDEO (2) -+ -+/* voice */ -+#define WSM_QUEUE_VOICE (3) -+ -+/* HT TX parameters */ -+/* Non-HT */ -+#define WSM_HT_TX_NON_HT (0) -+ -+/* Mixed format */ -+#define WSM_HT_TX_MIXED (1) -+ -+/* Greenfield format */ -+#define WSM_HT_TX_GREENFIELD (2) -+ -+/* STBC allowed */ -+#define WSM_HT_TX_STBC (BIT(7)) -+ -+/* EPTA prioirty flags for BT Coex */ -+/* default epta priority */ -+#define WSM_EPTA_PRIORITY_DEFAULT 4 -+/* use for normal data */ -+#define WSM_EPTA_PRIORITY_DATA 4 -+/* use for connect/disconnect/roaming*/ -+#define WSM_EPTA_PRIORITY_MGT 5 -+/* use for action frames */ -+#define WSM_EPTA_PRIORITY_ACTION 5 -+/* use for AC_VI data */ -+#define WSM_EPTA_PRIORITY_VIDEO 5 -+/* use for AC_VO data */ -+#define WSM_EPTA_PRIORITY_VOICE 6 -+/* use for EAPOL exchange */ -+#define WSM_EPTA_PRIORITY_EAPOL 7 -+ -+/* TX status */ -+/* Frame was sent aggregated */ -+/* Only valid for WSM_SUCCESS status. */ -+#define WSM_TX_STATUS_AGGREGATION (BIT(0)) -+ -+/* Host should requeue this frame later. */ -+/* Valid only when status is WSM_REQUEUE. */ -+#define WSM_TX_STATUS_REQUEUE (BIT(1)) -+ -+/* Normal Ack */ -+#define WSM_TX_STATUS_NORMAL_ACK (0<<2) -+ -+/* No Ack */ -+#define WSM_TX_STATUS_NO_ACK (1<<2) -+ -+/* No explicit acknowledgement */ -+#define WSM_TX_STATUS_NO_EXPLICIT_ACK (2<<2) -+ -+/* Block Ack */ -+/* Only valid for WSM_SUCCESS status. */ -+#define WSM_TX_STATUS_BLOCK_ACK (3<<2) -+ -+/* RX status */ -+/* Unencrypted */ -+#define WSM_RX_STATUS_UNENCRYPTED (0<<0) -+ -+/* WEP */ -+#define WSM_RX_STATUS_WEP (1<<0) -+ -+/* TKIP */ -+#define WSM_RX_STATUS_TKIP (2<<0) -+ -+/* AES */ -+#define WSM_RX_STATUS_AES (3<<0) -+ -+/* WAPI */ -+#define WSM_RX_STATUS_WAPI (4<<0) -+ -+/* Macro to fetch encryption subfield. */ -+#define WSM_RX_STATUS_ENCRYPTION(status) ((status) & 0x07) -+ -+/* Frame was part of an aggregation */ -+#define WSM_RX_STATUS_AGGREGATE (BIT(3)) -+ -+/* Frame was first in the aggregation */ -+#define WSM_RX_STATUS_AGGREGATE_FIRST (BIT(4)) -+ -+/* Frame was last in the aggregation */ -+#define WSM_RX_STATUS_AGGREGATE_LAST (BIT(5)) -+ -+/* Indicates a defragmented frame */ -+#define WSM_RX_STATUS_DEFRAGMENTED (BIT(6)) -+ -+/* Indicates a Beacon frame */ -+#define WSM_RX_STATUS_BEACON (BIT(7)) -+ -+/* Indicates STA bit beacon TIM field */ -+#define WSM_RX_STATUS_TIM (BIT(8)) -+ -+/* Indicates Beacon frame's virtual bitmap contains multicast bit */ -+#define WSM_RX_STATUS_MULTICAST (BIT(9)) -+ -+/* Indicates frame contains a matching SSID */ -+#define WSM_RX_STATUS_MATCHING_SSID (BIT(10)) -+ -+/* Indicates frame contains a matching BSSI */ -+#define WSM_RX_STATUS_MATCHING_BSSI (BIT(11)) -+ -+/* Indicates More bit set in Framectl field */ -+#define WSM_RX_STATUS_MORE_DATA (BIT(12)) -+ -+/* Indicates frame received during a measurement process */ -+#define WSM_RX_STATUS_MEASUREMENT (BIT(13)) -+ -+/* Indicates frame received as an HT packet */ -+#define WSM_RX_STATUS_HT (BIT(14)) -+ -+/* Indicates frame received with STBC */ -+#define WSM_RX_STATUS_STBC (BIT(15)) -+ -+/* Indicates Address 1 field matches dot11StationId */ -+#define WSM_RX_STATUS_ADDRESS1 (BIT(16)) -+ -+/* Indicates Group address present in the Address 1 field */ -+#define WSM_RX_STATUS_GROUP (BIT(17)) -+ -+/* Indicates Broadcast address present in the Address 1 field */ -+#define WSM_RX_STATUS_BROADCAST (BIT(18)) -+ -+/* Indicates group key used with encrypted frames */ -+#define WSM_RX_STATUS_GROUP_KEY (BIT(19)) -+ -+/* Macro to fetch encryption key index. */ -+#define WSM_RX_STATUS_KEY_IDX(status) (((status >> 20)) & 0x0F) -+ -+/* Frame Control field starts at Frame offset + 2 */ -+#define WSM_TX_2BYTES_SHIFT (BIT(7)) -+ -+/* Join mode */ -+/* IBSS */ -+#define WSM_JOIN_MODE_IBSS (0) -+ -+/* BSS */ -+#define WSM_JOIN_MODE_BSS (1) -+ -+/* PLCP preamble type */ -+/* For long preamble */ -+#define WSM_JOIN_PREAMBLE_LONG (0) -+ -+/* For short preamble (Long for 1Mbps) */ -+#define WSM_JOIN_PREAMBLE_SHORT (1) -+ -+/* For short preamble (Long for 1 and 2Mbps) */ -+#define WSM_JOIN_PREAMBLE_SHORT_2 (2) -+ -+/* Join flags */ -+/* Unsynchronized */ -+#define WSM_JOIN_FLAGS_UNSYNCRONIZED BIT(0) -+/* The BSS owner is a P2P GO */ -+#define WSM_JOIN_FLAGS_P2P_GO BIT(1) -+/* Force to join BSS with the BSSID and the -+ * SSID specified without waiting for beacons. The -+ * ProbeForJoin parameter is ignored. */ -+#define WSM_JOIN_FLAGS_FORCE BIT(2) -+/* Give probe request/response higher -+ * priority over the BT traffic */ -+#define WSM_JOIN_FLAGS_PRIO BIT(3) -+ -+/* Key types */ -+#define WSM_KEY_TYPE_WEP_DEFAULT (0) -+#define WSM_KEY_TYPE_WEP_PAIRWISE (1) -+#define WSM_KEY_TYPE_TKIP_GROUP (2) -+#define WSM_KEY_TYPE_TKIP_PAIRWISE (3) -+#define WSM_KEY_TYPE_AES_GROUP (4) -+#define WSM_KEY_TYPE_AES_PAIRWISE (5) -+#define WSM_KEY_TYPE_WAPI_GROUP (6) -+#define WSM_KEY_TYPE_WAPI_PAIRWISE (7) -+ -+/* Key indexes */ -+#define WSM_KEY_MAX_INDEX (10) -+ -+/* ACK policy */ -+#define WSM_ACK_POLICY_NORMAL (0) -+#define WSM_ACK_POLICY_NO_ACK (1) -+ -+/* Start modes */ -+#define WSM_START_MODE_AP (0) /* Mini AP */ -+#define WSM_START_MODE_P2P_GO (1) /* P2P GO */ -+#define WSM_START_MODE_P2P_DEV (2) /* P2P device */ -+ -+/* SetAssociationMode MIB flags */ -+#define WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE (BIT(0)) -+#define WSM_ASSOCIATION_MODE_USE_HT_MODE (BIT(1)) -+#define WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET (BIT(2)) -+#define WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING (BIT(3)) -+#define WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES (BIT(4)) -+ -+/* RcpiRssiThreshold MIB flags */ -+#define WSM_RCPI_RSSI_THRESHOLD_ENABLE (BIT(0)) -+#define WSM_RCPI_RSSI_USE_RSSI (BIT(1)) -+#define WSM_RCPI_RSSI_DONT_USE_UPPER (BIT(2)) -+#define WSM_RCPI_RSSI_DONT_USE_LOWER (BIT(3)) -+ -+/* Update-ie constants */ -+#define WSM_UPDATE_IE_BEACON (BIT(0)) -+#define WSM_UPDATE_IE_PROBE_RESP (BIT(1)) -+#define WSM_UPDATE_IE_PROBE_REQ (BIT(2)) -+ -+/* WSM events */ -+/* Error */ -+#define WSM_EVENT_ERROR (0) -+ -+/* BSS lost */ -+#define WSM_EVENT_BSS_LOST (1) -+ -+/* BSS regained */ -+#define WSM_EVENT_BSS_REGAINED (2) -+ -+/* Radar detected */ -+#define WSM_EVENT_RADAR_DETECTED (3) -+ -+/* RCPI or RSSI threshold triggered */ -+#define WSM_EVENT_RCPI_RSSI (4) -+ -+/* BT inactive */ -+#define WSM_EVENT_BT_INACTIVE (5) -+ -+/* BT active */ -+#define WSM_EVENT_BT_ACTIVE (6) -+ -+#define WSM_EVENT_PS_MODE_ERROR (7) -+ -+#define WSM_EVENT_INACTIVITY (9) -+ -+/* MAC Addr Filter */ -+#define WSM_MIB_ID_MAC_ADDR_FILTER 0x1030 -+ -+/* MIB IDs */ -+/* 4.1 dot11StationId */ -+#define WSM_MIB_ID_DOT11_STATION_ID 0x0000 -+ -+/* 4.2 dot11MaxtransmitMsduLifeTime */ -+#define WSM_MIB_ID_DOT11_MAX_TRANSMIT_LIFTIME 0x0001 -+ -+/* 4.3 dot11MaxReceiveLifeTime */ -+#define WSM_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME 0x0002 -+ -+/* 4.4 dot11SlotTime */ -+#define WSM_MIB_ID_DOT11_SLOT_TIME 0x0003 -+ -+/* 4.5 dot11GroupAddressesTable */ -+#define WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE 0x0004 -+#define WSM_MAX_GRP_ADDRTABLE_ENTRIES 8 -+ -+/* 4.6 dot11WepDefaultKeyId */ -+#define WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID 0x0005 -+ -+/* 4.7 dot11CurrentTxPowerLevel */ -+#define WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL 0x0006 -+ -+/* 4.8 dot11RTSThreshold */ -+#define WSM_MIB_ID_DOT11_RTS_THRESHOLD 0x0007 -+ -+/* Huanglu add for firmware debug control */ -+#define WSM_MIB_ID_FW_DEBUG_CONTROL 0x0008 -+ -+/* yangfh add for read/write registers from firmware*/ -+#define WSM_MIB_ID_RW_FW_REG 0x0009 -+ -+/* yangfh add for Set max number of mpdus in a-mpdu*/ -+#define WSM_MIB_ID_SET_AMPDU_NUM 0x000a -+ -+/* Huanglu add for tx-ampdu-len-adaption */ -+#define WSM_MIB_ID_SET_TALA_PARA 0x000b -+ -+/* yangfh add for set TPA param */ -+#define WSM_MIB_ID_SET_TPA_PARAM 0x000c -+ -+/* 4.9 NonErpProtection */ -+#define WSM_MIB_ID_NON_ERP_PROTECTION 0x1000 -+ -+/* 4.10 ArpIpAddressesTable */ -+#define WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE 0x1001 -+#define WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES 1 -+ -+/* 4.11 TemplateFrame */ -+#define WSM_MIB_ID_TEMPLATE_FRAME 0x1002 -+ -+/* 4.12 RxFilter */ -+#define WSM_MIB_ID_RX_FILTER 0x1003 -+ -+/* 4.13 BeaconFilterTable */ -+#define WSM_MIB_ID_BEACON_FILTER_TABLE 0x1004 -+ -+/* 4.14 BeaconFilterEnable */ -+#define WSM_MIB_ID_BEACON_FILTER_ENABLE 0x1005 -+ -+/* 4.15 OperationalPowerMode */ -+#define WSM_MIB_ID_OPERATIONAL_POWER_MODE 0x1006 -+ -+/* 4.16 BeaconWakeUpPeriod */ -+#define WSM_MIB_ID_BEACON_WAKEUP_PERIOD 0x1007 -+ -+/* 4.17 RcpiRssiThreshold */ -+#define WSM_MIB_ID_RCPI_RSSI_THRESHOLD 0x1009 -+ -+/* 4.18 StatisticsTable */ -+#define WSM_MIB_ID_STATISTICS_TABLE 0x100A -+ -+/* 4.19 IbssPsConfig */ -+#define WSM_MIB_ID_IBSS_PS_CONFIG 0x100B -+ -+/* 4.20 CountersTable */ -+#define WSM_MIB_ID_COUNTERS_TABLE 0x100C -+#define WSM_MIB_ID_AMPDUCOUNTERS_TABLE 0x1036 -+#define WSM_MIB_ID_TXPIPE_TABLE 0x1037 -+#define WSM_MIB_ID_BACKOFF_DBG 0x1038 -+#define WSM_MIB_ID_BACKOFF_CTRL 0x1039 -+ -+//add yangfh for requery packet status -+#define WSM_MIB_ID_REQ_PKT_STATUS 0x1040 -+ -+//add yangfh for TPA debug informations -+#define WSM_MIB_ID_TPA_DEBUG_INFO 0x1041 -+ -+//add yangfh for tx power informations -+#define WSM_MIB_ID_TX_POWER_INFO 0x1042 -+ -+//add yangfh for some hardware information -+#define WSM_MIB_ID_HW_INFO 0x1043 -+ -+/* 4.21 BlockAckPolicy */ -+#define WSM_MIB_ID_BLOCK_ACK_POLICY 0x100E -+ -+/* 4.22 OverrideInternalTxRate */ -+#define WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE 0x100F -+ -+/* 4.23 SetAssociationMode */ -+#define WSM_MIB_ID_SET_ASSOCIATION_MODE 0x1010 -+ -+/* 4.24 UpdateEptaConfigData */ -+#define WSM_MIB_ID_UPDATE_EPTA_CONFIG_DATA 0x1011 -+ -+/* 4.25 SelectCcaMethod */ -+#define WSM_MIB_ID_SELECT_CCA_METHOD 0x1012 -+ -+/* 4.26 SetUpasdInformation */ -+#define WSM_MIB_ID_SET_UAPSD_INFORMATION 0x1013 -+ -+/* 4.27 SetAutoCalibrationMode WBF00004073 */ -+#define WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE 0x1015 -+ -+/* 4.28 SetTxRateRetryPolicy */ -+#define WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY 0x1016 -+ -+/* 4.29 SetHostMessageTypeFilter */ -+#define WSM_MIB_ID_SET_HOST_MSG_TYPE_FILTER 0x1017 -+ -+/* 4.30 P2PFindInfo */ -+#define WSM_MIB_ID_P2P_FIND_INFO 0x1018 -+ -+/* 4.31 P2PPsModeInfo */ -+#define WSM_MIB_ID_P2P_PS_MODE_INFO 0x1019 -+ -+/* 4.32 SetEtherTypeDataFrameFilter */ -+#define WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER 0x101A -+ -+/* 4.33 SetUDPPortDataFrameFilter */ -+#define WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER 0x101B -+ -+/* 4.34 SetMagicDataFrameFilter */ -+#define WSM_MIB_ID_SET_MAGIC_DATAFRAME_FILTER 0x101C -+#define WSM_MIB_ID_SET_HOST_SLEEP 0x1050 -+ -+/* This is the end of specification. */ -+ -+/* 4.35 P2PDeviceInfo */ -+#define WSM_MIB_ID_P2P_DEVICE_INFO 0x101D -+ -+/* 4.36 SetWCDMABand */ -+#define WSM_MIB_ID_SET_WCDMA_BAND 0x101E -+ -+/* 4.37 GroupTxSequenceCounter */ -+#define WSM_MIB_ID_GRP_SEQ_COUNTER 0x101F -+ -+/* 4.38 ProtectedMgmtPolicy */ -+#define WSM_MIB_ID_PROTECTED_MGMT_POLICY 0x1020 -+ -+/* 4.39 SetHtProtection */ -+#define WSM_MID_ID_SET_HT_PROTECTION 0x1021 -+ -+/* 4.40 GPIO Command */ -+#define WSM_MIB_ID_GPIO_COMMAND 0x1022 -+ -+/* 4.41 TSF Counter Value */ -+#define WSM_MIB_ID_TSF_COUNTER 0x1023 -+ -+/* Test Purposes Only */ -+#define WSM_MIB_ID_BLOCK_ACK_INFO 0x100D -+ -+/* 4.42 UseMultiTxConfMessage */ -+#define WSM_MIB_USE_MULTI_TX_CONF 0x1024 -+ -+/* 4.43 Keep-alive period */ -+#define WSM_MIB_ID_KEEP_ALIVE_PERIOD 0x1025 -+ -+/* 4.44 Disable BSSID filter */ -+#define WSM_MIB_ID_DISABLE_BSSID_FILTER 0x1026 -+ -+/* Inactivity */ -+#define WSM_MIB_ID_SET_INACTIVITY 0x1035 -+ -+/* MAC Addr Filter */ -+#define WSM_MIB_ID_MAC_ADDR_FILTER 0x1030 -+ -+#ifdef MCAST_FWDING -+/* 4.51 Set Forwarding Offload */ -+#define WSM_MIB_ID_FORWARDING_OFFLOAD 0x1033 -+#endif -+ -+/* Frame template types */ -+#define WSM_FRAME_TYPE_PROBE_REQUEST (0) -+#define WSM_FRAME_TYPE_BEACON (1) -+#define WSM_FRAME_TYPE_NULL (2) -+#define WSM_FRAME_TYPE_QOS_NULL (3) -+#define WSM_FRAME_TYPE_PS_POLL (4) -+#define WSM_FRAME_TYPE_PROBE_RESPONSE (5) -+#define WSM_FRAME_TYPE_ARP_REPLY (6) -+ -+#define WSM_FRAME_GREENFIELD (0x80) /* See 4.11 */ -+ -+/* Status */ -+/* The WSM firmware has completed a request */ -+/* successfully. */ -+#define WSM_STATUS_SUCCESS (0) -+ -+/* This is a generic failure code if other error codes do */ -+/* not apply. */ -+#define WSM_STATUS_FAILURE (1) -+ -+/* A request contains one or more invalid parameters. */ -+#define WSM_INVALID_PARAMETER (2) -+ -+/* The request cannot perform because the device is in */ -+/* an inappropriate mode. */ -+#define WSM_ACCESS_DENIED (3) -+ -+/* The frame received includes a decryption error. */ -+#define WSM_STATUS_DECRYPTFAILURE (4) -+ -+/* A MIC failure is detected in the received packets. */ -+#define WSM_STATUS_MICFAILURE (5) -+ -+/* The transmit request failed due to retry limit being */ -+/* exceeded. */ -+#define WSM_STATUS_RETRY_EXCEEDED (6) -+ -+/* The transmit request failed due to MSDU life time */ -+/* being exceeded. */ -+#define WSM_STATUS_TX_LIFETIME_EXCEEDED (7) -+ -+/* The link to the AP is lost. */ -+#define WSM_STATUS_LINK_LOST (8) -+ -+/* No key was found for the encrypted frame */ -+#define WSM_STATUS_NO_KEY_FOUND (9) -+ -+/* Jammer was detected when transmitting this frame */ -+#define WSM_STATUS_JAMMER_DETECTED (10) -+ -+/* The message should be requeued later. */ -+/* This is applicable only to Transmit */ -+#define WSM_REQUEUE (11) -+ -+/* Advanced filtering options */ -+#define WSM_MAX_FILTER_ELEMENTS (4) -+ -+#define WSM_FILTER_ACTION_IGNORE (0) -+#define WSM_FILTER_ACTION_FILTER_IN (1) -+#define WSM_FILTER_ACTION_FILTER_OUT (2) -+ -+#define WSM_FILTER_PORT_TYPE_DST (0) -+#define WSM_FILTER_PORT_TYPE_SRC (1) -+ -+ -+ -+struct wsm_hdr { -+ __le16 len; -+ __le16 id; -+}; -+ -+#define WSM_TX_SEQ_MAX (7) -+#define WSM_TX_SEQ(seq) \ -+ ((seq & WSM_TX_SEQ_MAX) << 13) -+#define WSM_TX_LINK_ID_MAX (0x0F) -+#define WSM_TX_LINK_ID(link_id) \ -+ ((link_id & WSM_TX_LINK_ID_MAX) << 6) -+ -+#define WSM_TX_IF_ID_MAX (0x0F) -+#define WSM_TX_IF_ID(if_id) \ -+ ((if_id & WSM_TX_IF_ID_MAX) << 6) -+ -+#define MAX_BEACON_SKIP_TIME_MS 1000 -+ -+#ifdef FPGA_SETUP -+#define WSM_CMD_LAST_CHANCE_TIMEOUT (HZ * 9 / 2) -+#else -+#define WSM_CMD_LAST_CHANCE_TIMEOUT (HZ * 20 / 2) -+#endif -+#define WSM_CMD_EXTENDED_TIMEOUT (HZ * 20 / 2) -+ -+#define WSM_RI_GET_PEER_ID_FROM_FLAGS(_f) (((_f)&(0xF<<25)>>25)) -+ -+ -+/* ******************************************************************** */ -+/* WSM capcbility */ -+#define WSM_FW_LABEL 128 -+struct wsm_caps { -+ u16 numInpChBufs; -+ u16 sizeInpChBuf; -+ u16 hardwareId; -+ u16 hardwareSubId; -+ u16 firmwareCap; -+ u16 firmwareType; -+ u16 firmwareApiVer; -+ u16 firmwareBuildNumber; -+ u16 firmwareVersion; -+ char fw_label[WSM_FW_LABEL+2]; -+ int firmwareReady; -+}; -+ -+/* ******************************************************************** */ -+/* WSM commands */ -+ -+struct wsm_tx_power_range { -+ int min_power_level; -+ int max_power_level; -+ u32 stepping; -+}; -+ -+/* 3.1 */ -+struct wsm_configuration { -+ /* [in] */ u32 dot11MaxTransmitMsduLifeTime; -+ /* [in] */ u32 dot11MaxReceiveLifeTime; -+ /* [in] */ u32 dot11RtsThreshold; -+ /* [in, out] */ u8 *dot11StationId; -+ /* [in] */ const void *dpdData; -+ /* [in] */ size_t dpdData_size; -+ /* [out] */ u8 dot11FrequencyBandsSupported; -+ /* [out] */ u32 supportedRateMask; -+ /* [out] */ struct wsm_tx_power_range txPowerRange[2]; -+}; -+ -+int wsm_configuration(struct xradio_common *hw_priv, -+ struct wsm_configuration *arg, -+ int if_id); -+ -+/* 3.3 */ -+struct wsm_reset { -+ /* [in] */ int link_id; -+ /* [in] */ bool reset_statistics; -+}; -+ -+int wsm_reset(struct xradio_common *hw_priv, const struct wsm_reset *arg, -+ int if_id); -+ -+//add by yangfh -+void wsm_query_work(struct work_struct *work); -+ -+/* 3.5 */ -+int wsm_read_mib(struct xradio_common *hw_priv, u16 mibId, void *buf, -+ size_t buf_size, size_t arg_size); -+ -+/* 3.7 */ -+int wsm_write_mib(struct xradio_common *hw_priv, u16 mibId, void *buf, -+ size_t buf_size, int if_id); -+ -+/* 3.9 */ -+struct wsm_ssid { -+ u8 ssid[32]; -+ u32 length; -+}; -+ -+struct wsm_scan_ch { -+ u16 number; -+ u32 minChannelTime; -+ u32 maxChannelTime; -+ u32 txPowerLevel; -+}; -+ -+/* 3.13 */ -+struct wsm_scan_complete { -+ /* WSM_STATUS_... */ -+ u32 status; -+ -+ /* WSM_PSM_... */ -+ u8 psm; -+ -+ /* Number of channels that the scan operation completed. */ -+ u8 numChannels; -+#ifdef ROAM_OFFLOAD -+ u16 reserved; -+#endif /*ROAM_OFFLOAD*/ -+}; -+ -+/* 3.9 */ -+struct wsm_scan { -+ /* WSM_PHY_BAND_... */ -+ /* [in] */ u8 band; -+ -+ /* WSM_SCAN_TYPE_... */ -+ /* [in] */ u8 scanType; -+ -+ /* WSM_SCAN_FLAG_... */ -+ /* [in] */ u8 scanFlags; -+ -+ /* WSM_TRANSMIT_RATE_... */ -+ /* [in] */ u8 maxTransmitRate; -+ -+ /* Interval period in TUs that the device shall the re- */ -+ /* execute the requested scan. Max value supported by the device */ -+ /* is 256s. */ -+ /* [in] */ u32 autoScanInterval; -+ -+ /* Number of probe requests (per SSID) sent to one (1) */ -+ /* channel. Zero (0) means that none is send, which */ -+ /* means that a passive scan is to be done. Value */ -+ /* greater than zero (0) means that an active scan is to */ -+ /* be done. */ -+ /* [in] */ u32 numOfProbeRequests; -+ -+ /* Number of channels to be scanned. */ -+ /* Maximum value is WSM_SCAN_MAX_NUM_OF_CHANNELS. */ -+ /* [in] */ u8 numOfChannels; -+ -+ /* Number of SSID provided in the scan command (this */ -+ /* is zero (0) in broadcast scan) */ -+ /* The maximum number of SSIDs is WSM_SCAN_MAX_NUM_OF_SSIDS. */ -+ /* [in] */ u8 numOfSSIDs; -+ -+ /* The delay time (in microseconds) period */ -+ /* before sending a probe-request. */ -+ /* [in] */ u8 probeDelay; -+ -+ /* SSIDs to be scanned [numOfSSIDs]; */ -+ /* [in] */ struct wsm_ssid *ssids; -+ -+ /* Channels to be scanned [numOfChannels]; */ -+ /* [in] */ struct wsm_scan_ch *ch; -+}; -+ -+int wsm_scan(struct xradio_common *hw_priv, const struct wsm_scan *arg, -+ int if_id); -+ -+/* 3.11 */ -+int wsm_stop_scan(struct xradio_common *hw_priv, int if_id); -+ -+/* 3.14 */ -+struct wsm_tx_confirm { -+ /* Packet identifier used in wsm_tx. */ -+ /* [out] */ u32 packetID; -+ -+ /* WSM_STATUS_... */ -+ /* [out] */ u32 status; -+ -+ /* WSM_TRANSMIT_RATE_... */ -+ /* [out] */ u8 txedRate; -+ -+ /* The number of times the frame was transmitted */ -+ /* without receiving an acknowledgement. */ -+ /* [out] */ u8 ackFailures; -+ -+ /* WSM_TX_STATUS_... */ -+ /* [out] */ u16 flags; -+ -+ //rate feed back, add by yangfh -+ /* [out] */ u32 rate_try[3]; -+ -+ /* The total time in microseconds that the frame spent in */ -+ /* the WLAN device before transmission as completed. */ -+ /* [out] */ u32 mediaDelay; -+ -+ /* The total time in microseconds that the frame spent in */ -+ /* the WLAN device before transmission was started. */ -+ /* [out] */ u32 txQueueDelay; -+ -+ /* [out]*/ u32 link_id; -+ -+ /*[out]*/ int if_id; -+}; -+ -+/* 3.15 */ -+ -+/* Note that ideology of wsm_tx struct is different against the rest of -+ * WSM API. wsm_hdr is /not/ a caller-adapted struct to be used as an input -+ * argument for WSM call, but a prepared bytestream to be sent to firmware. -+ * It is filled partly in xradio_tx, partly in low-level WSM code. -+ * Please pay attention once again: ideology is different. -+ * -+ * Legend: -+ * - [in]: xradio_tx must fill this field. -+ * - [wsm]: the field is filled by low-level WSM. -+ */ -+struct wsm_tx { -+ /* common WSM header */ -+ /* [in/wsm] */ struct wsm_hdr hdr; -+ -+ /* Packet identifier that meant to be used in completion. */ -+ /* [in] */ __le32 packetID; -+ -+ /* WSM_TRANSMIT_RATE_... */ -+ /* [in] */ u8 maxTxRate; -+ -+ /* WSM_QUEUE_... */ -+ /* [in] */ u8 queueId; -+ -+ /* True: another packet is pending on the host for transmission. */ -+ /* [wsm] */ u8 more; -+ -+ /* Bit 0 = 0 - Start expiry time from first Tx attempt (default) */ -+ /* Bit 0 = 1 - Start expiry time from receipt of Tx Request */ -+ /* Bits 3:1 - PTA Priority */ -+ /* Bits 6:4 - Tx Rate Retry Policy */ -+ /* Bit 7 - Reserved */ -+ /* [in] */ u8 flags; -+ -+ /* Should be 0. */ -+ /* [in] */ __le32 reserved; -+ -+ /* The elapsed time in TUs, after the initial transmission */ -+ /* of an MSDU, after which further attempts to transmit */ -+ /* the MSDU shall be terminated. Overrides the global */ -+ /* dot11MaxTransmitMsduLifeTime setting [optional] */ -+ /* Device will set the default value if this is 0. */ -+ /* [wsm] */ __le32 expireTime; -+ -+ /* WSM_HT_TX_... */ -+ /* [in] */ __le32 htTxParameters; -+}; -+ -+/* = sizeof(generic hi hdr) + sizeof(wsm hdr) + sizeof(alignment) */ -+#define WSM_TX_EXTRA_HEADROOM (28) -+ -+/* 3.16 */ -+struct wsm_rx { -+ /* WSM_STATUS_... */ -+ /* [out] */ u32 status; -+ -+ /* Specifies the channel of the received packet. */ -+ /* [out] */ u16 channelNumber; -+ -+ /* WSM_TRANSMIT_RATE_... */ -+ /* [out] */ u8 rxedRate; -+ -+ /* This value is expressed in signed Q8.0 format for */ -+ /* RSSI and unsigned Q7.1 format for RCPI. */ -+ /* [out] */ u8 rcpiRssi; -+ -+ /* WSM_RX_STATUS_... */ -+ /* [out] */ u32 flags; -+ -+ /* An 802.11 frame. */ -+ /* [out] */ void *frame; -+ -+ /* Size of the frame */ -+ /* [out] */ size_t frame_size; -+ -+ /* Link ID */ -+ /* [out] */ int link_id; -+ /* [out] */ int if_id; -+}; -+ -+/* = sizeof(generic hi hdr) + sizeof(wsm hdr) */ -+#define WSM_RX_EXTRA_HEADROOM (16) -+ -+/* 3.17 */ -+struct wsm_event { -+ /* WSM_STATUS_... */ -+ /* [out] */ u32 eventId; -+ -+ /* Indication parameters. */ -+ /* For error indication, this shall be a 32-bit WSM status. */ -+ /* For RCPI or RSSI indication, this should be an 8-bit */ -+ /* RCPI or RSSI value. */ -+ /* [out] */ u32 eventData; -+}; -+ -+struct xradio_wsm_event { -+ struct list_head link; -+ struct wsm_event evt; -+ u8 if_id; -+}; -+ -+/* 3.18 - 3.22 */ -+/* Measurement. Skipped for now. Irrelevent. */ -+ -+ -+/* 3.23 */ -+struct wsm_join { -+ /* WSM_JOIN_MODE_... */ -+ /* [in] */ u8 mode; -+ -+ /* WSM_PHY_BAND_... */ -+ /* [in] */ u8 band; -+ -+ /* Specifies the channel number to join. The channel */ -+ /* number will be mapped to an actual frequency */ -+ /* according to the band */ -+ /* [in] */ u16 channelNumber; -+ -+ /* Specifies the BSSID of the BSS or IBSS to be joined */ -+ /* or the IBSS to be started. */ -+ /* [in] */ u8 bssid[6]; -+ -+ /* ATIM window of IBSS */ -+ /* When ATIM window is zero the initiated IBSS does */ -+ /* not support power saving. */ -+ /* [in] */ u16 atimWindow; -+ -+ /* WSM_JOIN_PREAMBLE_... */ -+ /* [in] */ u8 preambleType; -+ -+ /* Specifies if a probe request should be send with the */ -+ /* specified SSID when joining to the network. */ -+ /* [in] */ u8 probeForJoin; -+ -+ /* DTIM Period (In multiples of beacon interval) */ -+ /* [in] */ u8 dtimPeriod; -+ -+ /* WSM_JOIN_FLAGS_... */ -+ /* [in] */ u8 flags; -+ -+ /* Length of the SSID */ -+ /* [in] */ u32 ssidLength; -+ -+ /* Specifies the SSID of the IBSS to join or start */ -+ /* [in] */ u8 ssid[32]; -+ -+ /* Specifies the time between TBTTs in TUs */ -+ /* [in] */ u32 beaconInterval; -+ -+ /* A bit mask that defines the BSS basic rate set. */ -+ /* [in] */ u32 basicRateSet; -+ -+ /* Minimum transmission power level in units of 0.1dBm */ -+ /* [out] */ int minPowerLevel; -+ -+ /* Maximum transmission power level in units of 0.1dBm */ -+ /* [out] */ int maxPowerLevel; -+}; -+ -+int wsm_join(struct xradio_common *hw_priv, struct wsm_join *arg, int if_id); -+ -+/* 3.25 */ -+struct wsm_set_pm { -+ /* WSM_PSM_... */ -+ /* [in] */ u8 pmMode; -+ -+ /* in unit of 500us; 0 to use default */ -+ /* [in] */ u8 fastPsmIdlePeriod; -+ -+ /* in unit of 500us; 0 to use default */ -+ /* [in] */ u8 apPsmChangePeriod; -+ -+ /* in unit of 500us; 0 to disable auto-pspoll */ -+ /* [in] */ u8 minAutoPsPollPeriod; -+}; -+ -+int wsm_set_pm(struct xradio_common *hw_priv, const struct wsm_set_pm *arg, -+ int if_id); -+ -+/* 3.27 */ -+struct wsm_set_pm_complete { -+ u8 psm; /* WSM_PSM_... */ -+}; -+ -+/* 3.28 */ -+struct wsm_set_bss_params { -+ /* The number of lost consecutive beacons after which */ -+ /* the WLAN device should indicate the BSS-Lost event */ -+ /* to the WLAN host driver. */ -+ u8 beaconLostCount; -+ -+ /* The AID received during the association process. */ -+ u16 aid; -+ -+ /* The operational rate set mask */ -+ u32 operationalRateSet; -+}; -+ -+int wsm_set_bss_params(struct xradio_common *hw_priv, -+ const struct wsm_set_bss_params *arg, int if_id); -+ -+/* 3.30 */ -+struct wsm_add_key { -+ u8 type; /* WSM_KEY_TYPE_... */ -+ u8 entryIndex; /* Key entry index: 0 -- WSM_KEY_MAX_INDEX */ -+ u16 reserved; -+ union { -+ struct { -+ u8 peerAddress[6]; /* MAC address of the -+ * peer station */ -+ u8 reserved; -+ u8 keyLength; /* Key length in bytes */ -+ u8 keyData[16]; /* Key data */ -+ } __packed wepPairwiseKey; -+ struct { -+ u8 keyId; /* Unique per key identifier -+ * (0..3) */ -+ u8 keyLength; /* Key length in bytes */ -+ u16 reserved; -+ u8 keyData[16]; /* Key data */ -+ } __packed wepGroupKey; -+ struct { -+ u8 peerAddress[6]; /* MAC address of the -+ * peer station */ -+ u8 reserved[2]; -+ u8 tkipKeyData[16]; /* TKIP key data */ -+ u8 rxMicKey[8]; /* Rx MIC key */ -+ u8 txMicKey[8]; /* Tx MIC key */ -+ } __packed tkipPairwiseKey; -+ struct { -+ u8 tkipKeyData[16]; /* TKIP key data */ -+ u8 rxMicKey[8]; /* Rx MIC key */ -+ u8 keyId; /* Key ID */ -+ u8 reserved[3]; -+ u8 rxSeqCounter[8]; /* Receive Sequence Counter */ -+ } __packed tkipGroupKey; -+ struct { -+ u8 peerAddress[6]; /* MAC address of the -+ * peer station */ -+ u16 reserved; -+ u8 aesKeyData[16]; /* AES key data */ -+ } __packed aesPairwiseKey; -+ struct { -+ u8 aesKeyData[16]; /* AES key data */ -+ u8 keyId; /* Key ID */ -+ u8 reserved[3]; -+ u8 rxSeqCounter[8]; /* Receive Sequence Counter */ -+ } __packed aesGroupKey; -+ struct { -+ u8 peerAddress[6]; /* MAC address of the -+ * peer station */ -+ u8 keyId; /* Key ID */ -+ u8 reserved; -+ u8 wapiKeyData[16]; /* WAPI key data */ -+ u8 micKeyData[16]; /* MIC key data */ -+ } __packed wapiPairwiseKey; -+ struct { -+ u8 wapiKeyData[16]; /* WAPI key data */ -+ u8 micKeyData[16]; /* MIC key data */ -+ u8 keyId; /* Key ID */ -+ u8 reserved[3]; -+ } __packed wapiGroupKey; -+ } __packed; -+} __packed; -+ -+int wsm_add_key(struct xradio_common *hw_priv, const struct wsm_add_key *arg, -+ int if_id); -+ -+/* 3.32 */ -+struct wsm_remove_key { -+ /* Key entry index : 0-10 */ -+ u8 entryIndex; -+}; -+ -+int wsm_remove_key(struct xradio_common *hw_priv, -+ const struct wsm_remove_key *arg, int if_id); -+ -+/* 3.34 */ -+struct wsm_set_tx_queue_params { -+ /* WSM_ACK_POLICY_... */ -+ u8 ackPolicy; -+ -+ /* Medium Time of TSPEC (in 32us units) allowed per */ -+ /* One Second Averaging Period for this queue. */ -+ u16 allowedMediumTime; -+ -+ /* dot11MaxTransmitMsduLifetime to be used for the */ -+ /* specified queue. */ -+ u32 maxTransmitLifetime; -+}; -+ -+struct wsm_tx_queue_params { -+ /* NOTE: index is a linux queue id. */ -+ struct wsm_set_tx_queue_params params[4]; -+}; -+ -+#define WSM_TX_QUEUE_SET(queue_params, queue, ack_policy, allowed_time, \ -+ max_life_time) \ -+do { \ -+ struct wsm_set_tx_queue_params *p = &(queue_params)->params[queue]; \ -+ p->ackPolicy = (ack_policy); \ -+ p->allowedMediumTime = (allowed_time); \ -+ p->maxTransmitLifetime = (max_life_time); \ -+} while (0) -+ -+int wsm_set_tx_queue_params(struct xradio_common *hw_priv, -+ const struct wsm_set_tx_queue_params *arg, -+ u8 id, int if_id); -+ -+/* 3.36 */ -+struct wsm_edca_queue_params { -+ /* CWmin (in slots) for the access class. */ -+ /* [in] */ u16 cwMin; -+ -+ /* CWmax (in slots) for the access class. */ -+ /* [in] */ u16 cwMax; -+ -+ /* AIFS (in slots) for the access class. */ -+ /* [in] */ u8 aifns; -+ -+ /* TX OP Limit (in microseconds) for the access class. */ -+ /* [in] */ u16 txOpLimit; -+ -+ /* dot11MaxReceiveLifetime to be used for the specified */ -+ /* the access class. Overrides the global */ -+ /* dot11MaxReceiveLifetime value */ -+ /* [in] */ u32 maxReceiveLifetime; -+ -+ /* UAPSD trigger support for the access class. */ -+ /* [in] */ bool uapsdEnable; -+}; -+ -+struct wsm_edca_params { -+ /* NOTE: index is a linux queue id. */ -+ struct wsm_edca_queue_params params[4]; -+}; -+ -+#define TXOP_UNIT 32 -+#define WSM_EDCA_SET(edca, queue, aifs, cw_min, cw_max, txop, life_time,\ -+ uapsd) \ -+ do { \ -+ struct wsm_edca_queue_params *p = &(edca)->params[queue]; \ -+ p->cwMin = (cw_min); \ -+ p->cwMax = (cw_max); \ -+ p->aifns = (aifs); \ -+ p->txOpLimit = ((txop) * TXOP_UNIT); \ -+ p->maxReceiveLifetime = (life_time); \ -+ p->uapsdEnable = (uapsd); \ -+ } while (0) -+ -+int wsm_set_edca_params(struct xradio_common *hw_priv, -+ const struct wsm_edca_params *arg, int if_id); -+ -+int wsm_set_uapsd_param(struct xradio_common *hw_priv, -+ const struct wsm_edca_params *arg); -+ -+/* 3.38 */ -+/* Set-System info. Skipped for now. Irrelevent. */ -+ -+/* 3.40 */ -+struct wsm_switch_channel { -+ /* 1 - means the STA shall not transmit any further */ -+ /* frames until the channel switch has completed */ -+ /* [in] */ u8 channelMode; -+ -+ /* Number of TBTTs until channel switch occurs. */ -+ /* 0 - indicates switch shall occur at any time */ -+ /* 1 - occurs immediately before the next TBTT */ -+ /* [in] */ u8 channelSwitchCount; -+ -+ /* The new channel number to switch to. */ -+ /* Note this is defined as per section 2.7. */ -+ /* [in] */ u16 newChannelNumber; -+}; -+ -+int wsm_switch_channel(struct xradio_common *hw_priv, -+ const struct wsm_switch_channel *arg, int if_id); -+ -+struct wsm_start { -+ /* WSM_START_MODE_... */ -+ /* [in] */ u8 mode; -+ -+ /* WSM_PHY_BAND_... */ -+ /* [in] */ u8 band; -+ -+ /* Channel number */ -+ /* [in] */ u16 channelNumber; -+ -+ /* Client Traffic window in units of TU */ -+ /* Valid only when mode == ..._P2P */ -+ /* [in] */ u32 CTWindow; -+ -+ /* Interval between two consecutive */ -+ /* beacon transmissions in TU. */ -+ /* [in] */ u32 beaconInterval; -+ -+ /* DTIM period in terms of beacon intervals */ -+ /* [in] */ u8 DTIMPeriod; -+ -+ /* WSM_JOIN_PREAMBLE_... */ -+ /* [in] */ u8 preambleType; -+ -+ /* The delay time (in microseconds) period */ -+ /* before sending a probe-request. */ -+ /* [in] */ u8 probeDelay; -+ -+ /* Length of the SSID */ -+ /* [in] */ u8 ssidLength; -+ -+ /* SSID of the BSS or P2P_GO to be started now. */ -+ /* [in] */ u8 ssid[32]; -+ -+ /* The basic supported rates for the MiniAP. */ -+ /* [in] */ u32 basicRateSet; -+}; -+ -+int wsm_start(struct xradio_common *hw_priv, const struct wsm_start *arg, -+ int if_id); -+ -+#if 0 -+struct wsm_beacon_transmit { -+ /* 1: enable; 0: disable */ -+ /* [in] */ u8 enableBeaconing; -+}; -+ -+int wsm_beacon_transmit(struct xradio_common *hw_priv, -+ const struct wsm_beacon_transmit *arg, -+ int if_id); -+#endif -+ -+int wsm_start_find(struct xradio_common *hw_priv, int if_id); -+ -+int wsm_stop_find(struct xradio_common *hw_priv, int if_id); -+ -+struct wsm_suspend_resume { -+ /* See 3.52 */ -+ /* Link ID */ -+ /* [out] */ int link_id; -+ /* Stop sending further Tx requests down to device for this link */ -+ /* [out] */ bool stop; -+ /* Transmit multicast Frames */ -+ /* [out] */ bool multicast; -+ /* The AC on which Tx to be suspended /resumed. */ -+ /* This is applicable only for U-APSD */ -+ /* WSM_QUEUE_... */ -+ /* [out] */ int queue; -+ /* [out] */ int if_id; -+}; -+ -+/* 3.54 Update-IE request. */ -+struct wsm_update_ie { -+ /* WSM_UPDATE_IE_... */ -+ /* [in] */ u16 what; -+ /* [in] */ u16 count; -+ /* [in] */ u8 *ies; -+ /* [in] */ size_t length; -+}; -+ -+int wsm_update_ie(struct xradio_common *hw_priv, -+ const struct wsm_update_ie *arg, int if_id); -+ -+/* 3.56 */ -+struct wsm_map_link { -+ /* MAC address of the remote device */ -+ /* [in] */ u8 mac_addr[6]; -+ /* [in] */ u8 unmap; -+ /* [in] */ u8 link_id; -+}; -+ -+int wsm_map_link(struct xradio_common *hw_priv, const struct wsm_map_link *arg, -+ int if_id); -+ -+#ifdef MCAST_FWDING -+ -+/* 3.65 Give Buffer Request */ -+int wsm_init_release_buffer_request(struct xradio_common *priv, u8 index); -+ -+/* 3.65 fixed memory leakage by yangfh*/ -+int wsm_deinit_release_buffer(struct xradio_common *hw_priv); -+ -+/* 3.67 Request Buffer Request */ -+int wsm_request_buffer_request(struct xradio_vif *priv, -+ u8 *arg); -+#endif -+/* ******************************************************************** */ -+/* MIB shortcats */ -+#define XR_RRM 1 -+#ifdef XR_RRM//RadioResourceMeasurement -+/* RadioResourceMeasurement Request*/ -+#define MEAS_CCA 0 -+#define MEAS_CHANNELLOAD 1 -+typedef struct LMAC_MEAS_CHANNEL_LOAD_PARAMS_S -+{ -+ u8 Reserved; -+ u8 ChannelLoadCCA; -+ u16 ChannelNum; -+ u16 RandomInterval; -+ u16 MeasurementDuration; -+ u32 MeasurementStartTimel; -+ u32 MeasurementStartTimeh; -+}LMAC_MEAS_CHANNEL_LOAD_PARAMS; -+ -+#define MEAS_RPI 0 -+#define MEAS_IPI 1 -+ -+typedef struct LMAC_MEAS_NOISE_HISTOGRAM_PARAMS_S -+{ -+ u8 Reserved; -+ u8 IpiRpi; -+ u16 ChannelNum; -+ u16 RandomInterval; -+ u16 MeasurementDuration; -+ u32 MeasurementStartTimel; -+ u32 MeasurementStartTimeh; -+}LMAC_MEAS_NOISE_HISTOGRAM_PARAMS; -+ -+#define LMAC_MAX_SSIDS 16 -+#define LMAC_MAX_SSID_LENGTH 32 -+typedef struct LMAC_CHANNELS_S -+{ -+ u32 ChannelNum; -+ u32 MinChannelTime; -+ u32 MaxChannelTime; -+ s32 TxPowerLevel; -+}LMAC_CHANNELS; -+ -+typedef struct LMAC_SSIDS_S -+{ -+ u32 SSIDLength; -+ u8 SSID[LMAC_MAX_SSID_LENGTH]; -+}LMAC_SSIDS; -+ -+typedef struct LMAC_MEAS_BEACON_PARAMS_S -+{ -+ //u8 RegulatoryClass; -+ //u8 MeasurementMode; -+ //u16 ChannelNum; -+ u16 RandomInterval; -+ //u16 MeasurementDuration; -+ //u8 Bssid[6]; -+ u16 Reserved; -+ //SCAN_PARAMETERS ScanParameters; -+ u8 Band; -+ u8 ScanType; -+ u8 ScanFlags; -+ u8 MaxTransmitRate; -+ u32 AutoScanInterval; -+ u8 NumOfProbeRequests; -+ u8 NumOfChannels; -+ u8 NumOfSSIDs; -+ u8 ProbeDelay; -+ LMAC_CHANNELS Channels; -+ LMAC_SSIDS Ssids; // here for SCAN_PARAMETER sizing purposes -+}LMAC_MEAS_BEACON_PARAMS; -+ -+typedef struct LMAC_MEAS_STA_STATS_PARAMS_S -+{ -+ u8 PeerMacAddress[6]; -+ u16 RandomInterval; -+ u16 MeasurementDuration; -+ u8 GroupId; -+ u8 Reserved; -+}LMAC_MEAS_STA_STATS_PARAMS; -+ -+typedef struct LMAC_MEAS_LINK_MEASUREMENT_PARAMS_S -+{ -+ u8 Reserved[4]; -+}LMAC_MEAS_LINK_MEASUREMENT_PARAMS; -+ -+typedef union LMAC_MEAS_REQUEST_U -+{ -+ LMAC_MEAS_CHANNEL_LOAD_PARAMS ChannelLoadParams; -+ LMAC_MEAS_NOISE_HISTOGRAM_PARAMS NoisHistogramParams; -+ LMAC_MEAS_BEACON_PARAMS BeaconParams; -+ LMAC_MEAS_STA_STATS_PARAMS StaStatsParams; -+ LMAC_MEAS_LINK_MEASUREMENT_PARAMS LinkMeasurementParams; -+} LMAC_MEAS_REQUEST; -+ -+// This struct is a copy of WSM_HI_START_MEASUREMENT_REQ, except that MsgLen and MsgId is not included -+typedef struct MEASUREMENT_PARAMETERS_S -+{ -+// u16 MsgLen; -+// u16 MsgId; -+ s32 TxPowerLevel; -+ u8 DurationMandatory; -+ u8 MeasurementType; -+ u8 MeasurementRequestLength; -+ u8 Reserved[5]; -+ LMAC_MEAS_REQUEST MeasurementRequest; -+}MEASUREMENT_PARAMETERS; -+ -+/* RadioResourceMeasurement Result*/ -+ typedef struct LMAC_MEAS_CHANNEL_LOAD_RESULTS_S -+{ -+ u8 Reserved; -+ u8 ChannelLoadCCA; -+ u16 ChannelNum; -+ u32 ActualMeasurementStartTimel; -+ u32 ActualMeasurementStartTimeh; -+ u16 MeasurementDuration; -+ u8 CCAbusyFraction; -+ u8 ChannelLoad; -+}LMAC_MEAS_CHANNEL_LOAD_RESULTS; -+ -+typedef struct LMAC_MEAS_NOISE_HISTOGRAM_RESULTS_S -+{ -+ u16 Reserved; -+ u16 ChannelNum; -+ u32 ActualMeasurementStartTimel; -+ u32 ActualMeasurementStartTimeh; -+ u16 MeasurementDuration; -+ u8 AntennaID; -+ u8 IpiRpi; -+ u8 PI_0_Density; -+ u8 PI_1_Density; -+ u8 PI_2_Density; -+ u8 PI_3_Density; -+ u8 PI_4_Density; -+ u8 PI_5_Density; -+ u8 PI_6_Density; -+ u8 PI_7_Density; -+ u8 PI_8_Density; -+ u8 PI_9_Density; -+ u8 PI_10_Density; -+ u8 Reserved2; -+}LMAC_MEAS_NOISE_HISTOGRAM_RESULTS; -+ -+typedef struct LMAC_MEAS_BEACON_RESULTS_S -+{ -+ u16 MeasurementDuration; -+ u16 Reserved; -+ u32 StartTsfl; -+ u32 StartTsfh; -+ u32 Durationl; -+ u32 Durationh; -+ //SCAN_PARAMETERS ScanParameters; -+ u8 Band; -+ u8 ScanType; -+ u8 ScanFlags; -+ u8 MaxTransmitRate; -+ u32 AutoScanInterval; -+ u8 NumOfProbeRequests; -+ u8 NumOfChannels; -+ u8 NumOfSSIDs; -+ u8 ProbeDelay; -+ LMAC_CHANNELS Channels; -+ LMAC_SSIDS Ssids; -+}LMAC_MEAS_BEACON_RESULTS; -+ -+typedef struct LMAC_MEAS_STA_STATS_RESULTS_S -+{ -+ u16 MeasurementDuration; -+ u8 GroupId; -+ u8 StatisticsGroupDataLength; -+ u8 StatisticsGroupData[52]; -+}LMAC_MEAS_STA_STATS_RESULTS; -+ -+typedef struct LMAC_MEAS_LINK_MEASUREMENT_RESULTS_S -+{ -+ s16 TransmitPower; -+ u8 RxAntennaID; -+ u8 TxAntennaID; -+ s32 NoiseLeveldBm; -+ s8 LatestRssi; -+ u8 Reserved1; -+ u8 Reserved2; -+ u8 Reserved3; -+}LMAC_MEAS_LINK_MEASUREMENT_RESULTS; -+ -+typedef union LMAC_MEAS_REPORT_U -+{ -+ LMAC_MEAS_CHANNEL_LOAD_RESULTS ChannelLoadResults; -+ LMAC_MEAS_NOISE_HISTOGRAM_RESULTS NoiseHistogramResults; -+ LMAC_MEAS_BEACON_RESULTS BeaconResults; -+ LMAC_MEAS_STA_STATS_RESULTS StaStatsResults; -+ LMAC_MEAS_LINK_MEASUREMENT_RESULTS LinkMeasurementResults; -+}LMAC_MEAS_REPORT; -+ -+// Note: eMeasurementTypes MUST match the #define WSM_MEASURE_TYPE_XXX from wsm_api.h -+typedef enum { -+ ChannelLoadMeasurement=0, -+ NoiseHistrogramMeasurement, -+ BeaconReport, -+ STAstatisticsReport, -+ LinkMeasurement -+}eMeasurementTypes; -+ -+typedef struct MEASUREMENT_COMPLETE_S -+{ -+// u16 RandomInterval; -+// u16 Reserved0; -+ u8 Dot11PowerMgmtMode; // From here WSM_HI_MEASURE_CMPL_IND and MEASUREMENT_COMPLETE_S must be identical -+ u8 MeasurementType; -+ u16 MoreInd; // Set to 1 if more indications are to follow for this measurement, otherwise 0; -+ u32 Status; -+ u8 MeasurementReportLength; -+ u8 Reserved2[3]; -+ LMAC_MEAS_REPORT MeasurementReport; -+}MEASUREMENT_COMPLETE; // Note: must be 32 bit aligned -+ -+#endif -+int wsm_11k_measure_requset(struct xradio_common *hw_priv, -+ u8 measure_type, -+ u16 ChannelNum, -+ u16 Duration); -+ -+ -+static inline int wsm_set_fw_debug_control(struct xradio_common *hw_priv, -+ int debug_control, int if_id) -+{ -+ __le32 val = __cpu_to_le32(debug_control); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_FW_DEBUG_CONTROL, -+ &val, sizeof(val), if_id); -+} -+ -+static inline int wsm_set_host_sleep(struct xradio_common *hw_priv, -+ u8 host_sleep, int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_HOST_SLEEP, -+ &host_sleep, sizeof(host_sleep), if_id); -+} -+ -+static inline int wsm_set_output_power(struct xradio_common *hw_priv, -+ int power_level, int if_id) -+{ -+ __le32 val = __cpu_to_le32(power_level); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL, -+ &val, sizeof(val), if_id); -+} -+ -+static inline int wsm_set_beacon_wakeup_period(struct xradio_common *hw_priv, -+ unsigned dtim_interval, -+ unsigned listen_interval, -+ int if_id) -+{ -+ struct { -+ u8 numBeaconPeriods; -+ u8 reserved; -+ __le16 listenInterval; -+ } val = { -+ dtim_interval, 0, __cpu_to_le16(listen_interval)}; -+ if (dtim_interval > 0xFF || listen_interval > 0xFFFF) -+ return -EINVAL; -+ else -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_WAKEUP_PERIOD, -+ &val, sizeof(val), if_id); -+} -+ -+struct wsm_rcpi_rssi_threshold { -+ u8 rssiRcpiMode; /* WSM_RCPI_RSSI_... */ -+ u8 lowerThreshold; -+ u8 upperThreshold; -+ u8 rollingAverageCount; -+}; -+ -+static inline int wsm_set_rcpi_rssi_threshold(struct xradio_common *hw_priv, -+ struct wsm_rcpi_rssi_threshold *arg, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_RCPI_RSSI_THRESHOLD, arg, -+ sizeof(*arg), if_id); -+} -+ -+struct wsm_counters_table { -+ __le32 countPlcpErrors; -+ __le32 countFcsErrors; -+ __le32 countTxPackets; -+ __le32 countRxPackets; -+ __le32 countRxPacketErrors; -+ __le32 countRtsSuccess; -+ __le32 countRtsFailures; -+ __le32 countRxFramesSuccess; -+ __le32 countRxDecryptionFailures; -+ __le32 countRxMicFailures; -+ __le32 countRxNoKeyFailures; -+ __le32 countTxMulticastFrames; -+ __le32 countTxFramesSuccess; -+ __le32 countTxFrameFailures; -+ __le32 countTxFramesRetried; -+ __le32 countTxFramesMultiRetried; -+ __le32 countRxFrameDuplicates; -+ __le32 countAckFailures; -+ __le32 countRxMulticastFrames; -+ __le32 countRxCMACICVErrors; -+ __le32 countRxCMACReplays; -+ __le32 countRxMgmtCCMPReplays; -+ __le32 countRxBIPMICErrors; -+}; -+ -+ -+struct wsm_ampducounters_table { -+ u32 countTxAMPDUs; -+ u32 countTxMPDUsInAMPDUs; -+ u32 countTxOctetsInAMPDUs_l32; -+ u32 countTxOctetsInAMPDUs_h32; -+ u32 countRxAMPDUs; -+ u32 countRxMPDUsInAMPDUs; -+ u32 countRxOctetsInAMPDUs_l32; -+ u32 countRxOctetsInAMPDUs_h32; -+ u32 countRxDelimeterCRCErrorCount; -+ u32 countImplictBARFailures; -+ u32 countExplictBARFailures; -+}; -+ -+struct wsm_txpipe_counter { -+ u32 count1; -+ u32 count2; -+ u32 count3; -+ u32 count4; -+ u32 count5; -+ u32 count6; -+ u32 count7; -+ u32 count8; -+ u32 count9; -+ u32 counta; -+}; -+ -+struct wsm_backoff_counter { -+ u32 count0; -+ u32 count1; -+ u32 count2; -+ u32 count3; -+ u32 count4; -+ u32 count5; -+ u32 count6; -+ u32 count7; -+ u32 count8; -+ u32 count9; -+}; -+//add by yangfh for read/write fw registers -+#define WSM_REG_RW_F BIT(0) //0:read, 1:write -+#define WSM_REG_RET_F BIT(1) //results is valid. -+#define WSM_REG_BK_F BIT(4) //operate in block mode. -+ -+struct reg_data { -+ u32 reg_addr; -+ u32 reg_val; -+}; -+ -+typedef struct tag_wsm_reg_w { -+ u16 flag; -+ u16 data_size; -+ struct reg_data arg[16]; -+} WSM_REG_W; -+ -+typedef struct tag_wsm_reg_r { -+ u16 flag; -+ u16 data_size; -+ u32 arg[16]; -+} WSM_REG_R; -+ -+struct wsm_backoff_ctrl { -+ u32 enable; -+ u32 min; -+ u32 max; -+}; -+struct wsm_tala_para { -+ u32 para; -+ u32 thresh; -+}; -+static inline int wsm_get_counters_table(struct xradio_common *hw_priv, -+ struct wsm_counters_table *arg) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_COUNTERS_TABLE, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_get_ampducounters_table(struct xradio_common *hw_priv, -+ struct wsm_ampducounters_table *arg) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_AMPDUCOUNTERS_TABLE, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_get_txpipe_table(struct xradio_common *hw_priv, -+ struct wsm_txpipe_counter *arg) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_TXPIPE_TABLE, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_get_backoff_dbg(struct xradio_common *hw_priv, -+ struct wsm_backoff_counter *arg) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_BACKOFF_DBG, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_set_backoff_ctrl(struct xradio_common *hw_priv, -+ struct wsm_backoff_ctrl *arg) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BACKOFF_CTRL, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_set_tala(struct xradio_common *hw_priv, -+ struct wsm_tala_para *arg) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_TALA_PARA, -+ arg, sizeof(*arg), 0); -+} -+static inline int wsm_get_station_id(struct xradio_common *hw_priv, u8 *mac) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_DOT11_STATION_ID, mac, -+ ETH_ALEN, 0); -+} -+ -+struct wsm_rx_filter { -+ bool promiscuous; -+ bool bssid; -+ bool fcs; -+ bool probeResponder; -+ bool keepalive; -+}; -+ -+static inline int wsm_set_rx_filter(struct xradio_common *hw_priv, -+ const struct wsm_rx_filter *arg, -+ int if_id) -+{ -+ __le32 val = 0; -+ if (arg->promiscuous) -+ val |= __cpu_to_le32(BIT(0)); -+ if (arg->bssid) -+ val |= __cpu_to_le32(BIT(1)); -+ if (arg->fcs) -+ val |= __cpu_to_le32(BIT(2)); -+ if (arg->probeResponder) -+ val |= __cpu_to_le32(BIT(3)); -+ if (arg->keepalive) -+ val |= __cpu_to_le32(BIT(4)); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_RX_FILTER, &val, sizeof(val), -+ if_id); -+} -+ -+int wsm_set_probe_responder(struct xradio_vif *priv, bool enable); -+int wsm_set_keepalive_filter(struct xradio_vif *priv, bool enable); -+ -+#define WSM_BEACON_FILTER_IE_HAS_CHANGED BIT(0) -+#define WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT BIT(1) -+#define WSM_BEACON_FILTER_IE_HAS_APPEARED BIT(2) -+ -+struct wsm_beacon_filter_table_entry { -+ u8 ieId; -+ u8 actionFlags; -+ u8 oui[3]; -+ u8 matchData[3]; -+} __packed; -+ -+struct wsm_beacon_filter_table { -+ __le32 numOfIEs; -+ struct wsm_beacon_filter_table_entry entry[10]; -+} __packed; -+ -+static inline int wsm_set_beacon_filter_table(struct xradio_common *hw_priv, -+ struct wsm_beacon_filter_table *ft, -+ int if_id) -+{ -+ size_t size = __le32_to_cpu(ft->numOfIEs) * -+ sizeof(struct wsm_beacon_filter_table_entry) + -+ sizeof(__le32); -+ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_FILTER_TABLE, ft, size, -+ if_id); -+} -+ -+#define WSM_BEACON_FILTER_ENABLE BIT(0) /* Enable/disable beacon filtering */ -+#define WSM_BEACON_FILTER_AUTO_ERP BIT(1) /* If 1 FW will handle ERP IE changes internally */ -+ -+struct wsm_beacon_filter_control { -+ int enabled; -+ int bcn_count; -+}; -+ -+static inline int wsm_beacon_filter_control(struct xradio_common *hw_priv, -+ struct wsm_beacon_filter_control *arg, -+ int if_id) -+{ -+ struct { -+ __le32 enabled; -+ __le32 bcn_count; -+ } val; -+ val.enabled = __cpu_to_le32(arg->enabled); -+ val.bcn_count = __cpu_to_le32(arg->bcn_count); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_FILTER_ENABLE, &val, -+ sizeof(val), if_id); -+} -+ -+enum wsm_power_mode { -+ wsm_power_mode_active = 0, -+ wsm_power_mode_doze = 1, -+ wsm_power_mode_quiescent = 2, -+}; -+ -+struct wsm_operational_mode { -+ enum wsm_power_mode power_mode; -+ int disableMoreFlagUsage; -+ int performAntDiversity; -+}; -+ -+static const struct wsm_operational_mode defaultoperationalmode = { -+ .power_mode = wsm_power_mode_active, -+ .disableMoreFlagUsage = true, -+}; -+ -+static inline int wsm_set_operational_mode(struct xradio_common *hw_priv, -+ const struct wsm_operational_mode *arg, -+ int if_id) -+{ -+ u32 val = arg->power_mode; -+ -+ if (arg->disableMoreFlagUsage) -+ val |= BIT(4); -+ if (arg->performAntDiversity) -+ val |= BIT(5); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_OPERATIONAL_POWER_MODE, &val, -+ sizeof(val), if_id); -+} -+ -+struct wsm_inactivity { -+ u8 max_inactivity; -+ u8 min_inactivity; -+}; -+ -+static inline int wsm_set_inactivity(struct xradio_common *hw_priv, -+ const struct wsm_inactivity *arg, -+ int if_id) -+{ -+ struct { -+ u8 min_inactive; -+ u8 max_inactive; -+ u16 reserved; -+ } val; -+ -+ val.max_inactive = arg->max_inactivity; -+ val.min_inactive = arg->min_inactivity; -+ val.reserved = 0; -+ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_INACTIVITY, &val, -+ sizeof(val), if_id); -+} -+ -+struct wsm_template_frame { -+ u8 frame_type; -+ u8 rate; -+ bool disable; -+ struct sk_buff *skb; -+}; -+ -+static inline int wsm_set_template_frame(struct xradio_common *hw_priv, -+ struct wsm_template_frame *arg, -+ int if_id) -+{ -+ int ret; -+ u8 *p = skb_push(arg->skb, 4); -+ p[0] = arg->frame_type; -+ p[1] = arg->rate; -+ if (arg->disable) -+ ((u16 *) p)[1] = 0; -+ else -+ ((u16 *) p)[1] = __cpu_to_le16(arg->skb->len - 4); -+ ret = wsm_write_mib(hw_priv, WSM_MIB_ID_TEMPLATE_FRAME, p, -+ arg->skb->len, if_id); -+ skb_pull(arg->skb, 4); -+ return ret; -+} -+ -+ -+struct wsm_protected_mgmt_policy { -+ bool protectedMgmtEnable; -+ bool unprotectedMgmtFramesAllowed; -+ bool encryptionForAuthFrame; -+}; -+ -+static inline int -+wsm_set_protected_mgmt_policy(struct xradio_common *hw_priv, -+ struct wsm_protected_mgmt_policy *arg, -+ int if_id) -+{ -+ __le32 val = 0; -+ int ret; -+ if (arg->protectedMgmtEnable) -+ val |= __cpu_to_le32(BIT(0)); -+ if (arg->unprotectedMgmtFramesAllowed) -+ val |= __cpu_to_le32(BIT(1)); -+ if (arg->encryptionForAuthFrame) -+ val |= __cpu_to_le32(BIT(2)); -+ ret = wsm_write_mib(hw_priv, WSM_MIB_ID_PROTECTED_MGMT_POLICY, &val, -+ sizeof(val), if_id); -+ return ret; -+} -+ -+static inline int wsm_set_block_ack_policy(struct xradio_common *hw_priv, -+ u8 blockAckTxTidPolicy, -+ u8 blockAckRxTidPolicy, -+ int if_id) -+{ -+ struct { -+ u8 blockAckTxTidPolicy; -+ u8 reserved1; -+ u8 blockAckRxTidPolicy; -+ u8 reserved2; -+ } val = { -+ .blockAckTxTidPolicy = blockAckTxTidPolicy, -+ .blockAckRxTidPolicy = blockAckRxTidPolicy, -+ }; -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BLOCK_ACK_POLICY, &val, -+ sizeof(val), if_id); -+} -+ -+struct wsm_association_mode { -+ u8 flags; /* WSM_ASSOCIATION_MODE_... */ -+ u8 preambleType; /* WSM_JOIN_PREAMBLE_... */ -+ u8 greenfieldMode; /* 1 for greenfield */ -+ u8 mpduStartSpacing; -+ __le32 basicRateSet; -+}; -+ -+static inline int wsm_set_association_mode(struct xradio_common *hw_priv, -+ struct wsm_association_mode *arg, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_ASSOCIATION_MODE, arg, -+ sizeof(*arg), if_id); -+} -+ -+struct wsm_set_tx_rate_retry_policy_header { -+ u8 numTxRatePolicies; -+ u8 reserved[3]; -+} __packed; -+ -+struct wsm_set_tx_rate_retry_policy_policy { -+ u8 policyIndex; -+ u8 shortRetryCount; -+ u8 longRetryCount; -+ u8 policyFlags; -+ u8 rateRecoveryCount; -+ u8 reserved[3]; -+ __le32 rateCountIndices[3]; -+} __packed; -+ -+struct wsm_set_tx_rate_retry_policy { -+ struct wsm_set_tx_rate_retry_policy_header hdr; -+ struct wsm_set_tx_rate_retry_policy_policy tbl[8]; -+} __packed; -+ -+static inline int wsm_set_tx_rate_retry_policy(struct xradio_common *hw_priv, -+ struct wsm_set_tx_rate_retry_policy *arg, -+ int if_id) -+{ -+ size_t size = sizeof(struct wsm_set_tx_rate_retry_policy_header) + -+ arg->hdr.numTxRatePolicies * -+ sizeof(struct wsm_set_tx_rate_retry_policy_policy); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, -+ size, if_id); -+} -+ -+/* 4.32 SetEtherTypeDataFrameFilter */ -+struct wsm_ether_type_filter_hdr { -+ u8 nrFilters; /* Up to WSM_MAX_FILTER_ELEMENTS */ -+ u8 reserved[3]; -+} __packed; -+ -+struct wsm_ether_type_filter { -+ u8 filterAction; /* WSM_FILTER_ACTION_XXX */ -+ u8 reserved; -+ __le16 etherType; /* Type of ethernet frame */ -+} __packed; -+ -+static inline int wsm_set_ether_type_filter(struct xradio_common *hw_priv, -+ struct wsm_ether_type_filter_hdr *arg, -+ int if_id) -+{ -+ size_t size = sizeof(struct wsm_ether_type_filter_hdr) + -+ arg->nrFilters * sizeof(struct wsm_ether_type_filter); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER, -+ arg, size, if_id); -+} -+ -+ -+/* 4.33 SetUDPPortDataFrameFilter */ -+struct wsm_udp_port_filter_hdr { -+ u8 nrFilters; /* Up to WSM_MAX_FILTER_ELEMENTS */ -+ u8 reserved[3]; -+} __packed; -+ -+struct wsm_udp_port_filter { -+ u8 filterAction; /* WSM_FILTER_ACTION_XXX */ -+ u8 portType; /* WSM_FILTER_PORT_TYPE_XXX */ -+ __le16 udpPort; /* Port number */ -+} __packed; -+ -+static inline int wsm_set_udp_port_filter(struct xradio_common *hw_priv, -+ struct wsm_udp_port_filter_hdr *arg, -+ int if_id) -+{ -+ size_t size = sizeof(struct wsm_udp_port_filter_hdr) + -+ arg->nrFilters * sizeof(struct wsm_udp_port_filter); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER, -+ arg, size, if_id); -+} -+ -+/* Undocumented MIBs: */ -+/* 4.35 P2PDeviceInfo */ -+#define D11_MAX_SSID_LEN (32) -+ -+struct wsm_p2p_device_type { -+ __le16 categoryId; -+ u8 oui[4]; -+ __le16 subCategoryId; -+} __packed; -+ -+struct wsm_p2p_device_info { -+ struct wsm_p2p_device_type primaryDevice; -+ u8 reserved1[3]; -+ u8 devNameSize; -+ u8 localDevName[D11_MAX_SSID_LEN]; -+ u8 reserved2[3]; -+ u8 numSecDevSupported; -+ struct wsm_p2p_device_type secondaryDevices[0]; -+} __packed; -+ -+/* 4.36 SetWCDMABand - WO */ -+struct wsm_cdma_band { -+ u8 WCDMA_Band; -+ u8 reserved[3]; -+} __packed; -+ -+/* 4.37 GroupTxSequenceCounter - RO */ -+struct wsm_group_tx_seq { -+ __le32 bits_47_16; -+ __le16 bits_15_00; -+ __le16 reserved; -+} __packed; -+ -+/* 4.39 SetHtProtection - WO */ -+#define WSM_DUAL_CTS_PROT_ENB (1 << 0) -+#define WSM_NON_GREENFIELD_STA PRESENT(1 << 1) -+#define WSM_HT_PROT_MODE__NO_PROT (0 << 2) -+#define WSM_HT_PROT_MODE__NON_MEMBER (1 << 2) -+#define WSM_HT_PROT_MODE__20_MHZ (2 << 2) -+#define WSM_HT_PROT_MODE__NON_HT_MIXED (3 << 2) -+#define WSM_LSIG_TXOP_PROT_FULL (1 << 4) -+#define WSM_LARGE_L_LENGTH_PROT (1 << 5) -+ -+struct wsm_ht_protection { -+ __le32 flags; -+} __packed; -+ -+/* 4.40 GPIO Command - R/W */ -+#define WSM_GPIO_COMMAND_SETUP 0 -+#define WSM_GPIO_COMMAND_READ 1 -+#define WSM_GPIO_COMMAND_WRITE 2 -+#define WSM_GPIO_COMMAND_RESET 3 -+#define WSM_GPIO_ALL_PINS 0xFF -+ -+struct wsm_gpio_command { -+ u8 GPIO_Command; -+ u8 pin; -+ __le16 config; -+} __packed; -+ -+/* 4.41 TSFCounter - RO */ -+struct wsm_tsf_counter { -+ __le64 TSF_Counter; -+} __packed; -+ -+/* 4.43 Keep alive period */ -+struct wsm_keep_alive_period { -+ __le16 keepAlivePeriod; -+ u8 reserved[2]; -+} __packed; -+ -+static inline int wsm_keep_alive_period(struct xradio_common *hw_priv, -+ int period, int if_id) -+{ -+ struct wsm_keep_alive_period arg = { -+ .keepAlivePeriod = __cpu_to_le16(period), -+ }; -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_KEEP_ALIVE_PERIOD, -+ &arg, sizeof(arg), if_id); -+}; -+ -+/* BSSID filtering */ -+struct wsm_set_bssid_filtering { -+ u8 filter; -+ u8 reserved[3]; -+} __packed; -+ -+static inline int wsm_set_bssid_filtering(struct xradio_common *hw_priv, -+ bool enabled, int if_id) -+{ -+ struct wsm_set_bssid_filtering arg = { -+ .filter = !enabled, -+ }; -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_DISABLE_BSSID_FILTER, -+ &arg, sizeof(arg), if_id); -+} -+ -+/* Multicat filtering - 4.5 */ -+struct wsm_multicast_filter { -+ __le32 enable; -+ __le32 numOfAddresses; -+ u8 macAddress[WSM_MAX_GRP_ADDRTABLE_ENTRIES][ETH_ALEN]; -+} __packed; -+ -+/* Mac Addr Filter Info */ -+struct wsm_mac_addr_info { -+ u8 filter_mode; -+ u8 address_mode; -+ u8 MacAddr[6]; -+} __packed; -+ -+/* Mac Addr Filter */ -+struct wsm_mac_addr_filter { -+ u8 numfilter; -+ u8 action_mode; -+ u8 Reserved[2]; -+ struct wsm_mac_addr_info macaddrfilter[0]; -+} __packed; -+ -+/* Broadcast Addr Filter */ -+struct wsm_broadcast_addr_filter { -+ u8 action_mode; -+ u8 nummacaddr; -+ u8 filter_mode; -+ u8 address_mode; -+ u8 MacAddr[6]; -+} __packed; -+ -+static inline int wsm_set_multicast_filter(struct xradio_common *hw_priv, -+ struct wsm_multicast_filter *fp, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE, -+ fp, sizeof(*fp), if_id); -+} -+ -+/* ARP IPv4 filtering - 4.10 */ -+struct wsm_arp_ipv4_filter { -+ __le32 enable; -+ __be32 ipv4Address[WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES]; -+} __packed; -+ -+ -+static inline int wsm_set_arp_ipv4_filter(struct xradio_common *hw_priv, -+ struct wsm_arp_ipv4_filter *fp, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE, -+ fp, sizeof(*fp), if_id); -+} -+ -+/* P2P Power Save Mode Info - 4.31 */ -+struct wsm_p2p_ps_modeinfo { -+ u8 oppPsCTWindow; -+ u8 count; -+ u8 reserved; -+ u8 dtimCount; -+ __le32 duration; -+ __le32 interval; -+ __le32 startTime; -+} __packed; -+ -+static inline int wsm_set_p2p_ps_modeinfo(struct xradio_common *hw_priv, -+ struct wsm_p2p_ps_modeinfo *mi, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_P2P_PS_MODE_INFO, -+ mi, sizeof(*mi), if_id); -+} -+ -+static inline int wsm_get_p2p_ps_modeinfo(struct xradio_common *hw_priv, -+ struct wsm_p2p_ps_modeinfo *mi) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_P2P_PS_MODE_INFO, -+ mi, sizeof(*mi), 0); -+} -+ -+/* UseMultiTxConfMessage */ -+ -+static inline int wsm_use_multi_tx_conf(struct xradio_common *hw_priv, -+ bool enabled, int if_id) -+{ -+ __le32 arg = enabled ? __cpu_to_le32(1) : 0; -+ -+ return wsm_write_mib(hw_priv, WSM_MIB_USE_MULTI_TX_CONF, -+ &arg, sizeof(arg), if_id); -+} -+ -+ -+/* 4.26 SetUpasdInformation */ -+struct wsm_uapsd_info { -+ __le16 uapsdFlags; -+ __le16 minAutoTriggerInterval; -+ __le16 maxAutoTriggerInterval; -+ __le16 autoTriggerStep; -+}; -+ -+static inline int wsm_set_uapsd_info(struct xradio_common *hw_priv, -+ struct wsm_uapsd_info *arg, -+ int if_id) -+{ -+ /* TODO:COMBO:UAPSD will be supported only on one interface */ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_UAPSD_INFORMATION, -+ arg, sizeof(*arg), if_id); -+} -+ -+/* 4.22 OverrideInternalTxRate */ -+struct wsm_override_internal_txrate { -+ u8 internalTxRate; -+ u8 nonErpInternalTxRate; -+ u8 reserved[2]; -+} __packed; -+ -+static inline int -+wsm_set_override_internal_txrate(struct xradio_common *hw_priv, -+ struct wsm_override_internal_txrate *arg, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, -+ arg, sizeof(*arg), if_id); -+} -+#ifdef MCAST_FWDING -+/* 4.51 SetForwardingOffload */ -+struct wsm_forwarding_offload { -+ u8 fwenable; -+ u8 flags; -+ u8 reserved[2]; -+} __packed; -+ -+static inline int wsm_set_forwarding_offlad(struct xradio_common *hw_priv, -+ struct wsm_forwarding_offload *arg,int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_FORWARDING_OFFLOAD, -+ arg, sizeof(*arg),if_id); -+} -+ -+#endif -+/* ******************************************************************** */ -+/* WSM TX port control */ -+ -+void wsm_lock_tx(struct xradio_common *hw_priv); -+void wsm_vif_lock_tx(struct xradio_vif *priv); -+void wsm_lock_tx_async(struct xradio_common *hw_priv); -+bool wsm_flush_tx(struct xradio_common *hw_priv); -+bool wsm_vif_flush_tx(struct xradio_vif *priv); -+void wsm_unlock_tx(struct xradio_common *hw_priv); -+ -+/* ******************************************************************** */ -+/* WSM / BH API */ -+ -+int wsm_handle_exception(struct xradio_common *hw_priv, u8 * data, size_t len); -+int wsm_handle_rx(struct xradio_common *hw_priv, int id, struct wsm_hdr *wsm, -+ struct sk_buff **skb_p); -+void wms_send_deauth_to_self(struct xradio_common *hw_priv, struct xradio_vif *priv); -+void wms_send_disassoc_to_self(struct xradio_common *hw_priv, struct xradio_vif *priv); -+ -+/* ******************************************************************** */ -+/* wsm_buf API */ -+ -+struct wsm_buf { -+ u8 *begin; -+ u8 *data; -+ u8 *end; -+}; -+ -+void wsm_buf_init(struct wsm_buf *buf); -+void wsm_buf_deinit(struct wsm_buf *buf); -+ -+/* ******************************************************************** */ -+/* wsm_cmd API */ -+ -+struct wsm_cmd { -+ spinlock_t lock; -+ int done; -+ u8 *ptr; -+ size_t len; -+ void *arg; -+ int ret; -+ u16 cmd; -+}; -+ -+/* ******************************************************************** */ -+/* WSM TX buffer access */ -+ -+int wsm_get_tx(struct xradio_common *hw_priv, u8 **data, -+ size_t *tx_len, int *burst, int *vif_selected); -+void wsm_txed(struct xradio_common *hw_priv, u8 *data); -+ -+/* ******************************************************************** */ -+/* Queue mapping: WSM <---> linux */ -+/* Linux: VO VI BE BK */ -+/* WSM: BE BK VI VO */ -+ -+static inline u8 wsm_queue_id_to_linux(u8 queueId) -+{ -+ static const u8 queue_mapping[] = { -+ 2, 3, 1, 0 -+ }; -+ return queue_mapping[queueId]; -+} -+ -+static inline u8 wsm_queue_id_to_wsm(u8 queueId) -+{ -+ static const u8 queue_mapping[] = { -+ 3, 2, 0, 1 -+ }; -+ return queue_mapping[queueId]; -+} -+ -+#endif /* XRADIO_HWIO_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/xradio.h b/drivers/net/wireless/xradio/xradio.h -new file mode 100644 -index 0000000..d565db0 ---- /dev/null -+++ b/drivers/net/wireless/xradio/xradio.h -@@ -0,0 +1,577 @@ -+/* -+ * Common define of private data for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_H -+#define XRADIO_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+//Macroses for Driver parameters. -+#define XRWL_MAX_QUEUE_SZ (128) -+#define AC_QUEUE_NUM 4 -+ -+#define XRWL_MAX_VIFS (2) -+#define XRWL_GENERIC_IF_ID (2) -+#define XRWL_HOST_VIF0_11N_THROTTLE (58) //(XRWL_MAX_QUEUE_SZ/(XRWL_MAX_VIFS-1))*0.9 -+#define XRWL_HOST_VIF1_11N_THROTTLE (58) //(XRWL_MAX_QUEUE_SZ/(XRWL_MAX_VIFS-1))*0.9 -+#define XRWL_HOST_VIF0_11BG_THROTTLE (35) //XRWL_HOST_VIF0_11N_THROTTLE*0.6 = 35 -+#define XRWL_HOST_VIF1_11BG_THROTTLE (35) //XRWL_HOST_VIF0_11N_THROTTLE*0.6 = 35 -+#if 0 -+#define XRWL_FW_VIF0_THROTTLE (15) -+#define XRWL_FW_VIF1_THROTTLE (15) -+#endif -+ -+#define IEEE80211_FCTL_WEP 0x4000 -+#define IEEE80211_QOS_DATAGRP 0x0080 -+#define WSM_KEY_MAX_IDX 20 -+ -+#include "queue.h" -+#include "wsm.h" -+#include "scan.h" -+#include "tx.h" -+#include "ht.h" -+#include "pm.h" -+#include "fwio.h" -+ -+/* #define ROC_DEBUG */ -+/* hidden ssid is only supported when separate probe resp IE -+ configuration is supported */ -+#ifdef PROBE_RESP_EXTRA_IE -+#define HIDDEN_SSID 1 -+#endif -+ -+#define XRADIO_MAX_CTRL_FRAME_LEN (0x1000) -+ -+#define MAX_STA_IN_AP_MODE (14) -+#define WLAN_LINK_ID_MAX (MAX_STA_IN_AP_MODE + 3) -+ -+#define XRADIO_MAX_STA_IN_AP_MODE (5) -+#define XRADIO_MAX_REQUEUE_ATTEMPTS (5) -+#define XRADIO_LINK_ID_UNMAPPED (15) -+#define XRADIO_MAX_TID (8) -+ -+#define XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID (0x3F) -+#define XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID (0x3F) -+#define XRADIO_RX_BLOCK_ACK_ENABLED_FOR_BE_TID \ -+ (XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID & 0x01) -+#define XRADIO_TX_BLOCK_ACK_DISABLED_FOR_ALL_TID (0) -+#define XRADIO_RX_BLOCK_ACK_DISABLED_FOR_ALL_TID (0) -+ -+#define XRADIO_BLOCK_ACK_CNT (30) -+#define XRADIO_BLOCK_ACK_THLD (800) -+#define XRADIO_BLOCK_ACK_HIST (3) -+#define XRADIO_BLOCK_ACK_INTERVAL (1 * HZ / XRADIO_BLOCK_ACK_HIST) -+#define XRWL_ALL_IFS (-1) -+ -+#ifdef ROAM_OFFLOAD -+#define XRADIO_SCAN_TYPE_ACTIVE 0x1000 -+#define XRADIO_SCAN_BAND_5G 0x2000 -+#endif /*ROAM_OFFLOAD*/ -+ -+#define IEEE80211_FCTL_WEP 0x4000 -+#define IEEE80211_QOS_DATAGRP 0x0080 -+ -+#ifdef MCAST_FWDING -+#define WSM_MAX_BUF 30 -+#endif -+ -+#define MAX_RATES_STAGE 8 // -+#define MAX_RATES_RETRY 15 -+ -+#define XRADIO_WORKQUEUE "xradio_wq" -+#define WIFI_CONF_PATH "/data/xr_wifi.conf" -+ -+/* extern */ struct task_struct; -+/* extern */ struct xradio_debug_priv; -+/* extern */ struct xradio_debug_common; -+/* extern */ struct firmware; -+ -+/* Please keep order */ -+enum xradio_join_status { -+ XRADIO_JOIN_STATUS_PASSIVE = 0, -+ XRADIO_JOIN_STATUS_MONITOR, -+ XRADIO_JOIN_STATUS_STA, -+ XRADIO_JOIN_STATUS_AP, -+}; -+ -+enum xradio_link_status { -+ XRADIO_LINK_OFF, -+ XRADIO_LINK_RESERVE, -+ XRADIO_LINK_SOFT, -+ XRADIO_LINK_HARD, -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ XRADIO_LINK_RESET, -+ XRADIO_LINK_RESET_REMAP, -+#endif -+}; -+ -+enum xradio_bss_loss_status { -+ XRADIO_BSS_LOSS_NONE, -+ XRADIO_BSS_LOSS_CHECKING, -+ XRADIO_BSS_LOSS_CONFIRMING, -+ XRADIO_BSS_LOSS_CONFIRMED, -+}; -+ -+struct xradio_link_entry { -+ unsigned long timestamp; -+ enum xradio_link_status status; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ enum xradio_link_status prev_status; -+#endif -+ u8 mac[ETH_ALEN]; -+ u8 buffered[XRADIO_MAX_TID]; -+ struct sk_buff_head rx_queue; -+}; -+ -+#if defined(ROAM_OFFLOAD) -+struct xradio_testframe { -+ u8 len; -+ u8 *data; -+}; -+#endif -+ -+struct xradio_common { -+ struct xradio_debug_common *debug; -+ struct xradio_queue tx_queue[AC_QUEUE_NUM]; -+ struct xradio_queue_stats tx_queue_stats; -+ -+ struct ieee80211_hw *hw; -+ struct mac_address addresses[XRWL_MAX_VIFS]; -+ -+ /*Will be a pointer to a list of VIFs - Dynamically allocated */ -+ struct ieee80211_vif *vif_list[XRWL_MAX_VIFS]; -+ atomic_t num_vifs; -+ spinlock_t vif_list_lock; -+ u32 if_id_slot; -+ struct device *pdev; -+ struct workqueue_struct *workqueue; -+ -+ struct mutex conf_mutex; -+ -+ struct sdio_func *sdio_func; -+ int driver_ready; -+ -+ /* HW/FW type (HIF_...) */ -+ int hw_type; -+ int hw_revision; -+ int fw_revision; -+ -+ /* firmware/hardware info */ -+ unsigned int tx_hdr_len; -+ -+ /* Radio data */ -+ int output_power; -+ int noise; -+ -+ /* calibration, output power limit and rssi<->dBm conversation data */ -+ -+ /* BBP/MAC state */ -+ const struct firmware *sdd; -+ struct ieee80211_rate *rates; -+ struct ieee80211_rate *mcs_rates; -+ u8 mac_addr[ETH_ALEN]; -+ /*TODO:COMBO: To be made per VIFF after mac80211 support */ -+ struct ieee80211_channel *channel; -+ int channel_switch_in_progress; -+ wait_queue_head_t channel_switch_done; -+ u8 channel_changed; //add by yangfh 2015-5-15 16:57:38. -+ u8 long_frame_max_tx_count; -+ u8 short_frame_max_tx_count; -+ /* TODO:COMBO: According to Hong aggregation will happen per VIFF. -+ * Keeping in common structure for the time being. Will be moved to VIFF -+ * after the mechanism is clear */ -+ u8 ba_tid_mask; -+ int ba_acc; /*TODO: Same as above */ -+ int ba_cnt; /*TODO: Same as above */ -+ int ba_cnt_rx; /*TODO: Same as above */ -+ int ba_acc_rx; /*TODO: Same as above */ -+ int ba_hist; /*TODO: Same as above */ -+ struct timer_list ba_timer;/*TODO: Same as above */ -+ spinlock_t ba_lock; /*TODO: Same as above */ -+ bool ba_ena; /*TODO: Same as above */ -+ struct work_struct ba_work; /*TODO: Same as above */ -+ struct xradio_pm_state pm_state; -+ bool is_BT_Present; -+ bool is_go_thru_go_neg; -+ u8 conf_listen_interval; -+ -+ /* BH */ -+ atomic_t bh_tx; -+ atomic_t bh_term; -+ atomic_t bh_suspend; -+ struct task_struct *bh_thread; -+ int bh_error; -+ wait_queue_head_t bh_wq; -+ wait_queue_head_t bh_evt_wq; -+ -+ -+ int buf_id_tx; /* byte */ -+ int buf_id_rx; /* byte */ -+ int wsm_rx_seq; /* byte */ -+ int wsm_tx_seq; /* byte */ -+ int hw_bufs_used; -+ int hw_bufs_used_vif[XRWL_MAX_VIFS]; -+ struct sk_buff *skb_cache; -+ struct sk_buff *skb_reserved; -+ int skb_resv_len; -+ bool powersave_enabled; -+ bool device_can_sleep; -+ /* Keep xradio awake (WUP = 1) 1 second after each scan to avoid -+ * FW issue with sleeping/waking up. */ -+ atomic_t recent_scan; -+ long connet_time[XRWL_MAX_VIFS]; -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+ atomic_t suspend_state; -+#endif -+ -+ /* WSM */ -+ struct wsm_caps wsm_caps; -+ struct mutex wsm_cmd_mux; -+ struct wsm_buf wsm_cmd_buf; -+ struct wsm_cmd wsm_cmd; -+ wait_queue_head_t wsm_cmd_wq; -+ wait_queue_head_t wsm_startup_done; -+ struct semaphore tx_lock_sem; -+ atomic_t tx_lock; -+ u32 pending_frame_id; -+ -+ /* WSM debug */ -+ u32 query_packetID; -+ atomic_t query_cnt; -+ struct work_struct query_work; /* for query packet */ -+ -+ /* Scan status */ -+ struct xradio_scan scan; -+ -+ /* TX/RX */ -+ unsigned long rx_timestamp; -+ -+ /* WSM events */ -+ spinlock_t event_queue_lock; -+ struct list_head event_queue; -+ struct work_struct event_handler; -+ -+ /* TX rate policy cache */ -+ struct tx_policy_cache tx_policy_cache; -+ struct work_struct tx_policy_upload_work; -+ atomic_t upload_count; -+ -+ /* cryptographic engine information */ -+ -+ /* bit field of glowing LEDs */ -+ u16 softled_state; -+ -+ /* statistics */ -+ struct ieee80211_low_level_stats stats; -+ -+ struct xradio_ht_oper ht_oper; -+ int tx_burst_idx; -+ -+ struct ieee80211_iface_limit if_limits1[2]; -+ struct ieee80211_iface_limit if_limits2[2]; -+ struct ieee80211_iface_limit if_limits3[2]; -+ struct ieee80211_iface_combination if_combs[3]; -+ -+ struct mutex wsm_oper_lock; -+ struct delayed_work rem_chan_timeout; -+ atomic_t remain_on_channel; -+ int roc_if_id; -+ u64 roc_cookie; -+ wait_queue_head_t offchannel_wq; -+ u16 offchannel_done; -+ u16 prev_channel; -+ int if_id_selected; -+ u32 key_map; -+ struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1]; -+#ifdef MCAST_FWDING -+ struct wsm_buf wsm_release_buf[WSM_MAX_BUF]; -+ u8 buf_released; -+#endif -+#ifdef ROAM_OFFLOAD -+ u8 auto_scanning; -+ u8 frame_rcvd; -+ u8 num_scanchannels; -+ u8 num_2g_channels; -+ u8 num_5g_channels; -+ struct wsm_scan_ch scan_channels[48]; -+ struct sk_buff *beacon; -+ struct sk_buff *beacon_bkp; -+ struct xradio_testframe testframe; -+#endif /*ROAM_OFFLOAD*/ -+ -+ u8 connected_sta_cnt; -+ u16 vif0_throttle; -+ u16 vif1_throttle; -+}; -+ -+/* Virtual Interface State. One copy per VIF */ -+struct xradio_vif { -+ atomic_t enabled; -+ spinlock_t vif_lock; -+ int if_id; -+ /*TODO: Split into Common and VIF parts */ -+ struct xradio_debug_priv *debug; -+ /* BBP/MAC state */ -+ u8 bssid[ETH_ALEN]; -+ struct wsm_edca_params edca; -+ struct wsm_tx_queue_params tx_queue_params; -+ struct wsm_association_mode association_mode; -+ struct wsm_set_bss_params bss_params; -+ struct wsm_set_pm powersave_mode; -+ struct wsm_set_pm firmware_ps_mode; -+ int power_set_true; -+ int user_power_set_true; -+ u8 user_pm_mode; -+ int cqm_rssi_thold; -+ unsigned cqm_rssi_hyst; -+ unsigned cqm_tx_failure_thold; -+ unsigned cqm_tx_failure_count; -+ bool cqm_use_rssi; -+ int cqm_link_loss_count; -+ int cqm_beacon_loss_count; -+ int mode; -+ bool enable_beacon; -+ int beacon_int; -+ size_t ssid_length; -+ u8 ssid[IEEE80211_MAX_SSID_LEN]; -+#ifdef HIDDEN_SSID -+ bool hidden_ssid; -+#endif -+ bool listening; -+ struct wsm_rx_filter rx_filter; -+ struct wsm_beacon_filter_table bf_table; -+ struct wsm_beacon_filter_control bf_control; -+ struct wsm_multicast_filter multicast_filter; -+ bool has_multicast_subscription; -+ struct wsm_broadcast_addr_filter broadcast_filter; -+ bool disable_beacon_filter; -+ struct wsm_arp_ipv4_filter filter4; -+ struct work_struct update_filtering_work; -+ struct work_struct set_beacon_wakeup_period_work; -+ struct xradio_pm_state_vif pm_state_vif; -+ /*TODO: Add support in mac80211 for psmode info per VIF */ -+ struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo; -+ struct wsm_uapsd_info uapsd_info; -+ bool setbssparams_done; -+ u32 listen_interval; -+ u32 erp_info; -+ bool powersave_enabled; -+ -+ /* WSM Join */ -+ enum xradio_join_status join_status; -+ u8 join_bssid[ETH_ALEN]; -+ struct work_struct join_work; -+ struct delayed_work join_timeout; -+ struct work_struct unjoin_work; -+ struct work_struct offchannel_work; -+ int join_dtim_period; -+ atomic_t delayed_unjoin; -+ -+ /* Security */ -+ s8 wep_default_key_id; -+ struct work_struct wep_key_work; -+ unsigned long rx_timestamp; -+ u32 cipherType; -+ -+ -+ /* AP powersave */ -+ u32 link_id_map; -+ u32 max_sta_ap_mode; -+ u32 link_id_after_dtim; -+ u32 link_id_uapsd; -+ u32 link_id_max; -+ u32 wsm_key_max_idx; -+ struct xradio_link_entry link_id_db[MAX_STA_IN_AP_MODE]; -+ struct work_struct link_id_work; -+ struct delayed_work link_id_gc_work; -+ u32 sta_asleep_mask; -+ u32 pspoll_mask; -+ bool aid0_bit_set; -+ spinlock_t ps_state_lock; -+ bool buffered_multicasts; -+ bool tx_multicast; -+ u8 last_tim[8]; //for softap dtim, add by yangfh -+ struct work_struct set_tim_work; -+ struct delayed_work set_cts_work; -+ struct work_struct multicast_start_work; -+ struct work_struct multicast_stop_work; -+ struct timer_list mcast_timeout; -+ -+ /* CQM Implementation */ -+ struct delayed_work bss_loss_work; -+ struct delayed_work connection_loss_work; -+ struct work_struct tx_failure_work; -+ int delayed_link_loss; -+ spinlock_t bss_loss_lock; -+ int bss_loss_status; -+ int bss_loss_confirm_id; -+ -+ struct ieee80211_vif *vif; -+ struct xradio_common *hw_priv; -+ struct ieee80211_hw *hw; -+ -+ /* ROC implementation */ -+ struct delayed_work pending_offchanneltx_work; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ /* Workaround for WFD testcase 6.1.10*/ -+ struct work_struct linkid_reset_work; -+ u8 action_frame_sa[ETH_ALEN]; -+ u8 action_linkid; -+#endif -+ bool htcap; -+#ifdef AP_HT_CAP_UPDATE -+ u16 ht_oper; -+ struct work_struct ht_oper_update_work; -+#endif -+ -+#ifdef AP_HT_COMPAT_FIX -+ u16 ht_compat_cnt; -+ u16 ht_compat_det; -+#endif -+}; -+struct xradio_sta_priv { -+ int link_id; -+ struct xradio_vif *priv; -+}; -+enum xradio_data_filterid { -+ IPV4ADDR_FILTER_ID = 0, -+}; -+ -+/* Datastructure for LLC-SNAP HDR */ -+#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; -+ -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+extern s32 TES_P2P_0002_roc_dur; -+extern s32 TES_P2P_0002_roc_sec; -+extern s32 TES_P2P_0002_roc_usec; -+extern u32 TES_P2P_0002_packet_id; -+extern u32 TES_P2P_0002_state; -+ -+#define TES_P2P_0002_STATE_IDLE 0x00 -+#define TES_P2P_0002_STATE_SEND_RESP 0x01 -+#define TES_P2P_0002_STATE_GET_PKTID 0x02 -+#endif -+ -+/* debug.h must be here because refer to struct xradio_vif and -+ struct xradio_common.*/ -+#include "debug.h" -+ -+/******************************************************* -+ interfaces for operations of vif. -+********************************************************/ -+static inline -+struct xradio_common *xrwl_vifpriv_to_hwpriv(struct xradio_vif *priv) -+{ -+ return priv->hw_priv; -+} -+static inline -+struct xradio_vif *xrwl_get_vif_from_ieee80211(struct ieee80211_vif *vif) -+{ -+ return (struct xradio_vif *)vif->drv_priv; -+} -+ -+static inline -+struct xradio_vif *xrwl_hwpriv_to_vifpriv(struct xradio_common *hw_priv, -+ int if_id) -+{ -+ struct xradio_vif *vif; -+ -+ if (WARN_ON((-1 == if_id) || (if_id > XRWL_MAX_VIFS))) -+ return NULL; -+ /* TODO:COMBO: During scanning frames can be received -+ * on interface ID 3 */ -+ spin_lock(&hw_priv->vif_list_lock); -+ if (!hw_priv->vif_list[if_id]) { -+ spin_unlock(&hw_priv->vif_list_lock); -+ return NULL; -+ } -+ -+ vif = xrwl_get_vif_from_ieee80211(hw_priv->vif_list[if_id]); -+ WARN_ON(!vif); -+ if (vif) -+ spin_lock(&vif->vif_lock); -+ spin_unlock(&hw_priv->vif_list_lock); -+ return vif; -+} -+ -+static inline -+struct xradio_vif *__xrwl_hwpriv_to_vifpriv(struct xradio_common *hw_priv, -+ int if_id) -+{ -+ WARN_ON((-1 == if_id) || (if_id > XRWL_MAX_VIFS)); -+ /* TODO:COMBO: During scanning frames can be received -+ * on interface ID 3 */ -+ if (!hw_priv->vif_list[if_id]) { -+ return NULL; -+ } -+ -+ return xrwl_get_vif_from_ieee80211(hw_priv->vif_list[if_id]); -+} -+ -+static inline -+struct xradio_vif *xrwl_get_activevif(struct xradio_common *hw_priv) -+{ -+ return xrwl_hwpriv_to_vifpriv(hw_priv, ffs(hw_priv->if_id_slot)-1); -+} -+ -+static inline bool is_hardware_xradio(struct xradio_common *hw_priv) -+{ -+ return (hw_priv->hw_revision == XR819_HW_REV0); -+} -+ -+static inline int xrwl_get_nr_hw_ifaces(struct xradio_common *hw_priv) -+{ -+ switch(hw_priv->hw_revision) { -+ case XR819_HW_REV0: -+ default: -+ return 1; -+ } -+} -+ -+#define xradio_for_each_vif(_hw_priv, _priv, _i) \ -+ for( \ -+ _i = 0; \ -+ (_i < XRWL_MAX_VIFS) \ -+ && ((_priv = _hw_priv->vif_list[_i] ? \ -+ xrwl_get_vif_from_ieee80211(_hw_priv->vif_list[_i]) : NULL),1); \ -+ _i++ \ -+ ) -+ -+/******************************************************* -+ interfaces for operations of queue. -+********************************************************/ -+static inline void xradio_tx_queues_lock(struct xradio_common *hw_priv) -+{ -+ int i; -+ for (i = 0; i < 4; ++i) -+ xradio_queue_lock(&hw_priv->tx_queue[i]); -+} -+ -+static inline void xradio_tx_queues_unlock(struct xradio_common *hw_priv) -+{ -+ int i; -+ for (i = 0; i < 4; ++i) -+ xradio_queue_unlock(&hw_priv->tx_queue[i]); -+} -+ -+#endif /* XRADIO_H */ diff --git a/patch/kernel/sunxi-legacy/0135-clk-sunxi-ng-enable-so-said-LDOs-for-A64-SoC-s-pll-m.patch b/patch/kernel/sunxi-legacy/0135-clk-sunxi-ng-enable-so-said-LDOs-for-A64-SoC-s-pll-m.patch deleted file mode 100644 index 6aa68872f..000000000 --- a/patch/kernel/sunxi-legacy/0135-clk-sunxi-ng-enable-so-said-LDOs-for-A64-SoC-s-pll-m.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 734e26b5a4b061d5f0667d59ce27a4a50f6d5c25 Mon Sep 17 00:00:00 2001 -From: Icenowy Zheng -Date: Thu, 18 Oct 2018 15:07:29 +0800 -Subject: [PATCH 135/146] clk: sunxi-ng: enable so-said LDOs for A64 SoC's - pll-mipi clock - -In the user manual of A64 SoC, the bit 22 and 23 of pll-mipi control -register is called "LDO{1,2}_EN", and according to the BSP source code -from Allwinner , the LDOs are enabled during the clock's enabling -process. - -The clock failed to generate output if the two LDOs are not enabled. - -Add the two bits to the clock's gate bits, so that the LDOs are enabled -when the PLL is enabled. - -Fixes: c6a0637460c2 ("clk: sunxi-ng: Add A64 clocks") -Signed-off-by: Icenowy Zheng ---- - drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c -index 90ffee824c33..a637e62ae1c4 100644 ---- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c -+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c -@@ -162,7 +162,12 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", - #define SUN50I_A64_PLL_MIPI_REG 0x040 - - static struct ccu_nkm pll_mipi_clk = { -- .enable = BIT(31), -+ /* -+ * The bit 23 and 22 are called "LDO{1,2}_EN" on the SoC's -+ * user manual, and by experiments the PLL doesn't work without -+ * these bits toggled. -+ */ -+ .enable = BIT(31) | BIT(23) | BIT(22), - .lock = BIT(28), - .n = _SUNXI_CCU_MULT(8, 4), - .k = _SUNXI_CCU_MULT_MIN(4, 2, 2), --- -2.17.1 - diff --git a/patch/kernel/sunxi-legacy/board-a64-v3-13-19-arm64-dts-allwinner-a64-Olinuxino-fix-DRAM-voltage.patch b/patch/kernel/sunxi-legacy/board-a64-v3-13-19-arm64-dts-allwinner-a64-Olinuxino-fix-DRAM-voltage.patch deleted file mode 100644 index 0c6de7fe7..000000000 --- a/patch/kernel/sunxi-legacy/board-a64-v3-13-19-arm64-dts-allwinner-a64-Olinuxino-fix-DRAM-voltage.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts -index 3f531393eaee..b3f186434f36 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts -@@ -142,10 +142,14 @@ - - /* DCDC3 is polyphased with DCDC2 */ - -+/* -+ * The board uses DDR3L DRAM chips. 1.36V is the closest to the nominal -+ * 1.35V that the PMIC can drive. -+ */ - ®_dcdc5 { - regulator-always-on; -- regulator-min-microvolt = <1500000>; -- regulator-max-microvolt = <1500000>; -+ regulator-min-microvolt = <1360000>; -+ regulator-max-microvolt = <1360000>; - regulator-name = "vcc-ddr3"; - }; - diff --git a/patch/kernel/sunxi-legacy/board-a64-v3-16-19-arm64-dts-allwinner-a64-NanoPi-A64-Fix-DCDC1-voltage.patch b/patch/kernel/sunxi-legacy/board-a64-v3-16-19-arm64-dts-allwinner-a64-NanoPi-A64-Fix-DCDC1-voltage.patch deleted file mode 100644 index c6a9c4cae..000000000 --- a/patch/kernel/sunxi-legacy/board-a64-v3-16-19-arm64-dts-allwinner-a64-NanoPi-A64-Fix-DCDC1-voltage.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts -index 98dbff19f5cc..5caba225b4f7 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts -@@ -125,9 +125,9 @@ - - ®_dcdc1 { - regulator-always-on; -- regulator-min-microvolt = <3000000>; -- regulator-max-microvolt = <3000000>; -- regulator-name = "vcc-3v"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-name = "vcc-3v3"; - }; - - ®_dcdc2 { diff --git a/patch/kernel/sunxi-legacy/board-a83t-v7-4-4-ARM-dts-sun8i-h3-h5-ir-register-size-should-be-the-whole-memory-block.patch b/patch/kernel/sunxi-legacy/board-a83t-v7-4-4-ARM-dts-sun8i-h3-h5-ir-register-size-should-be-the-whole-memory-block.patch deleted file mode 100644 index 2a0897a8c..000000000 --- a/patch/kernel/sunxi-legacy/board-a83t-v7-4-4-ARM-dts-sun8i-h3-h5-ir-register-size-should-be-the-whole-memory-block.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi -index c3bff1105e5d..2f4d93de836e 100644 ---- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi -+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi -@@ -818,7 +818,7 @@ - clock-names = "apb", "ir"; - resets = <&r_ccu RST_APB0_IR>; - interrupts = ; -- reg = <0x01f02000 0x40>; -+ reg = <0x01f02000 0x400>; - status = "disabled"; - }; - diff --git a/patch/kernel/sunxi-legacy/general-spidev-remove-warnings.patch b/patch/kernel/sunxi-legacy/general-spidev-remove-warnings.patch deleted file mode 100644 index 25648e844..000000000 --- a/patch/kernel/sunxi-legacy/general-spidev-remove-warnings.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c -index 9e2e099b..a065943d 100644 ---- a/drivers/spi/spidev.c -+++ b/drivers/spi/spidev.c -@@ -749,13 +749,11 @@ static int spidev_probe(struct spi_device *spi) - - /* - * spidev should never be referenced in DT without a specific -- * compatible string, it is a Linux implementation thing -- * rather than a description of the hardware. -+ * compatible string, but people don't care and use DT overlays -+ * to activate SPIdev on demand - */ - if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) { -- dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n"); -- WARN_ON(spi->dev.of_node && -- !of_match_device(spidev_dt_ids, &spi->dev)); -+ dev_info(&spi->dev, "probing from DT"); - } - - spidev_probe_acpi(spi); diff --git a/patch/kernel/sunxi-legacy/wifi-add-xradio.patch b/patch/kernel/sunxi-legacy/wifi-add-xradio.patch deleted file mode 100644 index 65d8da1d0..000000000 --- a/patch/kernel/sunxi-legacy/wifi-add-xradio.patch +++ /dev/null @@ -1,18808 +0,0 @@ -diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig -index 3d1ffcb..bed2537 100644 ---- a/drivers/net/wireless/Kconfig -+++ b/drivers/net/wireless/Kconfig -@@ -45,6 +45,7 @@ source "drivers/net/wireless/realtek/Kconfig" - source "drivers/net/wireless/rsi/Kconfig" - source "drivers/net/wireless/st/Kconfig" - source "drivers/net/wireless/ti/Kconfig" -+source "drivers/net/wireless/xradio/Kconfig" - source "drivers/net/wireless/zydas/Kconfig" - source "drivers/net/wireless/quantenna/Kconfig" - source "drivers/net/wireless/rtl8812au/Kconfig" -diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile -index d0fbe9c..2442af0 100644 ---- a/drivers/net/wireless/Makefile -+++ b/drivers/net/wireless/Makefile -@@ -18,6 +18,7 @@ obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/ - obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/ - obj-$(CONFIG_WLAN_VENDOR_ST) += st/ - obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ -+obj-$(CONFIG_WLAN_VENDOR_XRADIO) += xradio/ - obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ - obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/ - -diff --git a/drivers/net/wireless/xradio/.7z b/drivers/net/wireless/xradio/.7z -new file mode 100644 -index 0000000..4f8fc9c -Binary files /dev/null and b/drivers/net/wireless/xradio/.7z differ -diff --git a/drivers/net/wireless/xradio/Kconfig b/drivers/net/wireless/xradio/Kconfig -new file mode 100644 -index 0000000..18d1e2b ---- /dev/null -+++ b/drivers/net/wireless/xradio/Kconfig -@@ -0,0 +1,46 @@ -+config WLAN_VENDOR_XRADIO -+ tristate "XRADIO WLAN support" -+ depends on MAC80211 -+ default m -+ help -+ -+ This is an experimental driver for the XRADIO chip-set. -+ Enabling this option enables the generic driver without -+ any platform support. -+ Please select the appropriate platform below. -+ -+if WLAN_VENDOR_XRADIO -+ -+config XRADIO_NON_POWER_OF_TWO_BLOCKSIZES -+ bool "Platform supports non-power-of-two SDIO transfer" -+ depends on WLAN_VENDOR_XRADIO -+ default y -+ ---help--- -+ Say N here only if you are running the driver on a platform -+ which does not have support for non-power-of-two SDIO transfer. -+ If unsure, say Y. -+ -+config XRADIO_5GHZ_SUPPORT -+ bool "5GHz band support" -+ depends on WLAN_VENDOR_XRADIO -+ default n -+ ---help--- -+ Say Y if your device supports 5GHz band. If unsure, say N. -+ -+config XRADIO_WAPI_SUPPORT -+ bool "WAPI support" -+ depends on WLAN_VENDOR_XRADIO -+ default n -+ ---help--- -+ Say Y if your compat-wireless support WAPI. -+ If unsure, say N. -+ -+config XRADIO_USE_EXTENSIONS -+ bool "Extensions for WFD and PS mode" -+ depends on WLAN_VENDOR_XRADIO -+ default y -+ ---help--- -+ Say Y if you want to include XR extensions -+ If unsure, say Y. -+ -+endif -diff --git a/drivers/net/wireless/xradio/LICENSE b/drivers/net/wireless/xradio/LICENSE -new file mode 100644 -index 0000000..23cb790 ---- /dev/null -+++ b/drivers/net/wireless/xradio/LICENSE -@@ -0,0 +1,339 @@ -+ GNU GENERAL PUBLIC LICENSE -+ Version 2, June 1991 -+ -+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ Preamble -+ -+ The licenses for most software are designed to take away your -+freedom to share and change it. By contrast, the GNU General Public -+License is intended to guarantee your freedom to share and change free -+software--to make sure the software is free for all its users. This -+General Public License applies to most of the Free Software -+Foundation's software and to any other program whose authors commit to -+using it. (Some other Free Software Foundation software is covered by -+the GNU Lesser General Public License instead.) You can apply it to -+your programs, too. -+ -+ When we speak of free software, we are referring to freedom, not -+price. Our General Public Licenses are designed to make sure that you -+have the freedom to distribute copies of free software (and charge for -+this service if you wish), that you receive source code or can get it -+if you want it, that you can change the software or use pieces of it -+in new free programs; and that you know you can do these things. -+ -+ To protect your rights, we need to make restrictions that forbid -+anyone to deny you these rights or to ask you to surrender the rights. -+These restrictions translate to certain responsibilities for you if you -+distribute copies of the software, or if you modify it. -+ -+ For example, if you distribute copies of such a program, whether -+gratis or for a fee, you must give the recipients all the rights that -+you have. You must make sure that they, too, receive or can get the -+source code. And you must show them these terms so they know their -+rights. -+ -+ We protect your rights with two steps: (1) copyright the software, and -+(2) offer you this license which gives you legal permission to copy, -+distribute and/or modify the software. -+ -+ Also, for each author's protection and ours, we want to make certain -+that everyone understands that there is no warranty for this free -+software. If the software is modified by someone else and passed on, we -+want its recipients to know that what they have is not the original, so -+that any problems introduced by others will not reflect on the original -+authors' reputations. -+ -+ Finally, any free program is threatened constantly by software -+patents. We wish to avoid the danger that redistributors of a free -+program will individually obtain patent licenses, in effect making the -+program proprietary. To prevent this, we have made it clear that any -+patent must be licensed for everyone's free use or not licensed at all. -+ -+ The precise terms and conditions for copying, distribution and -+modification follow. -+ -+ GNU GENERAL PUBLIC LICENSE -+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION -+ -+ 0. This License applies to any program or other work which contains -+a notice placed by the copyright holder saying it may be distributed -+under the terms of this General Public License. The "Program", below, -+refers to any such program or work, and a "work based on the Program" -+means either the Program or any derivative work under copyright law: -+that is to say, a work containing the Program or a portion of it, -+either verbatim or with modifications and/or translated into another -+language. (Hereinafter, translation is included without limitation in -+the term "modification".) Each licensee is addressed as "you". -+ -+Activities other than copying, distribution and modification are not -+covered by this License; they are outside its scope. The act of -+running the Program is not restricted, and the output from the Program -+is covered only if its contents constitute a work based on the -+Program (independent of having been made by running the Program). -+Whether that is true depends on what the Program does. -+ -+ 1. You may copy and distribute verbatim copies of the Program's -+source code as you receive it, in any medium, provided that you -+conspicuously and appropriately publish on each copy an appropriate -+copyright notice and disclaimer of warranty; keep intact all the -+notices that refer to this License and to the absence of any warranty; -+and give any other recipients of the Program a copy of this License -+along with the Program. -+ -+You may charge a fee for the physical act of transferring a copy, and -+you may at your option offer warranty protection in exchange for a fee. -+ -+ 2. You may modify your copy or copies of the Program or any portion -+of it, thus forming a work based on the Program, and copy and -+distribute such modifications or work under the terms of Section 1 -+above, provided that you also meet all of these conditions: -+ -+ a) You must cause the modified files to carry prominent notices -+ stating that you changed the files and the date of any change. -+ -+ b) You must cause any work that you distribute or publish, that in -+ whole or in part contains or is derived from the Program or any -+ part thereof, to be licensed as a whole at no charge to all third -+ parties under the terms of this License. -+ -+ c) If the modified program normally reads commands interactively -+ when run, you must cause it, when started running for such -+ interactive use in the most ordinary way, to print or display an -+ announcement including an appropriate copyright notice and a -+ notice that there is no warranty (or else, saying that you provide -+ a warranty) and that users may redistribute the program under -+ these conditions, and telling the user how to view a copy of this -+ License. (Exception: if the Program itself is interactive but -+ does not normally print such an announcement, your work based on -+ the Program is not required to print an announcement.) -+ -+These requirements apply to the modified work as a whole. If -+identifiable sections of that work are not derived from the Program, -+and can be reasonably considered independent and separate works in -+themselves, then this License, and its terms, do not apply to those -+sections when you distribute them as separate works. But when you -+distribute the same sections as part of a whole which is a work based -+on the Program, the distribution of the whole must be on the terms of -+this License, whose permissions for other licensees extend to the -+entire whole, and thus to each and every part regardless of who wrote it. -+ -+Thus, it is not the intent of this section to claim rights or contest -+your rights to work written entirely by you; rather, the intent is to -+exercise the right to control the distribution of derivative or -+collective works based on the Program. -+ -+In addition, mere aggregation of another work not based on the Program -+with the Program (or with a work based on the Program) on a volume of -+a storage or distribution medium does not bring the other work under -+the scope of this License. -+ -+ 3. You may copy and distribute the Program (or a work based on it, -+under Section 2) in object code or executable form under the terms of -+Sections 1 and 2 above provided that you also do one of the following: -+ -+ a) Accompany it with the complete corresponding machine-readable -+ source code, which must be distributed under the terms of Sections -+ 1 and 2 above on a medium customarily used for software interchange; or, -+ -+ b) Accompany it with a written offer, valid for at least three -+ years, to give any third party, for a charge no more than your -+ cost of physically performing source distribution, a complete -+ machine-readable copy of the corresponding source code, to be -+ distributed under the terms of Sections 1 and 2 above on a medium -+ customarily used for software interchange; or, -+ -+ c) Accompany it with the information you received as to the offer -+ to distribute corresponding source code. (This alternative is -+ allowed only for noncommercial distribution and only if you -+ received the program in object code or executable form with such -+ an offer, in accord with Subsection b above.) -+ -+The source code for a work means the preferred form of the work for -+making modifications to it. For an executable work, complete source -+code means all the source code for all modules it contains, plus any -+associated interface definition files, plus the scripts used to -+control compilation and installation of the executable. However, as a -+special exception, the source code distributed need not include -+anything that is normally distributed (in either source or binary -+form) with the major components (compiler, kernel, and so on) of the -+operating system on which the executable runs, unless that component -+itself accompanies the executable. -+ -+If distribution of executable or object code is made by offering -+access to copy from a designated place, then offering equivalent -+access to copy the source code from the same place counts as -+distribution of the source code, even though third parties are not -+compelled to copy the source along with the object code. -+ -+ 4. You may not copy, modify, sublicense, or distribute the Program -+except as expressly provided under this License. Any attempt -+otherwise to copy, modify, sublicense or distribute the Program is -+void, and will automatically terminate your rights under this License. -+However, parties who have received copies, or rights, from you under -+this License will not have their licenses terminated so long as such -+parties remain in full compliance. -+ -+ 5. You are not required to accept this License, since you have not -+signed it. However, nothing else grants you permission to modify or -+distribute the Program or its derivative works. These actions are -+prohibited by law if you do not accept this License. Therefore, by -+modifying or distributing the Program (or any work based on the -+Program), you indicate your acceptance of this License to do so, and -+all its terms and conditions for copying, distributing or modifying -+the Program or works based on it. -+ -+ 6. Each time you redistribute the Program (or any work based on the -+Program), the recipient automatically receives a license from the -+original licensor to copy, distribute or modify the Program subject to -+these terms and conditions. You may not impose any further -+restrictions on the recipients' exercise of the rights granted herein. -+You are not responsible for enforcing compliance by third parties to -+this License. -+ -+ 7. If, as a consequence of a court judgment or allegation of patent -+infringement or for any other reason (not limited to patent issues), -+conditions are imposed on you (whether by court order, agreement or -+otherwise) that contradict the conditions of this License, they do not -+excuse you from the conditions of this License. If you cannot -+distribute so as to satisfy simultaneously your obligations under this -+License and any other pertinent obligations, then as a consequence you -+may not distribute the Program at all. For example, if a patent -+license would not permit royalty-free redistribution of the Program by -+all those who receive copies directly or indirectly through you, then -+the only way you could satisfy both it and this License would be to -+refrain entirely from distribution of the Program. -+ -+If any portion of this section is held invalid or unenforceable under -+any particular circumstance, the balance of the section is intended to -+apply and the section as a whole is intended to apply in other -+circumstances. -+ -+It is not the purpose of this section to induce you to infringe any -+patents or other property right claims or to contest validity of any -+such claims; this section has the sole purpose of protecting the -+integrity of the free software distribution system, which is -+implemented by public license practices. Many people have made -+generous contributions to the wide range of software distributed -+through that system in reliance on consistent application of that -+system; it is up to the author/donor to decide if he or she is willing -+to distribute software through any other system and a licensee cannot -+impose that choice. -+ -+This section is intended to make thoroughly clear what is believed to -+be a consequence of the rest of this License. -+ -+ 8. If the distribution and/or use of the Program is restricted in -+certain countries either by patents or by copyrighted interfaces, the -+original copyright holder who places the Program under this License -+may add an explicit geographical distribution limitation excluding -+those countries, so that distribution is permitted only in or among -+countries not thus excluded. In such case, this License incorporates -+the limitation as if written in the body of this License. -+ -+ 9. The Free Software Foundation may publish revised and/or new versions -+of the General Public License from time to time. Such new versions will -+be similar in spirit to the present version, but may differ in detail to -+address new problems or concerns. -+ -+Each version is given a distinguishing version number. If the Program -+specifies a version number of this License which applies to it and "any -+later version", you have the option of following the terms and conditions -+either of that version or of any later version published by the Free -+Software Foundation. If the Program does not specify a version number of -+this License, you may choose any version ever published by the Free Software -+Foundation. -+ -+ 10. If you wish to incorporate parts of the Program into other free -+programs whose distribution conditions are different, write to the author -+to ask for permission. For software which is copyrighted by the Free -+Software Foundation, write to the Free Software Foundation; we sometimes -+make exceptions for this. Our decision will be guided by the two goals -+of preserving the free status of all derivatives of our free software and -+of promoting the sharing and reuse of software generally. -+ -+ NO WARRANTY -+ -+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -+REPAIR OR CORRECTION. -+ -+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -+POSSIBILITY OF SUCH DAMAGES. -+ -+ END OF TERMS AND CONDITIONS -+ -+ How to Apply These Terms to Your New Programs -+ -+ If you develop a new program, and you want it to be of the greatest -+possible use to the public, the best way to achieve this is to make it -+free software which everyone can redistribute and change under these terms. -+ -+ To do so, attach the following notices to the program. It is safest -+to attach them to the start of each source file to most effectively -+convey the exclusion of warranty; and each file should have at least -+the "copyright" line and a pointer to where the full notice is found. -+ -+ {description} -+ Copyright (C) {year} {fullname} -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License along -+ with this program; if not, write to the Free Software Foundation, Inc., -+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ -+Also add information on how to contact you by electronic and paper mail. -+ -+If the program is interactive, make it output a short notice like this -+when it starts in an interactive mode: -+ -+ Gnomovision version 69, Copyright (C) year name of author -+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. -+ This is free software, and you are welcome to redistribute it -+ under certain conditions; type `show c' for details. -+ -+The hypothetical commands `show w' and `show c' should show the appropriate -+parts of the General Public License. Of course, the commands you use may -+be called something other than `show w' and `show c'; they could even be -+mouse-clicks or menu items--whatever suits your program. -+ -+You should also get your employer (if you work as a programmer) or your -+school, if any, to sign a "copyright disclaimer" for the program, if -+necessary. Here is a sample; alter the names: -+ -+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program -+ `Gnomovision' (which makes passes at compilers) written by James Hacker. -+ -+ {signature of Ty Coon}, 1 April 1989 -+ Ty Coon, President of Vice -+ -+This General Public License does not permit incorporating your program into -+proprietary programs. If your program is a subroutine library, you may -+consider it more useful to permit linking proprietary applications with the -+library. If this is what you want to do, use the GNU Lesser General -+Public License instead of this License. -diff --git a/drivers/net/wireless/xradio/Makefile b/drivers/net/wireless/xradio/Makefile -new file mode 100644 -index 0000000..80a9a14 ---- /dev/null -+++ b/drivers/net/wireless/xradio/Makefile -@@ -0,0 +1,54 @@ -+# Standalone Makefile - uncomment for out-of-tree compilation -+#CONFIG_WLAN_VENDOR_XRADIO := m -+#CONFIG_XRADIO_USE_EXTENSIONS := y -+#CONFIG_XRADIO_WAPI_SUPPORT := n -+ -+# Kernel part -+ -+obj-$(CONFIG_WLAN_VENDOR_XRADIO) += xradio_wlan.o -+ -+xradio_wlan-objs := \ -+ fwio.o \ -+ tx.o \ -+ rx.o \ -+ main.o \ -+ queue.o \ -+ hwio.o \ -+ bh.o \ -+ wsm.o \ -+ sta.o \ -+ ap.o \ -+ keys.o \ -+ scan.o \ -+ module.o \ -+ sdio.o \ -+ pm.o \ -+ ht.o \ -+ p2p.o -+ -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DMCAST_FWDING -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DXRADIO_SUSPEND_RESUME_FILTER_ENABLE -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DAP_AGGREGATE_FW_FIX -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DAP_HT_CAP_UPDATE -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DAP_HT_COMPAT_FIX -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DCONFIG_XRADIO_DUMP_ON_ERROR -+ -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DCONFIG_XRADIO_SUSPEND_POWER_OFF -+ -+# Extra IE for probe response from upper layer is needed in P2P GO -+# For offloading probe response to FW, the extra IE must be included -+# in the probe response template -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DPROBE_RESP_EXTRA_IE -+ -+# Modified by wzw -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DTES_P2P_0002_ROC_RESTART -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DTES_P2P_000B_EXTEND_INACTIVITY_CNT -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DTES_P2P_000B_DISABLE_EAPOL_FILTER -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DXRADIO_USE_LONG_DTIM_PERIOD -+ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DXRADIO_USE_LONG_KEEP_ALIVE_PERIOD -+ -+#ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DDEBUG -+#ccflags-$(CONFIG_WLAN_VENDOR_XRADIO) += -DXRADIO_DISABLE_HW_CRYPTO -+ -+ldflags-$(CONFIG_WLAN_VENDOR_XRADIO) += --strip-debug -+ -diff --git a/drivers/net/wireless/xradio/ap.c b/drivers/net/wireless/xradio/ap.c -new file mode 100644 -index 0000000..5276c5a ---- /dev/null -+++ b/drivers/net/wireless/xradio/ap.c -@@ -0,0 +1,1624 @@ -+/* -+ * STA and AP APIs for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "xradio.h" -+#include "sta.h" -+#include "ap.h" -+#include "bh.h" -+#include "net/mac80211.h" -+ -+#define XRADIO_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ)) -+#define XRADIO_ENABLE_ARP_FILTER_OFFLOAD 3 -+ -+#ifndef ERP_INFO_BYTE_OFFSET -+#define ERP_INFO_BYTE_OFFSET 2 -+#endif -+ -+static int xradio_upload_beacon(struct xradio_vif *priv); -+#ifdef PROBE_RESP_EXTRA_IE -+static int xradio_upload_proberesp(struct xradio_vif *priv); -+#endif -+static int xradio_upload_pspoll(struct xradio_vif *priv); -+static int xradio_upload_null(struct xradio_vif *priv); -+static int xradio_upload_qosnull(struct xradio_vif *priv); -+static int xradio_start_ap(struct xradio_vif *priv); -+static int xradio_update_beaconing(struct xradio_vif *priv); -+/* -+static int xradio_enable_beaconing(struct xradio_vif *priv, -+ bool enable); -+*/ -+static void __xradio_sta_notify(struct xradio_vif *priv, -+ enum sta_notify_cmd notify_cmd, -+ int link_id); -+ -+/* ******************************************************************** */ -+/* AP API */ -+int xradio_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta) -+{ -+ struct xradio_sta_priv *sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct xradio_link_entry *entry; -+ struct sk_buff *skb; -+#ifdef AP_AGGREGATE_FW_FIX -+ struct xradio_common *hw_priv = hw->priv; -+#endif -+ -+ if (priv->mode != NL80211_IFTYPE_AP) { -+ return 0; -+ } -+ -+ sta_priv->priv = priv; -+ sta_priv->link_id = xradio_find_link_id(priv, sta->addr); -+ if (WARN_ON(!sta_priv->link_id)) { -+ /* Impossible error */ -+ wiphy_debug(hw->wiphy, "No more link IDs available.\n"); -+ return -ENOENT; -+ } -+ -+ entry = &priv->link_id_db[sta_priv->link_id - 1]; -+ spin_lock_bh(&priv->ps_state_lock); -+ if ((sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) == -+ IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) { -+ priv->sta_asleep_mask |= BIT(sta_priv->link_id); -+ } -+ entry->status = XRADIO_LINK_HARD; -+ while ((skb = skb_dequeue(&entry->rx_queue))) -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+#ifdef AP_AGGREGATE_FW_FIX -+ hw_priv->connected_sta_cnt++; -+ if(hw_priv->connected_sta_cnt>1) { -+ wsm_lock_tx(hw_priv); -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_DISABLED_FOR_ALL_TID, -+ XRADIO_RX_BLOCK_ACK_DISABLED_FOR_ALL_TID, -+ priv->if_id)); -+ wsm_unlock_tx(hw_priv); -+ } -+#endif -+ -+ return 0; -+} -+ -+int xradio_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_sta_priv *sta_priv = -+ (struct xradio_sta_priv *)&sta->drv_priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct xradio_link_entry *entry; -+ -+ if (priv->mode != NL80211_IFTYPE_AP || !sta_priv->link_id) { -+ wiphy_warn(hw->wiphy, "no station to remove\n"); -+ return 0; -+ } -+ -+ entry = &priv->link_id_db[sta_priv->link_id - 1]; -+ spin_lock_bh(&priv->ps_state_lock); -+ entry->status = XRADIO_LINK_RESERVE; -+ entry->timestamp = jiffies; -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->link_id_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ spin_unlock_bh(&priv->ps_state_lock); -+ flush_workqueue(hw_priv->workqueue); -+ -+#ifdef AP_AGGREGATE_FW_FIX -+ hw_priv->connected_sta_cnt--; -+ if(hw_priv->connected_sta_cnt <= 1) { -+ if ((priv->if_id != 1) || -+ ((priv->if_id == 1) && hw_priv->is_go_thru_go_neg)) { -+ wsm_lock_tx(hw_priv); -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID, -+ XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID, -+ priv->if_id)); -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+#endif -+ -+ return 0; -+} -+ -+static void __xradio_sta_notify(struct xradio_vif *priv, -+ enum sta_notify_cmd notify_cmd, -+ int link_id) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u32 bit, prev; -+ -+ /* Zero link id means "for all link IDs" */ -+ if (link_id) -+ bit = BIT(link_id); -+ else if (WARN_ON_ONCE(notify_cmd != STA_NOTIFY_AWAKE)) -+ bit = 0; -+ else -+ bit = priv->link_id_map; -+ prev = priv->sta_asleep_mask & bit; -+ -+ switch (notify_cmd) { -+ case STA_NOTIFY_SLEEP: -+ if (!prev) { -+ if (priv->buffered_multicasts && -+ !priv->sta_asleep_mask) -+ queue_work(hw_priv->workqueue, -+ &priv->multicast_start_work); -+ priv->sta_asleep_mask |= bit; -+ } -+ break; -+ case STA_NOTIFY_AWAKE: -+ if (prev) { -+ priv->sta_asleep_mask &= ~bit; -+ priv->pspoll_mask &= ~bit; -+ if (priv->tx_multicast && link_id && -+ !priv->sta_asleep_mask) -+ queue_work(hw_priv->workqueue, -+ &priv->multicast_stop_work); -+ xradio_bh_wakeup(hw_priv); -+ } -+ break; -+ } -+} -+ -+void xradio_sta_notify(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ enum sta_notify_cmd notify_cmd, -+ struct ieee80211_sta *sta) -+{ -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct xradio_sta_priv *sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ __xradio_sta_notify(priv, notify_cmd, sta_priv->link_id); -+ spin_unlock_bh(&priv->ps_state_lock); -+} -+ -+static void xradio_ps_notify(struct xradio_vif *priv, -+ int link_id, bool ps) -+{ -+ if (link_id > MAX_STA_IN_AP_MODE) { -+ ap_printk(XRADIO_DBG_WARN,"link_id is invalid=%d\n", link_id); -+ return; -+ } -+ -+ ap_printk(XRADIO_DBG_NIY, "%s for LinkId: %d. STAs asleep: %.8X\n", -+ ps ? "Stop" : "Start", link_id, priv->sta_asleep_mask); -+ -+ /* TODO:COMBO: __xradio_sta_notify changed. */ -+ __xradio_sta_notify(priv, ps ? STA_NOTIFY_SLEEP : STA_NOTIFY_AWAKE, link_id); -+} -+ -+static int xradio_set_tim_impl(struct xradio_vif *priv, bool aid0_bit_set) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct sk_buff *skb; -+ struct wsm_update_ie update_ie = { -+ .what = WSM_UPDATE_IE_BEACON, -+ .count = 1, -+ }; -+ u16 tim_offset, tim_length; -+ ap_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ ap_printk(XRADIO_DBG_MSG, "%s mcast: %s.\n", __func__, -+ aid0_bit_set ? "ena" : "dis"); -+ -+ skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, &tim_offset, &tim_length); -+ if (!skb) { -+ __xradio_flush(hw_priv, true, priv->if_id); -+ return -ENOENT; -+ } -+ -+ if (tim_offset && tim_length >= 6) { -+ /* Ignore DTIM count from mac80211: -+ * firmware handles DTIM internally. */ -+ skb->data[tim_offset + 2] = 0; -+ -+ /* Set/reset aid0 bit */ -+ if (aid0_bit_set) -+ skb->data[tim_offset + 4] |= 1; -+ else -+ skb->data[tim_offset + 4] &= ~1; -+ } -+ -+ update_ie.ies = &skb->data[tim_offset]; -+ update_ie.length = tim_length; -+ //filter same tim info, yangfh -+ if(memcmp(priv->last_tim, update_ie.ies, tim_length)) { -+ WARN_ON(wsm_update_ie(hw_priv, &update_ie, priv->if_id)); -+ memcpy(priv->last_tim, update_ie.ies, tim_length); -+ ap_printk(XRADIO_DBG_MSG,"%02x %02x %02x %02x %02x %02x\n", -+ update_ie.ies[0], update_ie.ies[1], update_ie.ies[2], -+ update_ie.ies[3], update_ie.ies[4], update_ie.ies[5]); -+ } -+ -+ dev_kfree_skb(skb); -+ -+ return 0; -+} -+ -+void xradio_set_tim_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = container_of(work, struct xradio_vif, set_tim_work); -+ xradio_set_tim_impl(priv, priv->aid0_bit_set); -+} -+ -+int xradio_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, -+ bool set) -+{ -+ struct xradio_sta_priv *sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; -+ struct xradio_vif *priv = sta_priv->priv; -+ -+ WARN_ON(priv->mode != NL80211_IFTYPE_AP); -+ queue_work(priv->hw_priv->workqueue, &priv->set_tim_work); -+ return 0; -+} -+ -+void xradio_set_cts_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, set_cts_work.work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u8 erp_ie[3] = {WLAN_EID_ERP_INFO, 0x1, 0}; -+ struct wsm_update_ie update_ie = { -+ .what = WSM_UPDATE_IE_BEACON, -+ .count = 1, -+ .ies = erp_ie, -+ .length = 3, -+ }; -+ u32 erp_info; -+ __le32 use_cts_prot; -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ erp_info = priv->erp_info; -+ mutex_unlock(&hw_priv->conf_mutex); -+ use_cts_prot = (erp_info & WLAN_ERP_USE_PROTECTION)? __cpu_to_le32(1) : 0; -+ -+ erp_ie[ERP_INFO_BYTE_OFFSET] = erp_info; -+ -+ ap_printk(XRADIO_DBG_MSG, "ERP information 0x%x\n", erp_info); -+ -+ /* TODO:COMBO: If 2 interfaces are on the same channel they share -+ the same ERP values */ -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_NON_ERP_PROTECTION, -+ &use_cts_prot, sizeof(use_cts_prot), priv->if_id)); -+ /* If STA Mode update_ie is not required */ -+ if (priv->mode != NL80211_IFTYPE_STATION) { -+ WARN_ON(wsm_update_ie(hw_priv, &update_ie, priv->if_id)); -+ } -+ -+ return; -+} -+ -+static int xradio_set_btcoexinfo(struct xradio_vif *priv) -+{ -+ struct wsm_override_internal_txrate arg; -+ int ret = 0; -+ -+ if (priv->mode == NL80211_IFTYPE_STATION) { -+ /* Plumb PSPOLL and NULL template */ -+ WARN_ON(xradio_upload_pspoll(priv)); -+ WARN_ON(xradio_upload_null(priv)); -+ } else { -+ return 0; -+ } -+ -+ memset(&arg, 0, sizeof(struct wsm_override_internal_txrate)); -+ -+ if (!priv->vif->p2p) { -+ /* STATION mode */ -+ if (priv->bss_params.operationalRateSet & ~0xF) { -+ ap_printk(XRADIO_DBG_NIY, "STA has ERP rates\n"); -+ /* G or BG mode */ -+ arg.internalTxRate = (__ffs( -+ priv->bss_params.operationalRateSet & ~0xF)); -+ } else { -+ ap_printk(XRADIO_DBG_NIY, "STA has non ERP rates\n"); -+ /* B only mode */ -+ arg.internalTxRate = (__ffs( -+ priv->association_mode.basicRateSet)); -+ } -+ arg.nonErpInternalTxRate = (__ffs( -+ priv->association_mode.basicRateSet)); -+ } else { -+ /* P2P mode */ -+ arg.internalTxRate = (__ffs( -+ priv->bss_params.operationalRateSet & ~0xF)); -+ arg.nonErpInternalTxRate = (__ffs( -+ priv->bss_params.operationalRateSet & ~0xF)); -+ } -+ -+ ap_printk(XRADIO_DBG_NIY, "BTCOEX_INFO" "MODE %d, internalTxRate : %x," -+ "nonErpInternalTxRate: %x\n", priv->mode, arg.internalTxRate, -+ arg.nonErpInternalTxRate); -+ -+ ret = WARN_ON(wsm_write_mib(xrwl_vifpriv_to_hwpriv(priv), -+ WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, -+ &arg, sizeof(arg), priv->if_id)); -+ -+ return ret; -+} -+ -+void xradio_bss_info_changed(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ struct ieee80211_bss_conf *info, -+ u32 changed) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ if (changed & BSS_CHANGED_BSSID) { -+ memcpy(priv->bssid, info->bssid, ETH_ALEN); -+ xradio_setup_mac_pvif(priv); -+ } -+ -+ /* TODO: BSS_CHANGED_IBSS */ -+ if (changed & BSS_CHANGED_ARP_FILTER) { -+ struct wsm_arp_ipv4_filter filter = {0}; -+ int i; -+ ap_printk(XRADIO_DBG_MSG, "[STA] BSS_CHANGED_ARP_FILTER cnt: %d\n", -+ info->arp_addr_cnt); -+ -+ if (info->arp_addr_cnt){ -+ if (vif->type == NL80211_IFTYPE_STATION) -+ filter.enable = (u32)XRADIO_ENABLE_ARP_FILTER_OFFLOAD; -+ else if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ filter.enable = (u32)(1<<1); -+ else -+ filter.enable = 0; -+ } -+ -+ /* Currently only one IP address is supported by firmware. -+ * In case of more IPs arp filtering will be disabled. */ -+ if (info->arp_addr_cnt > 0 && -+ info->arp_addr_cnt <= WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES) { -+ for (i = 0; i < info->arp_addr_cnt; i++) { -+ filter.ipv4Address[i] = info->arp_addr_list[i]; -+ ap_printk(XRADIO_DBG_NIY, "[STA]addr[%d]: 0x%X\n", i, filter.ipv4Address[i]); -+ } -+ } else -+ filter.enable = 0; -+ -+ if (filter.enable) -+ xradio_set_arpreply(dev, vif); -+ -+ priv->filter4.enable = filter.enable; -+ ap_printk(XRADIO_DBG_NIY, "[STA]arp ip filter enable: %d\n", __le32_to_cpu(filter.enable)); -+ -+ if (wsm_set_arp_ipv4_filter(hw_priv, &filter, priv->if_id)) -+ WARN_ON(1); -+ -+ if (filter.enable && -+ (priv->join_status == XRADIO_JOIN_STATUS_STA)) { -+ /* Firmware requires that value for this 1-byte field must -+ * be specified in units of 500us. Values above the 128ms -+ * threshold are not supported. */ -+ //if (info->dynamic_ps_timeout >= 0x80) -+ // priv->powersave_mode.fastPsmIdlePeriod = 0xFF; -+ //else -+ // priv->powersave_mode.fastPsmIdlePeriod = info->dynamic_ps_timeout << 1; -+ -+ priv->powersave_mode.fastPsmIdlePeriod = 200;//when connected,the dev->conf.dynamic_ps_timeout value is 0 -+ priv->powersave_mode.apPsmChangePeriod = 200; //100ms, add by yangfh -+ ap_printk(XRADIO_DBG_NIY, "[STA]fastPsmIdle=%d, apPsmChange=%d\n", -+ priv->powersave_mode.fastPsmIdlePeriod, -+ priv->powersave_mode.apPsmChangePeriod); -+ -+ if (priv->setbssparams_done) { -+ int ret = 0; -+ struct wsm_set_pm pm = priv->powersave_mode; -+ if (priv->user_power_set_true) -+ priv->powersave_mode.pmMode = priv->user_pm_mode; -+ else if ((priv->power_set_true && -+ ((priv->powersave_mode.pmMode == WSM_PSM_ACTIVE) || -+ (priv->powersave_mode.pmMode == WSM_PSM_PS))) || -+ !priv->power_set_true) -+ priv->powersave_mode.pmMode = WSM_PSM_FAST_PS; -+ -+ ret = xradio_set_pm (priv, &priv->powersave_mode); -+ if(ret) -+ priv->powersave_mode = pm; -+ } else { -+ priv->powersave_mode.pmMode = WSM_PSM_FAST_PS; -+ } -+ priv->power_set_true = 0; -+ priv->user_power_set_true = 0; -+ } -+ } -+ -+ if (changed & BSS_CHANGED_BEACON) { -+ ap_printk(XRADIO_DBG_NIY, "BSS_CHANGED_BEACON\n"); -+#ifdef HIDDEN_SSID -+ if(priv->join_status != XRADIO_JOIN_STATUS_AP) { -+ priv->hidden_ssid = info->hidden_ssid; -+ priv->ssid_length = info->ssid_len; -+ memcpy(priv->ssid, info->ssid, info->ssid_len); -+ } else -+ ap_printk(XRADIO_DBG_NIY, "priv->join_status=%d\n", priv->join_status); -+#endif -+ WARN_ON(xradio_upload_beacon(priv)); -+ WARN_ON(xradio_update_beaconing(priv)); -+ } -+ -+ if (changed & BSS_CHANGED_BEACON_ENABLED) { -+ ap_printk(XRADIO_DBG_NIY, "BSS_CHANGED_BEACON_ENABLED dummy\n"); -+ priv->enable_beacon = info->enable_beacon; -+ } -+ -+ if (changed & BSS_CHANGED_BEACON_INT) { -+ ap_printk(XRADIO_DBG_NIY, "CHANGED_BEACON_INT\n"); -+ /* Restart AP only when connected */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(xradio_update_beaconing(priv)); -+ } -+ -+ -+ if (changed & BSS_CHANGED_ASSOC) { -+ wsm_lock_tx(hw_priv); -+ priv->wep_default_key_id = -1; -+ wsm_unlock_tx(hw_priv); -+ -+ if (!info->assoc /* && !info->ibss_joined */) { -+ priv->cqm_link_loss_count = XRADIO_LINK_LOSS_THOLD_DEF; -+ priv->cqm_beacon_loss_count = XRADIO_BSS_LOSS_THOLD_DEF; -+ priv->cqm_tx_failure_thold = 0; -+ } -+ priv->cqm_tx_failure_count = 0; -+ } -+ -+ if (changed & -+ (BSS_CHANGED_ASSOC | -+ BSS_CHANGED_BASIC_RATES | -+ BSS_CHANGED_ERP_PREAMBLE | -+ BSS_CHANGED_HT | -+ BSS_CHANGED_ERP_SLOT)) { -+ int is_combo = 0; -+ int i; -+ struct xradio_vif *tmp_priv; -+ ap_printk(XRADIO_DBG_NIY, "BSS_CHANGED_ASSOC.\n"); -+ if (info->assoc) { /* TODO: ibss_joined */ -+ struct ieee80211_sta *sta = NULL; -+ if (info->dtim_period) -+ priv->join_dtim_period = info->dtim_period; -+ priv->beacon_int = info->beacon_int; -+ -+ /* Associated: kill join timeout */ -+ cancel_delayed_work_sync(&priv->join_timeout); -+ -+ rcu_read_lock(); -+ if (info->bssid) -+ sta = ieee80211_find_sta(vif, info->bssid); -+ if (sta) { -+ /* TODO:COMBO:Change this once -+ * mac80211 changes are available */ -+ BUG_ON(!hw_priv->channel); -+ hw_priv->ht_oper.ht_cap = sta->ht_cap; -+ priv->bss_params.operationalRateSet =__cpu_to_le32( -+ xradio_rate_mask_to_wsm(hw_priv, sta->supp_rates[hw_priv->channel->band])); -+ /* TODO by Icenowy: I think this may lead to some problems. */ -+// hw_priv->ht_oper.channel_type = info->channel_type; -+ hw_priv->ht_oper.operation_mode = info->ht_operation_mode; -+ } else { -+ memset(&hw_priv->ht_oper, 0, sizeof(hw_priv->ht_oper)); -+ priv->bss_params.operationalRateSet = -1; -+ } -+ rcu_read_unlock(); -+ priv->htcap = (sta && xradio_is_ht(&hw_priv->ht_oper)); -+ xradio_for_each_vif(hw_priv, tmp_priv, i) { -+ if (!tmp_priv) -+ continue; -+ if (tmp_priv->join_status >= XRADIO_JOIN_STATUS_STA) -+ is_combo++; -+ } -+ -+ if (is_combo > 1) { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ ap_printk(XRADIO_DBG_WARN, "%sASSOC is_combo %d\n", -+ (priv->join_status == XRADIO_JOIN_STATUS_STA)?"[STA] ":"", -+ hw_priv->vif0_throttle); -+ } else if ((priv->join_status == XRADIO_JOIN_STATUS_STA) && priv->htcap) { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11N_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11N_THROTTLE; -+ ap_printk(XRADIO_DBG_WARN, "[STA] ASSOC HTCAP 11N %d\n",hw_priv->vif0_throttle); -+ } else { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ ap_printk(XRADIO_DBG_WARN, "ASSOC not_combo 11BG %d\n",hw_priv->vif0_throttle); -+ } -+ -+ if (sta) { -+ __le32 val = 0; -+ if (hw_priv->ht_oper.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) { -+ ap_printk(XRADIO_DBG_NIY,"[STA] Non-GF STA present\n"); -+ /* Non Green field capable STA */ -+ val = __cpu_to_le32(BIT(1)); -+ } -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MID_ID_SET_HT_PROTECTION, -+ &val, sizeof(val), priv->if_id)); -+ } -+ -+ priv->association_mode.greenfieldMode = xradio_ht_greenfield(&hw_priv->ht_oper); -+ priv->association_mode.flags = -+ WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES | -+ WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE | -+ WSM_ASSOCIATION_MODE_USE_HT_MODE | -+ WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET | -+ WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING; -+ -+ priv->association_mode.preambleType = -+ (info->use_short_preamble ? WSM_JOIN_PREAMBLE_SHORT : WSM_JOIN_PREAMBLE_LONG); -+ priv->association_mode.basicRateSet = __cpu_to_le32( -+ xradio_rate_mask_to_wsm(hw_priv,info->basic_rates)); -+ priv->association_mode.mpduStartSpacing = -+ xradio_ht_ampdu_density(&hw_priv->ht_oper); -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //priv->cqm_beacon_loss_count = info->cqm_beacon_miss_thold; -+ //priv->cqm_tx_failure_thold = info->cqm_tx_fail_thold; -+ //priv->cqm_tx_failure_count = 0; -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ -+ priv->bss_params.beaconLostCount = (priv->cqm_beacon_loss_count ? -+ priv->cqm_beacon_loss_count : priv->cqm_link_loss_count); -+ -+ priv->bss_params.aid = info->aid; -+ -+ if (priv->join_dtim_period < 1) -+ priv->join_dtim_period = 1; -+ -+ ap_printk(XRADIO_DBG_MSG, "[STA] DTIM %d, interval: %d\n", -+ priv->join_dtim_period, priv->beacon_int); -+ ap_printk(XRADIO_DBG_MSG, "[STA] Preamble: %d, " \ -+ "Greenfield: %d, Aid: %d, Rates: 0x%.8X, Basic: 0x%.8X\n", -+ priv->association_mode.preambleType, -+ priv->association_mode.greenfieldMode, -+ priv->bss_params.aid, -+ priv->bss_params.operationalRateSet, -+ priv->association_mode.basicRateSet); -+ WARN_ON(wsm_set_association_mode(hw_priv, &priv->association_mode, priv->if_id)); -+ WARN_ON(wsm_keep_alive_period(hw_priv, XRADIO_KEEP_ALIVE_PERIOD /* sec */, -+ priv->if_id)); -+ WARN_ON(wsm_set_bss_params(hw_priv, &priv->bss_params, priv->if_id)); -+ priv->setbssparams_done = true; -+#ifdef XRADIO_USE_LONG_DTIM_PERIOD -+{ -+ int join_dtim_period_extend; -+ if (priv->join_dtim_period <= 3) { -+ join_dtim_period_extend = priv->join_dtim_period * 3; -+ } else if (priv->join_dtim_period <= 5) { -+ join_dtim_period_extend = priv->join_dtim_period * 2; -+ } else { -+ join_dtim_period_extend = priv->join_dtim_period; -+ } -+ WARN_ON(wsm_set_beacon_wakeup_period(hw_priv, -+ ((priv->beacon_int * join_dtim_period_extend) > MAX_BEACON_SKIP_TIME_MS -+ ? 1 : join_dtim_period_extend) , 0, priv->if_id)); -+} -+#else -+ WARN_ON(wsm_set_beacon_wakeup_period(hw_priv, -+ ((priv->beacon_int * priv->join_dtim_period) > MAX_BEACON_SKIP_TIME_MS -+ ? 1 : priv->join_dtim_period) , 0, priv->if_id)); -+#endif -+ if (priv->htcap) { -+ wsm_lock_tx(hw_priv); -+ /* Statically enabling block ack for TX/RX */ -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, hw_priv->ba_tid_mask, -+ hw_priv->ba_tid_mask, priv->if_id)); -+ wsm_unlock_tx(hw_priv); -+ } -+ /*set ps active,avoid that when connecting process,the device sleeps,then can't receive pkts.*/ -+ if (changed & BSS_CHANGED_ASSOC) -+ priv->powersave_mode.pmMode = WSM_PSM_ACTIVE; -+ xradio_set_pm(priv, &priv->powersave_mode); -+ if (priv->vif->p2p) { -+ ap_printk(XRADIO_DBG_NIY, "[STA] Setting p2p powersave configuration.\n"); -+ WARN_ON(wsm_set_p2p_ps_modeinfo(hw_priv, &priv->p2p_ps_modeinfo, priv->if_id)); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //xradio_notify_noa(priv, XRADIO_NOA_NOTIFICATION_DELAY); -+#endif -+ } -+ -+ if (priv->mode == NL80211_IFTYPE_STATION) -+ WARN_ON(xradio_upload_qosnull(priv)); -+ -+ if (hw_priv->is_BT_Present) -+ WARN_ON(xradio_set_btcoexinfo(priv)); -+#if 0 -+ /* It's better to override internal TX rete; otherwise -+ * device sends RTS at too high rate. However device -+ * can't receive CTS at 1 and 2 Mbps. Well, 5.5 is a -+ * good choice for RTS/CTS, but that means PS poll -+ * will be sent at the same rate - impact on link -+ * budget. Not sure what is better.. */ -+ -+ /* Update: internal rate selection algorythm is not -+ * bad: if device is not receiving CTS at high rate, -+ * it drops RTS rate. -+ * So, conclusion: if-0 the code. Keep code just for -+ * information: -+ * Do not touch WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE! */ -+ -+ /* ~3 is a bug in device: RTS/CTS is not working at -+ * low rates */ -+ __le32 internal_tx_rate = __cpu_to_le32( -+ __ffs(priv->association_mode.basicRateSet & ~3)); -+ WARN_ON(wsm_write_mib(priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, -+ &internal_tx_rate,sizeof(internal_tx_rate))); -+#endif -+ } else { -+ memset(&priv->association_mode, 0, sizeof(priv->association_mode)); -+ memset(&priv->bss_params, 0, sizeof(priv->bss_params)); -+ } -+ } -+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_CTS_PROT)) { -+ u32 prev_erp_info = priv->erp_info; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ if (info->use_cts_prot) -+ priv->erp_info |= WLAN_ERP_USE_PROTECTION; -+ else if (!(prev_erp_info & WLAN_ERP_NON_ERP_PRESENT)) -+ priv->erp_info &= ~WLAN_ERP_USE_PROTECTION; -+ -+ if (prev_erp_info != priv->erp_info) -+ queue_delayed_work(hw_priv->workqueue, &priv->set_cts_work, 0*HZ); -+ } -+ } -+ -+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_SLOT)) { -+ __le32 slot_time = info->use_short_slot ? __cpu_to_le32(9) : __cpu_to_le32(20); -+ ap_printk(XRADIO_DBG_MSG, "[STA] Slot time :%d us.\n", __le32_to_cpu(slot_time)); -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_SLOT_TIME, &slot_time, -+ sizeof(slot_time), priv->if_id)); -+ } -+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_CQM)) { -+ struct wsm_rcpi_rssi_threshold threshold = { -+ .rollingAverageCount = 8, -+ }; -+ -+#if 0 -+ /* For verification purposes */ -+ info->cqm_rssi_thold = -50; -+ info->cqm_rssi_hyst = 4; -+#endif /* 0 */ -+ -+ ap_printk(XRADIO_DBG_NIY, "[CQM] RSSI threshold subscribe: %d(+-%d)\n", -+ info->cqm_rssi_thold, info->cqm_rssi_hyst); -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ priv->cqm_rssi_thold = info->cqm_rssi_thold; -+ priv->cqm_rssi_hyst = info->cqm_rssi_hyst; -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ -+ if (info->cqm_rssi_thold || info->cqm_rssi_hyst) { -+ /* RSSI subscription enabled */ -+ /* TODO: It's not a correct way of setting threshold. -+ * Upper and lower must be set equal here and adjusted -+ * in callback. However current implementation is much -+ * more relaible and stable. */ -+ if (priv->cqm_use_rssi) { -+ threshold.upperThreshold = info->cqm_rssi_thold + info->cqm_rssi_hyst; -+ threshold.lowerThreshold = info->cqm_rssi_thold; -+ } else { -+ /* convert RSSI to RCPI, RCPI = (RSSI + 110) * 2 */ -+ threshold.upperThreshold = (info->cqm_rssi_thold + info->cqm_rssi_hyst + 110)<<1; -+ threshold.lowerThreshold = (info->cqm_rssi_thold + 110)<<1; -+ } -+ threshold.rssiRcpiMode |= WSM_RCPI_RSSI_THRESHOLD_ENABLE; -+ } else { -+ /* There is a bug in FW, see sta.c. We have to enable -+ * dummy subscription to get correct RSSI values. */ -+ threshold.rssiRcpiMode |= WSM_RCPI_RSSI_THRESHOLD_ENABLE | -+ WSM_RCPI_RSSI_DONT_USE_UPPER | -+ WSM_RCPI_RSSI_DONT_USE_LOWER; -+ } -+ WARN_ON(wsm_set_rcpi_rssi_threshold(hw_priv, &threshold, priv->if_id)); -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //priv->cqm_tx_failure_thold = info->cqm_tx_fail_thold; -+ //priv->cqm_tx_failure_count = 0; -+ -+ //if (priv->cqm_beacon_loss_count != info->cqm_beacon_miss_thold) { -+ // priv->cqm_beacon_loss_count = info->cqm_beacon_miss_thold; -+ // priv->bss_params.beaconLostCount = (priv->cqm_beacon_loss_count? -+ // priv->cqm_beacon_loss_count : priv->cqm_link_loss_count); -+ /* Make sure we are associated before sending -+ * set_bss_params to firmware */ -+ if (priv->bss_params.aid) { -+ WARN_ON(wsm_set_bss_params(hw_priv, &priv->bss_params, priv->if_id)); -+ priv->setbssparams_done = true; -+ } -+ //} -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ } -+ /* -+ * in linux3.4 mac,the enum ieee80211_bss_change variable doesn't have -+ * BSS_CHANGED_PS and BSS_CHANGED_RETRY_LIMITS enum value. -+ */ -+#if 0 -+ if (changed & BSS_CHANGED_PS) { -+ if (info->ps_enabled == false) -+ priv->powersave_mode.pmMode = WSM_PSM_ACTIVE; -+ else if (info->dynamic_ps_timeout <= 0) -+ priv->powersave_mode.pmMode = WSM_PSM_PS; -+ else -+ priv->powersave_mode.pmMode = WSM_PSM_FAST_PS; -+ -+ ap_printk(XRADIO_DBG_MSG, "[STA] Aid: %d, Joined: %s, Powersave: %s\n", -+ priv->bss_params.aid, -+ priv->join_status == XRADIO_JOIN_STATUS_STA ? "yes" : "no", -+ (priv->powersave_mode.pmMode == WSM_PSM_ACTIVE ? "WSM_PSM_ACTIVE" : -+ priv->powersave_mode.pmMode == WSM_PSM_PS ? "WSM_PSM_PS" : -+ priv->powersave_mode.pmMode == WSM_PSM_FAST_PS ? "WSM_PSM_FAST_PS" : -+ "UNKNOWN")); -+ -+ /* Firmware requires that value for this 1-byte field must -+ * be specified in units of 500us. Values above the 128ms -+ * threshold are not supported. */ -+ if (info->dynamic_ps_timeout >= 0x80) -+ priv->powersave_mode.fastPsmIdlePeriod = 0xFF; -+ else -+ priv->powersave_mode.fastPsmIdlePeriod = info->dynamic_ps_timeout << 1; -+ ap_printk(XRADIO_DBG_NIY, "[STA]CHANGED_PS fastPsmIdle=%d, apPsmChange=%d\n", -+ priv->powersave_mode.fastPsmIdlePeriod, -+ priv->powersave_mode.apPsmChangePeriod); -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA && priv->bss_params.aid && -+ priv->setbssparams_done && priv->filter4.enable) -+ xradio_set_pm(priv, &priv->powersave_mode); -+ else -+ priv->power_set_true = 1; -+ } -+ -+ if (changed & BSS_CHANGED_RETRY_LIMITS) { -+ ap_printk(XRADIO_DBG_NIY, "Retry limits: %d (long), %d (short).\n", -+ info->retry_long, info->retry_short); -+ spin_lock_bh(&hw_priv->tx_policy_cache.lock); -+ /*TODO:COMBO: for now it's still handled per hw and kept -+ * in xradio_common */ -+ hw_priv->long_frame_max_tx_count = info->retry_long; -+ hw_priv->short_frame_max_tx_count = -+ (info->retry_short < 0x0F ? info->retry_short : 0x0F); -+ hw_priv->hw->max_rate_tries = hw_priv->short_frame_max_tx_count; -+ spin_unlock_bh(&hw_priv->tx_policy_cache.lock); -+ /* TBD: I think we don't need tx_policy_force_upload(). -+ * Outdated policies will leave cache in a normal way. */ -+ /* WARN_ON(tx_policy_force_upload(priv)); */ -+ } -+#endif -+ /*in linux3.4 mac,the enum ieee80211_bss_change variable doesn't have BSS_CHANGED_P2P_PS enum value*/ -+#if 0 -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ if (changed & BSS_CHANGED_P2P_PS) { -+ struct wsm_p2p_ps_modeinfo *modeinfo; -+ modeinfo = &priv->p2p_ps_modeinfo; -+ ap_printk(XRADIO_DBG_NIY, "[AP] BSS_CHANGED_P2P_PS\n"); -+ ap_printk(XRADIO_DBG_NIY, "[AP] Legacy PS: %d for AID %d in %d mode.\n", -+ info->p2p_ps.legacy_ps, priv->bss_params.aid, priv->join_status); -+ -+ if (info->p2p_ps.legacy_ps >= 0) { -+ if (info->p2p_ps.legacy_ps > 0) -+ priv->powersave_mode.pmMode = WSM_PSM_PS; -+ else -+ priv->powersave_mode.pmMode = WSM_PSM_ACTIVE; -+ -+ if(info->p2p_ps.ctwindow && info->p2p_ps.opp_ps) -+ priv->powersave_mode.pmMode = WSM_PSM_PS; -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) -+ xradio_set_pm(priv, &priv->powersave_mode); -+ } -+ -+ ap_printk(XRADIO_DBG_MSG, "[AP] CTWindow: %d\n", info->p2p_ps.ctwindow); -+ if (info->p2p_ps.ctwindow >= 128) -+ modeinfo->oppPsCTWindow = 127; -+ else if (info->p2p_ps.ctwindow >= 0) -+ modeinfo->oppPsCTWindow = info->p2p_ps.ctwindow; -+ -+ ap_printk(XRADIO_DBG_MSG, "[AP] Opportunistic: %d\n", info->p2p_ps.opp_ps); -+ switch (info->p2p_ps.opp_ps) { -+ case 0: -+ modeinfo->oppPsCTWindow &= ~(BIT(7)); -+ break; -+ case 1: -+ modeinfo->oppPsCTWindow |= BIT(7); -+ break; -+ default: -+ break; -+ } -+ -+ ap_printk(XRADIO_DBG_MSG, "[AP] NOA: %d, %d, %d, %d\n", -+ info->p2p_ps.count, info->p2p_ps.start, -+ info->p2p_ps.duration, info->p2p_ps.interval); -+ /* Notice of Absence */ -+ modeinfo->count = info->p2p_ps.count; -+ -+ if (info->p2p_ps.count) { -+ /* In case P2P_GO we need some extra time to be sure -+ * we will update beacon/probe_resp IEs correctly */ -+#define NOA_DELAY_START_MS 300 -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ modeinfo->startTime = __cpu_to_le32(info->p2p_ps.start + NOA_DELAY_START_MS); -+ else -+ modeinfo->startTime = __cpu_to_le32(info->p2p_ps.start); -+ modeinfo->duration = __cpu_to_le32(info->p2p_ps.duration); -+ modeinfo->interval = __cpu_to_le32(info->p2p_ps.interval); -+ modeinfo->dtimCount = 1; -+ modeinfo->reserved = 0; -+ } else { -+ modeinfo->dtimCount = 0; -+ modeinfo->startTime = 0; -+ modeinfo->reserved = 0; -+ modeinfo->duration = 0; -+ modeinfo->interval = 0; -+ } -+ -+#if defined(CONFIG_XRADIO_DEBUG) -+ print_hex_dump_bytes("p2p_set_ps_modeinfo: ", DUMP_PREFIX_NONE, -+ (u8 *)modeinfo, sizeof(*modeinfo)); -+#endif /* CONFIG_XRADIO_DEBUG */ -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA || -+ priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ WARN_ON(wsm_set_p2p_ps_modeinfo(hw_priv, modeinfo, priv->if_id)); -+ } -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ /* Temporary solution while firmware don't support NOA change -+ * notification yet */ -+ xradio_notify_noa(priv, 10); -+#endif -+ } -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+#endif -+ mutex_unlock(&hw_priv->conf_mutex); -+} -+ -+void xradio_multicast_start_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, multicast_start_work); -+ long tmo = priv->join_dtim_period * (priv->beacon_int + 20) * HZ / 1024; -+ -+ cancel_work_sync(&priv->multicast_stop_work); -+ if (!priv->aid0_bit_set) { -+ wsm_lock_tx(priv->hw_priv); -+ xradio_set_tim_impl(priv, true); -+ priv->aid0_bit_set = true; -+ mod_timer(&priv->mcast_timeout, jiffies + tmo); -+ wsm_unlock_tx(priv->hw_priv); -+ } -+} -+ -+void xradio_multicast_stop_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, multicast_stop_work); -+ -+ if (priv->aid0_bit_set) { -+ del_timer_sync(&priv->mcast_timeout); -+ wsm_lock_tx(priv->hw_priv); -+ priv->aid0_bit_set = false; -+ xradio_set_tim_impl(priv, false); -+ wsm_unlock_tx(priv->hw_priv); -+ } -+} -+ -+void xradio_mcast_timeout(struct timer_list *t) -+{ -+ struct xradio_vif *priv = from_timer(priv, t, mcast_timeout); -+ -+ ap_printk(XRADIO_DBG_WARN, "Multicast delivery timeout.\n"); -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->tx_multicast = priv->aid0_bit_set && priv->buffered_multicasts; -+ if (priv->tx_multicast) -+ xradio_bh_wakeup(xrwl_vifpriv_to_hwpriv(priv)); -+ spin_unlock_bh(&priv->ps_state_lock); -+} -+ -+int xradio_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_ampdu_params *params) -+{ -+ /* Aggregation is implemented fully in firmware, -+ * including block ack negotiation. -+ * In case of AMPDU aggregation in RX direction -+ * re-ordering of packets takes place on host. mac80211 -+ * needs the ADDBA Request to setup reodering.mac80211 also -+ * sends ADDBA Response which is discarded in the driver as -+ * FW generates the ADDBA Response on its own.*/ -+ int ret; -+ -+ switch (params->action) { -+ case IEEE80211_AMPDU_RX_START: -+ case IEEE80211_AMPDU_RX_STOP: -+ /* Just return OK to mac80211 */ -+ ret = 0; -+ break; -+ default: -+ ret = -ENOTSUPP; -+ } -+ return ret; -+} -+ -+/* ******************************************************************** */ -+/* WSM callback */ -+void xradio_suspend_resume(struct xradio_vif *priv, struct wsm_suspend_resume *arg) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+#if 0 -+ ap_printk(XRADIO_DBG_MSG, "[AP] %s: %s\n", -+ arg->stop ? "stop" : "start", -+ arg->multicast ? "broadcast" : "unicast"); -+#endif -+ if (arg->multicast) { -+ bool cancel_tmo = false; -+ spin_lock_bh(&priv->ps_state_lock); -+ if (arg->stop) { -+ priv->tx_multicast = false; -+ } else { -+ /* Firmware sends this indication every DTIM if there -+ * is a STA in powersave connected. There is no reason -+ * to suspend, following wakeup will consume much more -+ * power than it could be saved. */ -+ xradio_pm_stay_awake(&hw_priv->pm_state, (priv->join_dtim_period * -+ (priv->beacon_int + 20) * HZ / 1024)); -+ priv->tx_multicast = priv->aid0_bit_set && priv->buffered_multicasts; -+ if (priv->tx_multicast) { -+ cancel_tmo = true; -+ xradio_bh_wakeup(hw_priv); -+ } -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ if (cancel_tmo) -+ del_timer_sync(&priv->mcast_timeout); -+ } else { -+ spin_lock_bh(&priv->ps_state_lock); -+ xradio_ps_notify(priv, arg->link_id, arg->stop); -+ spin_unlock_bh(&priv->ps_state_lock); -+ if (!arg->stop) -+ xradio_bh_wakeup(hw_priv); -+ } -+ return; -+} -+ -+/* ******************************************************************** */ -+/* AP privates */ -+ -+static int xradio_upload_beacon(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_BEACON, -+ }; -+ struct ieee80211_mgmt *mgmt; -+ u8 *erp_inf, *ies, *ht_oper; -+ u32 ies_len; -+ -+ if (priv->vif->p2p || hw_priv->channel->band == NL80211_BAND_5GHZ) -+ frame.rate = WSM_TRANSMIT_RATE_6; -+ -+ frame.skb = ieee80211_beacon_get(priv->hw, priv->vif); -+ if (WARN_ON(!frame.skb)) -+ return -ENOMEM; -+ -+ mgmt = (void *)frame.skb->data; -+ ies = mgmt->u.beacon.variable; -+ ies_len = frame.skb->len - (u32)(ies - (u8 *)mgmt); -+ -+ ht_oper = (u8 *)cfg80211_find_ie( WLAN_EID_HT_OPERATION, ies, ies_len); -+ if (ht_oper) { -+ /* Enable RIFS*/ -+ ht_oper[3] |= 8; -+ } -+ -+ erp_inf = (u8 *)cfg80211_find_ie(WLAN_EID_ERP_INFO, ies, ies_len); -+ if (erp_inf) { -+ if (erp_inf[ERP_INFO_BYTE_OFFSET] -+ & WLAN_ERP_BARKER_PREAMBLE) -+ priv->erp_info |= WLAN_ERP_BARKER_PREAMBLE; -+ else -+ priv->erp_info &= ~WLAN_ERP_BARKER_PREAMBLE; -+ -+ if (erp_inf[ERP_INFO_BYTE_OFFSET] -+ & WLAN_ERP_NON_ERP_PRESENT) { -+ priv->erp_info |= WLAN_ERP_USE_PROTECTION; -+ priv->erp_info |= WLAN_ERP_NON_ERP_PRESENT; -+ } else { -+ priv->erp_info &= ~WLAN_ERP_USE_PROTECTION; -+ priv->erp_info &= ~WLAN_ERP_NON_ERP_PRESENT; -+ } -+ } -+ -+#ifdef HIDDEN_SSID -+ if (priv->hidden_ssid) { -+ u8 *ssid_ie; -+ u8 ssid_len; -+ -+ ap_printk(XRADIO_DBG_NIY, "%s: hidden_ssid set\n", __func__); -+ ssid_ie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len); -+ WARN_ON(!ssid_ie); -+ ssid_len = ssid_ie[1]; -+ if (ssid_len) { -+ ap_printk(XRADIO_DBG_MSG, "hidden_ssid with zero content ssid\n"); -+ ssid_ie[1] = 0; -+ memmove(ssid_ie + 2, ssid_ie + 2 + ssid_len, -+ (ies + ies_len - -+ (ssid_ie + 2 + ssid_len))); -+ frame.skb->len -= ssid_len; -+ } else { -+ ap_printk(XRADIO_DBG_WARN, "hidden ssid with ssid len 0 not supported"); -+ dev_kfree_skb(frame.skb); -+ return -1; -+ } -+ } -+#endif -+ -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ if (!ret) { -+#ifdef PROBE_RESP_EXTRA_IE -+ ret = xradio_upload_proberesp(priv); -+#else -+ /* TODO: Distille probe resp; remove TIM -+ * and other beacon-specific IEs */ -+ *(__le16 *)frame.skb->data = __cpu_to_le16( -+ IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); -+ frame.frame_type = WSM_FRAME_TYPE_PROBE_RESPONSE; -+ /* TODO: Ideally probe response template should separately -+ configured by supplicant through openmac. This is a -+ temporary work-around known to fail p2p group info -+ attribute related tests -+ */ -+ if (0 /* priv->vif->p2p */) -+ ret = wsm_set_probe_responder(priv, true); -+ else { -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ WARN_ON(wsm_set_probe_responder(priv, false)); -+ } -+#endif -+ } -+ dev_kfree_skb(frame.skb); -+ -+ return ret; -+} -+ -+#ifdef PROBE_RESP_EXTRA_IE -+static int xradio_upload_proberesp(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PROBE_RESPONSE, -+ }; -+#ifdef HIDDEN_SSID -+ u8 *ssid_ie; -+#endif -+ -+ if (priv->vif->p2p || hw_priv->channel->band == NL80211_BAND_5GHZ) -+ frame.rate = WSM_TRANSMIT_RATE_6; -+ -+ frame.skb = ieee80211_proberesp_get(priv->hw, priv->vif); -+ if (WARN_ON(!frame.skb)) -+ return -ENOMEM; -+ -+#ifdef HIDDEN_SSID -+ if (priv->hidden_ssid) { -+ int offset; -+ u8 ssid_len; -+ /* we are assuming beacon from upper layer will always contain -+ zero filled ssid for hidden ap. The beacon shall never have -+ ssid len = 0. -+ */ -+ -+ offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); -+ ssid_ie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, frame.skb->data + offset, -+ frame.skb->len - offset); -+ ssid_len = ssid_ie[1]; -+ if (ssid_len && (ssid_len == priv->ssid_length)) { -+ memcpy(ssid_ie + 2, priv->ssid, ssid_len); -+ } else { -+ ap_printk(XRADIO_DBG_ERROR, "%s: hidden ssid with mismatched ssid_len %d\n", -+ __func__, ssid_len); -+ dev_kfree_skb(frame.skb); -+ return -1; -+ } -+ } -+#endif -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ WARN_ON(wsm_set_probe_responder(priv, false)); -+ -+ dev_kfree_skb(frame.skb); -+ -+ return ret; -+} -+#endif -+ -+static int xradio_upload_pspoll(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PS_POLL, -+ .rate = 0xFF, -+ }; -+ -+ frame.skb = ieee80211_pspoll_get(priv->hw, priv->vif); -+ if (WARN_ON(!frame.skb)) -+ return -ENOMEM; -+ ret = wsm_set_template_frame(xrwl_vifpriv_to_hwpriv(priv), &frame, priv->if_id); -+ dev_kfree_skb(frame.skb); -+ return ret; -+} -+ -+static int xradio_upload_null(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_NULL, -+ .rate = 0xFF, -+ }; -+ -+ frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false); -+ if (WARN_ON(!frame.skb)) -+ return -ENOMEM; -+ -+ ret = wsm_set_template_frame(xrwl_vifpriv_to_hwpriv(priv), &frame, priv->if_id); -+ dev_kfree_skb(frame.skb); -+ return ret; -+} -+ -+static int xradio_upload_qosnull(struct xradio_vif *priv) -+{ -+ struct ieee80211_qos_hdr* qos_null_template; -+ struct sk_buff* skb; -+ int ret = 0; -+ struct xradio_common *hw_priv =xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_QOS_NULL, -+ .rate = 0xFF, -+ }; -+ if (!hw_priv) -+ ap_printk(XRADIO_DBG_ERROR,"%s: Cannot find xradio_common pointer!\n",__FUNCTION__); -+ /*set qos template*/ -+ skb = dev_alloc_skb(hw_priv->hw->extra_tx_headroom + sizeof(struct ieee80211_qos_hdr)); -+ if (!skb) { -+ ap_printk(XRADIO_DBG_ERROR,"%s: failed to allocate buffer for qos nullfunc template!\n",__FUNCTION__); -+ return -1; -+ } -+ skb_reserve(skb, hw_priv->hw->extra_tx_headroom); -+ qos_null_template = (struct ieee80211_qos_hdr *)skb_put(skb,sizeof(struct ieee80211_qos_hdr)); -+ memset(qos_null_template, 0, sizeof(struct ieee80211_qos_hdr)); -+ memcpy(qos_null_template->addr1, priv->vif->bss_conf.bssid, ETH_ALEN); -+ memcpy(qos_null_template->addr2, priv->vif->addr, ETH_ALEN); -+ memcpy(qos_null_template->addr3, priv->vif->bss_conf.bssid, ETH_ALEN); -+ qos_null_template->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | -+ IEEE80211_STYPE_QOS_NULLFUNC | -+ IEEE80211_FCTL_TODS); -+ frame.skb = skb; -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ dev_kfree_skb(frame.skb); -+ return ret; -+} -+ -+/* This API is nolonegr present in WSC */ -+#if 0 -+static int xradio_enable_beaconing(struct xradio_vif *priv, -+ bool enable) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_beacon_transmit transmit = { -+ .enableBeaconing = enable, -+ }; -+ -+ return wsm_beacon_transmit(hw_priv, &transmit, priv->if_id); -+} -+#endif -+ -+static int xradio_start_ap(struct xradio_vif *priv) -+{ -+ int ret; -+#ifndef HIDDEN_SSID -+ const u8 *ssidie; -+ struct sk_buff *skb; -+ int offset; -+#endif -+ struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_start start = { -+ .mode = priv->vif->p2p ? WSM_START_MODE_P2P_GO : WSM_START_MODE_AP, -+ /* TODO:COMBO:Change once mac80211 support is available */ -+ .band = (hw_priv->channel->band == NL80211_BAND_5GHZ) ? -+ WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G, -+ .channelNumber = hw_priv->channel->hw_value, -+ .beaconInterval = conf->beacon_int, -+ .DTIMPeriod = conf->dtim_period, -+ .preambleType = conf->use_short_preamble ? -+ WSM_JOIN_PREAMBLE_SHORT :WSM_JOIN_PREAMBLE_LONG, -+ .probeDelay = 100, -+ .basicRateSet = xradio_rate_mask_to_wsm(hw_priv, conf->basic_rates), -+ }; -+ -+#ifdef TES_P2P_000B_EXTEND_INACTIVITY_CNT -+ ///w, TES_P2P_000B WorkAround: -+ ///w, when inactivity count of a peer device is zero, -+ ///w, which will reset while receiving a peer device frame, -+ ///w, firmware will disconnect with it. -+ ///w, due to some reason, such as scan/phy error, we miss these frame. -+ ///w, then we can't keep connection with peer device. -+ ///w, we set the min_inactivity value to large as WorkAround. -+ //min_inactivity be modified to 20, yangfh. -+ struct wsm_inactivity inactivity = { -+ .min_inactivity = 20, -+ .max_inactivity = 10, -+ }; -+#else -+ struct wsm_inactivity inactivity = { -+ .min_inactivity = 9, -+ .max_inactivity = 1, -+ }; -+#endif -+ -+ ap_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ -+ if (priv->if_id) -+ start.mode |= WSM_FLAG_MAC_INSTANCE_1; -+ else -+ start.mode &= ~WSM_FLAG_MAC_INSTANCE_1; -+ -+ hw_priv->connected_sta_cnt = 0; -+ -+#ifndef HIDDEN_SSID -+ /* Get SSID */ -+ skb = ieee80211_beacon_get(priv->hw, priv->vif); -+ if (WARN_ON(!skb)) { -+ ap_printk(XRADIO_DBG_ERROR,"%s, ieee80211_beacon_get failed\n", __func__); -+ return -ENOMEM; -+ } -+ -+ offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); -+ ssidie = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset, skb->len - offset); -+ -+ memset(priv->ssid, 0, sizeof(priv->ssid)); -+ if (ssidie) { -+ priv->ssid_length = ssidie[1]; -+ if (WARN_ON(priv->ssid_length > sizeof(priv->ssid))) -+ priv->ssid_length = sizeof(priv->ssid); -+ memcpy(priv->ssid, &ssidie[2], priv->ssid_length); -+ } else { -+ priv->ssid_length = 0; -+ } -+ dev_kfree_skb(skb); -+#endif -+ -+ priv->beacon_int = conf->beacon_int; -+ priv->join_dtim_period = conf->dtim_period; -+ memset(&priv->last_tim[0], 0, sizeof(priv->last_tim)); //yangfh -+ -+ start.ssidLength = priv->ssid_length; -+ memcpy(&start.ssid[0], priv->ssid, start.ssidLength); -+ -+ memset(&priv->link_id_db, 0, sizeof(priv->link_id_db)); -+ -+ ap_printk(XRADIO_DBG_NIY, "[AP] ch: %d(%d), bcn: %d(%d)," -+ "bss_rate: 0x%.8X, ssid: %.*s.\n", -+ start.channelNumber, start.band, -+ start.beaconInterval, start.DTIMPeriod, -+ start.basicRateSet, start.ssidLength, start.ssid); -+ ret = WARN_ON(wsm_start(hw_priv, &start, priv->if_id)); -+ -+ if (!ret && priv->vif->p2p) { -+ ap_printk(XRADIO_DBG_NIY,"[AP] Setting p2p powersave configuration.\n"); -+ WARN_ON(wsm_set_p2p_ps_modeinfo(hw_priv, -+ &priv->p2p_ps_modeinfo, priv->if_id)); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //xradio_notify_noa(priv, XRADIO_NOA_NOTIFICATION_DELAY); -+#endif -+ } -+ -+ /*Set Inactivity time*/ -+ if(!(strstr(&start.ssid[0], "6.1.12"))) { -+ wsm_set_inactivity(hw_priv, &inactivity, priv->if_id); -+ } -+ if (!ret) { -+#ifndef AP_AGGREGATE_FW_FIX -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_DISABLED_FOR_ALL_TID, -+ XRADIO_RX_BLOCK_ACK_DISABLED_FOR_ALL_TID, priv->if_id)); -+#else -+ if ((priv->if_id ==1) && !hw_priv->is_go_thru_go_neg) -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID, //modified for WFD by yangfh -+ XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID, priv->if_id)); -+ else -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID, -+ XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID, priv->if_id)); -+#endif -+ priv->join_status = XRADIO_JOIN_STATUS_AP; -+ /* xradio_update_filtering(priv); */ -+ } -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ ap_printk(XRADIO_DBG_WARN, "vif%d, AP/GO mode THROTTLE=%d\n", priv->if_id, -+ priv->if_id==0?hw_priv->vif0_throttle:hw_priv->vif1_throttle); -+ return ret; -+} -+ -+static int xradio_update_beaconing(struct xradio_vif *priv) -+{ -+ struct ieee80211_bss_conf *conf = &priv->vif->bss_conf; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_reset reset = { -+ .link_id = 0, -+ .reset_statistics = true, -+ }; -+ ap_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ -+ if (priv->mode == NL80211_IFTYPE_AP) { -+ /* TODO: check if changed channel, band */ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP || -+ priv->beacon_int != conf->beacon_int) { -+ ap_printk(XRADIO_DBG_WARN, "ap restarting!\n"); -+ wsm_lock_tx(hw_priv); -+ if (priv->join_status != XRADIO_JOIN_STATUS_PASSIVE) -+ WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id)); -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ WARN_ON(xradio_start_ap(priv)); -+ wsm_unlock_tx(hw_priv); -+ } else -+ ap_printk(XRADIO_DBG_NIY, "ap started join_status: %d\n", priv->join_status); -+ } -+ return 0; -+} -+ -+int xradio_find_link_id(struct xradio_vif *priv, const u8 *mac) -+{ -+ int i, ret = 0; -+ spin_lock_bh(&priv->ps_state_lock); -+ for (i = 0; i < MAX_STA_IN_AP_MODE; ++i) { -+ if (!memcmp(mac, priv->link_id_db[i].mac, ETH_ALEN) && -+ priv->link_id_db[i].status) { -+ priv->link_id_db[i].timestamp = jiffies; -+ ret = i + 1; -+ break; -+ } -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ return ret; -+} -+ -+int xradio_alloc_link_id(struct xradio_vif *priv, const u8 *mac) -+{ -+ int i, ret = 0; -+ unsigned long max_inactivity = 0; -+ unsigned long now = jiffies; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ for (i = 0; i < MAX_STA_IN_AP_MODE; ++i) { -+ if (!priv->link_id_db[i].status) { -+ ret = i + 1; -+ break; -+ } else if (priv->link_id_db[i].status != XRADIO_LINK_HARD && -+ !hw_priv->tx_queue_stats.link_map_cache[i + 1]) { -+ unsigned long inactivity = now - priv->link_id_db[i].timestamp; -+ if (inactivity < max_inactivity) -+ continue; -+ max_inactivity = inactivity; -+ ret = i + 1; -+ } -+ } -+ if (ret) { -+ struct xradio_link_entry *entry = &priv->link_id_db[ret - 1]; -+ ap_printk(XRADIO_DBG_NIY, "STA added, link_id: %d\n", ret); -+ entry->status = XRADIO_LINK_RESERVE; -+ memcpy(&entry->mac, mac, ETH_ALEN); -+ memset(&entry->buffered, 0, XRADIO_MAX_TID); -+ skb_queue_head_init(&entry->rx_queue); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->link_id_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } else { -+ ap_printk(XRADIO_DBG_WARN, "Early: no more link IDs available.\n"); -+ } -+ -+ spin_unlock_bh(&priv->ps_state_lock); -+ return ret; -+} -+ -+void xradio_link_id_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = container_of(work, struct xradio_vif, link_id_work); -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ wsm_flush_tx(hw_priv); -+ xradio_link_id_gc_work(&priv->link_id_gc_work.work); -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_link_id_gc_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, link_id_gc_work.work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_map_link map_link = { -+ .link_id = 0, -+ }; -+ unsigned long now = jiffies; -+ unsigned long next_gc = -1; -+ long ttl; -+ bool need_reset; -+ u32 mask; -+ int i; -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP) -+ return; -+ -+ wsm_lock_tx(hw_priv); -+ spin_lock_bh(&priv->ps_state_lock); -+ for (i = 0; i < MAX_STA_IN_AP_MODE; ++i) { -+ need_reset = false; -+ mask = BIT(i + 1); -+ if (priv->link_id_db[i].status == XRADIO_LINK_RESERVE || -+ (priv->link_id_db[i].status == XRADIO_LINK_HARD && -+ !(priv->link_id_map & mask))) { -+ if (priv->link_id_map & mask) { -+ priv->sta_asleep_mask &= ~mask; -+ priv->pspoll_mask &= ~mask; -+ need_reset = true; -+ } -+ priv->link_id_map |= mask; -+ if (priv->link_id_db[i].status != XRADIO_LINK_HARD) -+ priv->link_id_db[i].status = XRADIO_LINK_SOFT; -+ memcpy(map_link.mac_addr, priv->link_id_db[i].mac, ETH_ALEN); -+ spin_unlock_bh(&priv->ps_state_lock); -+ if (need_reset) { -+ WARN_ON(xrwl_unmap_link(priv, i + 1)); -+ } -+ map_link.link_id = i + 1; -+ WARN_ON(wsm_map_link(hw_priv, &map_link, priv->if_id)); -+ next_gc = min(next_gc, XRADIO_LINK_ID_GC_TIMEOUT); -+ spin_lock_bh(&priv->ps_state_lock); -+ } else if (priv->link_id_db[i].status == XRADIO_LINK_SOFT) { -+ ttl = priv->link_id_db[i].timestamp - now + XRADIO_LINK_ID_GC_TIMEOUT; -+ if (ttl <= 0) { -+ need_reset = true; -+ priv->link_id_db[i].status = XRADIO_LINK_OFF; -+ priv->link_id_map &= ~mask; -+ priv->sta_asleep_mask &= ~mask; -+ priv->pspoll_mask &= ~mask; -+ memset(map_link.mac_addr, 0, ETH_ALEN); -+ spin_unlock_bh(&priv->ps_state_lock); -+ WARN_ON(xrwl_unmap_link(priv, i + 1)); -+ spin_lock_bh(&priv->ps_state_lock); -+ } else { -+ next_gc = min_t(unsigned long, next_gc, ttl); -+ } -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ } else if (priv->link_id_db[i].status == XRADIO_LINK_RESET || -+ priv->link_id_db[i].status == XRADIO_LINK_RESET_REMAP) { -+ int status = priv->link_id_db[i].status; -+ priv->link_id_db[i].status = XRADIO_LINK_OFF; -+ priv->link_id_db[i].timestamp = now; -+ spin_unlock_bh(&priv->ps_state_lock); -+ WARN_ON(xrwl_unmap_link(priv, i + 1)); -+ if (status == XRADIO_LINK_RESET_REMAP) { -+ memcpy(map_link.mac_addr, priv->link_id_db[i].mac, ETH_ALEN); -+ map_link.link_id = i + 1; -+ WARN_ON(wsm_map_link(hw_priv, &map_link, priv->if_id)); -+ next_gc = min(next_gc, XRADIO_LINK_ID_GC_TIMEOUT); -+ priv->link_id_db[i].status = priv->link_id_db[i].prev_status; -+ } -+ spin_lock_bh(&priv->ps_state_lock); -+#endif -+ } -+ if (need_reset) { -+ skb_queue_purge(&priv->link_id_db[i].rx_queue); -+ ap_printk(XRADIO_DBG_NIY, "STA removed, link_id: %d\n", i + 1); -+ } -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ if (next_gc != -1) -+ queue_delayed_work(hw_priv->workqueue, &priv->link_id_gc_work, next_gc); -+ wsm_unlock_tx(hw_priv); -+} -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+#if 0 -+void xradio_notify_noa(struct xradio_vif *priv, int delay) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct cfg80211_p2p_ps p2p_ps = {0}; -+ struct wsm_p2p_ps_modeinfo *modeinfo; -+ modeinfo = &priv->p2p_ps_modeinfo; -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP) -+ return; -+ -+ if (delay) -+ msleep(delay); -+ -+ if (!WARN_ON(wsm_get_p2p_ps_modeinfo(hw_priv, modeinfo))) { -+#if defined(CONFIG_XRADIO_DEBUG) -+ print_hex_dump_bytes("[AP] p2p_get_ps_modeinfo: ", DUMP_PREFIX_NONE, -+ (u8 *)modeinfo, sizeof(*modeinfo)); -+#endif /* CONFIG_XRADIO_DEBUG */ -+ p2p_ps.opp_ps = !!(modeinfo->oppPsCTWindow & BIT(7)); -+ p2p_ps.ctwindow = modeinfo->oppPsCTWindow & (~BIT(7)); -+ p2p_ps.count = modeinfo->count; -+ p2p_ps.start = __le32_to_cpu(modeinfo->startTime); -+ p2p_ps.duration = __le32_to_cpu(modeinfo->duration); -+ p2p_ps.interval = __le32_to_cpu(modeinfo->interval); -+ p2p_ps.index = modeinfo->reserved; -+ -+ ieee80211_p2p_noa_notify(priv->vif, &p2p_ps, GFP_KERNEL); -+ } -+} -+#endif -+#endif -+int xrwl_unmap_link(struct xradio_vif *priv, int link_id) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int ret = 0; -+ -+ if (is_hardware_xradio(hw_priv)) { -+ struct wsm_map_link maplink = { -+ .link_id = link_id, -+ .unmap = true, -+ }; -+ if (link_id) -+ memcpy(&maplink.mac_addr[0], priv->link_id_db[link_id - 1].mac, ETH_ALEN); -+ return wsm_map_link(hw_priv, &maplink, priv->if_id); -+ } else { -+ struct wsm_reset reset = { -+ .link_id = link_id, -+ .reset_statistics = true, -+ }; -+ ret = wsm_reset(hw_priv, &reset, priv->if_id); -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ return ret; -+ } -+} -+#ifdef AP_HT_CAP_UPDATE -+void xradio_ht_oper_update_work(struct work_struct *work) -+{ -+ struct sk_buff *skb; -+ struct ieee80211_mgmt *mgmt; -+ u8 *ht_oper, *ies; -+ u32 ies_len; -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, ht_oper_update_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_update_ie update_ie = { -+ .what = WSM_UPDATE_IE_BEACON, -+ .count = 1, -+ }; -+ -+ skb = ieee80211_beacon_get(priv->hw, priv->vif); -+ if (WARN_ON(!skb)) -+ return; -+ -+ mgmt = (void *)skb->data; -+ ies = mgmt->u.beacon.variable; -+ ies_len = skb->len - (u32)(ies - (u8 *)mgmt); -+ ht_oper= (u8 *)cfg80211_find_ie( WLAN_EID_HT_OPERATION, ies, ies_len); -+ if(ht_oper && priv->ht_oper == HT_INFO_MASK) { -+ ht_oper[HT_INFO_OFFSET] |= 0x11; -+ update_ie.ies = ht_oper; -+ update_ie.length = HT_INFO_IE_LEN; -+ WARN_ON(wsm_update_ie(hw_priv, &update_ie, priv->if_id)); -+ } -+ dev_kfree_skb(skb); -+} -+#endif -diff --git a/drivers/net/wireless/xradio/ap.h b/drivers/net/wireless/xradio/ap.h -new file mode 100644 -index 0000000..9d55fb8 ---- /dev/null -+++ b/drivers/net/wireless/xradio/ap.h -@@ -0,0 +1,63 @@ -+/* -+ * STA and AP APIs for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef AP_H_INCLUDED -+#define AP_H_INCLUDED -+ -+#define XRADIO_NOA_NOTIFICATION_DELAY 10 -+ -+#ifdef AP_HT_CAP_UPDATE -+#define HT_INFO_OFFSET 4 -+#define HT_INFO_MASK 0x0011 -+#define HT_INFO_IE_LEN 22 -+#endif -+ -+int xradio_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, -+ bool set); -+int xradio_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta); -+int xradio_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta); -+void xradio_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, -+ enum sta_notify_cmd notify_cmd, -+ struct ieee80211_sta *sta); -+void xradio_bss_info_changed(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ struct ieee80211_bss_conf *info, -+ u32 changed); -+int xradio_ampdu_action(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_ampdu_params *params); -+/* enum ieee80211_ampdu_mlme_action action, -+ struct ieee80211_sta *sta, u16 tid, u16 *ssn, -+ u8 buf_size);*/ -+ -+void xradio_suspend_resume(struct xradio_vif *priv, -+ struct wsm_suspend_resume *arg); -+void xradio_set_tim_work(struct work_struct *work); -+void xradio_set_cts_work(struct work_struct *work); -+void xradio_multicast_start_work(struct work_struct *work); -+void xradio_multicast_stop_work(struct work_struct *work); -+void xradio_mcast_timeout(struct timer_list *t); -+int xradio_find_link_id(struct xradio_vif *priv, const u8 *mac); -+int xradio_alloc_link_id(struct xradio_vif *priv, const u8 *mac); -+void xradio_link_id_work(struct work_struct *work); -+void xradio_link_id_gc_work(struct work_struct *work); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+/*in linux3.4 mac,it does't have the noa pass*/ -+//void xradio_notify_noa(struct xradio_vif *priv, int delay); -+#endif -+int xrwl_unmap_link(struct xradio_vif *priv, int link_id); -+#ifdef AP_HT_CAP_UPDATE -+void xradio_ht_oper_update_work(struct work_struct *work); -+#endif -+ -+#endif -diff --git a/drivers/net/wireless/xradio/bh.c b/drivers/net/wireless/xradio/bh.c -new file mode 100644 -index 0000000..5b53778 ---- /dev/null -+++ b/drivers/net/wireless/xradio/bh.c -@@ -0,0 +1,836 @@ -+/* -+ * Data Transmission thread implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include "xradio.h" -+#include "bh.h" -+#include "hwio.h" -+#include "wsm.h" -+#include "sdio.h" -+ -+/* TODO: Verify these numbers with WSM specification. */ -+#define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4) -+/* an SPI message cannot be bigger than (2"12-1)*2 bytes -+ * "*2" to cvt to bytes */ -+#define MAX_SZ_RD_WR_BUFFERS (DOWNLOAD_BLOCK_SIZE_WR*2) -+#define PIGGYBACK_CTRL_REG (2) -+#define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG) -+ -+/* Suspend state privates */ -+enum xradio_bh_pm_state { -+ XRADIO_BH_RESUMED = 0, -+ XRADIO_BH_SUSPEND, -+ XRADIO_BH_SUSPENDED, -+ XRADIO_BH_RESUME, -+}; -+typedef int (*xradio_wsm_handler)(struct xradio_common *hw_priv, u8 *data, size_t size); -+ -+#ifdef MCAST_FWDING -+int wsm_release_buffer_to_fw(struct xradio_vif *priv, int count); -+#endif -+static int xradio_bh(void *arg); -+ -+int xradio_register_bh(struct xradio_common *hw_priv) -+{ -+ int ret = 0; -+ -+ atomic_set(&hw_priv->bh_tx, 0); -+ atomic_set(&hw_priv->bh_term, 0); -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUMED); -+ hw_priv->buf_id_tx = 0; -+ hw_priv->buf_id_rx = 0; -+ init_waitqueue_head(&hw_priv->bh_wq); -+ init_waitqueue_head(&hw_priv->bh_evt_wq); -+ -+ hw_priv->bh_thread = kthread_run(&xradio_bh, hw_priv, XRADIO_BH_THREAD); -+ if (IS_ERR(hw_priv->bh_thread)) { -+ ret = PTR_ERR(hw_priv->bh_thread); -+ hw_priv->bh_thread = NULL; -+ } -+ -+ return ret; -+} -+ -+void xradio_unregister_bh(struct xradio_common *hw_priv) -+{ -+ struct task_struct *thread = hw_priv->bh_thread; -+ -+ if (WARN_ON(!thread)) -+ return; -+ -+ hw_priv->bh_thread = NULL; -+ kthread_stop(thread); -+#ifdef HAS_PUT_TASK_STRUCT -+ put_task_struct(thread); -+#endif -+ dev_dbg(hw_priv->pdev, "Unregister success.\n"); -+} -+ -+void xradio_irq_handler(struct xradio_common *hw_priv) -+{ -+ xradio_bh_wakeup(hw_priv); -+} -+ -+void xradio_bh_wakeup(struct xradio_common *hw_priv) -+{ -+ atomic_set(&hw_priv->bh_tx, 1); -+ wake_up(&hw_priv->bh_wq); -+} -+ -+int xradio_bh_suspend(struct xradio_common *hw_priv) -+{ -+#ifdef MCAST_FWDING -+ int i =0; -+ struct xradio_vif *priv = NULL; -+#endif -+ -+ if (hw_priv->bh_error) { -+ return -EINVAL; -+ } -+ -+#ifdef MCAST_FWDING -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ if ( (priv->multicast_filter.enable) -+ && (priv->join_status == XRADIO_JOIN_STATUS_AP) ) { -+ wsm_release_buffer_to_fw(priv, -+ (hw_priv->wsm_caps.numInpChBufs - 1)); -+ break; -+ } -+ } -+#endif -+ -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_SUSPEND); -+ wake_up(&hw_priv->bh_wq); -+ return wait_event_timeout(hw_priv->bh_evt_wq, (hw_priv->bh_error || -+ XRADIO_BH_SUSPENDED == atomic_read(&hw_priv->bh_suspend)), -+ 1 * HZ)? 0 : -ETIMEDOUT; -+} -+ -+int xradio_bh_resume(struct xradio_common *hw_priv) -+{ -+#ifdef MCAST_FWDING -+ int ret; -+ int i =0; -+ struct xradio_vif *priv =NULL; -+#endif -+ -+ -+ if (hw_priv->bh_error) { -+ return -EINVAL; -+ } -+ -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUME); -+ wake_up(&hw_priv->bh_wq); -+ -+#ifdef MCAST_FWDING -+ ret = wait_event_timeout(hw_priv->bh_evt_wq, (hw_priv->bh_error || -+ XRADIO_BH_RESUMED == atomic_read(&hw_priv->bh_suspend)) -+ ,1 * HZ)? 0 : -ETIMEDOUT; -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ if ((priv->join_status == XRADIO_JOIN_STATUS_AP) && -+ (priv->multicast_filter.enable)) { -+ u8 count = 0; -+ WARN_ON(wsm_request_buffer_request(priv, &count)); -+ dev_dbg(hw_priv->pdev, "Reclaim Buff %d \n",count); -+ break; -+ } -+ } -+ -+ return ret; -+#else -+ return wait_event_timeout(hw_priv->bh_evt_wq,hw_priv->bh_error || -+ (XRADIO_BH_RESUMED == atomic_read(&hw_priv->bh_suspend)), -+ 1 * HZ) ? 0 : -ETIMEDOUT; -+#endif -+ -+} -+ -+static inline void wsm_alloc_tx_buffer(struct xradio_common *hw_priv) -+{ -+ ++hw_priv->hw_bufs_used; -+} -+ -+int wsm_release_tx_buffer(struct xradio_common *hw_priv, int count) -+{ -+ int ret = 0; -+ int hw_bufs_used = hw_priv->hw_bufs_used; -+ -+ hw_priv->hw_bufs_used -= count; -+ if (WARN_ON(hw_priv->hw_bufs_used < 0)) { -+ /* Tx data patch stops when all but one hw buffers are used. -+ So, re-start tx path in case we find hw_bufs_used equals -+ numInputChBufs - 1. -+ */ -+ dev_err(hw_priv->pdev, "hw_bufs_used=%d, count=%d.\n", -+ hw_priv->hw_bufs_used, count); -+ ret = -1; -+ } else if (hw_bufs_used >= (hw_priv->wsm_caps.numInpChBufs - 1)) -+ ret = 1; -+ if (!hw_priv->hw_bufs_used) -+ wake_up(&hw_priv->bh_evt_wq); -+ return ret; -+} -+ -+int wsm_release_vif_tx_buffer(struct xradio_common *hw_priv, int if_id, int count) -+{ -+ int ret = 0; -+ -+ hw_priv->hw_bufs_used_vif[if_id] -= count; -+ if (!hw_priv->hw_bufs_used_vif[if_id]) -+ wake_up(&hw_priv->bh_evt_wq); -+ -+ if (WARN_ON(hw_priv->hw_bufs_used_vif[if_id] < 0)) -+ ret = -1; -+ return ret; -+} -+#ifdef MCAST_FWDING -+int wsm_release_buffer_to_fw(struct xradio_vif *priv, int count) -+{ -+ int i; -+ u8 flags; -+ struct wsm_buf *buf; -+ size_t buf_len; -+ struct wsm_hdr *wsm; -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP) { -+ return 0; -+ } -+ dev_dbg(hw_priv->pdev, "Rel buffer to FW %d, %d\n", count, hw_priv->hw_bufs_used); -+ -+ for (i = 0; i < count; i++) { -+ if ((hw_priv->hw_bufs_used + 1) < hw_priv->wsm_caps.numInpChBufs) { -+ flags = i ? 0: 0x1; -+ -+ wsm_alloc_tx_buffer(hw_priv); -+ buf = &hw_priv->wsm_release_buf[i]; -+ buf_len = buf->data - buf->begin; -+ -+ /* Add sequence number */ -+ wsm = (struct wsm_hdr *)buf->begin; -+ BUG_ON(buf_len < sizeof(*wsm)); -+ -+ wsm->id &= __cpu_to_le32(~WSM_TX_SEQ(WSM_TX_SEQ_MAX)); -+ wsm->id |= cpu_to_le32(WSM_TX_SEQ(hw_priv->wsm_tx_seq)); -+ -+ dev_dbg(hw_priv->pdev, "REL %d\n", hw_priv->wsm_tx_seq); -+ if (WARN_ON(xradio_data_write(hw_priv, buf->begin, buf_len))) { -+ break; -+ } -+ hw_priv->buf_released = 1; -+ hw_priv->wsm_tx_seq = (hw_priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; -+ } else -+ break; -+ } -+ -+ if (i == count) { -+ return 0; -+ } -+ -+ /* Should not be here */ -+ dev_dbg(hw_priv->pdev, "Error, Less HW buf %d,%d.\n", -+ hw_priv->hw_bufs_used, hw_priv->wsm_caps.numInpChBufs); -+ WARN_ON(1); -+ return -1; -+} -+#endif -+ -+/* reserve a packet for the case dev_alloc_skb failed in bh.*/ -+int xradio_init_resv_skb(struct xradio_common *hw_priv) -+{ -+ int len = (SDIO_BLOCK_SIZE<<2) + WSM_TX_EXTRA_HEADROOM + \ -+ 8 + 12; /* TKIP IV + ICV and MIC */ -+ -+ hw_priv->skb_reserved = dev_alloc_skb(len); -+ if (hw_priv->skb_reserved) { -+ hw_priv->skb_resv_len = len; -+ } else { -+ dev_warn(hw_priv->pdev, "xr_alloc_skb failed(%d)\n", len); -+ } -+ return 0; -+} -+ -+void xradio_deinit_resv_skb(struct xradio_common *hw_priv) -+{ -+ if (hw_priv->skb_reserved) { -+ dev_kfree_skb(hw_priv->skb_reserved); -+ hw_priv->skb_reserved = NULL; -+ hw_priv->skb_resv_len = 0; -+ } -+} -+ -+int xradio_realloc_resv_skb(struct xradio_common *hw_priv, -+ struct sk_buff *skb) -+{ -+ if (!hw_priv->skb_reserved && hw_priv->skb_resv_len) { -+ hw_priv->skb_reserved = dev_alloc_skb(hw_priv->skb_resv_len); -+ if (!hw_priv->skb_reserved) { -+ hw_priv->skb_reserved = skb; -+ dev_warn(hw_priv->pdev, "xr_alloc_skb failed(%d)\n", -+ hw_priv->skb_resv_len); -+ return -1; -+ } -+ } -+ return 0; /* realloc sbk success, deliver to upper.*/ -+} -+ -+static inline struct sk_buff *xradio_get_resv_skb(struct xradio_common *hw_priv, -+ size_t len) -+{ struct sk_buff *skb = NULL; -+ if (hw_priv->skb_reserved && len <= hw_priv->skb_resv_len) { -+ skb = hw_priv->skb_reserved; -+ hw_priv->skb_reserved = NULL; -+ } -+ return skb; -+} -+ -+static inline int xradio_put_resv_skb(struct xradio_common *hw_priv, -+ struct sk_buff *skb) -+{ -+ if (!hw_priv->skb_reserved && hw_priv->skb_resv_len) { -+ hw_priv->skb_reserved = skb; -+ return 0; -+ } -+ return 1; /* sbk not put to reserve*/ -+} -+ -+static struct sk_buff *xradio_get_skb(struct xradio_common *hw_priv, size_t len) -+{ -+ struct sk_buff *skb = NULL; -+ size_t alloc_len = (len > SDIO_BLOCK_SIZE) ? len : SDIO_BLOCK_SIZE; -+ -+ /* TKIP IV + TKIP ICV and MIC - Piggyback.*/ -+ alloc_len += WSM_TX_EXTRA_HEADROOM + 8 + 12- 2; -+ if (len > SDIO_BLOCK_SIZE || !hw_priv->skb_cache) { -+ skb = dev_alloc_skb(alloc_len); -+ /* In AP mode RXed SKB can be looped back as a broadcast. -+ * Here we reserve enough space for headers. */ -+ if (skb) { -+ skb_reserve(skb, WSM_TX_EXTRA_HEADROOM + 8 /* TKIP IV */ -+ - WSM_RX_EXTRA_HEADROOM); -+ } else { -+ skb = xradio_get_resv_skb(hw_priv, alloc_len); -+ if (skb) { -+ dev_dbg(hw_priv->pdev, "get skb_reserved(%d)!\n", alloc_len); -+ skb_reserve(skb, WSM_TX_EXTRA_HEADROOM + 8 /* TKIP IV */ -+ - WSM_RX_EXTRA_HEADROOM); -+ } else { -+ dev_dbg(hw_priv->pdev, "xr_alloc_skb failed(%d)!\n", alloc_len); -+ } -+ } -+ } else { -+ skb = hw_priv->skb_cache; -+ hw_priv->skb_cache = NULL; -+ } -+ return skb; -+} -+ -+static void xradio_put_skb(struct xradio_common *hw_priv, struct sk_buff *skb) -+{ -+ if (hw_priv->skb_cache) -+ dev_kfree_skb(skb); -+ else -+ hw_priv->skb_cache = skb; -+} -+ -+static int xradio_bh_read_ctrl_reg(struct xradio_common *hw_priv, -+ u16 *ctrl_reg) -+{ -+ int ret; -+ ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, ctrl_reg); -+ if (ret) { -+ ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, ctrl_reg); -+ if (ret) { -+ hw_priv->bh_error = 1; -+ dev_err(hw_priv->pdev, "Failed to read control register.\n"); -+ } -+ } -+ -+ return ret; -+} -+ -+static int xradio_device_wakeup(struct xradio_common *hw_priv) -+{ -+ u16 ctrl_reg; -+ int ret, i=0; -+ -+ /* To force the device to be always-on, the host sets WLAN_UP to 1 */ -+ ret = xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, HIF_CTRL_WUP_BIT); -+ if (WARN_ON(ret)) -+ return ret; -+ -+ ret = xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg); -+ if (WARN_ON(ret)) -+ return ret; -+ -+ /* If the device returns WLAN_RDY as 1, the device is active and will -+ * remain active. */ -+ while (!(ctrl_reg & HIF_CTRL_RDY_BIT) && i < 500) { -+ ret = xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg); -+ msleep(1); -+ i++; -+ } -+ if (unlikely(i >= 500)) { -+ dev_err(hw_priv->pdev, "Device cannot wakeup.\n"); -+ return -1; -+ } else if (unlikely(i >= 50)) -+ dev_warn(hw_priv->pdev, "Device wakeup time=%dms.\n", i); -+ dev_dbg(hw_priv->pdev, "Device awake, t=%dms.\n", i); -+ return 1; -+} -+ -+/* Must be called from BH thraed. */ -+void xradio_enable_powersave(struct xradio_vif *priv, -+ bool enable) -+{ -+ priv->powersave_enabled = enable; -+} -+ -+static void xradio_bh_rx_dump(struct device *dev, u8 *data, size_t len){ -+#ifdef DEBUG -+ static const char *msgnames[0xffff] = { -+ // 0x4?? is a sync response to a command -+ [0x0404] = "tx confirm", -+ [0x0406] = "mib confirm", -+ [0x0407] = "scan started", -+ [0x0409] = "configuration confirm", -+ [0x040a] = "reset confirm", -+ [0x040b] = "join confirm", -+ [0x040c] = "key added", -+ [0x040d] = "key removed", -+ [0x0410] = "pm confirm", -+ [0x0411] = "set bss params", -+ [0x0412] = "tx queue params", -+ [0x0413] = "edca confirm", -+ [0x0417] = "start confirm", -+ [0x041b] = "update ie confirm", -+ [0x041c] = "map link confirm", -+ // 0x8?? seem to be async responses or events -+ [0x0801] = "firmware startup complete", -+ [0x0804] = "rx", -+ [0x0805] = "event", -+ [0x0806] = "scan complete", -+ [0x0810] = "set pm indication" -+ }; -+ -+ u16 msgid, ifid; -+ u16 *p = (u16 *)data; -+ msgid = (*(p + 1)) & 0xC3F; -+ ifid = (*(p + 1)) >> 6; -+ ifid &= 0xF; -+ const char *msgname = msgnames[msgid]; -+ if(msgid == 0x804 && ifid == 2){ -+ msgname = "scan result"; -+ } -+ -+ dev_dbg(dev, "vif %d: sdio rx, msgid %s(0x%.4X) len %d\n", -+ ifid, msgname, msgid, *p); -+// print_hex_dump_bytes("<-- ", DUMP_PREFIX_NONE, -+// data, min(len, (size_t) 64)); -+#endif -+} -+ -+#define READLEN(ctrl) ((ctrl & HIF_CTRL_NEXT_LEN_MASK) << 1) //read_len=ctrl_reg*2. -+ -+static int xradio_bh_rx_availlen(struct xradio_common *hw_priv){ -+ u16 ctrl_reg = 0; -+ if (xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg)) { -+ return -EIO; -+ } -+ return READLEN(ctrl_reg); -+} -+ -+static int xradio_bh_rx(struct xradio_common *hw_priv, u16* nextlen) { -+ size_t read_len = 0; -+ struct sk_buff *skb_rx = NULL; -+ struct wsm_hdr *wsm; -+ size_t wsm_len; -+ int wsm_id; -+ u8 wsm_seq; -+ size_t alloc_len; -+ u8 *data; -+ int ret; -+ -+ read_len = *nextlen > 0 ? *nextlen : xradio_bh_rx_availlen(hw_priv); -+ if(read_len <= 0) -+ return read_len; -+ -+ if (read_len < sizeof(struct wsm_hdr) || (read_len > EFFECTIVE_BUF_SIZE)) { -+ dev_err(hw_priv->pdev, "Invalid read len: %d", read_len); -+ return -1; -+ } -+ -+ /* Add SIZE of PIGGYBACK reg (CONTROL Reg) -+ * to the NEXT Message length + 2 Bytes for SKB */ -+ read_len = read_len + 2; -+ -+ alloc_len = sdio_align_len(hw_priv, read_len); -+ /* Check if not exceeding XRADIO capabilities */ -+ if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) { -+ dev_err(hw_priv->pdev, "Read aligned len: %d\n", alloc_len); -+ } -+ -+ /* Get skb buffer. */ -+ skb_rx = xradio_get_skb(hw_priv, alloc_len); -+ if (!skb_rx) { -+ dev_err(hw_priv->pdev, "xradio_get_skb failed.\n"); -+ return -ENOMEM; -+ } -+ skb_trim(skb_rx, 0); -+ skb_put(skb_rx, read_len); -+ data = skb_rx->data; -+ if (!data) { -+ dev_err(hw_priv->pdev, "skb data is NULL.\n"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ /* Read data from device. */ -+ if (xradio_data_read(hw_priv, data, alloc_len)) { -+ ret = -EIO; -+ goto out; -+ } -+ -+ /* the ctrl register is appened to the end of the wsm frame -+ * so we can use this to avoid reading the control register -+ * again for the next read .. but if this is invalid we'll -+ * do an invalid read and the firmware will crash so this -+ * probably needs some sort of validation */ -+ *nextlen = READLEN(__le16_to_cpu(((__le16 *) data)[(alloc_len >> 1) - 1])); -+ -+ /* check wsm length. */ -+ wsm = (struct wsm_hdr *) data; -+ wsm_len = __le32_to_cpu(wsm->len); -+ -+ if (WARN_ON(wsm_len > read_len)) { -+ dev_err(hw_priv->pdev, "wsm is bigger than data read, read %d but frame is %d\n", -+ read_len, wsm_len); -+ ret = -1; -+ goto out; -+ } -+ -+ /* dump rx data. */ -+ xradio_bh_rx_dump(hw_priv->pdev, data, wsm_len); -+ -+ /* extract wsm id and seq. */ -+ wsm_id = __le32_to_cpu(wsm->id) & 0xFFF; -+ wsm_seq = (__le32_to_cpu(wsm->id) >> 13) & 7; -+ skb_trim(skb_rx, wsm_len); -+ -+ /* process exceptions. */ -+ if (wsm_id == 0) { -+ printk("wtf?\n"); -+ ret = 0; -+ goto out; -+ } else if (unlikely(wsm_id == 0x0800)) { -+ dev_err(hw_priv->pdev, "firmware exception!\n"); -+ wsm_handle_exception(hw_priv, &data[sizeof(*wsm)], -+ wsm_len - sizeof(*wsm)); -+ ret = -1; -+ goto out; -+ } -+ -+ hw_priv->wsm_rx_seq = (wsm_seq + 1) & 7; -+ -+ /* Process tx frames confirm. */ -+ if (wsm_id & 0x0400) { -+ if (wsm_release_tx_buffer(hw_priv, 1) < 0) { -+ dev_err(hw_priv->pdev, "tx buffer < 0.\n"); -+ ret = -1; -+ goto out; -+ } -+ } -+ -+ /* WSM processing frames. */ -+ if (wsm_handle_rx(hw_priv, wsm_id, wsm, &skb_rx)) { -+ dev_err(hw_priv->pdev, "wsm_handle_rx failed.\n"); -+ ret = -1; -+ goto out; -+ } -+ -+ ret = 1; -+ -+out: -+ /* Reclaim the SKB buffer */ -+ if (skb_rx) { -+ if (xradio_put_resv_skb(hw_priv, skb_rx)) -+ xradio_put_skb(hw_priv, skb_rx); -+ } -+ -+ return ret; -+} -+ -+static void xradio_bh_tx_dump(struct device *dev, u8 *data, size_t len){ -+#ifdef DEBUG -+ static const char *msgnames[0xffff] = { -+ [0x0004] = "tx", -+ [0x0006] = "MIB", -+ [0x0007] = "start scan", -+ [0x0009] = "configure", -+ [0x000A] = "reset", -+ [0x000B] = "join", -+ [0x000C] = "add key", -+ [0x000D] = "remove key", -+ [0x0010] = "set pm", -+ [0x0011] = "set bss params", -+ [0x0012] = "set tx queue params", -+ [0x0013] = "set edca", -+ [0x0017] = "start", -+ [0x001b] = "update ie", -+ [0x001c] = "map link", -+ }; -+ static const char *mibnames[0xffff] = { -+ [0x0003] = "DOT11_SLOT_TIME", -+ [0x1002] = "TEMPLATE_FRAME", -+ [0x1003] = "RX_FILTER", -+ [0x1004] = "BEACON_FILTER_TABLE", -+ [0x1005] = "BEACON_FILTER_ENABLE", -+ [0x1006] = "OPERATIONAL POWER MODE", -+ [0x1007] = "BEACON_WAKEUP_PERIOD", -+ [0x1009] = "RCPI_RSSI_THRESHOLD", -+ [0x1010] = "SET_ASSOCIATION_MODE", -+ [0x100e] = "BLOCK_ACK_POLICY", -+ [0x100f] = "OVERRIDE_INTERNAL_TX_RATE", -+ [0x1013] = "SET_UAPSD_INFORMATION", -+ [0x1016] = "SET_TX_RATE_RETRY_POLICY", -+ [0x1020] = "PROTECTED_MGMT_POLICY", -+ [0x1021] = "SET_HT_PROTECTION", -+ [0x1024] = "USE_MULTI_TX_CONF", -+ [0x1025] = "KEEP_ALIVE_PERIOD", -+ [0x1026] = "DISABLE_BSSID_FILTER", -+ [0x1035] = "SET_INACTIVITY", -+ }; -+ -+ u16 msgid, ifid, mib; -+ u16 *p = (u16 *)data; -+ msgid = (*(p + 1)) & 0x3F; -+ ifid = (*(p + 1)) >> 6; -+ ifid &= 0xF; -+ mib = *(p + 2); -+ -+ WARN_ON(msgnames[msgid] == NULL); -+ -+ if (msgid == 0x0006) { -+ dev_dbg(dev, "vif %d: sdio tx, msgid %s(0x%.4X) len %d MIB %s(0x%.4X)\n", -+ ifid, msgnames[msgid], msgid,*p, mibnames[mib], mib); -+ } else { -+ dev_dbg(dev, "vif %d: sdio tx, msgid %s(0x%.4X) len %d\n", ifid, msgnames[msgid], msgid, *p); -+ } -+ -+// print_hex_dump_bytes("--> ", DUMP_PREFIX_NONE, data, -+// min(len, (size_t) 64)); -+#endif -+} -+ -+static int xradio_bh_tx(struct xradio_common *hw_priv){ -+ int txavailable; -+ int txburst; -+ int vif_selected; -+ struct wsm_hdr *wsm; -+ size_t tx_len; -+ int ret; -+ u8 *data; -+ -+ BUG_ON(hw_priv->hw_bufs_used > hw_priv->wsm_caps.numInpChBufs); -+ txavailable = hw_priv->wsm_caps.numInpChBufs - hw_priv->hw_bufs_used; -+ if (txavailable) { -+ /* Wake up the devices */ -+ if (hw_priv->device_can_sleep) { -+ ret = xradio_device_wakeup(hw_priv); -+ if (WARN_ON(ret < 0)) { -+ return -1; -+ } else if (ret) { -+ hw_priv->device_can_sleep = false; -+ } else { /* Wait for "awake" interrupt */ -+ dev_dbg(hw_priv->pdev, -+ "need to wait for device to wake before doing tx\n"); -+ return 0; -+ } -+ } -+ /* Increase Tx buffer*/ -+ wsm_alloc_tx_buffer(hw_priv); -+ -+ /* Get data to send and send it. */ -+ ret = wsm_get_tx(hw_priv, &data, &tx_len, &txburst, &vif_selected); -+ if (ret <= 0) { -+ wsm_release_tx_buffer(hw_priv, 1); -+ if (WARN_ON(ret < 0)) { -+ dev_err(hw_priv->pdev, "wsm_get_tx=%d.\n", ret); -+ return -ENOMEM; -+ } else { -+ return 0; -+ } -+ } else { -+ wsm = (struct wsm_hdr *) data; -+ BUG_ON(tx_len < sizeof(*wsm)); -+ BUG_ON(__le32_to_cpu(wsm->len) != tx_len); -+ -+ /* Align tx length and check it. */ -+ if (tx_len <= 8) -+ tx_len = 16; -+ tx_len = sdio_align_len(hw_priv, tx_len); -+ -+ /* Check if not exceeding XRADIO capabilities */ -+ if (tx_len > EFFECTIVE_BUF_SIZE) { -+ dev_warn(hw_priv->pdev, "Write aligned len: %d\n", tx_len); -+ } -+ -+ /* Make sequence number. */ -+ wsm->id &= __cpu_to_le32(~WSM_TX_SEQ(WSM_TX_SEQ_MAX)); -+ wsm->id |= cpu_to_le32(WSM_TX_SEQ(hw_priv->wsm_tx_seq)); -+ -+ /* Send the data to devices. */ -+ if (WARN_ON(xradio_data_write(hw_priv, data, tx_len))) { -+ wsm_release_tx_buffer(hw_priv, 1); -+ dev_err(hw_priv->pdev, "xradio_data_write failed\n"); -+ return -EIO; -+ } -+ -+ xradio_bh_tx_dump(hw_priv->pdev, data, tx_len); -+ -+ /* Process after data have sent. */ -+ if (vif_selected != -1) { -+ hw_priv->hw_bufs_used_vif[vif_selected]++; -+ } -+ wsm_txed(hw_priv, data); -+ hw_priv->wsm_tx_seq = (hw_priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; -+ -+ return 1; -+ } -+ } else -+ return 0; -+} -+ -+static int xradio_bh_exchange(struct xradio_common *hw_priv) { -+ int rxdone; -+ int txdone; -+ u16 nextlen = 0; -+ -+ /* query stuck frames in firmware. */ -+ if (atomic_xchg(&hw_priv->query_cnt, 0)) { -+ if (schedule_work(&hw_priv->query_work) <= 0) -+ atomic_add(1, &hw_priv->query_cnt); -+ } -+ -+ /* keep doing tx and rx until they both stop or we are told -+ * to terminate */ -+ do { -+ txdone = xradio_bh_tx(hw_priv); -+ if (txdone < 0) { -+ break; -+ } -+ rxdone = xradio_bh_rx(hw_priv, &nextlen); -+ if (rxdone < 0) { -+ break; -+ } -+ } while ((txdone > 0 || rxdone > 0) && !kthread_should_stop()); -+ return 0; -+} -+ -+static int xradio_bh(void *arg) -+{ -+ struct xradio_common *hw_priv = arg; -+ int term, suspend; -+ int wake = 0; -+ long timeout; -+ long status; -+ -+ for (;;) { -+ timeout = HZ / 30; -+ -+ // wait for something to happen or a timeout -+ status = wait_event_interruptible_timeout(hw_priv->bh_wq, ( { -+ wake = atomic_xchg(&hw_priv->bh_tx, 0); -+ term = kthread_should_stop(); -+ suspend = atomic_read(&hw_priv->bh_suspend); -+ (wake || term || suspend);}), timeout); -+ -+ if (wake) { -+ if(xradio_bh_exchange(hw_priv) < 0){ -+ break; -+ } -+ } else if (term) { -+ dev_dbg(hw_priv->pdev, "xradio_bh exit!\n"); -+ break; -+ } else if (status < 0) { -+ dev_err(hw_priv->pdev, "bh_error=%d, status=%ld\n", -+ hw_priv->bh_error, status); -+ break; -+ } else if (!status) { -+ /* check if there is data waiting but we missed the interrupt*/ -+ if (xradio_bh_rx_availlen(hw_priv) > 0) { -+ dev_warn(hw_priv->pdev, "missed interrupt\n"); -+ if(xradio_bh_exchange(hw_priv) < 0){ -+ break; -+ } -+ } -+ /* There are some frames to be confirmed. */ -+ else if (hw_priv->hw_bufs_used) { -+ long timeout = 0; -+ bool pending = 0; -+ dev_dbg(hw_priv->pdev, "Need confirm:%d!\n", -+ hw_priv->hw_bufs_used); -+ /* Check if frame transmission is timed out. */ -+ pending = xradio_query_txpkt_timeout(hw_priv, XRWL_ALL_IFS, -+ hw_priv->pending_frame_id, &timeout); -+ /* There are some frames confirm time out. */ -+ if (pending && timeout < 0) { -+ dev_err(hw_priv->pdev, "query_txpkt_timeout:%ld!\n", -+ timeout); -+ break; -+ } -+ } //else if (!txpending){ -+ //if (hw_priv->powersave_enabled && !hw_priv->device_can_sleep && !atomic_read(&hw_priv->recent_scan)) { -+ // /* Device is idle, we can go to sleep. */ -+ // dev_dbg(hw_priv->pdev, "Device idle(timeout), can sleep.\n"); -+ // WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, 0)); -+ // hw_priv->device_can_sleep = true; -+ //} -+ //continue; -+ //} -+ } else if (suspend) { -+ dev_dbg(hw_priv->pdev, "Host suspend request.\n"); -+ /* Check powersave setting again. */ -+ if (hw_priv->powersave_enabled) { -+ dev_dbg(hw_priv->pdev, -+ "Device idle(host suspend), can sleep.\n"); -+ WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, 0)); -+ hw_priv->device_can_sleep = true; -+ } -+ -+ /* bh thread go to suspend. */ -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_SUSPENDED); -+ wake_up(&hw_priv->bh_evt_wq); -+ status = wait_event_interruptible(hw_priv->bh_wq, -+ XRADIO_BH_RESUME == atomic_read(&hw_priv->bh_suspend)); -+ -+ if (status < 0) { -+ dev_err(hw_priv->pdev, "Failed to wait for resume: %ld.\n", -+ status); -+ break; -+ } -+ dev_dbg(hw_priv->pdev, "Host resume.\n"); -+ atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUMED); -+ wake_up(&hw_priv->bh_evt_wq); -+ } -+ } /* for (;;)*/ -+ -+ dev_err(hw_priv->pdev, "bh thread exiting\n"); -+ -+ return 0; -+} -diff --git a/drivers/net/wireless/xradio/bh.h b/drivers/net/wireless/xradio/bh.h -new file mode 100644 -index 0000000..ca9187e ---- /dev/null -+++ b/drivers/net/wireless/xradio/bh.h -@@ -0,0 +1,36 @@ -+/* -+ * Data Transmission thread for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_BH_H -+#define XRADIO_BH_H -+ -+#define XRADIO_BH_THREAD "xradio_bh" -+ -+/* extern */ struct xradio_common; -+ -+#define SDIO_BLOCK_SIZE (528) -+ -+int xradio_register_bh(struct xradio_common *hw_priv); -+void xradio_unregister_bh(struct xradio_common *hw_priv); -+void xradio_irq_handler(struct xradio_common *hw_priv); -+void xradio_bh_wakeup(struct xradio_common *hw_priv); -+int xradio_bh_suspend(struct xradio_common *hw_priv); -+int xradio_bh_resume(struct xradio_common *hw_priv); -+/* Must be called from BH thread. */ -+void xradio_enable_powersave(struct xradio_vif *priv, bool enable); -+int wsm_release_tx_buffer(struct xradio_common *hw_priv, int count); -+int wsm_release_vif_tx_buffer(struct xradio_common *hw_priv, int if_id, -+ int count); -+int xradio_init_resv_skb(struct xradio_common *hw_priv); -+void xradio_deinit_resv_skb(struct xradio_common *hw_priv); -+int xradio_realloc_resv_skb(struct xradio_common *hw_priv, -+ struct sk_buff *skb); -+#endif /* XRADIO_BH_H */ -diff --git a/drivers/net/wireless/xradio/common.h b/drivers/net/wireless/xradio/common.h -new file mode 100644 -index 0000000..1ce23de ---- /dev/null -+++ b/drivers/net/wireless/xradio/common.h -@@ -0,0 +1,101 @@ -+/* -+ * Common interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_COMMON_H -+#define XRADIO_COMMON_H -+ -+/******************************************************* -+ interfaces for parse frame protocol info. -+********************************************************/ -+#define LLC_LEN 8 -+#define LLC_TYPE_OFF 6 //Ether type offset -+#define IP_PROTO_OFF 9 //protocol offset -+#define IP_S_ADD_OFF 12 -+#define IP_D_ADD_OFF 16 -+#define UDP_LEN 8 -+//DHCP -+#define DHCP_BOOTP_C 68 -+#define DHCP_BOOTP_S 67 -+#define UDP_BOOTP_LEN 236 //exclude "Options:64" -+#define BOOTP_OPS_LEN 64 -+#define DHCP_MAGIC 0x63825363 -+#define DHCP_DISCOVER 0x01 -+#define DHCP_OFFER 0x02 -+#define DHCP_REQUEST 0x03 -+#define DHCP_DECLINE 0x04 -+#define DHCP_ACK 0x05 -+#define DHCP_NACK 0x06 -+#define DHCP_RELEASE 0x07 -+ -+//LLC layer. -+static inline bool is_SNAP(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data) == 0xAAAA && llc_data[2] == 0x03); //0xAA, 0xAA, 0x03. -+} -+ -+static inline bool is_STP(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data) == 0xAAAA && llc_data[2] == 0x03); //0x42, 0x42, 0x03. -+} -+ -+//IP/IPV6/ARP layer... -+static inline bool is_ip(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_IP)); //0x0800 -+} -+static inline bool is_ipv6(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_IPV6)); //0x08dd -+} -+static inline bool is_arp(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_ARP)); //0x0806 -+} -+static inline bool is_8021x(u8* llc_data) -+{ -+ return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_PAE)); //0x888E -+} -+ -+//TCP/UDP layer... -+static inline bool is_tcp(u8* llc_data) -+{ -+ return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_TCP); // -+} -+ -+static inline bool is_udp(u8* llc_data) -+{ -+ return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_UDP); // -+} -+ -+static inline bool is_icmp(u8* llc_data) -+{ -+ return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_ICMP); // -+} -+ -+static inline bool is_igmp(u8* llc_data) -+{ -+ return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_IGMP); // -+} -+ -+static inline bool is_dhcp(u8* llc_data) -+{ -+ u8* ip_hdr = llc_data+LLC_LEN; -+ if(!is_ip(llc_data)) -+ return (bool)0; -+ if(ip_hdr[IP_PROTO_OFF] == IPPROTO_UDP) { -+ u8* udp_hdr = ip_hdr+((ip_hdr[0]&0xf)<<2); //ihl:words -+ return (bool)((((udp_hdr[0]<<8)|udp_hdr[1]) == DHCP_BOOTP_C) || //DHCP client -+ (((udp_hdr[0]<<8)|udp_hdr[1]) == DHCP_BOOTP_S)); //DHCP server -+ } -+ return (bool)0; -+} -+ -+#endif //XRADIO_COMMON_H -diff --git a/drivers/net/wireless/xradio/debug.h b/drivers/net/wireless/xradio/debug.h -new file mode 100644 -index 0000000..30a59f3 ---- /dev/null -+++ b/drivers/net/wireless/xradio/debug.h -@@ -0,0 +1,22 @@ -+/* -+ * DebugFS code for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef XRADIO_DEBUG_H_INCLUDED -+#define XRADIO_DEBUG_H_INCLUDED -+ -+#define xradio_dbg(level, ...) -+#define txrx_printk(level, ...) -+#define wsm_printk(level, ...) -+#define sta_printk(level, ...) -+#define scan_printk(level, ...) -+#define ap_printk(level, ...) -+#define pm_printk(level, ...) -+ -+#endif /* XRADIO_DEBUG_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/fwio.c b/drivers/net/wireless/xradio/fwio.c -new file mode 100644 -index 0000000..cfb45eb ---- /dev/null -+++ b/drivers/net/wireless/xradio/fwio.c -@@ -0,0 +1,560 @@ -+/* -+ * Firmware I/O implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "fwio.h" -+#include "hwio.h" -+#include "bh.h" -+#include "sdio.h" -+ -+/* Macroses are local. */ -+#define APB_WRITE(reg, val) \ -+ do { \ -+ ret = xradio_apb_write_32(hw_priv, APB_ADDR(reg), (val)); \ -+ if (ret < 0) { \ -+ dev_err(hw_priv->pdev, \ -+ "%s: can't write %s at line %d.\n", \ -+ __func__, #reg, __LINE__); \ -+ goto error; \ -+ } \ -+ } while (0) -+#define APB_READ(reg, val) \ -+ do { \ -+ ret = xradio_apb_read_32(hw_priv, APB_ADDR(reg), &(val)); \ -+ if (ret < 0) { \ -+ dev_err(hw_priv->pdev, \ -+ "%s: can't read %s at line %d.\n", \ -+ __func__, #reg, __LINE__); \ -+ goto error; \ -+ } \ -+ } while (0) -+#define REG_WRITE(reg, val) \ -+ do { \ -+ ret = xradio_reg_write_32(hw_priv, (reg), (val)); \ -+ if (ret < 0) { \ -+ dev_err(hw_priv->pdev, \ -+ "%s: can't write %s at line %d.\n", \ -+ __func__, #reg, __LINE__); \ -+ goto error; \ -+ } \ -+ } while (0) -+#define REG_READ(reg, val) \ -+ do { \ -+ ret = xradio_reg_read_32(hw_priv, (reg), &(val)); \ -+ if (ret < 0) { \ -+ dev_err(hw_priv->pdev, \ -+ "%s: can't read %s at line %d.\n", \ -+ __func__, #reg, __LINE__); \ -+ goto error; \ -+ } \ -+ } while (0) -+ -+ -+static int xradio_get_hw_type(u32 config_reg_val, int *major_revision) -+{ -+ int hw_type = -1; -+ u32 hif_type = (config_reg_val >> 24) & 0x4; -+ //u32 hif_vers = (config_reg_val >> 31) & 0x1; -+ -+ /* Check if we have XRADIO*/ -+ if (hif_type == 0x4) { -+ *major_revision = 0x4; -+ hw_type = HIF_HW_TYPE_XRADIO; -+ } else { -+ //hw type unknown. -+ *major_revision = 0x0; -+ } -+ return hw_type; -+} -+ -+/* -+ * This function is called to Parse the SDD file -+ * to extract some informations -+ */ -+static int xradio_parse_sdd(struct xradio_common *hw_priv, u32 *dpll) -+{ -+ int ret = 0; -+ const char *sdd_path = NULL; -+ struct xradio_sdd *pElement = NULL; -+ int parsedLength = 0; -+ -+ BUG_ON(hw_priv->sdd != NULL); -+ -+ /* select and load sdd file depend on hardware version. */ -+ switch (hw_priv->hw_revision) { -+ case XR819_HW_REV0: -+ sdd_path = XR819_SDD_FILE; -+ break; -+ default: -+ dev_dbg(hw_priv->pdev, "unknown hardware version.\n"); -+ return ret; -+ } -+ -+ ret = request_firmware(&hw_priv->sdd, sdd_path, hw_priv->pdev); -+ if (unlikely(ret)) { -+ dev_dbg(hw_priv->pdev, "can't load sdd file %s.\n", -+ sdd_path); -+ return ret; -+ } -+ -+ //parse SDD config. -+ hw_priv->is_BT_Present = false; -+ pElement = (struct xradio_sdd *)hw_priv->sdd->data; -+ parsedLength += (FIELD_OFFSET(struct xradio_sdd, data) + pElement->length); -+ pElement = FIND_NEXT_ELT(pElement); -+ -+ while (parsedLength < hw_priv->sdd->size) { -+ switch (pElement->id) { -+ case SDD_PTA_CFG_ELT_ID: -+ hw_priv->conf_listen_interval = (*((u16 *)pElement->data+1) >> 7) & 0x1F; -+ hw_priv->is_BT_Present = true; -+ xradio_dbg(XRADIO_DBG_NIY, "PTA element found.Listen Interval %d\n", -+ hw_priv->conf_listen_interval); -+ break; -+ case SDD_REFERENCE_FREQUENCY_ELT_ID: -+ switch(*((uint16_t*)pElement->data)) { -+ case 0x32C8: -+ *dpll = 0x1D89D241; -+ break; -+ case 0x3E80: -+ *dpll = 0x1E1; -+ break; -+ case 0x41A0: -+ *dpll = 0x124931C1; -+ break; -+ case 0x4B00: -+ *dpll = 0x191; -+ break; -+ case 0x5DC0: -+ *dpll = 0x141; -+ break; -+ case 0x6590: -+ *dpll = 0x0EC4F121; -+ break; -+ case 0x8340: -+ *dpll = 0x92490E1; -+ break; -+ case 0x9600: -+ *dpll = 0x100010C1; -+ break; -+ case 0x9C40: -+ *dpll = 0xC1; -+ break; -+ case 0xBB80: -+ *dpll = 0xA1; -+ break; -+ case 0xCB20: -+ *dpll = 0x7627091; -+ break; -+ default: -+ *dpll = DPLL_INIT_VAL_XRADIO; -+ xradio_dbg(XRADIO_DBG_WARN, "Unknown Reference clock frequency." -+ "Use default DPLL value=0x%08x.", DPLL_INIT_VAL_XRADIO); -+ break; -+ } -+ default: -+ break; -+ } -+ parsedLength += (FIELD_OFFSET(struct xradio_sdd, data) + pElement->length); -+ pElement = FIND_NEXT_ELT(pElement); -+ } -+ -+ dev_dbg(hw_priv->pdev, "sdd size=%d parse len=%d.\n", -+ hw_priv->sdd->size, parsedLength); -+ -+ // -+ if (hw_priv->is_BT_Present == false) { -+ hw_priv->conf_listen_interval = 0; -+ xradio_dbg(XRADIO_DBG_NIY, "PTA element NOT found.\n"); -+ } -+ return ret; -+} -+ -+static int xradio_firmware(struct xradio_common *hw_priv) -+{ -+ int ret, block, num_blocks; -+ unsigned i; -+ u32 val32; -+ u32 put = 0, get = 0; -+ u8 *buf = NULL; -+ const char *fw_path; -+ const struct firmware *firmware = NULL; -+ -+ switch (hw_priv->hw_revision) { -+ case XR819_HW_REV0: -+ fw_path = XR819_FIRMWARE; -+ break; -+ default: -+ dev_dbg(hw_priv->pdev, "invalid silicon revision %d.\n", -+ hw_priv->hw_revision); -+ return -EINVAL; -+ } -+ /* Initialize common registers */ -+ APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, DOWNLOAD_ARE_YOU_HERE); -+ APB_WRITE(DOWNLOAD_PUT_REG, 0); -+ APB_WRITE(DOWNLOAD_GET_REG, 0); -+ APB_WRITE(DOWNLOAD_STATUS_REG, DOWNLOAD_PENDING); -+ APB_WRITE(DOWNLOAD_FLAGS_REG, 0); -+ -+ /* Release CPU from RESET */ -+ REG_READ(HIF_CONFIG_REG_ID, val32); -+ val32 &= ~HIF_CONFIG_CPU_RESET_BIT; -+ REG_WRITE(HIF_CONFIG_REG_ID, val32); -+ -+ /* Enable Clock */ -+ val32 &= ~HIF_CONFIG_CPU_CLK_DIS_BIT; -+ REG_WRITE(HIF_CONFIG_REG_ID, val32); -+ -+ /* Load a firmware file */ -+ ret = request_firmware(&firmware, fw_path, hw_priv->pdev); -+ if (ret) { -+ dev_dbg(hw_priv->pdev, "can't load firmware file %s.\n", -+ fw_path); -+ goto error; -+ } -+ BUG_ON(!firmware->data); -+ -+ buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL); -+ if (!buf) { -+ dev_dbg(hw_priv->pdev, "can't allocate firmware buffer.\n"); -+ ret = -ENOMEM; -+ goto error; -+ } -+ -+ /* Check if the bootloader is ready */ -+ for (i = 0; i < 100; i++/*= 1 + i / 2*/) { -+ APB_READ(DOWNLOAD_IMAGE_SIZE_REG, val32); -+ if (val32 == DOWNLOAD_I_AM_HERE) -+ break; -+ mdelay(10); -+ } /* End of for loop */ -+ if (val32 != DOWNLOAD_I_AM_HERE) { -+ dev_dbg(hw_priv->pdev, "bootloader is not ready.\n"); -+ ret = -ETIMEDOUT; -+ goto error; -+ } -+ -+ /* Calculcate number of download blocks */ -+ num_blocks = (firmware->size - 1) / DOWNLOAD_BLOCK_SIZE + 1; -+ -+ /* Updating the length in Download Ctrl Area */ -+ val32 = firmware->size; /* Explicit cast from size_t to u32 */ -+ APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32); -+ -+ /* Firmware downloading loop */ -+ for (block = 0; block < num_blocks ; block++) { -+ size_t tx_size; -+ size_t block_size; -+ -+ /* check the download status */ -+ APB_READ(DOWNLOAD_STATUS_REG, val32); -+ if (val32 != DOWNLOAD_PENDING) { -+ dev_dbg(hw_priv->pdev, "bootloader reported error %d.\n", -+ val32); -+ ret = -EIO; -+ goto error; -+ } -+ -+ /* loop until put - get <= 24K */ -+ for (i = 0; i < 100; i++) { -+ APB_READ(DOWNLOAD_GET_REG, get); -+ if ((put - get) <= (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) -+ break; -+ mdelay(i); -+ } -+ -+ if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { -+ dev_dbg(hw_priv->pdev, "Timeout waiting for FIFO.\n"); -+ ret = -ETIMEDOUT; -+ goto error; -+ } -+ -+ /* calculate the block size */ -+ tx_size = block_size = min((size_t)(firmware->size - put), (size_t)DOWNLOAD_BLOCK_SIZE); -+ memcpy(buf, &firmware->data[put], block_size); -+ -+ if (block_size < DOWNLOAD_BLOCK_SIZE) { -+ memset(&buf[block_size], 0, DOWNLOAD_BLOCK_SIZE - block_size); -+ tx_size = DOWNLOAD_BLOCK_SIZE; -+ } -+ -+ /* send the block to sram */ -+ ret = xradio_apb_write(hw_priv, APB_ADDR(DOWNLOAD_FIFO_OFFSET + (put & (DOWNLOAD_FIFO_SIZE - 1))), -+ buf, tx_size); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "%s: can't write block at line %d.\n", __func__, __LINE__); -+ goto error; -+ } -+ -+ /* update the put register */ -+ put += block_size; -+ APB_WRITE(DOWNLOAD_PUT_REG, put); -+ } /* End of firmware download loop */ -+ -+ /* Wait for the download completion */ -+ for (i = 0; i < 300; i += 1 + i / 2) { -+ APB_READ(DOWNLOAD_STATUS_REG, val32); -+ if (val32 != DOWNLOAD_PENDING) -+ break; -+ mdelay(i); -+ } -+ if (val32 != DOWNLOAD_SUCCESS) { -+ dev_dbg(hw_priv->pdev, "wait for download completion failed. " \ -+ "Read: 0x%.8X\n", val32); -+ ret = -ETIMEDOUT; -+ goto error; -+ } else { -+ dev_dbg(hw_priv->pdev, "Firmware completed.\n"); -+ ret = 0; -+ } -+ -+error: -+ if(buf) -+ kfree(buf); -+ if (firmware) { -+ release_firmware(firmware); -+ } -+ return ret; -+} -+ -+static int xradio_bootloader(struct xradio_common *hw_priv) -+{ -+ const char *bl_path = XR819_BOOTLOADER; -+ u32 addr = AHB_MEMORY_ADDRESS; -+ int ret; -+ u32 i; -+ u32 *data; -+ const struct firmware *bootloader; -+ -+ /* Load a bootloader file */ -+ ret = request_firmware(&bootloader, bl_path, hw_priv->pdev); -+ if (ret) { -+ dev_dbg(hw_priv->pdev, "can't load bootloader file %s.\n", -+ bl_path); -+ goto error; -+ } -+ -+ /* Down bootloader. */ -+ data = (u32 *)bootloader->data; -+ for(i = 0; i < (bootloader->size)/4; i++, addr+=4) { -+ REG_WRITE(HIF_SRAM_BASE_ADDR_REG_ID, addr); -+ REG_WRITE(HIF_AHB_DPORT_REG_ID,data[i]); -+ } -+ dev_dbg(hw_priv->pdev, "Bootloader complete\n"); -+ -+error: -+ if(bootloader) { -+ release_firmware(bootloader); -+ } -+ return ret; -+} -+ -+bool test_retry = false; -+int xradio_load_firmware(struct xradio_common *hw_priv) -+{ -+ int ret; -+ int i; -+ u32 val32; -+ u16 val16; -+ u32 dpll = 0; -+ int major_revision; -+ -+ /* Read CONFIG Register Value - We will read 32 bits */ -+ ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't read config register, err=%d.\n", -+ ret); -+ return ret; -+ } -+ -+ //check hardware type and revision. -+ hw_priv->hw_type = xradio_get_hw_type(val32, &major_revision); -+ switch (hw_priv->hw_type) { -+ case HIF_HW_TYPE_XRADIO: -+ dev_dbg(hw_priv->pdev, "HW_TYPE_XRADIO detected.\n"); -+ break; -+ default: -+ dev_dbg(hw_priv->pdev, "Unknown hardware: %d.\n", -+ hw_priv->hw_type); -+ return -ENOTSUPP; -+ } -+ if (major_revision == 4) { -+ hw_priv->hw_revision = XR819_HW_REV0; -+ dev_dbg(hw_priv->pdev, "XRADIO_HW_REV 1.0 detected.\n"); -+ } else { -+ dev_dbg(hw_priv->pdev, "Unsupported major revision %d.\n", -+ major_revision); -+ return -ENOTSUPP; -+ } -+ -+ //load sdd file, and get config from it. -+ ret = xradio_parse_sdd(hw_priv, &dpll); -+ if (ret < 0) { -+ return ret; -+ } -+ -+ //set dpll initial value and check. -+ ret = xradio_reg_write_32(hw_priv, HIF_TSET_GEN_R_W_REG_ID, dpll); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't write DPLL register.\n"); -+ goto out; -+ } -+ msleep(5); -+ ret = xradio_reg_read_32(hw_priv, HIF_TSET_GEN_R_W_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't read DPLL register.\n"); -+ goto out; -+ } -+ if (val32 != dpll) { -+ dev_dbg(hw_priv->pdev, "unable to initialise " \ -+ "DPLL register. Wrote 0x%.8X, read 0x%.8X.\n", -+ dpll, val32); -+ ret = -EIO; -+ goto out; -+ } -+ -+ /* Set wakeup bit in device */ -+ ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, &val16); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "set_wakeup: can't read control register.\n"); -+ goto out; -+ } -+ ret = xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, val16 | HIF_CTRL_WUP_BIT); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "set_wakeup: can't write control register.\n"); -+ goto out; -+ } -+ -+ /* Wait for wakeup */ -+ for (i = 0 ; i < 300 ; i += 1 + i / 2) { -+ ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, &val16); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "Wait_for_wakeup: " -+ "can't read control register.\n"); -+ goto out; -+ } -+ if (val16 & HIF_CTRL_RDY_BIT) { -+ break; -+ } -+ msleep(i); -+ } -+ if ((val16 & HIF_CTRL_RDY_BIT) == 0) { -+ dev_dbg(hw_priv->pdev, "Wait for wakeup:" -+ "device is not responding.\n"); -+ ret = -ETIMEDOUT; -+ goto out; -+ } else { -+ dev_dbg(hw_priv->pdev, "WLAN device is ready.\n"); -+ } -+ -+ /* Checking for access mode and download firmware. */ -+ ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "check_access_mode: " -+ "can't read config register.\n"); -+ goto out; -+ } -+ if (val32 & HIF_CONFIG_ACCESS_MODE_BIT) { -+ /* Down bootloader. */ -+ ret = xradio_bootloader(hw_priv); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't download bootloader.\n"); -+ goto out; -+ } -+ /* Down firmware. */ -+ ret = xradio_firmware(hw_priv); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "can't download firmware.\n"); -+ goto out; -+ } -+ } else { -+ dev_dbg(hw_priv->pdev, "check_access_mode: " -+ "device is already in QUEUE mode.\n"); -+ /* TODO: verify this branch. Do we need something to do? */ -+ } -+ -+ if (HIF_HW_TYPE_XRADIO == hw_priv->hw_type) { -+ /* If device is XRADIO the IRQ enable/disable bits -+ * are in CONFIG register */ -+ ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "enable_irq: can't read " \ -+ "config register.\n"); -+ goto unsubscribe; -+ } -+ ret = xradio_reg_write_32(hw_priv, HIF_CONFIG_REG_ID, -+ val32 | HIF_CONF_IRQ_RDY_ENABLE); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "enable_irq: can't write " \ -+ "config register.\n"); -+ goto unsubscribe; -+ } -+ } else { -+ /* If device is XRADIO the IRQ enable/disable bits -+ * are in CONTROL register */ -+ /* Enable device interrupts - Both DATA_RDY and WLAN_RDY */ -+ ret = xradio_reg_read_16(hw_priv, HIF_CONFIG_REG_ID, &val16); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "enable_irq: can't read " \ -+ "control register.\n"); -+ goto unsubscribe; -+ } -+ ret = xradio_reg_write_16(hw_priv, HIF_CONFIG_REG_ID, -+ val16 | HIF_CTRL_IRQ_RDY_ENABLE); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "enable_irq: can't write " \ -+ "control register.\n"); -+ goto unsubscribe; -+ } -+ -+ } -+ -+ /* Configure device for MESSSAGE MODE */ -+ ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "set_mode: can't read config register.\n"); -+ goto unsubscribe; -+ } -+ ret = xradio_reg_write_32(hw_priv, HIF_CONFIG_REG_ID, -+ val32 & ~HIF_CONFIG_ACCESS_MODE_BIT); -+ if (ret < 0) { -+ dev_dbg(hw_priv->pdev, "set_mode: can't write config register.\n"); -+ goto unsubscribe; -+ } -+ -+ /* Unless we read the CONFIG Register we are -+ * not able to get an interrupt */ -+ mdelay(10); -+ xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ return 0; -+ -+unsubscribe: -+out: -+ if (hw_priv->sdd) { -+ release_firmware(hw_priv->sdd); -+ hw_priv->sdd = NULL; -+ } -+ return ret; -+} -+ -+int xradio_dev_deinit(struct xradio_common *hw_priv) -+{ -+ if (hw_priv->sdd) { -+ release_firmware(hw_priv->sdd); -+ hw_priv->sdd = NULL; -+ } -+ return 0; -+} -diff --git a/drivers/net/wireless/xradio/fwio.h b/drivers/net/wireless/xradio/fwio.h -new file mode 100644 -index 0000000..b5efeb1 ---- /dev/null -+++ b/drivers/net/wireless/xradio/fwio.h -@@ -0,0 +1,33 @@ -+/* -+ * Firmware APIs for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef FWIO_H_INCLUDED -+#define FWIO_H_INCLUDED -+ -+#define XR819_HW_REV0 (8190) -+#define XR819_BOOTLOADER ("xr819/boot_xr819.bin") -+#define XR819_FIRMWARE ("xr819/fw_xr819.bin") -+#define XR819_SDD_FILE ("xr819/sdd_xr819.bin") -+ -+#define SDD_PTA_CFG_ELT_ID 0xEB -+#define SDD_REFERENCE_FREQUENCY_ELT_ID 0xC5 -+#define FIELD_OFFSET(type, field) ((u8 *)&((type *)0)->field - (u8 *)0) -+#define FIND_NEXT_ELT(e) (struct xradio_sdd *)((u8 *)&e->data + e->length) -+struct xradio_sdd { -+ u8 id; -+ u8 length; -+ u8 data[]; -+}; -+ -+struct xradio_common; -+int xradio_load_firmware(struct xradio_common *hw_priv); -+int xradio_dev_deinit(struct xradio_common *hw_priv); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/ht.c b/drivers/net/wireless/xradio/ht.c -new file mode 100644 -index 0000000..a9b3630 ---- /dev/null -+++ b/drivers/net/wireless/xradio/ht.c -@@ -0,0 +1,86 @@ -+#include -+ -+#include "xradio.h" -+#include "sta.h" -+ -+#define AG_RATE_INDEX 6 //11a/g rate for important short frames in 5G. -+ -+#ifdef AP_HT_COMPAT_FIX -+#define AP_COMPAT_THRESHOLD 2000 -+#define AP_COMPAT_MIN_CNT 200 -+u8 ap_compat_bssid[ETH_ALEN] = {0}; -+int xradio_apcompat_detect(struct xradio_vif *priv, u8 rx_rate) -+{ -+ if (rx_rate < AG_RATE_INDEX) { -+ priv->ht_compat_cnt++; -+ txrx_printk(XRADIO_DBG_MSG,"%s:rate=%d.\n", __func__, rx_rate); -+ } else { -+ priv->ht_compat_det |= 1; -+ priv->ht_compat_cnt = 0; -+ txrx_printk(XRADIO_DBG_NIY,"%s:HT compat detect\n", __func__); -+ return 0; -+ } -+ -+ /* Enhance compatibility with some illegal APs.*/ -+ if (priv->ht_compat_cnt > AP_COMPAT_THRESHOLD || -+ (priv->ht_compat_cnt > AP_COMPAT_MIN_CNT && -+ priv->bssid[0] == 0xC8 && -+ priv->bssid[1] == 0x3A && -+ priv->bssid[2] == 0x35)) { -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ memcpy(ap_compat_bssid, priv->bssid, ETH_ALEN); -+ wms_send_disassoc_to_self(hw_priv, priv); -+ txrx_printk(XRADIO_DBG_WARN, "%s:SSID=%s, BSSID=" \ -+ "%02x:%02x:%02x:%02x:%02x:%02x\n", __func__, priv->ssid, -+ ap_compat_bssid[0], ap_compat_bssid[1], -+ ap_compat_bssid[2], ap_compat_bssid[3], -+ ap_compat_bssid[4], ap_compat_bssid[5]); -+ return 1; -+ } -+ return 0; -+} -+ -+void xradio_remove_ht_ie(struct xradio_vif *priv, struct sk_buff *skb) -+{ -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -+ u8 *ies = NULL; -+ size_t ies_len = 0; -+ u8 *ht_ie = NULL; -+ -+ if (!mgmt || memcmp(ap_compat_bssid, mgmt->bssid, ETH_ALEN)) -+ return; -+ -+ if (ieee80211_is_probe_resp(mgmt->frame_control)) -+ ies = mgmt->u.probe_resp.variable; -+ else if (ieee80211_is_beacon(mgmt->frame_control)) -+ ies = mgmt->u.beacon.variable; -+ else if (ieee80211_is_assoc_resp(mgmt->frame_control)) -+ ies = mgmt->u.assoc_resp.variable; -+ else if (ieee80211_is_assoc_req(mgmt->frame_control)) -+ ies = mgmt->u.assoc_req.variable; -+ else -+ return; -+ -+ ies_len = skb->len - (ies - (u8 *)(skb->data)); -+ ht_ie = (u8 *)xradio_get_ie(ies, ies_len, WLAN_EID_HT_CAPABILITY); -+ if (ht_ie) { -+ u8 ht_len = *(ht_ie + 1) + 2; -+ u8 move_len = (ies + ies_len) - (ht_ie + ht_len); -+ memmove(ht_ie, (ht_ie + ht_len), move_len); -+ skb_trim(skb, skb->len - ht_len); -+ ies_len = skb->len - (ies - (u8 *)(skb->data)); -+ ht_ie = (u8 *)xradio_get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); -+ if (ht_ie) { -+ ht_len = *(ht_ie + 1) + 2; -+ move_len = (ies + ies_len) - (ht_ie + ht_len); -+ memmove(ht_ie, (ht_ie + ht_len), move_len); -+ skb_trim(skb, skb->len - ht_len); -+ } -+ } -+ txrx_printk(XRADIO_DBG_WARN, "%s: BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n", -+ __func__, -+ mgmt->bssid[0], mgmt->bssid[1], -+ mgmt->bssid[2], mgmt->bssid[3], -+ mgmt->bssid[4], mgmt->bssid[5]); -+} -+#endif //AP_HT_COMPAT_FIX -\ No newline at end of file -diff --git a/drivers/net/wireless/xradio/ht.h b/drivers/net/wireless/xradio/ht.h -new file mode 100644 -index 0000000..346b425 ---- /dev/null -+++ b/drivers/net/wireless/xradio/ht.h -@@ -0,0 +1,44 @@ -+/* -+ * HT-related code for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef XRADIO_HT_H_INCLUDED -+#define XRADIO_HT_H_INCLUDED -+ -+#include -+ -+struct xradio_ht_oper { -+ struct ieee80211_sta_ht_cap ht_cap; -+ enum nl80211_channel_type channel_type; -+ u16 operation_mode; -+}; -+ -+static inline int xradio_is_ht(const struct xradio_ht_oper *ht_oper) -+{ -+ return ht_oper->channel_type != NL80211_CHAN_NO_HT; -+} -+ -+static inline int xradio_ht_greenfield(const struct xradio_ht_oper *ht_oper) -+{ -+ return (xradio_is_ht(ht_oper) && -+ (ht_oper->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && -+ !(ht_oper->operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)); -+} -+ -+static inline int xradio_ht_ampdu_density(const struct xradio_ht_oper *ht_oper) -+{ -+ if (!xradio_is_ht(ht_oper)) -+ return 0; -+ return ht_oper->ht_cap.ampdu_density; -+} -+ -+int xradio_apcompat_detect(struct xradio_vif *priv, u8 rx_rate); -+void xradio_remove_ht_ie(struct xradio_vif *priv, struct sk_buff *skb); -+ -+#endif /* XRADIO_HT_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/hwio.c b/drivers/net/wireless/xradio/hwio.c -new file mode 100644 -index 0000000..b813333 ---- /dev/null -+++ b/drivers/net/wireless/xradio/hwio.c -@@ -0,0 +1,280 @@ -+/* -+ * Hardware I/O implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+ -+#include "xradio.h" -+#include "hwio.h" -+#include "sdio.h" -+ -+#define CHECK_ADDR_LEN 1 -+ -+ /* Sdio addr is 4*spi_addr */ -+#define SPI_REG_ADDR_TO_SDIO(spi_reg_addr) ((spi_reg_addr) << 2) -+#define SDIO_ADDR17BIT(buf_id, mpf, rfu, reg_id_ofs) \ -+ ((((buf_id) & 0x1F) << 7) \ -+ | (((mpf) & 1) << 6) \ -+ | (((rfu) & 1) << 5) \ -+ | (((reg_id_ofs) & 0x1F) << 0)) -+#define MAX_RETRY 3 -+ -+ -+static int __xradio_read(struct xradio_common *hw_priv, u16 addr, -+ void *buf, size_t buf_len, int buf_id) -+{ -+ u16 addr_sdio; -+ u32 sdio_reg_addr_17bit ; -+ -+#if (CHECK_ADDR_LEN) -+ /* Check if buffer is aligned to 4 byte boundary */ -+ if (WARN_ON(((unsigned long)buf & 3) && (buf_len > 4))) { -+ dev_dbg(hw_priv->pdev, "buffer is not aligned.\n"); -+ return -EINVAL; -+ } -+#endif -+ -+ /* Convert to SDIO Register Address */ -+ addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); -+ sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); -+ return sdio_data_read(hw_priv, -+ sdio_reg_addr_17bit, -+ buf, buf_len); -+} -+ -+static int __xradio_write(struct xradio_common *hw_priv, u16 addr, -+ const void *buf, size_t buf_len, int buf_id) -+{ -+ u16 addr_sdio; -+ u32 sdio_reg_addr_17bit ; -+ -+#if (CHECK_ADDR_LEN) -+ /* Check if buffer is aligned to 4 byte boundary */ -+ if (WARN_ON(((unsigned long)buf & 3) && (buf_len > 4))) { -+ dev_err(hw_priv->pdev, "buffer is not aligned.\n"); -+ return -EINVAL; -+ } -+#endif -+ -+ /* Convert to SDIO Register Address */ -+ addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); -+ sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); -+ -+ return sdio_data_write(hw_priv, -+ sdio_reg_addr_17bit, -+ buf, buf_len); -+} -+ -+static inline int __xradio_read_reg32(struct xradio_common *hw_priv, -+ u16 addr, u32 *val) -+{ -+ return __xradio_read(hw_priv, addr, val, sizeof(val), 0); -+} -+ -+static inline int __xradio_write_reg32(struct xradio_common *hw_priv, -+ u16 addr, u32 val) -+{ -+ return __xradio_write(hw_priv, addr, &val, sizeof(val), 0); -+} -+ -+int xradio_reg_read(struct xradio_common *hw_priv, u16 addr, -+ void *buf, size_t buf_len) -+{ -+ int ret; -+ sdio_lock(hw_priv); -+ ret = __xradio_read(hw_priv, addr, buf, buf_len, 0); -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_reg_write(struct xradio_common *hw_priv, u16 addr, -+ const void *buf, size_t buf_len) -+{ -+ int ret; -+ sdio_lock(hw_priv); -+ ret = __xradio_write(hw_priv, addr, buf, buf_len, 0); -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_data_read(struct xradio_common *hw_priv, void *buf, size_t buf_len) -+{ -+ int ret, retry = 1; -+ sdio_lock(hw_priv); -+ { -+ int buf_id_rx = hw_priv->buf_id_rx; -+ while (retry <= MAX_RETRY) { -+ ret = __xradio_read(hw_priv, HIF_IN_OUT_QUEUE_REG_ID, buf, -+ buf_len, buf_id_rx + 1); -+ if (!ret) { -+ buf_id_rx = (buf_id_rx + 1) & 3; -+ hw_priv->buf_id_rx = buf_id_rx; -+ break; -+ } else { -+ //~dgp this retrying stuff is silly as it can crash the fw if there is nothing to read -+ dev_err(hw_priv->pdev, "data read error :%d - attempt %d of %d\n", ret, retry, MAX_RETRY); -+ retry++; -+ mdelay(1); -+ } -+ } -+ } -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_data_write(struct xradio_common *hw_priv, const void *buf, -+ size_t buf_len) -+{ -+ int ret, retry = 1; -+ sdio_lock(hw_priv); -+ { -+ int buf_id_tx = hw_priv->buf_id_tx; -+ while (retry <= MAX_RETRY) { -+ ret = __xradio_write(hw_priv, HIF_IN_OUT_QUEUE_REG_ID, buf, -+ buf_len, buf_id_tx); -+ if (!ret) { -+ buf_id_tx = (buf_id_tx + 1) & 31; -+ hw_priv->buf_id_tx = buf_id_tx; -+ break; -+ } else { -+ dev_err(hw_priv->pdev, "data write error :%d - attempt %d - %d\n", ret, retry, MAX_RETRY); -+ retry++; -+ mdelay(1); -+ } -+ } -+ } -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_indirect_read(struct xradio_common *hw_priv, u32 addr, void *buf, -+ size_t buf_len, u32 prefetch, u16 port_addr) -+{ -+ u32 val32 = 0; -+ int i, ret; -+ -+ if ((buf_len / 2) >= 0x1000) { -+ dev_err(hw_priv->pdev, "Can't read more than 0xfff words.\n"); -+ return -EINVAL; -+ goto out; -+ } -+ -+ sdio_lock(hw_priv); -+ /* Write address */ -+ ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write address register.\n"); -+ goto out; -+ } -+ -+ /* Read CONFIG Register Value - We will read 32 bits */ -+ ret = __xradio_read_reg32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't read config register.\n"); -+ goto out; -+ } -+ -+ /* Set PREFETCH bit */ -+ ret = __xradio_write_reg32(hw_priv, HIF_CONFIG_REG_ID, val32 | prefetch); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write prefetch bit.\n"); -+ goto out; -+ } -+ -+ /* Check for PRE-FETCH bit to be cleared */ -+ for (i = 0; i < 20; i++) { -+ ret = __xradio_read_reg32(hw_priv, HIF_CONFIG_REG_ID, &val32); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't check prefetch bit.\n"); -+ goto out; -+ } -+ if (!(val32 & prefetch)) -+ break; -+ mdelay(i); -+ } -+ -+ if (val32 & prefetch) { -+ dev_err(hw_priv->pdev, "Prefetch bit is not cleared.\n"); -+ goto out; -+ } -+ -+ /* Read data port */ -+ ret = __xradio_read(hw_priv, port_addr, buf, buf_len, 0); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't read data port.\n"); -+ goto out; -+ } -+ -+out: -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_apb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, -+ size_t buf_len) -+{ -+ int ret; -+ -+ if ((buf_len / 2) >= 0x1000) { -+ dev_err(hw_priv->pdev, "Can't wrire more than 0xfff words.\n"); -+ return -EINVAL; -+ } -+ -+ sdio_lock(hw_priv); -+ -+ /* Write address */ -+ ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write address register.\n"); -+ goto out; -+ } -+ -+ /* Write data port */ -+ ret = __xradio_write(hw_priv, HIF_SRAM_DPORT_REG_ID, buf, buf_len, 0); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write data port.\n"); -+ goto out; -+ } -+ -+out: -+ sdio_unlock(hw_priv); -+ return ret; -+} -+ -+int xradio_ahb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, -+ size_t buf_len) -+{ -+ int ret; -+ -+ if ((buf_len / 2) >= 0x1000) { -+ dev_err(hw_priv->pdev, "Can't wrire more than 0xfff words.\n"); -+ return -EINVAL; -+ } -+ -+ sdio_lock(hw_priv); -+ -+ /* Write address */ -+ ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write address register.\n"); -+ goto out; -+ } -+ -+ /* Write data port */ -+ ret = __xradio_write(hw_priv, HIF_AHB_DPORT_REG_ID, buf, buf_len, 0); -+ if (ret < 0) { -+ dev_err(hw_priv->pdev, "Can't write data port.\n"); -+ goto out; -+ } -+ -+out: -+ sdio_unlock(hw_priv); -+ return ret; -+} -diff --git a/drivers/net/wireless/xradio/hwio.h b/drivers/net/wireless/xradio/hwio.h -new file mode 100644 -index 0000000..531c2b8 ---- /dev/null -+++ b/drivers/net/wireless/xradio/hwio.h -@@ -0,0 +1,229 @@ -+/* -+ * hardware interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_HWIO_H_INCLUDED -+#define XRADIO_HWIO_H_INCLUDED -+ -+/* extern */ struct xradio_common; -+ -+/* DPLL initial values */ -+#define DPLL_INIT_VAL_XRADIO (0x0EC4F121) -+ -+/* Hardware Type Definitions */ -+#define HIF_HW_TYPE_XRADIO (1) -+ -+ -+/* boot loader start address in SRAM */ -+#define DOWNLOAD_BOOT_LOADER_OFFSET (0x00000000) -+/* 32K, 0x4000 to 0xDFFF */ -+#define DOWNLOAD_FIFO_OFFSET (0x00004000) -+/* 32K */ -+#define DOWNLOAD_FIFO_SIZE (0x00008000) -+/* 128 bytes, 0xFF80 to 0xFFFF */ -+#define DOWNLOAD_CTRL_OFFSET (0x0000FF80) -+#define DOWNLOAD_CTRL_DATA_DWORDS (32-6) -+ -+/* Download control area */ -+struct download_cntl_t { -+ /* size of whole firmware file (including Cheksum), host init */ -+ u32 ImageSize; -+ /* downloading flags */ -+ u32 Flags; -+ /* No. of bytes put into the download, init & updated by host */ -+ u32 Put; -+ /* last traced program counter, last ARM reg_pc */ -+ u32 TracePc; -+ /* No. of bytes read from the download, host init, device updates */ -+ u32 Get; -+ /* r0, boot losader status, host init to pending, device updates */ -+ u32 Status; -+ /* Extra debug info, r1 to r14 if status=r0=DOWNLOAD_EXCEPTION */ -+ u32 DebugData[DOWNLOAD_CTRL_DATA_DWORDS]; -+}; -+ -+#define DOWNLOAD_IMAGE_SIZE_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, ImageSize)) -+#define DOWNLOAD_FLAGS_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Flags)) -+#define DOWNLOAD_PUT_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Put)) -+#define DOWNLOAD_TRACE_PC_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, TracePc)) -+#define DOWNLOAD_GET_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Get)) -+#define DOWNLOAD_STATUS_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Status)) -+#define DOWNLOAD_DEBUG_DATA_REG \ -+ (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, DebugData)) -+ -+#define DOWNLOAD_DEBUG_DATA_LEN (108) -+#define DOWNLOAD_BLOCK_SIZE (1024) -+ -+/* For boot loader detection */ -+#define DOWNLOAD_ARE_YOU_HERE (0x87654321) -+#define DOWNLOAD_I_AM_HERE (0x12345678) -+ -+/* Download error code */ -+#define DOWNLOAD_PENDING (0xFFFFFFFF) -+#define DOWNLOAD_SUCCESS (0) -+#define DOWNLOAD_EXCEPTION (1) -+#define DOWNLOAD_ERR_MEM_1 (2) -+#define DOWNLOAD_ERR_MEM_2 (3) -+#define DOWNLOAD_ERR_SOFTWARE (4) -+#define DOWNLOAD_ERR_FILE_SIZE (5) -+#define DOWNLOAD_ERR_CHECKSUM (6) -+#define DOWNLOAD_ERR_OVERFLOW (7) -+#define DOWNLOAD_ERR_IMAGE (8) -+#define DOWNLOAD_ERR_HOST (9) -+#define DOWNLOAD_ERR_ABORT (10) -+ -+#define SYS_BASE_ADDR_SILICON (0) -+#define AHB_MEMORY_ADDRESS (SYS_BASE_ADDR_SILICON + 0x08000000) -+#define PAC_BASE_ADDRESS_SILICON (SYS_BASE_ADDR_SILICON + 0x09000000) -+#define PAC_SHARED_MEMORY_SILICON (PAC_BASE_ADDRESS_SILICON) -+#define APB_ADDR(addr) (PAC_SHARED_MEMORY_SILICON + (addr)) -+ -+/* *************************************************************** -+*Device register definitions -+*************************************************************** */ -+/* WBF - SPI Register Addresses */ -+#define HIF_ADDR_ID_BASE (0x0000) -+/* 16/32 bits */ -+#define HIF_CONFIG_REG_ID (0x0000) -+/* 16/32 bits */ -+#define HIF_CONTROL_REG_ID (0x0001) -+/* 16 bits, Q mode W/R */ -+#define HIF_IN_OUT_QUEUE_REG_ID (0x0002) -+/* 32 bits, AHB bus R/W */ -+#define HIF_AHB_DPORT_REG_ID (0x0003) -+/* 16/32 bits */ -+#define HIF_SRAM_BASE_ADDR_REG_ID (0x0004) -+/* 32 bits, APB bus R/W */ -+#define HIF_SRAM_DPORT_REG_ID (0x0005) -+/* 32 bits, t_settle/general */ -+#define HIF_TSET_GEN_R_W_REG_ID (0x0006) -+/* 16 bits, Q mode read, no length */ -+#define HIF_FRAME_OUT_REG_ID (0x0007) -+#define HIF_ADDR_ID_MAX (HIF_FRAME_OUT_REG_ID) -+ -+/* WBF - Control register bit set */ -+/* next o/p length, bit 11 to 0 */ -+#define HIF_CTRL_NEXT_LEN_MASK (0x0FFF) -+#define HIF_CTRL_WUP_BIT (BIT(12)) -+#define HIF_CTRL_RDY_BIT (BIT(13)) -+#define HIF_CTRL_IRQ_ENABLE (BIT(14)) -+#define HIF_CTRL_RDY_ENABLE (BIT(15)) -+#define HIF_CTRL_IRQ_RDY_ENABLE (BIT(14)|BIT(15)) -+ -+/* SPI Config register bit set */ -+#define HIF_CONFIG_FRAME_BIT (BIT(2)) -+#define HIF_CONFIG_WORD_MODE_BITS (BIT(3)|BIT(4)) -+#define HIF_CONFIG_WORD_MODE_1 (BIT(3)) -+#define HIF_CONFIG_WORD_MODE_2 (BIT(4)) -+#define HIF_CONFIG_ERROR_0_BIT (BIT(5)) -+#define HIF_CONFIG_ERROR_1_BIT (BIT(6)) -+#define HIF_CONFIG_ERROR_2_BIT (BIT(7)) -+/* TBD: Sure??? */ -+#define HIF_CONFIG_CSN_FRAME_BIT (BIT(7)) -+#define HIF_CONFIG_ERROR_3_BIT (BIT(8)) -+#define HIF_CONFIG_ERROR_4_BIT (BIT(9)) -+/* QueueM */ -+#define HIF_CONFIG_ACCESS_MODE_BIT (BIT(10)) -+/* AHB bus */ -+#define HIF_CONFIG_AHB_PFETCH_BIT (BIT(11)) -+#define HIF_CONFIG_CPU_CLK_DIS_BIT (BIT(12)) -+/* APB bus */ -+#define HIF_CONFIG_PFETCH_BIT (BIT(13)) -+/* cpu reset */ -+#define HIF_CONFIG_CPU_RESET_BIT (BIT(14)) -+#define HIF_CONFIG_CLEAR_INT_BIT (BIT(15)) -+ -+/* For XRADIO the IRQ Enable and Ready Bits are in CONFIG register */ -+#define HIF_CONF_IRQ_RDY_ENABLE (BIT(16)|BIT(17)) -+ -+int xradio_data_read(struct xradio_common *hw_priv, void *buf, size_t buf_len); -+int xradio_data_write(struct xradio_common *hw_priv, const void *buf, size_t buf_len); -+int xradio_reg_read(struct xradio_common *hw_priv, u16 addr, void *buf, size_t buf_len); -+int xradio_reg_write(struct xradio_common *hw_priv, u16 addr, const void *buf, size_t buf_len); -+int xradio_indirect_read(struct xradio_common *hw_priv, u32 addr, void *buf, -+ size_t buf_len, u32 prefetch, u16 port_addr); -+int xradio_apb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, size_t buf_len); -+int xradio_ahb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, size_t buf_len); -+ -+ -+static inline int xradio_reg_read_16(struct xradio_common *hw_priv, -+ u16 addr, u16 *val) -+{ -+ int ret = 0; -+ u32 bigVal = 0; -+ ret = xradio_reg_read(hw_priv, addr, &bigVal, sizeof(bigVal)); -+ *val = (u16)bigVal; -+ return ret; -+} -+ -+static inline int xradio_reg_write_16(struct xradio_common *hw_priv, -+ u16 addr, u16 val) -+{ -+ u32 bigVal = (u32)val; -+ return xradio_reg_write(hw_priv, addr, &bigVal, sizeof(bigVal)); -+} -+ -+static inline int xradio_reg_read_32(struct xradio_common *hw_priv, -+ u16 addr, u32 *val) -+{ -+ return xradio_reg_read(hw_priv, addr, val, sizeof(val)); -+} -+ -+static inline int xradio_reg_write_32(struct xradio_common *hw_priv, -+ u16 addr, u32 val) -+{ -+ return xradio_reg_write(hw_priv, addr, &val, sizeof(val)); -+} -+ -+static inline int xradio_apb_read(struct xradio_common *hw_priv, u32 addr, -+ void *buf, size_t buf_len) -+{ -+ return xradio_indirect_read(hw_priv, addr, buf, buf_len, HIF_CONFIG_PFETCH_BIT, -+ HIF_SRAM_DPORT_REG_ID); -+} -+ -+static inline int xradio_ahb_read(struct xradio_common *hw_priv, u32 addr, -+ void *buf, size_t buf_len) -+{ -+ return xradio_indirect_read(hw_priv, addr, buf, buf_len, HIF_CONFIG_AHB_PFETCH_BIT, -+ HIF_AHB_DPORT_REG_ID); -+} -+ -+static inline int xradio_apb_read_32(struct xradio_common *hw_priv, -+ u32 addr, u32 *val) -+{ -+ return xradio_apb_read(hw_priv, addr, val, sizeof(val)); -+} -+ -+static inline int xradio_apb_write_32(struct xradio_common *hw_priv, -+ u32 addr, u32 val) -+{ -+ return xradio_apb_write(hw_priv, addr, &val, sizeof(val)); -+} -+ -+static inline int xradio_ahb_read_32(struct xradio_common *hw_priv, -+ u32 addr, u32 *val) -+{ -+ return xradio_ahb_read(hw_priv, addr, val, sizeof(val)); -+} -+ -+static inline int xradio_ahb_write_32(struct xradio_common *hw_priv, -+ u32 addr, u32 val) -+{ -+ return xradio_ahb_write(hw_priv, addr, &val, sizeof(val)); -+} -+ -+#endif /* XRADIO_HWIO_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/keys.c b/drivers/net/wireless/xradio/keys.c -new file mode 100644 -index 0000000..20050e1 ---- /dev/null -+++ b/drivers/net/wireless/xradio/keys.c -@@ -0,0 +1,193 @@ -+#include -+ -+#include "xradio.h" -+#include "sta.h" -+#include "keys.h" -+ -+int xradio_alloc_key(struct xradio_common *hw_priv) -+{ -+ int idx; -+ -+ idx = ffs(~hw_priv->key_map) - 1; -+ if (idx < 0 || idx > WSM_KEY_MAX_INDEX) -+ return -1; -+ -+ hw_priv->key_map |= BIT(idx); -+ hw_priv->keys[idx].entryIndex = idx; -+ return idx; -+} -+ -+void xradio_free_key(struct xradio_common *hw_priv, int idx) -+{ -+ BUG_ON(!(hw_priv->key_map & BIT(idx))); -+ memset(&hw_priv->keys[idx], 0, sizeof(hw_priv->keys[idx])); -+ hw_priv->key_map &= ~BIT(idx); -+} -+ -+void xradio_free_keys(struct xradio_common *hw_priv) -+{ -+ memset(&hw_priv->keys, 0, sizeof(hw_priv->keys)); -+ hw_priv->key_map = 0; -+} -+ -+int xradio_upload_keys(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int idx, ret = 0; -+ -+ -+ for (idx = 0; idx <= WSM_KEY_MAX_IDX; ++idx) -+ if (hw_priv->key_map & BIT(idx)) { -+ ret = wsm_add_key(hw_priv, &hw_priv->keys[idx], priv->if_id); -+ if (ret < 0) -+ break; -+ } -+ return ret; -+} -+ -+int xradio_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, -+ struct ieee80211_vif *vif, struct ieee80211_sta *sta, -+ struct ieee80211_key_conf *key) -+{ -+#ifdef XRADIO_DISABLE_HW_CRYPTO -+ wiphy_info(dev->wiphy, "hw crypto is disabled, ignoring key request\n"); -+ return -EOPNOTSUPP; -+#else -+ int ret = -EOPNOTSUPP; -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ -+ wiphy_dbg(dev->wiphy, "vif %d: set_key cmd %d\n", priv->if_id, (int) cmd); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ if (cmd == SET_KEY) { -+ u8 *peer_addr = NULL; -+ int pairwise = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ? 1 : 0; -+ int idx = xradio_alloc_key(hw_priv); -+ struct wsm_add_key *wsm_key = &hw_priv->keys[idx]; -+ -+ if (idx < 0) { -+ wiphy_err(dev->wiphy, "xradio_alloc_key failed!\n"); -+ ret = -EINVAL; -+ goto finally; -+ } -+ -+ BUG_ON(pairwise && !sta); -+ if (sta) -+ peer_addr = sta->addr; -+ -+ key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; -+ -+ priv->cipherType = key->cipher; -+ switch (key->cipher) { -+ case WLAN_CIPHER_SUITE_WEP40: -+ case WLAN_CIPHER_SUITE_WEP104: -+ if (key->keylen > 16) { -+ xradio_free_key(hw_priv, idx); -+ wiphy_err(dev->wiphy, "keylen too long=%d!\n", key->keylen); -+ ret = -EINVAL; -+ goto finally; -+ } -+ -+ if (pairwise) { -+ wsm_key->type = WSM_KEY_TYPE_WEP_PAIRWISE; -+ memcpy(wsm_key->wepPairwiseKey.peerAddress, peer_addr, ETH_ALEN); -+ memcpy(wsm_key->wepPairwiseKey.keyData, &key->key[0], key->keylen); -+ wsm_key->wepPairwiseKey.keyLength = key->keylen; -+ } else { -+ wsm_key->type = WSM_KEY_TYPE_WEP_DEFAULT; -+ memcpy(wsm_key->wepGroupKey.keyData, &key->key[0], key->keylen); -+ wsm_key->wepGroupKey.keyLength = key->keylen; -+ wsm_key->wepGroupKey.keyId = key->keyidx; -+ } -+ break; -+ case WLAN_CIPHER_SUITE_TKIP: -+ if (pairwise) { -+ wsm_key->type = WSM_KEY_TYPE_TKIP_PAIRWISE; -+ memcpy(wsm_key->tkipPairwiseKey.peerAddress, peer_addr, ETH_ALEN); -+ memcpy(wsm_key->tkipPairwiseKey.tkipKeyData, &key->key[0], 16); -+ memcpy(wsm_key->tkipPairwiseKey.txMicKey, &key->key[16], 8); -+ memcpy(wsm_key->tkipPairwiseKey.rxMicKey, &key->key[24], 8); -+ } else { -+ size_t mic_offset = (priv->mode == NL80211_IFTYPE_AP) ? 16 : 24; -+ wsm_key->type = WSM_KEY_TYPE_TKIP_GROUP; -+ memcpy(wsm_key->tkipGroupKey.tkipKeyData,&key->key[0], 16); -+ memcpy(wsm_key->tkipGroupKey.rxMicKey, &key->key[mic_offset], 8); -+ -+ /* TODO: Where can I find TKIP SEQ? */ -+ memset(wsm_key->tkipGroupKey.rxSeqCounter, 0, 8); -+ wsm_key->tkipGroupKey.keyId = key->keyidx; -+ } -+ break; -+ case WLAN_CIPHER_SUITE_CCMP: -+ if (pairwise) { -+ wsm_key->type = WSM_KEY_TYPE_AES_PAIRWISE; -+ memcpy(wsm_key->aesPairwiseKey.peerAddress, peer_addr, ETH_ALEN); -+ memcpy(wsm_key->aesPairwiseKey.aesKeyData, &key->key[0], 16); -+ wiphy_debug(dev->wiphy, "CCMP_PAIRWISE keylen=%d!\n", -+ key->keylen); -+ } else { -+ wsm_key->type = WSM_KEY_TYPE_AES_GROUP; -+ memcpy(wsm_key->aesGroupKey.aesKeyData, &key->key[0], 16); -+ /* TODO: Where can I find AES SEQ? */ -+ memset(wsm_key->aesGroupKey.rxSeqCounter, 0, 8); -+ wsm_key->aesGroupKey.keyId = key->keyidx; -+ } -+ break; -+#ifdef CONFIG_XRADIO_WAPI_SUPPORT -+ case WLAN_CIPHER_SUITE_SMS4: -+ if (pairwise) { -+ wsm_key->type = WSM_KEY_TYPE_WAPI_PAIRWISE; -+ memcpy(wsm_key->wapiPairwiseKey.peerAddress, peer_addr, ETH_ALEN); -+ memcpy(wsm_key->wapiPairwiseKey.wapiKeyData, &key->key[0], 16); -+ memcpy(wsm_key->wapiPairwiseKey.micKeyData, &key->key[16], 16); -+ wsm_key->wapiPairwiseKey.keyId = key->keyidx; -+ sta_printk(XRADIO_DBG_NIY,"%s: WAPI_PAIRWISE keylen=%d!\n", -+ __func__, key->keylen); -+ } else { -+ wsm_key->type = WSM_KEY_TYPE_WAPI_GROUP; -+ memcpy(wsm_key->wapiGroupKey.wapiKeyData, &key->key[0], 16); -+ memcpy(wsm_key->wapiGroupKey.micKeyData, &key->key[16], 16); -+ wsm_key->wapiGroupKey.keyId = key->keyidx; -+ sta_printk(XRADIO_DBG_NIY,"%s: WAPI_GROUP keylen=%d!\n", -+ __func__, key->keylen); -+ } -+ break; -+#endif /* CONFIG_XRADIO_WAPI_SUPPORT */ -+ default: -+ wiphy_err(dev->wiphy, "key->cipher unknown(%d)!\n", key->cipher); -+ xradio_free_key(hw_priv, idx); -+ ret = -EOPNOTSUPP; -+ goto finally; -+ } -+ ret = WARN_ON(wsm_add_key(hw_priv, wsm_key, priv->if_id)); -+ if (!ret) -+ key->hw_key_idx = idx; -+ else -+ xradio_free_key(hw_priv, idx); -+ -+ if (!ret && (pairwise || wsm_key->type == WSM_KEY_TYPE_WEP_DEFAULT) && -+ (priv->filter4.enable & 0x2)) -+ xradio_set_arpreply(dev, vif); -+ } else if (cmd == DISABLE_KEY) { -+ struct wsm_remove_key wsm_key = { -+ .entryIndex = key->hw_key_idx, -+ }; -+ -+ if (wsm_key.entryIndex > WSM_KEY_MAX_IDX) { -+ ret = -EINVAL; -+ goto finally; -+ } -+ -+ xradio_free_key(hw_priv, wsm_key.entryIndex); -+ ret = wsm_remove_key(hw_priv, &wsm_key, priv->if_id); -+ } else { -+ wiphy_err(dev->wiphy, "Unsupported command\n"); -+ } -+ -+finally: -+ mutex_unlock(&hw_priv->conf_mutex); -+ return ret; -+#endif // XRADIO_DISABLE_HW_CRYPTO -+} -diff --git a/drivers/net/wireless/xradio/keys.h b/drivers/net/wireless/xradio/keys.h -new file mode 100644 -index 0000000..23c5880 ---- /dev/null -+++ b/drivers/net/wireless/xradio/keys.h -@@ -0,0 +1,12 @@ -+#ifndef __KEYS_H_ -+#define __KEYS_H_INCLUDED -+ -+int xradio_alloc_key(struct xradio_common *hw_priv); -+void xradio_free_key(struct xradio_common *hw_priv, int idx); -+void xradio_free_keys(struct xradio_common *hw_priv); -+int xradio_upload_keys(struct xradio_vif *priv); -+int xradio_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, -+ struct ieee80211_vif *vif, struct ieee80211_sta *sta, -+ struct ieee80211_key_conf *key); -+ -+#endif -\ No newline at end of file -diff --git a/drivers/net/wireless/xradio/main.c b/drivers/net/wireless/xradio/main.c -new file mode 100644 -index 0000000..346710c ---- /dev/null -+++ b/drivers/net/wireless/xradio/main.c -@@ -0,0 +1,609 @@ -+/* -+ * Main code of XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "fwio.h" -+#include "hwio.h" -+#include "bh.h" -+#include "sta.h" -+#include "ap.h" -+#include "keys.h" -+#include "scan.h" -+#include "pm.h" -+#include "sdio.h" -+ -+/* TODO: use rates and channels from the device */ -+#define RATETAB_ENT(_rate, _rateid, _flags) \ -+ { \ -+ .bitrate = (_rate), \ -+ .hw_value = (_rateid), \ -+ .flags = (_flags), \ -+ } -+ -+static struct ieee80211_rate xradio_rates[] = { -+ RATETAB_ENT(10, 0, 0), -+ RATETAB_ENT(20, 1, 0), -+ RATETAB_ENT(55, 2, 0), -+ RATETAB_ENT(110, 3, 0), -+ RATETAB_ENT(60, 6, 0), -+ RATETAB_ENT(90, 7, 0), -+ RATETAB_ENT(120, 8, 0), -+ RATETAB_ENT(180, 9, 0), -+ RATETAB_ENT(240, 10, 0), -+ RATETAB_ENT(360, 11, 0), -+ RATETAB_ENT(480, 12, 0), -+ RATETAB_ENT(540, 13, 0), -+}; -+ -+static struct ieee80211_rate xradio_mcs_rates[] = { -+ RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS), -+ RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS), -+}; -+ -+#define xradio_g_rates (xradio_rates + 0) -+#define xradio_a_rates (xradio_rates + 4) -+#define xradio_n_rates (xradio_mcs_rates) -+ -+#define xradio_g_rates_size (ARRAY_SIZE(xradio_rates)) -+#define xradio_a_rates_size (ARRAY_SIZE(xradio_rates) - 4) -+#define xradio_n_rates_size (ARRAY_SIZE(xradio_mcs_rates)) -+ -+#define CHAN2G(_channel, _freq, _flags) { \ -+ .band = NL80211_BAND_2GHZ, \ -+ .center_freq = (_freq), \ -+ .hw_value = (_channel), \ -+ .flags = (_flags), \ -+ .max_antenna_gain = 0, \ -+ .max_power = 30, \ -+} -+ -+#define CHAN5G(_channel, _flags) { \ -+ .band = NL80211_BAND_5GHZ, \ -+ .center_freq = 5000 + (5 * (_channel)), \ -+ .hw_value = (_channel), \ -+ .flags = (_flags), \ -+ .max_antenna_gain = 0, \ -+ .max_power = 30, \ -+} -+ -+static struct ieee80211_channel xradio_2ghz_chantable[] = { -+ CHAN2G(1, 2412, 0), -+ CHAN2G(2, 2417, 0), -+ CHAN2G(3, 2422, 0), -+ CHAN2G(4, 2427, 0), -+ CHAN2G(5, 2432, 0), -+ CHAN2G(6, 2437, 0), -+ CHAN2G(7, 2442, 0), -+ CHAN2G(8, 2447, 0), -+ CHAN2G(9, 2452, 0), -+ CHAN2G(10, 2457, 0), -+ CHAN2G(11, 2462, 0), -+ CHAN2G(12, 2467, 0), -+ CHAN2G(13, 2472, 0), -+ CHAN2G(14, 2484, 0), -+}; -+ -+static struct ieee80211_supported_band xradio_band_2ghz = { -+ .channels = xradio_2ghz_chantable, -+ .n_channels = ARRAY_SIZE(xradio_2ghz_chantable), -+ .bitrates = xradio_g_rates, -+ .n_bitrates = xradio_g_rates_size, -+ .ht_cap = { -+ .cap = IEEE80211_HT_CAP_GRN_FLD | -+ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), -+ .ht_supported = 1, -+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_32K, -+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, -+ .mcs = { -+ .rx_mask[0] = 0xFF, -+ .rx_highest = __cpu_to_le16(0x41), -+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, -+ }, -+ }, -+}; -+ -+static const unsigned long xradio_ttl[] = { -+ 1 * HZ, /* VO */ -+ 2 * HZ, /* VI */ -+ 5 * HZ, /* BE */ -+ 10 * HZ /* BK */ -+}; -+ -+static const struct ieee80211_ops xradio_ops = { -+ .start = xradio_start, -+ .stop = xradio_stop, -+ .add_interface = xradio_add_interface, -+ .remove_interface = xradio_remove_interface, -+ .change_interface = xradio_change_interface, -+ .tx = xradio_tx, -+ .hw_scan = xradio_hw_scan, -+#ifdef ROAM_OFFLOAD -+ .sched_scan_start = xradio_hw_sched_scan_start, -+ .sched_scan_stop = xradio_hw_sched_scan_stop, -+#endif /*ROAM_OFFLOAD*/ -+ .set_tim = xradio_set_tim, -+ .sta_notify = xradio_sta_notify, -+ .sta_add = xradio_sta_add, -+ .sta_remove = xradio_sta_remove, -+ .set_key = xradio_set_key, -+ .set_rts_threshold = xradio_set_rts_threshold, -+ .config = xradio_config, -+ .bss_info_changed = xradio_bss_info_changed, -+ .prepare_multicast = xradio_prepare_multicast, -+ .configure_filter = xradio_configure_filter, -+ .conf_tx = xradio_conf_tx, -+ .get_stats = xradio_get_stats, -+ .ampdu_action = xradio_ampdu_action, -+ .flush = xradio_flush, -+#ifdef CONFIG_PM -+ .suspend = xradio_wow_suspend, -+ .resume = xradio_wow_resume, -+#endif /* CONFIG_PM */ -+ /* Intentionally not offloaded: */ -+ /*.channel_switch = xradio_channel_switch, */ -+ .remain_on_channel = xradio_remain_on_channel, -+ .cancel_remain_on_channel = xradio_cancel_remain_on_channel, -+}; -+ -+ -+/*************************************** functions ***************************************/ -+ -+static void xradio_set_ifce_comb(struct xradio_common *hw_priv, -+ struct ieee80211_hw *hw) -+{ -+ hw_priv->if_limits1[0].max = 1; -+ -+ hw_priv->if_limits1[0].types = BIT(NL80211_IFTYPE_STATION); -+ hw_priv->if_limits1[1].max = 1; -+ hw_priv->if_limits1[1].types = BIT(NL80211_IFTYPE_AP); -+ -+ hw_priv->if_limits2[0].max = 2; -+ hw_priv->if_limits2[0].types = BIT(NL80211_IFTYPE_STATION); -+ -+ hw_priv->if_limits3[0].max = 1; -+ -+ hw_priv->if_limits3[0].types = BIT(NL80211_IFTYPE_STATION); -+ hw_priv->if_limits3[1].max = 1; -+ hw_priv->if_limits3[1].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | -+ BIT(NL80211_IFTYPE_P2P_GO); -+ -+ /* TODO:COMBO: mac80211 doesn't yet support more than 1 -+ * different channel */ -+ hw_priv->if_combs[0].num_different_channels = 1; -+ hw_priv->if_combs[0].max_interfaces = 2; -+ hw_priv->if_combs[0].limits = hw_priv->if_limits1; -+ hw_priv->if_combs[0].n_limits = 2; -+ -+ hw_priv->if_combs[1].num_different_channels = 1; -+ -+ hw_priv->if_combs[1].max_interfaces = 2; -+ hw_priv->if_combs[1].limits = hw_priv->if_limits2; -+ hw_priv->if_combs[1].n_limits = 1; -+ -+ hw_priv->if_combs[2].num_different_channels = 1; -+ hw_priv->if_combs[2].max_interfaces = 2; -+ hw_priv->if_combs[2].limits = hw_priv->if_limits3; -+ hw_priv->if_combs[2].n_limits = 2; -+ -+ hw->wiphy->iface_combinations = &hw_priv->if_combs[0]; -+ hw->wiphy->n_iface_combinations = 3; -+} -+ -+struct ieee80211_hw *xradio_init_common(size_t hw_priv_data_len) -+{ -+ int i; -+ struct ieee80211_hw *hw; -+ struct xradio_common *hw_priv; -+ struct ieee80211_supported_band *sband; -+ int band; -+ -+ /* Alloc ieee_802.11 hw and xradio_common struct. */ -+ hw = ieee80211_alloc_hw(hw_priv_data_len, &xradio_ops); -+ if (!hw) -+ return NULL; -+ hw_priv = hw->priv; -+ memset(hw_priv, 0, sizeof(*hw_priv)); -+ -+ /* Initialize members of hw_priv. */ -+ hw_priv->hw = hw; -+ hw_priv->if_id_slot = 0; -+ hw_priv->roc_if_id = -1; -+ atomic_set(&hw_priv->num_vifs, 0); -+ /* initial rates and channels TODO: fetch from FW */ -+ hw_priv->rates = xradio_rates; -+ hw_priv->mcs_rates = xradio_n_rates; -+#ifdef ROAM_OFFLOAD -+ hw_priv->auto_scanning = 0; -+ hw_priv->frame_rcvd = 0; -+ hw_priv->num_scanchannels = 0; -+ hw_priv->num_2g_channels = 0; -+ hw_priv->num_5g_channels = 0; -+#endif /*ROAM_OFFLOAD*/ -+#ifdef AP_AGGREGATE_FW_FIX -+ /* Enable block ACK for 4 TID (BE,VI,VI,VO). */ -+ hw_priv->ba_tid_mask = 0xB1; /*due to HW limitations*/ -+#else -+ /* Enable block ACK for every TID but voice. */ -+ hw_priv->ba_tid_mask = 0x3F; -+#endif -+ hw_priv->noise = -94; -+ /* hw_priv->beacon_req_id = cpu_to_le32(0); */ -+ -+ /* Initialize members of ieee80211_hw, it works in UMAC. */ -+ hw->sta_data_size = sizeof(struct xradio_sta_priv); -+ hw->vif_data_size = sizeof(struct xradio_vif); -+ -+ ieee80211_hw_set(hw, SIGNAL_DBM); -+ ieee80211_hw_set(hw, SUPPORTS_PS); -+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); -+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); -+ ieee80211_hw_set(hw, CONNECTION_MONITOR); -+ -+/* hw->flags = IEEE80211_HW_SIGNAL_DBM | -+ IEEE80211_HW_SUPPORTS_PS | -+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS | -+ IEEE80211_HW_REPORTS_TX_ACK_STATUS | -+ IEEE80211_HW_CONNECTION_MONITOR;*/ -+ //IEEE80211_HW_SUPPORTS_CQM_RSSI | -+ /* Aggregation is fully controlled by firmware. -+ * Do not need any support from the mac80211 stack */ -+ /* IEEE80211_HW_AMPDU_AGGREGATION | */ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //IEEE80211_HW_SUPPORTS_P2P_PS | -+ //IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS | -+ // IEEE80211_HW_SUPPORTS_CQM_TX_FAIL | -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ //IEEE80211_HW_BEACON_FILTER; -+ -+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -+ BIT(NL80211_IFTYPE_ADHOC) | -+ BIT(NL80211_IFTYPE_AP) | -+ BIT(NL80211_IFTYPE_MESH_POINT) | -+ BIT(NL80211_IFTYPE_P2P_CLIENT) | -+ BIT(NL80211_IFTYPE_P2P_GO); -+ -+ /* Support only for limited wowlan functionalities */ -+ /* TODO by Icenowy: RESTORE THIS */ -+/* hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT; -+ hw->wiphy->wowlan.n_patterns = 0;*/ -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ /* fix the problem that driver can not set pro-resp template frame to fw */ -+ hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; -+ -+#if defined(CONFIG_XRADIO_DISABLE_BEACON_HINTS) -+ hw->wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; -+#endif -+ hw->wiphy->n_addresses = XRWL_MAX_VIFS; -+ hw->wiphy->addresses = hw_priv->addresses; -+ hw->wiphy->max_remain_on_channel_duration = 500; -+ hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + -+ 8 /* TKIP IV */ + -+ 12 /* TKIP ICV and MIC */; -+ hw->wiphy->bands[NL80211_BAND_2GHZ] = &xradio_band_2ghz; -+ hw->queues = AC_QUEUE_NUM; -+ hw->max_rates = MAX_RATES_STAGE; -+ hw->max_rate_tries = MAX_RATES_RETRY; -+ /* Channel params have to be cleared before registering wiphy again */ -+ for (band = 0; band < NUM_NL80211_BANDS; band++) { -+ sband = hw->wiphy->bands[band]; -+ if (!sband) -+ continue; -+ for (i = 0; i < sband->n_channels; i++) { -+ sband->channels[i].flags = 0; -+ sband->channels[i].max_antenna_gain = 0; -+ sband->channels[i].max_power = 30; -+ } -+ } -+ /* hw_priv->channel init value is the local->oper_channel init value;when transplanting,take care */ -+ for (band = 0; band < NUM_NL80211_BANDS; band++) { -+ sband = hw->wiphy->bands[band]; -+ if (!sband) -+ continue; -+ if(!hw_priv->channel){ -+ hw_priv->channel = &sband->channels[2]; -+ } -+ } -+ hw->wiphy->max_scan_ssids = WSM_SCAN_MAX_NUM_OF_SSIDS; -+ hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; -+ SET_IEEE80211_PERM_ADDR(hw, hw_priv->addresses[0].addr); -+ -+ /* Initialize locks. */ -+ spin_lock_init(&hw_priv->vif_list_lock); -+ mutex_init(&hw_priv->wsm_cmd_mux); -+ mutex_init(&hw_priv->conf_mutex); -+ mutex_init(&hw_priv->wsm_oper_lock); -+ atomic_set(&hw_priv->tx_lock, 0); -+ sema_init(&hw_priv->tx_lock_sem, 1); -+ -+ hw_priv->workqueue = create_singlethread_workqueue(XRADIO_WORKQUEUE); -+ sema_init(&hw_priv->scan.lock, 1); -+ sema_init(&hw_priv->scan.status_lock,1); -+ INIT_WORK(&hw_priv->scan.work, xradio_scan_work); -+#ifdef ROAM_OFFLOAD -+ INIT_WORK(&hw_priv->scan.swork, xradio_sched_scan_work); -+#endif /*ROAM_OFFLOAD*/ -+ INIT_DELAYED_WORK(&hw_priv->scan.probe_work, xradio_probe_work); -+ INIT_DELAYED_WORK(&hw_priv->scan.timeout, xradio_scan_timeout); -+ INIT_DELAYED_WORK(&hw_priv->rem_chan_timeout, xradio_rem_chan_timeout); -+ INIT_WORK(&hw_priv->tx_policy_upload_work, tx_policy_upload_work); -+ atomic_set(&hw_priv->upload_count, 0); -+ memset(&hw_priv->connet_time, 0, sizeof(hw_priv->connet_time)); -+ -+ spin_lock_init(&hw_priv->event_queue_lock); -+ INIT_LIST_HEAD(&hw_priv->event_queue); -+ INIT_WORK(&hw_priv->event_handler, xradio_event_handler); -+ INIT_WORK(&hw_priv->ba_work, xradio_ba_work); -+ spin_lock_init(&hw_priv->ba_lock); -+ timer_setup(&hw_priv->ba_timer, xradio_ba_timer, 0); -+ -+ if (unlikely(xradio_queue_stats_init(&hw_priv->tx_queue_stats, -+ WLAN_LINK_ID_MAX,xradio_skb_dtor, hw_priv))) { -+ ieee80211_free_hw(hw); -+ return NULL; -+ } -+ for (i = 0; i < AC_QUEUE_NUM; ++i) { -+ if (unlikely(xradio_queue_init(&hw_priv->tx_queue[i], -+ &hw_priv->tx_queue_stats, i, XRWL_MAX_QUEUE_SZ, xradio_ttl[i]))) { -+ for (; i > 0; i--) -+ xradio_queue_deinit(&hw_priv->tx_queue[i - 1]); -+ xradio_queue_stats_deinit(&hw_priv->tx_queue_stats); -+ ieee80211_free_hw(hw); -+ return NULL; -+ } -+ } -+ -+ init_waitqueue_head(&hw_priv->channel_switch_done); -+ init_waitqueue_head(&hw_priv->wsm_cmd_wq); -+ init_waitqueue_head(&hw_priv->wsm_startup_done); -+ init_waitqueue_head(&hw_priv->offchannel_wq); -+ hw_priv->wsm_caps.firmwareReady = 0; -+ hw_priv->driver_ready = 0; -+ hw_priv->offchannel_done = 0; -+ wsm_buf_init(&hw_priv->wsm_cmd_buf); -+ spin_lock_init(&hw_priv->wsm_cmd.lock); -+ tx_policy_init(hw_priv); -+ xradio_init_resv_skb(hw_priv); -+ /* add for setting short_frame_max_tx_count(mean wdev->retry_short) to drv,init the max_rate_tries */ -+ spin_lock_bh(&hw_priv->tx_policy_cache.lock); -+ hw_priv->long_frame_max_tx_count = hw->conf.long_frame_max_tx_count; -+ hw_priv->short_frame_max_tx_count = -+ (hw->conf.short_frame_max_tx_count< 0x0F) ? -+ hw->conf.short_frame_max_tx_count : 0x0F; -+ hw_priv->hw->max_rate_tries = hw->conf.short_frame_max_tx_count; -+ spin_unlock_bh(&hw_priv->tx_policy_cache.lock); -+ -+ for (i = 0; i < XRWL_MAX_VIFS; i++) -+ hw_priv->hw_bufs_used_vif[i] = 0; -+ -+#ifdef MCAST_FWDING -+ for (i = 0; i < WSM_MAX_BUF; i++) -+ wsm_init_release_buffer_request(hw_priv, i); -+ hw_priv->buf_released = 0; -+#endif -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ -+ hw_priv->query_packetID = 0; -+ atomic_set(&hw_priv->query_cnt, 0); -+ INIT_WORK(&hw_priv->query_work, wsm_query_work); -+ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+ atomic_set(&hw_priv->suspend_state, XRADIO_RESUME); -+#endif -+ -+ xradio_set_ifce_comb(hw_priv, hw_priv->hw); -+ -+ return hw; -+} -+ -+void xradio_free_common(struct ieee80211_hw *dev) -+{ -+ int i; -+ struct xradio_common *hw_priv = dev->priv; -+ -+ cancel_work_sync(&hw_priv->query_work); -+ del_timer_sync(&hw_priv->ba_timer); -+ mutex_destroy(&hw_priv->wsm_oper_lock); -+ mutex_destroy(&hw_priv->conf_mutex); -+ mutex_destroy(&hw_priv->wsm_cmd_mux); -+ wsm_buf_deinit(&hw_priv->wsm_cmd_buf); -+ flush_workqueue(hw_priv->workqueue); -+ destroy_workqueue(hw_priv->workqueue); -+ hw_priv->workqueue = NULL; -+ -+ xradio_deinit_resv_skb(hw_priv); -+ if (hw_priv->skb_cache) { -+ dev_kfree_skb(hw_priv->skb_cache); -+ hw_priv->skb_cache = NULL; -+ } -+ -+ for (i = 0; i < 4; ++i) -+ xradio_queue_deinit(&hw_priv->tx_queue[i]); -+ xradio_queue_stats_deinit(&hw_priv->tx_queue_stats); -+ -+ for (i = 0; i < XRWL_MAX_VIFS; i++) { -+ kfree(hw_priv->vif_list[i]); -+ hw_priv->vif_list[i] = NULL; -+ } -+ -+//fixed memory leakage by yangfh -+#ifdef MCAST_FWDING -+ wsm_deinit_release_buffer(hw_priv); -+#endif -+ /* unsigned int i; */ -+ ieee80211_free_hw(dev); -+} -+ -+int xradio_register_common(struct ieee80211_hw *dev) -+{ -+ int err = 0; -+ struct xradio_common *hw_priv = dev->priv; -+ -+ SET_IEEE80211_DEV(dev, hw_priv->pdev); -+ err = ieee80211_register_hw(dev); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "Cannot register device (%d).\n", err); -+ return err; -+ } -+ dev_dbg(hw_priv->pdev, "is registered as '%s'\n", -+ wiphy_name(dev->wiphy)); -+ -+ hw_priv->driver_ready = 1; -+ wake_up(&hw_priv->wsm_startup_done); -+ return 0; -+} -+ -+void xradio_unregister_common(struct ieee80211_hw *dev) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ -+ if (wiphy_dev(dev->wiphy)) { -+ ieee80211_unregister_hw(dev); -+ SET_IEEE80211_DEV(dev, NULL); -+ } -+ hw_priv->driver_ready = 0; -+} -+ -+int xradio_core_init(struct sdio_func* func) -+{ -+ int err = -ENOMEM; -+ u16 ctrl_reg; -+ int if_id; -+ struct ieee80211_hw *dev; -+ struct xradio_common *hw_priv; -+ unsigned char randomaddr[ETH_ALEN]; -+ const unsigned char *addr = NULL; -+ -+ //init xradio_common -+ dev = xradio_init_common(sizeof(struct xradio_common)); -+ if (!dev) { -+ dev_dbg(&func->dev, "xradio_init_common failed\n"); -+ return err; -+ } -+ hw_priv = dev->priv; -+ hw_priv->pdev = &func->dev; -+ hw_priv->sdio_func = func; -+ sdio_set_drvdata(func, hw_priv); -+ -+ // fill in mac addresses -+ if (hw_priv->pdev->of_node) { -+ addr = of_get_mac_address(hw_priv->pdev->of_node); -+ } -+ if (!addr) { -+ dev_warn(hw_priv->pdev, "no mac address provided, using random\n"); -+ eth_random_addr(randomaddr); -+ addr = randomaddr; -+ } -+ memcpy(hw_priv->addresses[0].addr, addr, ETH_ALEN); -+ memcpy(hw_priv->addresses[1].addr, addr, ETH_ALEN); -+ hw_priv->addresses[1].addr[5] += 0x01; -+ -+ /*init pm and wakelock. */ -+#ifdef CONFIG_PM -+ err = xradio_pm_init(&hw_priv->pm_state, hw_priv); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "xradio_pm_init failed(%d).\n", err); -+ goto err2; -+ } -+#endif -+ /* Register bh thread*/ -+ err = xradio_register_bh(hw_priv); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "xradio_register_bh failed(%d).\n", err); -+ goto err3; -+ } -+ -+ /* Load firmware and register Interrupt Handler */ -+ err = xradio_load_firmware(hw_priv); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "xradio_load_firmware failed(%d).\n", err); -+ goto err4; -+ } -+ -+ /* Set sdio blocksize. */ -+ sdio_lock(hw_priv); -+ WARN_ON(sdio_set_blk_size(hw_priv, -+ SDIO_BLOCK_SIZE)); -+ sdio_unlock(hw_priv); -+ -+ if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, -+ hw_priv->wsm_caps.firmwareReady, 3*HZ) <= 0) { -+ -+ /* TODO: Needs to find how to reset device */ -+ /* in QUEUE mode properly. */ -+ dev_dbg(hw_priv->pdev, "Firmware Startup Timeout!\n"); -+ err = -ETIMEDOUT; -+ goto err5; -+ } -+ dev_dbg(hw_priv->pdev, "Firmware Startup Done.\n"); -+ -+ /* Keep device wake up. */ -+ WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, HIF_CTRL_WUP_BIT)); -+ if (xradio_reg_read_16(hw_priv,HIF_CONTROL_REG_ID, &ctrl_reg)) -+ WARN_ON(xradio_reg_read_16(hw_priv,HIF_CONTROL_REG_ID, &ctrl_reg)); -+ WARN_ON(!(ctrl_reg & HIF_CTRL_RDY_BIT)); -+ -+ /* Set device mode parameter. */ -+ for (if_id = 0; if_id < xrwl_get_nr_hw_ifaces(hw_priv); if_id++) { -+ /* Set low-power mode. */ -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, if_id)); -+ /* Enable multi-TX confirmation */ -+ WARN_ON(wsm_use_multi_tx_conf(hw_priv, true, if_id)); -+ } -+ -+ /* Register wireless net device. */ -+ err = xradio_register_common(dev); -+ if (err) { -+ dev_dbg(hw_priv->pdev, "xradio_register_common failed(%d)!\n", err); -+ goto err5; -+ } -+ -+ return err; -+ -+err5: -+ xradio_dev_deinit(hw_priv); -+err4: -+ xradio_unregister_bh(hw_priv); -+err3: -+ xradio_pm_deinit(&hw_priv->pm_state); -+err2: -+/* err1: MRK: unused label*/ -+ xradio_free_common(dev); -+ return err; -+} -+ -+void xradio_core_deinit(struct sdio_func* func) -+{ -+ struct xradio_common* hw_priv = sdio_get_drvdata(func); -+ if (hw_priv) { -+ xradio_unregister_common(hw_priv->hw); -+ xradio_dev_deinit(hw_priv); -+ xradio_unregister_bh(hw_priv); -+ xradio_pm_deinit(&hw_priv->pm_state); -+ xradio_free_common(hw_priv->hw); -+ } -+ return; -+} -diff --git a/drivers/net/wireless/xradio/main.h b/drivers/net/wireless/xradio/main.h -new file mode 100644 -index 0000000..2238d75 ---- /dev/null -+++ b/drivers/net/wireless/xradio/main.h -@@ -0,0 +1,7 @@ -+#ifndef __XRADIO_MAIN_H -+#define __XRADIO_MAIN_H -+ -+int xradio_core_init(struct sdio_func* func); -+void xradio_core_deinit(struct sdio_func* func); -+ -+#endif -\ No newline at end of file -diff --git a/drivers/net/wireless/xradio/module.c b/drivers/net/wireless/xradio/module.c -new file mode 100644 -index 0000000..2a41c75 ---- /dev/null -+++ b/drivers/net/wireless/xradio/module.c -@@ -0,0 +1,27 @@ -+#include -+ -+#include "xradio.h" -+#include "debug.h" -+#include "sdio.h" -+ -+MODULE_AUTHOR("XRadioTech"); -+MODULE_DESCRIPTION("XRadioTech WLAN driver core"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("xradio_core"); -+ -+/* Init Module function -> Called by insmod */ -+static int __init xradio_core_entry(void) -+{ -+ int ret = 0; -+ ret = xradio_sdio_register(); -+ return ret; -+} -+ -+/* Called at Driver Unloading */ -+static void __exit xradio_core_exit(void) -+{ -+ xradio_sdio_unregister(); -+} -+ -+module_init(xradio_core_entry); -+module_exit(xradio_core_exit); -diff --git a/drivers/net/wireless/xradio/p2p.c b/drivers/net/wireless/xradio/p2p.c -new file mode 100644 -index 0000000..f32fb43 ---- /dev/null -+++ b/drivers/net/wireless/xradio/p2p.c -@@ -0,0 +1,62 @@ -+#include "xradio.h" -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+///w, TES_P2P_0002 WorkAround: -+///w, P2P GO Neg Process and P2P FIND may be collision. -+///w, When P2P Device is waiting for GO NEG CFM in 30ms, -+///w, P2P FIND may end with p2p listen, and then goes to p2p search. -+///w, Then xradio scan will occupy phy on other channel in 3+ seconds. -+///w, P2P Device will not be able to receive the GO NEG CFM. -+///w, We extend the roc period to remaind phy to receive GO NEG CFM as WorkAround. -+ -+s32 TES_P2P_0002_roc_dur; -+s32 TES_P2P_0002_roc_sec; -+s32 TES_P2P_0002_roc_usec; -+u32 TES_P2P_0002_packet_id; -+u32 TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; -+ -+void xradio_frame_monitor(struct xradio_common *hw_priv, struct sk_buff *skb, bool tx) { -+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -+ -+ u8 *action = (u8*)&mgmt->u.action.category; -+ u8 *category_code = &(action[0]); -+ u8 *action_code = &(action[1]); -+ u8 *oui = &(action[2]); -+ u8 *subtype = &(action[5]); -+ u8 *oui_subtype = &(action[6]); -+ -+ -+ if(ieee80211_is_action(frame->frame_control)) { -+ if( *category_code == WLAN_CATEGORY_PUBLIC) { -+ if (*action_code == 0x09) { -+ if((oui[0] == 0x50) && (oui[1] == 0x6F) && -+ (oui[2] == 0x9A) && (*subtype == 0x09)) { -+ if ( *oui_subtype == 0x01 ) { ///w, GO Negotiation Response -+ if((TES_P2P_0002_state == TES_P2P_0002_STATE_IDLE) && -+ (tx == true)) { ///w, p2p atturbute:status,id=0 -+ u8 *go_neg_resp_res = &(action[17]); -+ if (*go_neg_resp_res == 0x0) { -+ TES_P2P_0002_state = TES_P2P_0002_STATE_SEND_RESP; -+ txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_SEND_RESP]\n"); -+ } -+ } -+ } else if ( *oui_subtype == 0x02 ) { ///w, GO Negotiation Confirmation -+ if( tx == false ) { -+ TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; -+ txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_IDLE]" -+ "[GO Negotiation Confirmation]\n"); -+ } -+ } else if ( *oui_subtype == 0x08 ) { ///w, Provision Discovery Response -+ if(tx == false) { -+ TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; -+ txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_IDLE]" -+ "[Provision Discovery Response]\n"); -+ } -+ } -+ } -+ } -+ } -+ } -+} -+#endif -\ No newline at end of file -diff --git a/drivers/net/wireless/xradio/p2p.h b/drivers/net/wireless/xradio/p2p.h -new file mode 100644 -index 0000000..d86686b ---- /dev/null -+++ b/drivers/net/wireless/xradio/p2p.h -@@ -0,0 +1,6 @@ -+#ifndef XRADIO_P2P_H -+#define XRADIO_P2P_H -+ -+void xradio_frame_monitor(struct xradio_common *hw_priv, struct sk_buff *skb, bool tx); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/pm.c b/drivers/net/wireless/xradio/pm.c -new file mode 100644 -index 0000000..488c26c ---- /dev/null -+++ b/drivers/net/wireless/xradio/pm.c -@@ -0,0 +1,800 @@ -+/* -+ * PM implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include "xradio.h" -+#include "pm.h" -+#include "sta.h" -+#include "bh.h" -+#include "sdio.h" -+ -+#define XRADIO_BEACON_SKIPPING_MULTIPLIER 3 -+ -+struct xradio_udp_port_filter { -+ struct wsm_udp_port_filter_hdr hdr; -+ struct wsm_udp_port_filter dhcp; -+ struct wsm_udp_port_filter upnp; -+} __packed; -+ -+struct xradio_ether_type_filter { -+ struct wsm_ether_type_filter_hdr hdr; -+ struct wsm_ether_type_filter ip; -+ struct wsm_ether_type_filter pae; -+ struct wsm_ether_type_filter wapi; -+} __packed; -+ -+static struct xradio_udp_port_filter xradio_udp_port_filter_on = { -+ .hdr.nrFilters = 2, -+ .dhcp = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_OUT, -+ .portType = WSM_FILTER_PORT_TYPE_DST, -+ .udpPort = __cpu_to_le16(67), -+ }, -+ .upnp = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_OUT, -+ .portType = WSM_FILTER_PORT_TYPE_DST, -+ .udpPort = __cpu_to_le16(1900), -+ }, -+ /* Please add other known ports to be filtered out here and -+ * update nrFilters field in the header. -+ * Up to 4 filters are allowed. */ -+}; -+ -+static struct wsm_udp_port_filter_hdr xradio_udp_port_filter_off = { -+ .nrFilters = 0, -+}; -+ -+#ifndef ETH_P_WAPI -+#define ETH_P_WAPI 0x88B4 -+#endif -+ -+#ifdef TES_P2P_000B_DISABLE_EAPOL_FILTER -+/* TES_P2P_000B WorkAround: -+ * when the link keep 10min more or less(i am not sure), -+ * wpa_s session maybe expired, and want to update group key. -+ * it will use eapol frame(802.1x,0x888E). -+ * if driver suspend, and discard eapol frame, then session end. -+ * i don't know why original code discards eapol frame in suspend. -+ * but now make this filter disable as WorkAround. wzw */ -+static struct xradio_ether_type_filter xradio_ether_type_filter_on = { -+ .hdr.nrFilters = 1, -+/* .ip = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_IP), -+ },*/ -+/* .pae = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_PAE), -+ },*/ -+ .wapi = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_WAPI), -+ }, -+ /* Please add other known ether types to be filtered out here and -+ * update nrFilters field in the header. -+ * Up to 4 filters are allowed. */ -+}; -+#else -+static struct xradio_ether_type_filter xradio_ether_type_filter_on = { -+ .hdr.nrFilters = 2, -+/* .ip = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_IP), -+ },*/ -+ .pae = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_PAE), -+ }, -+ .wapi = { -+ .filterAction = WSM_FILTER_ACTION_FILTER_IN, -+ .etherType = __cpu_to_le16(ETH_P_WAPI), -+ }, -+ /* Please add other known ether types to be filtered out here and -+ * update nrFilters field in the header. -+ * Up to 4 filters are allowed. */ -+}; -+#endif -+ -+static struct wsm_ether_type_filter_hdr xradio_ether_type_filter_off = { -+ .nrFilters = 0, -+}; -+ -+static int xradio_suspend_late(struct device *dev); -+static void xradio_pm_release(struct device *dev); -+static int xradio_pm_probe(struct platform_device *pdev); -+static int __xradio_wow_suspend(struct xradio_vif *priv, -+ struct cfg80211_wowlan *wowlan); -+static int __xradio_wow_resume(struct xradio_vif *priv); -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+static int xradio_poweroff_suspend(struct xradio_common *hw_priv); -+static int xradio_poweroff_resume(struct xradio_common *hw_priv); -+#endif -+ -+ -+/* private */ -+struct xradio_suspend_state { -+ unsigned long bss_loss_tmo; -+ unsigned long connection_loss_tmo; -+ unsigned long join_tmo; -+ unsigned long direct_probe; -+ unsigned long link_id_gc; -+ bool beacon_skipping; -+}; -+ -+static const struct dev_pm_ops xradio_pm_ops = { -+ .suspend_noirq = xradio_suspend_late, -+}; -+ -+static struct platform_driver xradio_power_driver = { -+ .probe = xradio_pm_probe, -+ .driver = { -+ .name = XRADIO_PM_DEVICE, -+ .pm = &xradio_pm_ops, -+ }, -+}; -+ -+static int xradio_pm_init_common(struct xradio_pm_state *pm, -+ struct xradio_common *hw_priv) -+{ -+ int ret; -+ pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ -+ spin_lock_init(&pm->lock); -+ /* Register pm driver. */ -+ ret = platform_driver_register(&xradio_power_driver); -+ if (ret) { -+ pm_printk(XRADIO_DBG_ERROR, "%s:platform_driver_register failed(%d)!\n", -+ __FUNCTION__, ret); -+ return ret; -+ } -+ -+ /* Add pm device. */ -+ pm->pm_dev = platform_device_alloc(XRADIO_PM_DEVICE, 0); -+ if (!pm->pm_dev) { -+ pm_printk(XRADIO_DBG_ERROR, "%s:platform_device_alloc failed!\n", -+ __FUNCTION__); -+ platform_driver_unregister(&xradio_power_driver); -+ return -ENOMEM; -+ } -+ pm->pm_dev->dev.platform_data = hw_priv; -+ ret = platform_device_add(pm->pm_dev); -+ if (ret) { -+ pm_printk(XRADIO_DBG_ERROR, "%s:platform_device_add failed(%d)!\n", -+ __FUNCTION__, ret); -+ platform_driver_unregister(&xradio_power_driver); -+ kfree(pm->pm_dev); -+ pm->pm_dev = NULL; -+ } -+ -+ return ret; -+} -+ -+static void xradio_pm_deinit_common(struct xradio_pm_state *pm) -+{ -+ pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ platform_driver_unregister(&xradio_power_driver); -+ if (pm->pm_dev) { -+ pm->pm_dev->dev.platform_data = NULL; -+ platform_device_unregister(pm->pm_dev); /* kfree is already do */ -+ pm->pm_dev = NULL; -+ } -+} -+ -+#ifdef CONFIG_WAKELOCK -+ -+int xradio_pm_init(struct xradio_pm_state *pm, -+ struct xradio_common *hw_priv) -+{ -+ int ret = 0; -+ pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ -+ ret = xradio_pm_init_common(pm, hw_priv); -+ if (!ret) -+ wake_lock_init(&pm->wakelock, WAKE_LOCK_SUSPEND, XRADIO_WAKE_LOCK); -+ else -+ pm_printk(XRADIO_DBG_ERROR,"xradio_pm_init_common failed!\n"); -+ return ret; -+} -+ -+void xradio_pm_deinit(struct xradio_pm_state *pm) -+{ -+ pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); -+ if (wake_lock_active(&pm->wakelock)) -+ wake_unlock(&pm->wakelock); -+ wake_lock_destroy(&pm->wakelock); -+ xradio_pm_deinit_common(pm); -+} -+ -+void xradio_pm_stay_awake(struct xradio_pm_state *pm, -+ unsigned long tmo) -+{ -+ long cur_tmo; -+ pm_printk(XRADIO_DBG_MSG,"%s\n", __FUNCTION__); -+ -+ spin_lock_bh(&pm->lock); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) -+ cur_tmo = pm->wakelock.ws.timer.expires - jiffies; -+#else -+ cur_tmo = pm->wakelock.expires - jiffies; -+#endif -+ if (!wake_lock_active(&pm->wakelock) || cur_tmo < (long)tmo) -+ wake_lock_timeout(&pm->wakelock, tmo); -+ spin_unlock_bh(&pm->lock); -+} -+void xradio_pm_lock_awake(struct xradio_pm_state *pm) -+{ -+ -+ spin_lock_bh(&pm->lock); -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) -+ pm->expires_save = pm->wakelock.ws.timer.expires; -+#else -+ pm->expires_save = pm->wakelock.expires; -+#endif -+ wake_lock_timeout(&pm->wakelock, LONG_MAX); -+ spin_unlock_bh(&pm->lock); -+} -+void xradio_pm_unlock_awake(struct xradio_pm_state *pm) -+{ -+ -+ spin_lock_bh(&pm->lock); -+ pm->expires_save -= jiffies; -+ if (pm->expires_save) -+ wake_lock_timeout(&pm->wakelock, pm->expires_save); -+ else -+ wake_lock_timeout(&pm->wakelock, 1); -+ spin_unlock_bh(&pm->lock); -+} -+ -+#else /* CONFIG_WAKELOCK */ -+ -+static void xradio_pm_stay_awake_tmo(struct timer_list *t) -+{ -+ struct xradio_pm_state *pm = from_timer(pm, t, stay_awake); -+ (void)pm; -+} -+ -+int xradio_pm_init(struct xradio_pm_state *pm, -+ struct xradio_common *hw_priv) -+{ -+ int ret = 0; -+ pm_printk(XRADIO_DBG_MSG,"%s\n", __FUNCTION__); -+ -+ ret = xradio_pm_init_common(pm, hw_priv); -+ if (!ret) { -+ timer_setup(&pm->stay_awake, xradio_pm_stay_awake_tmo, 0); -+ } else -+ pm_printk(XRADIO_DBG_ERROR,"xradio_pm_init_common failed!\n"); -+ return ret; -+} -+ -+void xradio_pm_deinit(struct xradio_pm_state *pm) -+{ -+ del_timer_sync(&pm->stay_awake); -+ xradio_pm_deinit_common(pm); -+} -+ -+void xradio_pm_stay_awake(struct xradio_pm_state *pm, -+ unsigned long tmo) -+{ -+ long cur_tmo; -+ -+ spin_lock_bh(&pm->lock); -+ cur_tmo = pm->stay_awake.expires - jiffies; -+ if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo) -+ mod_timer(&pm->stay_awake, jiffies + tmo); -+ spin_unlock_bh(&pm->lock); -+} -+void xradio_pm_lock_awake(struct xradio_pm_state *pm) -+{ -+ -+ spin_lock_bh(&pm->lock); -+ pm->expires_save = pm->stay_awake.expires; -+ mod_timer(&pm->stay_awake, jiffies + LONG_MAX); -+ spin_unlock_bh(&pm->lock); -+} -+void xradio_pm_unlock_awake(struct xradio_pm_state *pm) -+{ -+ -+ spin_lock_bh(&pm->lock); -+ if (time_before(jiffies, pm->expires_save)) -+ mod_timer(&pm->stay_awake, pm->expires_save); -+ else -+ mod_timer(&pm->stay_awake, jiffies + 1); -+ spin_unlock_bh(&pm->lock); -+} -+#endif /* CONFIG_WAKELOCK */ -+ -+static long xradio_suspend_work(struct delayed_work *work) -+{ -+ int ret = cancel_delayed_work(work); -+ long tmo; -+ pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); -+ -+ if (ret > 0) { -+ /* Timer is pending */ -+ tmo = work->timer.expires - jiffies; -+ if (tmo < 0) -+ tmo = 0; -+ } else { -+ tmo = -1; -+ } -+ return tmo; -+} -+ -+static int xradio_resume_work(struct xradio_common *hw_priv, -+ struct delayed_work *work, -+ unsigned long tmo) -+{ -+ pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); -+ if ((long)tmo < 0) -+ return 1; -+ -+ return queue_delayed_work(hw_priv->workqueue, work, tmo); -+} -+ -+static int xradio_suspend_late(struct device *dev) -+{ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+ struct xradio_common *hw_priv = dev->platform_data; -+ -+ if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) { -+ return 0; /* we don't rx data when power down wifi.*/ -+ } -+#endif -+ -+ //if (atomic_read(&hw_priv->bh_rx)) { -+ // pm_printk(XRADIO_DBG_WARN, "%s: Suspend interrupted.\n", __func__); -+ // return -EAGAIN; -+ //} -+ return 0; -+} -+ -+static void xradio_pm_release(struct device *dev) -+{ -+ pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); -+} -+ -+static int xradio_pm_probe(struct platform_device *pdev) -+{ -+ pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); -+ pdev->dev.release = xradio_pm_release; -+ return 0; -+} -+ -+int xradio_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv; -+ int i, ret = 0; -+ -+ -+ if(hw_priv->bh_error) return -EBUSY; -+ WARN_ON(!atomic_read(&hw_priv->num_vifs)); -+ -+ if (work_pending(&hw_priv->query_work)) -+ return -EBUSY; -+ -+#ifdef ROAM_OFFLOAD -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ if((priv->vif->type == NL80211_IFTYPE_STATION) -+ && (priv->join_status == XRADIO_JOIN_STATUS_STA)) { -+ down(&hw_priv->scan.lock); -+ hw_priv->scan.if_id = priv->if_id; -+ xradio_sched_scan_work(&hw_priv->scan.swork); -+ } -+ } -+#endif /*ROAM_OFFLOAD*/ -+ -+ /* Do not suspend when datapath is not idle */ -+ if (hw_priv->tx_queue_stats.num_queued[0] + -+ hw_priv->tx_queue_stats.num_queued[1]) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of tx_queue is not empty.\n"); -+ return -EBUSY; -+ } -+ -+ /* Make sure there is no configuration requests in progress. */ -+ if (!mutex_trylock(&hw_priv->conf_mutex)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of configuration requests.\n"); -+ return -EBUSY; -+ } -+ -+ /* Make sure there is no wsm_oper_lock in progress. */ -+ if (!mutex_trylock(&hw_priv->wsm_oper_lock)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of wsm_oper_lock.\n"); -+ mutex_unlock(&hw_priv->conf_mutex); -+ return -EBUSY; -+ } -+ -+ /* Do not suspend when scanning or ROC*/ -+ if (down_trylock(&hw_priv->scan.lock)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of scan requests.\n"); -+ goto revert1; -+ } -+ -+ if (delayed_work_pending(&hw_priv->scan.probe_work)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of probe frames tx in progress.\n"); -+ goto revert2; -+ } -+ -+ /* Lock TX. */ -+ wsm_lock_tx_async(hw_priv); -+ -+ /* Wait to avoid possible race with bh code. -+ * But do not wait too long... */ -+ if (wait_event_timeout(hw_priv->bh_evt_wq, -+ !hw_priv->hw_bufs_used, HZ / 10) <= 0) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of there are frames not confirm.\n"); -+ goto revert3; -+ } -+ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+// if (STANDBY_WITH_POWER_OFF == standby_level) { -+ if (1) { -+ return xradio_poweroff_suspend(hw_priv); -+ } -+#endif -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ -+ ret = __xradio_wow_suspend(priv, wowlan); -+ if (ret) { -+ for (; i >= 0; i--) { -+ if (!hw_priv->vif_list[i]) -+ continue; -+ priv = (struct xradio_vif *)hw_priv->vif_list[i]->drv_priv; -+ __xradio_wow_resume(priv); -+ } -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of __xradio_wow_suspend failed!\n"); -+ goto revert3; -+ } -+ } -+ -+ /* Stop serving thread */ -+ if (xradio_bh_suspend(hw_priv)) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ "because of xradio_bh_suspend failed!\n"); -+ xradio_wow_resume(hw); -+ return -EBUSY; -+ } -+ -+ /* Enable IRQ wake */ -+ ret = sdio_pm(hw_priv, true); -+ if (ret) { -+ pm_printk(XRADIO_DBG_WARN, "Don't suspend sbus pm failed\n"); -+ xradio_wow_resume(hw); -+ return -EBUSY; -+ } -+ -+ /* Force resume if event is coming from the device. */ -+ //if (atomic_read(&hw_priv->bh_rx)) { -+ // pm_printk(XRADIO_DBG_WARN, "Don't suspend " -+ // "because of recieved rx event!\n"); -+ // xradio_wow_resume(hw); -+ // return -EAGAIN; -+ //} -+ return 0; -+ -+revert3: -+ wsm_unlock_tx(hw_priv); -+revert2: -+ up(&hw_priv->scan.lock); -+revert1: -+ mutex_unlock(&hw_priv->conf_mutex); -+ mutex_unlock(&hw_priv->wsm_oper_lock); -+ return -EBUSY; -+} -+ -+static int __xradio_wow_suspend(struct xradio_vif *priv, -+ struct cfg80211_wowlan *wowlan) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif; -+ struct xradio_suspend_state *state; -+ int ret; -+#ifdef MCAST_FWDING -+ struct wsm_forwarding_offload fwdoffload = { -+ .fwenable = 0x1, -+ .flags = 0x1, -+ }; -+#endif -+ -+ -+ /* Do not suspend when join work is scheduled */ -+ if (work_pending(&priv->join_work)) { -+ pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " -+ "when join work is scheduled\n", __func__); -+ goto revert1; -+ } -+ -+ /* Set UDP filter */ -+ wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_on.hdr, -+ priv->if_id); -+ -+ /* Set ethernet frame type filter */ -+ wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_on.hdr, -+ priv->if_id); -+ -+ /* Set IP multicast filter */ -+ wsm_set_host_sleep(hw_priv, 1, priv->if_id); -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_keepalive_filter(priv, true)); -+ -+#ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE -+ /* Set Multicast Address Filter */ -+ if (priv->multicast_filter.numOfAddresses) { -+ priv->multicast_filter.enable = 1; -+ wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); -+ } -+ -+ /* Set Enable Broadcast Address Filter */ -+ priv->broadcast_filter.action_mode = 1; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ priv->broadcast_filter.address_mode = 3; -+ -+ xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); -+#endif -+ -+#ifdef MCAST_FWDING -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); -+#endif -+ -+ /* Allocate state */ -+ state = kzalloc(sizeof(struct xradio_suspend_state), GFP_KERNEL); -+ if (!state) { -+ pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " -+ "alloc xradio_suspend_state failed.\n", __func__); -+ goto revert2; -+ } -+ /* Store delayed work states. */ -+ state->bss_loss_tmo = xradio_suspend_work(&priv->bss_loss_work); -+ state->connection_loss_tmo = xradio_suspend_work(&priv->connection_loss_work); -+ state->join_tmo = xradio_suspend_work(&priv->join_timeout); -+ state->link_id_gc = xradio_suspend_work(&priv->link_id_gc_work); -+ -+ /* Enable beacon skipping */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA && -+ priv->join_dtim_period && !priv->has_multicast_subscription) { -+ state->beacon_skipping = true; -+ wsm_set_beacon_wakeup_period(hw_priv, priv->join_dtim_period, -+ XRADIO_BEACON_SKIPPING_MULTIPLIER * \ -+ priv->join_dtim_period, priv->if_id); -+ } -+ -+ ret = timer_pending(&priv->mcast_timeout); -+ if (ret) { -+ pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " -+ "mcast timeout timer_pending failed.\n", __func__); -+ goto revert3; -+ } -+ -+ /* Store suspend state */ -+ pm_state_vif->suspend_state = state; -+ -+ return 0; -+ -+revert3: -+ xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo); -+ xradio_resume_work(hw_priv, &priv->connection_loss_work, -+ state->connection_loss_tmo); -+ xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo); -+ xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc); -+ kfree(state); -+ -+revert2: -+ wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off, priv->if_id); -+ wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off, priv->if_id); -+ wsm_set_host_sleep(hw_priv, 0, priv->if_id); -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_keepalive_filter(priv, false)); -+ -+#ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE -+ /* Set Multicast Address Filter */ -+ if (priv->multicast_filter.numOfAddresses) { -+ priv->multicast_filter.enable = 0; -+ wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); -+ } -+ -+ /* Set Enable Broadcast Address Filter */ -+ priv->broadcast_filter.action_mode = 0; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ priv->broadcast_filter.address_mode = 0; -+ xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); -+#endif -+ -+#ifdef MCAST_FWDING -+ fwdoffload.flags = 0x0; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); -+#endif -+ -+revert1: -+ /* mutex_unlock(&hw_priv->conf_mutex); */ -+ return -EBUSY; -+} -+ -+int xradio_wow_resume(struct ieee80211_hw *hw) -+{ -+ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv; -+ int i, ret = 0; -+ -+ -+ WARN_ON(!atomic_read(&hw_priv->num_vifs)); -+ if(hw_priv->bh_error) return 0; -+ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+ if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) { -+ return xradio_poweroff_resume(hw_priv); -+ } -+#endif -+ -+ /* Disable IRQ wake */ -+ sdio_pm(hw_priv, false); -+ -+ up(&hw_priv->scan.lock); -+ -+ /* Resume BH thread */ -+ WARN_ON(xradio_bh_resume(hw_priv)); -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ ret = __xradio_wow_resume(priv); -+ if (ret) { -+ pm_printk(XRADIO_DBG_ERROR, "%s:__xradio_wow_resume failed!\n", __func__); -+ break; -+ } -+ } -+ -+ wsm_unlock_tx(hw_priv); -+ -+ /* Unlock configuration mutex */ -+ mutex_unlock(&hw_priv->conf_mutex); -+ mutex_unlock(&hw_priv->wsm_oper_lock); -+ -+ return ret; -+} -+ -+static int __xradio_wow_resume(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif; -+ struct xradio_suspend_state *state; -+#ifdef MCAST_FWDING -+ struct wsm_forwarding_offload fwdoffload = { -+ .fwenable = 0x1, -+ .flags = 0x0, -+ }; -+#endif -+ -+ -+ /* Restore suspend state */ -+ state = pm_state_vif->suspend_state; -+ pm_state_vif->suspend_state = NULL; -+ -+#ifdef ROAM_OFFLOAD -+ if((priv->vif->type == NL80211_IFTYPE_STATION) -+ && (priv->join_status == XRADIO_JOIN_STATUS_STA)) -+ xradio_hw_sched_scan_stop(hw_priv); -+#endif /*ROAM_OFFLOAD*/ -+ -+ if (state->beacon_skipping) { -+#ifdef XRADIO_USE_LONG_DTIM_PERIOD -+ int join_dtim_period_extend; -+ if (priv->join_dtim_period <= 3) { -+ join_dtim_period_extend = priv->join_dtim_period * 3; -+ } else if (priv->join_dtim_period <= 5) { -+ join_dtim_period_extend = priv->join_dtim_period * 2; -+ } else { -+ join_dtim_period_extend = priv->join_dtim_period; -+ } -+ wsm_set_beacon_wakeup_period(hw_priv, -+ ((priv->beacon_int * join_dtim_period_extend) > MAX_BEACON_SKIP_TIME_MS ? -+ 1 : join_dtim_period_extend) , 0, priv->if_id); -+#else -+ wsm_set_beacon_wakeup_period(hw_priv, priv->beacon_int * -+ (priv->join_dtim_period > MAX_BEACON_SKIP_TIME_MS ? 1 : priv->join_dtim_period), -+ 0, priv->if_id); -+#endif -+ state->beacon_skipping = false; -+ } -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_keepalive_filter(priv, false)); -+ -+#ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE -+ /* Set Multicast Address Filter */ -+ if (priv->multicast_filter.numOfAddresses) { -+ priv->multicast_filter.enable = 0; -+ wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); -+ } -+ /* Set Enable Broadcast Address Filter */ -+ priv->broadcast_filter.action_mode = 0; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ priv->broadcast_filter.address_mode = 0; -+ xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); -+#endif -+ -+#ifdef MCAST_FWDING -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) -+ WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); -+#endif -+ -+ /* Resume delayed work */ -+ xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo); -+ xradio_resume_work(hw_priv, &priv->connection_loss_work, -+ state->connection_loss_tmo); -+ xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo); -+ xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc); -+ -+ /* Remove UDP port filter */ -+ wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off, priv->if_id); -+ -+ /* Remove ethernet frame type filter */ -+ wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off, priv->if_id); -+ -+ /* Remove IP multicast filter */ -+ wsm_set_host_sleep(hw_priv, 0, priv->if_id); -+ /* Free memory */ -+ kfree(state); -+ -+ return 0; -+} -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+static int xradio_poweroff_suspend(struct xradio_common *hw_priv) -+{ -+ -+ //flush all work. -+ cancel_work_sync(&hw_priv->query_work); -+ flush_workqueue(hw_priv->workqueue); -+ /* Schedule hardware restart, ensure no cmds in progress.*/ -+ mutex_lock(&hw_priv->wsm_cmd_mux); -+ atomic_set(&hw_priv->suspend_state, XRADIO_POWEROFF_SUSP); -+ //hw_priv->hw_restart = true; -+ mutex_unlock(&hw_priv->wsm_cmd_mux); -+ /* Stop serving thread */ -+ if (xradio_bh_suspend(hw_priv)) { -+ pm_printk(XRADIO_DBG_WARN, "%s, xradio_bh_suspend failed!\n", __func__); -+ return -EBUSY; -+ } -+ -+ return 0; -+} -+ -+static int xradio_poweroff_resume(struct xradio_common *hw_priv) -+{ -+ -+ /* Revert locks */ -+ wsm_unlock_tx(hw_priv); -+ up(&hw_priv->scan.lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ mutex_unlock(&hw_priv->wsm_oper_lock); -+ //if (schedule_work(&hw_priv->hw_restart_work) <= 0) -+ // pm_printk(XRADIO_DBG_ERROR, "%s restart_work failed!\n", __func__); -+ return 0; -+} -+#endif -diff --git a/drivers/net/wireless/xradio/pm.h b/drivers/net/wireless/xradio/pm.h -new file mode 100644 -index 0000000..6443cbc ---- /dev/null -+++ b/drivers/net/wireless/xradio/pm.h -@@ -0,0 +1,64 @@ -+/* -+ * power management interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#ifndef PM_H_INCLUDED -+#define PM_H_INCLUDED -+ -+#ifdef CONFIG_WAKELOCK -+#include -+#endif -+ -+/* ******************************************************************** */ -+/* mac80211 API */ -+ -+#ifdef CONFIG_PM -+ -+#define XRADIO_PM_DEVICE "xradio_pm" -+#define XRADIO_WAKE_LOCK "xradio_wlan" -+ -+/* extern */ struct xradio_common; -+ /* private */ struct xradio_suspend_state; -+ -+struct xradio_pm_state { -+#ifdef CONFIG_WAKELOCK -+ struct wake_lock wakelock; -+#else -+ struct timer_list stay_awake; -+#endif -+ struct platform_device *pm_dev; -+ spinlock_t lock; -+ unsigned long expires_save; -+}; -+ -+struct xradio_pm_state_vif { -+ struct xradio_suspend_state *suspend_state; -+}; -+ -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+enum suspend_state { -+ XRADIO_RESUME = 0, -+ XRADIO_CONNECT_SUSP, -+ XRADIO_DISCONNECT_SUSP, -+ XRADIO_POWEROFF_SUSP -+}; -+#endif -+int xradio_pm_init(struct xradio_pm_state *pm, struct xradio_common *priv); -+void xradio_pm_deinit(struct xradio_pm_state *pm); -+void xradio_pm_stay_awake(struct xradio_pm_state *pm, unsigned long tmo); -+void xradio_pm_lock_awake(struct xradio_pm_state *pm); -+void xradio_pm_unlock_awake(struct xradio_pm_state *pm); -+int xradio_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); -+int xradio_wow_resume(struct ieee80211_hw *hw); -+ -+#endif /* CONFIG_PM */ -+ -+#endif -diff --git a/drivers/net/wireless/xradio/queue.c b/drivers/net/wireless/xradio/queue.c -new file mode 100644 -index 0000000..e4b00ea ---- /dev/null -+++ b/drivers/net/wireless/xradio/queue.c -@@ -0,0 +1,820 @@ -+/* -+ * Queue implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include "xradio.h" -+#include "queue.h" -+ -+/* private */ struct xradio_queue_item -+{ -+ struct list_head head; -+ struct sk_buff *skb; -+ u32 packetID; -+ unsigned long queue_timestamp; -+ unsigned long xmit_timestamp; -+ struct xradio_txpriv txpriv; -+ u8 generation; -+ u8 pack_stk_wr; -+}; -+ -+static inline void __xradio_queue_lock(struct xradio_queue *queue) -+{ -+ struct xradio_queue_stats *stats = queue->stats; -+ if (queue->tx_locked_cnt++ == 0) { -+ txrx_printk(XRADIO_DBG_MSG, "[TX] Queue %d is locked.\n", -+ queue->queue_id); -+ ieee80211_stop_queue(stats->hw_priv->hw, queue->queue_id); -+ } -+} -+ -+static inline void __xradio_queue_unlock(struct xradio_queue *queue) -+{ -+ struct xradio_queue_stats *stats = queue->stats; -+ BUG_ON(!queue->tx_locked_cnt); -+ if (--queue->tx_locked_cnt == 0) { -+ txrx_printk(XRADIO_DBG_MSG, "[TX] Queue %d is unlocked.\n", -+ queue->queue_id); -+ ieee80211_wake_queue(stats->hw_priv->hw, queue->queue_id); -+ } -+} -+ -+static inline void xradio_queue_parse_id(u32 packetID, u8 *queue_generation, -+ u8 *queue_id, -+ u8 *item_generation, -+ u8 *item_id, -+ u8 *if_id, -+ u8 *link_id) -+{ -+ *item_id = (packetID >> 0) & 0xFF; -+ *item_generation = (packetID >> 8) & 0xFF; -+ *queue_id = (packetID >> 16) & 0xF; -+ *if_id = (packetID >> 20) & 0xF; -+ *link_id = (packetID >> 24) & 0xF; -+ *queue_generation = (packetID >> 28) & 0xF; -+} -+ -+static inline u32 xradio_queue_make_packet_id(u8 queue_generation, u8 queue_id, -+ u8 item_generation, u8 item_id, -+ u8 if_id, u8 link_id) -+{ -+ /*TODO:COMBO: Add interfaceID to the packetID */ -+ return ((u32)item_id << 0) | -+ ((u32)item_generation << 8) | -+ ((u32)queue_id << 16) | -+ ((u32)if_id << 20) | -+ ((u32)link_id << 24) | -+ ((u32)queue_generation << 28); -+} -+ -+static void xradio_queue_post_gc(struct xradio_queue_stats *stats, -+ struct list_head *gc_list) -+{ -+ struct xradio_queue_item *item; -+ -+ while (!list_empty(gc_list)) { -+ item = list_first_entry( -+ gc_list, struct xradio_queue_item, head); -+ list_del(&item->head); -+ stats->skb_dtor(stats->hw_priv, item->skb, &item->txpriv); -+ kfree(item); -+ } -+} -+ -+static void xradio_queue_register_post_gc(struct list_head *gc_list, -+ struct xradio_queue_item *item) -+{ -+ struct xradio_queue_item *gc_item; -+ gc_item = kmalloc(sizeof(struct xradio_queue_item), GFP_KERNEL); -+ BUG_ON(!gc_item); -+ memcpy(gc_item, item, sizeof(struct xradio_queue_item)); -+ list_add_tail(&gc_item->head, gc_list); -+} -+ -+static void __xradio_queue_gc(struct xradio_queue *queue, -+ struct list_head *head, -+ bool unlock) -+{ -+ struct xradio_queue_stats *stats = queue->stats; -+ struct xradio_queue_item *item = NULL; -+ //struct xradio_vif *priv; -+ int if_id; -+ bool wakeup_stats = false; -+ -+ while (!list_empty(&queue->queue)) { -+ struct xradio_txpriv *txpriv; -+ item = list_first_entry( -+ &queue->queue, struct xradio_queue_item, head); -+ if (time_before(jiffies, item->queue_timestamp+queue->ttl)) -+ break; -+ -+ txpriv = &item->txpriv; -+ if_id = txpriv->if_id; -+ --queue->num_queued; -+ --queue->num_queued_vif[if_id]; -+ --queue->link_map_cache[if_id][txpriv->link_id]; -+ spin_lock_bh(&stats->lock); -+ --stats->num_queued[if_id]; -+ if (!--stats->link_map_cache[if_id][txpriv->link_id]) -+ wakeup_stats = true; -+ spin_unlock_bh(&stats->lock); -+ //priv = xrwl_hwpriv_to_vifpriv(stats->hw_priv, if_id); -+ //if (priv) { -+ // xradio_debug_tx_ttl(priv); -+ // spin_unlock(&priv->vif_lock); -+ //} -+ xradio_queue_register_post_gc(head, item); -+ item->skb = NULL; -+ list_move_tail(&item->head, &queue->free_pool); -+ } -+ -+ if (wakeup_stats) -+ wake_up(&stats->wait_link_id_empty); -+ -+ //modified by yangfh for test WFD -+ if (queue->overfull) { -+ if (queue->num_queued <= ((stats->hw_priv->vif0_throttle + -+ stats->hw_priv->vif1_throttle+2)>>1)) { -+ queue->overfull = false; -+ if (unlock) { -+ __xradio_queue_unlock(queue); -+ } -+ } else if (item) { -+ unsigned long tmo = item->queue_timestamp + queue->ttl; -+ mod_timer(&queue->gc, tmo); -+ xradio_pm_stay_awake(&stats->hw_priv->pm_state, -+ tmo - jiffies); -+ } -+ } -+} -+ -+static void xradio_queue_gc(struct timer_list *t) -+{ -+ struct xradio_queue *queue = from_timer(queue, t, gc); -+ -+ LIST_HEAD(list); -+ -+ spin_lock_bh(&queue->lock); -+ __xradio_queue_gc(queue, &list, true); -+ spin_unlock_bh(&queue->lock); -+ xradio_queue_post_gc(queue->stats, &list); -+} -+ -+int xradio_queue_stats_init(struct xradio_queue_stats *stats, -+ size_t map_capacity, -+ xradio_queue_skb_dtor_t skb_dtor, -+ struct xradio_common *hw_priv) -+{ -+ int i; -+ -+ memset(stats, 0, sizeof(*stats)); -+ stats->map_capacity = map_capacity; -+ stats->skb_dtor = skb_dtor; -+ stats->hw_priv = hw_priv; -+ spin_lock_init(&stats->lock); -+ init_waitqueue_head(&stats->wait_link_id_empty); -+ for (i = 0; i < XRWL_MAX_VIFS; i++) { -+ stats->link_map_cache[i] = kzalloc(sizeof(int[map_capacity]), GFP_KERNEL); -+ if (!stats->link_map_cache[i]) { -+ for (; i >= 0; i--) -+ kfree(stats->link_map_cache[i]); -+ return -ENOMEM; -+ } -+ } -+ -+ return 0; -+} -+ -+int xradio_queue_init(struct xradio_queue *queue, -+ struct xradio_queue_stats *stats, -+ u8 queue_id, -+ size_t capacity, -+ unsigned long ttl) -+{ -+ int i; -+ -+ memset(queue, 0, sizeof(*queue)); -+ queue->stats = stats; -+ queue->capacity = capacity; -+ queue->queue_id = queue_id; -+ queue->ttl = ttl; -+ INIT_LIST_HEAD(&queue->queue); -+ INIT_LIST_HEAD(&queue->pending); -+ INIT_LIST_HEAD(&queue->free_pool); -+ spin_lock_init(&queue->lock); -+ timer_setup(&queue->gc, xradio_queue_gc, 0); -+ -+ queue->pool = kzalloc(sizeof(struct xradio_queue_item) * capacity, -+ GFP_KERNEL); -+ if (!queue->pool) -+ return -ENOMEM; -+ -+ for (i = 0; i < XRWL_MAX_VIFS; i++) { -+ queue->link_map_cache[i] = -+ kzalloc(sizeof(int[stats->map_capacity]), GFP_KERNEL); -+ if (!queue->link_map_cache[i]) { -+ for (; i >= 0; i--) -+ kfree(queue->link_map_cache[i]); -+ kfree(queue->pool); -+ queue->pool = NULL; -+ return -ENOMEM; -+ } -+ } -+ -+ for (i = 0; i < capacity; ++i) -+ list_add_tail(&queue->pool[i].head, &queue->free_pool); -+ -+ return 0; -+} -+ -+/* TODO:COMBO: Flush only a particular interface specific parts */ -+int xradio_queue_clear(struct xradio_queue *queue, int if_id) -+{ -+ int i, cnt, iter; -+ struct xradio_queue_stats *stats = queue->stats; -+ LIST_HEAD(gc_list); -+ -+ cnt = 0; -+ spin_lock_bh(&queue->lock); -+ queue->generation++; -+ queue->generation &= 0xf; -+ list_splice_tail_init(&queue->queue, &queue->pending); -+ while (!list_empty(&queue->pending)) { -+ struct xradio_queue_item *item = list_first_entry( -+ &queue->pending, struct xradio_queue_item, head); -+ WARN_ON(!item->skb); -+ if (XRWL_ALL_IFS == if_id || item->txpriv.if_id == if_id) { -+ xradio_queue_register_post_gc(&gc_list, item); -+ item->skb = NULL; -+ list_move_tail(&item->head, &queue->free_pool); -+ cnt++; -+ } -+ } -+ queue->num_queued -= cnt; -+ queue->num_pending = 0; -+ if (XRWL_ALL_IFS != if_id) { -+ queue->num_queued_vif[if_id] = 0; -+ queue->num_pending_vif[if_id] = 0; -+ } else { -+ for (iter = 0; iter < XRWL_MAX_VIFS; iter++) { -+ queue->num_queued_vif[iter] = 0; -+ queue->num_pending_vif[iter] = 0; -+ } -+ } -+ spin_lock_bh(&stats->lock); -+ if (XRWL_ALL_IFS != if_id) { -+ for (i = 0; i < stats->map_capacity; ++i) { -+ stats->num_queued[if_id] -= -+ queue->link_map_cache[if_id][i]; -+ stats->link_map_cache[if_id][i] -= -+ queue->link_map_cache[if_id][i]; -+ queue->link_map_cache[if_id][i] = 0; -+ } -+ } else { -+ for (iter = 0; iter < XRWL_MAX_VIFS; iter++) { -+ for (i = 0; i < stats->map_capacity; ++i) { -+ stats->num_queued[iter] -= -+ queue->link_map_cache[iter][i]; -+ stats->link_map_cache[iter][i] -= -+ queue->link_map_cache[iter][i]; -+ queue->link_map_cache[iter][i] = 0; -+ } -+ } -+ } -+ spin_unlock_bh(&stats->lock); -+ if (unlikely(queue->overfull)) { -+ queue->overfull = false; -+ __xradio_queue_unlock(queue); -+ } -+ spin_unlock_bh(&queue->lock); -+ wake_up(&stats->wait_link_id_empty); -+ xradio_queue_post_gc(stats, &gc_list); -+ return 0; -+} -+ -+void xradio_queue_stats_deinit(struct xradio_queue_stats *stats) -+{ -+ int i; -+ -+ for (i = 0; i < XRWL_MAX_VIFS ; i++) { -+ kfree(stats->link_map_cache[i]); -+ stats->link_map_cache[i] = NULL; -+ } -+} -+ -+void xradio_queue_deinit(struct xradio_queue *queue) -+{ -+ int i; -+ -+ xradio_queue_clear(queue, XRWL_ALL_IFS); -+ del_timer_sync(&queue->gc); -+ INIT_LIST_HEAD(&queue->free_pool); -+ kfree(queue->pool); -+ for (i = 0; i < XRWL_MAX_VIFS; i++) { -+ kfree(queue->link_map_cache[i]); -+ queue->link_map_cache[i] = NULL; -+ } -+ queue->pool = NULL; -+ queue->capacity = 0; -+} -+ -+size_t xradio_queue_get_num_queued(struct xradio_vif *priv, -+ struct xradio_queue *queue, -+ u32 link_id_map) -+{ -+ size_t ret; -+ int i, bit; -+ size_t map_capacity = queue->stats->map_capacity; -+ -+ if (!link_id_map) -+ return 0; -+ -+ spin_lock_bh(&queue->lock); -+ if (likely(link_id_map == (u32) -1)) { -+ ret = queue->num_queued_vif[priv->if_id] - -+ queue->num_pending_vif[priv->if_id]; -+ } else { -+ ret = 0; -+ for (i = 0, bit = 1; i < map_capacity; ++i, bit <<= 1) { -+ if (link_id_map & bit) -+ ret += -+ queue->link_map_cache[priv->if_id][i]; -+ } -+ } -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+int xradio_queue_put(struct xradio_queue *queue, struct sk_buff *skb, -+ struct xradio_txpriv *txpriv) -+{ -+ int ret = 0; -+ LIST_HEAD(gc_list); -+ struct xradio_queue_stats *stats = queue->stats; -+ /* TODO:COMBO: Add interface ID info to queue item */ -+ -+ if (txpriv->link_id >= queue->stats->map_capacity) -+ return -EINVAL; -+ -+ spin_lock_bh(&queue->lock); -+ if (!WARN_ON(list_empty(&queue->free_pool))) { -+ struct xradio_queue_item *item = list_first_entry( -+ &queue->free_pool, struct xradio_queue_item, head); -+ BUG_ON(item->skb); -+ -+ list_move_tail(&item->head, &queue->queue); -+ item->skb = skb; -+ item->txpriv = *txpriv; -+ item->generation = 1; /* avoid packet ID is 0.*/ -+ item->pack_stk_wr = 0; -+ item->packetID = xradio_queue_make_packet_id( -+ queue->generation, queue->queue_id, -+ item->generation, item - queue->pool, -+ txpriv->if_id, txpriv->raw_link_id); -+ item->queue_timestamp = jiffies; -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ if (TES_P2P_0002_state == TES_P2P_0002_STATE_SEND_RESP) { -+ TES_P2P_0002_packet_id = item->packetID; -+ TES_P2P_0002_state = TES_P2P_0002_STATE_GET_PKTID; -+ txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_GET_PKTID]\n"); -+ } -+#endif -+ -+ ++queue->num_queued; -+ ++queue->num_queued_vif[txpriv->if_id]; -+ ++queue->link_map_cache[txpriv->if_id][txpriv->link_id]; -+ -+ spin_lock_bh(&stats->lock); -+ ++stats->num_queued[txpriv->if_id]; -+ ++stats->link_map_cache[txpriv->if_id][txpriv->link_id]; -+ spin_unlock_bh(&stats->lock); -+ -+ /* -+ * TX may happen in parallel sometimes. -+ * Leave extra queue slots so we don't overflow. -+ */ -+ if (queue->overfull == false && -+ queue->num_queued >= -+ ((stats->hw_priv->vif0_throttle +stats->hw_priv->vif1_throttle) -+ - (num_present_cpus() - 1))) { -+ queue->overfull = true; -+ __xradio_queue_lock(queue); -+ mod_timer(&queue->gc, jiffies); -+ txrx_printk(XRADIO_DBG_NIY,"!lock queue\n"); -+ } -+ } else { -+ ret = -ENOENT; -+ } -+#if 0 -+ txrx_printk(XRADIO_DBG_ERROR, "queue_put queue %d, %d, %d\n", -+ queue->num_queued, -+ queue->link_map_cache[txpriv->if_id][txpriv->link_id], -+ queue->num_pending); -+ txrx_printk(XRADIO_DBG_ERROR, "queue_put stats %d, %d\n", stats->num_queued, -+ stats->link_map_cache[txpriv->if_id][txpriv->link_id]); -+#endif -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+int xradio_queue_get(struct xradio_queue *queue, -+ int if_id, -+ u32 link_id_map, -+ struct wsm_tx **tx, -+ struct ieee80211_tx_info **tx_info, -+ struct xradio_txpriv **txpriv) -+{ -+ int ret = -ENOENT; -+ struct xradio_queue_item *item; -+ struct xradio_queue_stats *stats = queue->stats; -+ bool wakeup_stats = false; -+ -+ spin_lock_bh(&queue->lock); -+ list_for_each_entry(item, &queue->queue, head) { -+ if ((item->txpriv.if_id == if_id) && -+ (link_id_map & BIT(item->txpriv.link_id))) { -+ ret = 0; -+ break; -+ } -+ } -+ -+ if (!WARN_ON(ret)) { -+ *tx = (struct wsm_tx *)item->skb->data; -+ *tx_info = IEEE80211_SKB_CB(item->skb); -+ *txpriv = &item->txpriv; -+ (*tx)->packetID = __cpu_to_le32(item->packetID); -+ list_move_tail(&item->head, &queue->pending); -+ ++queue->num_pending; -+ ++queue->num_pending_vif[item->txpriv.if_id]; -+ --queue->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]; -+ item->xmit_timestamp = jiffies; -+ -+ spin_lock_bh(&stats->lock); -+ --stats->num_queued[item->txpriv.if_id]; -+ if (!--stats->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]) -+ wakeup_stats = true; -+ -+ spin_unlock_bh(&stats->lock); -+#if 0 -+ txrx_printk(XRADIO_DBG_ERROR, "queue_get queue %d, %d, %d\n", -+ queue->num_queued, -+ queue->link_map_cache[item->txpriv.if_id][item->txpriv.link_id], -+ queue->num_pending); -+ txrx_printk(XRADIO_DBG_ERROR, "queue_get stats %d, %d\n", stats->num_queued, -+ stats->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]); -+#endif -+ } -+ spin_unlock_bh(&queue->lock); -+ if (wakeup_stats) -+ wake_up(&stats->wait_link_id_empty); -+ -+ return ret; -+} -+ -+int xradio_queue_requeue(struct xradio_queue *queue, u32 packetID, bool check) -+{ -+ int ret = 0; -+ u8 queue_generation, queue_id, item_generation, item_id, if_id, link_id; -+ struct xradio_queue_item *item; -+ struct xradio_queue_stats *stats = queue->stats; -+ -+ xradio_queue_parse_id(packetID, &queue_generation, &queue_id, -+ &item_generation, &item_id, &if_id, &link_id); -+ -+ item = &queue->pool[item_id]; -+ if (check && item->txpriv.offchannel_if_id == XRWL_GENERIC_IF_ID) { -+ txrx_printk(XRADIO_DBG_MSG, "Requeued frame dropped for " -+ "generic interface id.\n"); -+ xradio_queue_remove(queue, packetID); -+ return 0; -+ } -+ -+ if (!check) -+ item->txpriv.offchannel_if_id = XRWL_GENERIC_IF_ID; -+ -+ /*if_id = item->txpriv.if_id;*/ -+ -+ spin_lock_bh(&queue->lock); -+ BUG_ON(queue_id != queue->queue_id); -+ if (unlikely(queue_generation != queue->generation)) { -+ ret = -ENOENT; -+ } else if (unlikely(item_id >= (unsigned) queue->capacity)) { -+ WARN_ON(1); -+ ret = -EINVAL; -+ } else if (unlikely(item->generation != item_generation)) { -+ WARN_ON(1); -+ ret = -ENOENT; -+ } else { -+ --queue->num_pending; -+ --queue->num_pending_vif[if_id]; -+ ++queue->link_map_cache[if_id][item->txpriv.link_id]; -+ -+ spin_lock_bh(&stats->lock); -+ ++stats->num_queued[item->txpriv.if_id]; -+ ++stats->link_map_cache[if_id][item->txpriv.link_id]; -+ spin_unlock_bh(&stats->lock); -+ -+ item->generation = ++item_generation; -+ item->packetID = xradio_queue_make_packet_id( -+ queue_generation, queue_id, item_generation, item_id, -+ if_id, link_id); -+ list_move(&item->head, &queue->queue); -+#if 0 -+ txrx_printk(XRADIO_DBG_ERROR, "queue_requeue queue %d, %d, %d\n", -+ queue->num_queued, -+ queue->link_map_cache[if_id][item->txpriv.link_id], -+ queue->num_pending); -+ txrx_printk(XRADIO_DBG_ERROR, "queue_requeue stats %d, %d\n", -+ stats->num_queued, -+ stats->link_map_cache[if_id][item->txpriv.link_id]); -+#endif -+ } -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+int xradio_queue_requeue_all(struct xradio_queue *queue) -+{ -+ struct xradio_queue_stats *stats = queue->stats; -+ spin_lock_bh(&queue->lock); -+ while (!list_empty(&queue->pending)) { -+ struct xradio_queue_item *item = list_entry( -+ queue->pending.prev, struct xradio_queue_item, head); -+ -+ --queue->num_pending; -+ --queue->num_pending_vif[item->txpriv.if_id]; -+ ++queue->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]; -+ -+ spin_lock_bh(&stats->lock); -+ ++stats->num_queued[item->txpriv.if_id]; -+ ++stats->link_map_cache[item->txpriv.if_id] -+ [item->txpriv.link_id]; -+ spin_unlock_bh(&stats->lock); -+ -+ ++item->generation; -+ item->packetID = xradio_queue_make_packet_id( -+ queue->generation, queue->queue_id, -+ item->generation, item - queue->pool, -+ item->txpriv.if_id, item->txpriv.raw_link_id); -+ list_move(&item->head, &queue->queue); -+ } -+ spin_unlock_bh(&queue->lock); -+ -+ return 0; -+} -+ -+int xradio_queue_remove(struct xradio_queue *queue, u32 packetID) -+{ -+ int ret = 0; -+ u8 queue_generation, queue_id, item_generation, item_id, if_id, link_id; -+ struct xradio_queue_item *item; -+ struct xradio_queue_stats *stats = queue->stats; -+ struct sk_buff *gc_skb = NULL; -+ struct xradio_txpriv gc_txpriv; -+ -+ xradio_queue_parse_id(packetID, &queue_generation, &queue_id, -+ &item_generation, &item_id, &if_id, &link_id); -+ -+ item = &queue->pool[item_id]; -+ -+ spin_lock_bh(&queue->lock); -+ BUG_ON(queue_id != queue->queue_id); -+ /*TODO:COMBO:Add check for interface ID also */ -+ if (unlikely(queue_generation != queue->generation)) { -+ ret = -ENOENT; -+ } else if (unlikely(item_id >= (unsigned) queue->capacity)) { -+ WARN_ON(1); -+ ret = -EINVAL; -+ } else if (unlikely(item->generation != item_generation)) { -+ WARN_ON(1); -+ ret = -ENOENT; -+ } else { -+ gc_txpriv = item->txpriv; -+ gc_skb = item->skb; -+ item->skb = NULL; -+ --queue->num_pending; -+ --queue->num_pending_vif[if_id]; -+ --queue->num_queued; -+ --queue->num_queued_vif[if_id]; -+ ++queue->num_sent; -+ ++item->generation; -+ -+ /* Do not use list_move_tail here, but list_move: -+ * try to utilize cache row. -+ */ -+ list_move(&item->head, &queue->free_pool); -+ -+ if (unlikely(queue->overfull) && -+ (queue->num_queued <= ((stats->hw_priv->vif0_throttle + stats->hw_priv->vif1_throttle + 2)>>1))) { -+ queue->overfull = false; -+ __xradio_queue_unlock(queue); -+ } -+ } -+ spin_unlock_bh(&queue->lock); -+ -+#if 0 -+ txrx_printk(XRADIO_DBG_ERROR, "queue_drop queue %d, %d, %d\n", -+ queue->num_queued, queue->link_map_cache[if_id][0], -+ queue->num_pending); -+ txrx_printk(XRADIO_DBG_ERROR, "queue_drop stats %d, %d\n", stats->num_queued, -+ stats->link_map_cache[if_id][0]); -+#endif -+ if (gc_skb) -+ stats->skb_dtor(stats->hw_priv, gc_skb, &gc_txpriv); -+ -+ return ret; -+} -+ -+int xradio_queue_get_skb(struct xradio_queue *queue, u32 packetID, -+ struct sk_buff **skb, -+ const struct xradio_txpriv **txpriv) -+{ -+ int ret = 0; -+ u8 queue_generation, queue_id, item_generation, item_id, if_id, link_id; -+ struct xradio_queue_item *item; -+ -+ xradio_queue_parse_id(packetID, &queue_generation, &queue_id, -+ &item_generation, &item_id, &if_id, &link_id); -+ -+ item = &queue->pool[item_id]; -+ -+ spin_lock_bh(&queue->lock); -+ BUG_ON(queue_id != queue->queue_id); -+ /* TODO:COMBO: Add check for interface ID here */ -+ if (unlikely(queue_generation != queue->generation)) { -+ ret = -ENOENT; -+ } else if (unlikely(item_id >= (unsigned) queue->capacity)) { -+ WARN_ON(1); -+ ret = -EINVAL; -+ } else if (unlikely(item->generation != item_generation)) { -+ WARN_ON(1); -+ ret = -ENOENT; -+ } else { -+ *skb = item->skb; -+ *txpriv = &item->txpriv; -+ } -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+void xradio_queue_lock(struct xradio_queue *queue) -+{ -+ spin_lock_bh(&queue->lock); -+ __xradio_queue_lock(queue); -+ spin_unlock_bh(&queue->lock); -+} -+ -+void xradio_queue_unlock(struct xradio_queue *queue) -+{ -+ spin_lock_bh(&queue->lock); -+ __xradio_queue_unlock(queue); -+ spin_unlock_bh(&queue->lock); -+} -+ -+bool xradio_queue_get_xmit_timestamp(struct xradio_queue *queue, -+ unsigned long *timestamp, int if_id, -+ u32 pending_frameID, u32 *Old_frame_ID) -+{ -+ struct xradio_queue_item *item; -+ bool ret; -+ -+ spin_lock_bh(&queue->lock); -+ ret = !list_empty(&queue->pending); -+ if (ret) { -+ list_for_each_entry(item, &queue->pending, head) { -+ if (((if_id == XRWL_GENERIC_IF_ID) || -+ (if_id == XRWL_ALL_IFS) || -+ (item->txpriv.if_id == if_id)) && -+ (item->packetID != pending_frameID)) { -+ if (time_before(item->xmit_timestamp, -+ *timestamp)) { -+ *timestamp = item->xmit_timestamp; -+ *Old_frame_ID = item->packetID; -+ } -+ } -+ } -+ } -+ spin_unlock_bh(&queue->lock); -+ return ret; -+} -+ -+bool xradio_queue_stats_is_empty(struct xradio_queue_stats *stats, -+ u32 link_id_map, int if_id) -+{ -+ bool empty = true; -+ -+ spin_lock_bh(&stats->lock); -+ if (link_id_map == (u32)-1) -+ empty = stats->num_queued[if_id] == 0; -+ else { -+ int i, if_id; -+ for (if_id = 0; if_id < XRWL_MAX_VIFS; if_id++) { -+ for (i = 0; i < stats->map_capacity; ++i) { -+ if (link_id_map & BIT(i)) { -+ if (stats->link_map_cache[if_id][i]) { -+ empty = false; -+ break; -+ } -+ } -+ } -+ } -+ } -+ spin_unlock_bh(&stats->lock); -+ -+ return empty; -+} -+ -+bool xradio_query_txpkt_timeout(struct xradio_common *hw_priv, int if_id, -+ u32 pending_pkt_id, long *timeout) -+{ -+ int i; -+ bool pending = false; -+ unsigned long timestamp = jiffies; -+ struct xradio_queue *queue = NULL; -+ struct xradio_queue_item *item = NULL; -+ struct xradio_queue *old_queue = NULL; -+ struct xradio_queue_item *old_item = NULL; -+ u8 pack_stk_wr = 0; -+ -+ /* Get oldest frame.*/ -+ for (i = 0; i < AC_QUEUE_NUM; ++i) { -+ queue = &hw_priv->tx_queue[i]; -+ spin_lock_bh(&queue->lock); -+ if (!list_empty(&queue->pending)) { -+ list_for_each_entry(item, &queue->pending, head) { -+ if (((if_id == XRWL_GENERIC_IF_ID) || -+ (if_id == XRWL_ALL_IFS) || -+ (item->txpriv.if_id == if_id)) && -+ (item->packetID != pending_pkt_id)) { -+ if (time_before(item->xmit_timestamp, timestamp)) { -+ timestamp = item->xmit_timestamp; -+ pack_stk_wr = item->pack_stk_wr; -+ old_queue = queue; -+ old_item = item; -+ } -+ } -+ } -+ pending = true; -+ } -+ spin_unlock_bh(&queue->lock); -+ } -+ if (!pending) -+ return false; -+ -+ /* Check if frame transmission is timed out. -+ * add (WSM_CMD_LAST_CHANCE_TIMEOUT>>1) for stuck workaround.*/ -+ *timeout = timestamp + WSM_CMD_LAST_CHANCE_TIMEOUT - jiffies; -+ if (unlikely(*timeout < 0) && !pack_stk_wr) { -+ struct ieee80211_hdr *frame = NULL; -+ const struct xradio_txpriv *txpriv = NULL; -+ u16 fctl = 0x0; -+ u32 len = 0x0; -+ u8 if_id = 0, link_id = 0, tid = 0; -+ -+ /* query the timeout frame. */ -+ spin_lock_bh(&old_queue->lock); -+ if (likely(old_item->skb && !hw_priv->query_packetID)) { -+ hw_priv->query_packetID = old_item->packetID; -+ old_item->pack_stk_wr = 1; -+ atomic_add(1, &hw_priv->query_cnt); -+ -+ /* Info of stuck frames for debug.*/ -+ txpriv = &old_item->txpriv; -+ frame = (struct ieee80211_hdr *)(&old_item->skb->data[txpriv->offset]); -+ fctl = frame->frame_control; -+ len = old_item->skb->len; -+ if_id = txpriv->if_id; -+ link_id = txpriv->link_id; -+ tid = txpriv->tid; -+ } -+ spin_unlock_bh(&old_queue->lock); -+ /* Dump Info of stuck frames. */ -+ if (frame) { -+ txrx_printk(XRADIO_DBG_ERROR, "TX confirm timeout(%ds).\n", -+ WSM_CMD_LAST_CHANCE_TIMEOUT/HZ); -+ txrx_printk(XRADIO_DBG_ERROR, "if=%d, linkid=%d, tid=%d, " \ -+ "old_packetID=0x%08x, fctl=0x%04x, len=%d, wr=%d\n", -+ if_id, link_id, tid, hw_priv->query_packetID, fctl, len, -+ pack_stk_wr); -+ } -+ /* Return half of timeout for query packet. */ -+ *timeout = (WSM_CMD_LAST_CHANCE_TIMEOUT>>1); -+ } else if (unlikely(pack_stk_wr)){ -+ *timeout = *timeout + (WSM_CMD_LAST_CHANCE_TIMEOUT>>1); -+ txrx_printk(XRADIO_DBG_MSG,"%s, wr and timeout=%ld\n", __func__, *timeout); -+ } -+ return pending; -+} -diff --git a/drivers/net/wireless/xradio/queue.h b/drivers/net/wireless/xradio/queue.h -new file mode 100644 -index 0000000..d6b64ce ---- /dev/null -+++ b/drivers/net/wireless/xradio/queue.h -@@ -0,0 +1,139 @@ -+/* -+ * queue operations for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#ifndef XRADIO_QUEUE_H_INCLUDED -+#define XRADIO_QUEUE_H_INCLUDED -+ -+/* private */ struct xradio_queue_item; -+ -+/* extern */ struct sk_buff; -+/* extern */ struct wsm_tx; -+/* extern */ struct xradio_common; -+/* extern */ struct xradio_vif; -+/* extern */ struct ieee80211_tx_queue_stats; -+/* extern */ struct xradio_txpriv; -+ -+/* forward */ struct xradio_queue_stats; -+ -+typedef void (*xradio_queue_skb_dtor_t)(struct xradio_common *priv, -+ struct sk_buff *skb, -+ const struct xradio_txpriv *txpriv); -+ -+struct xradio_queue { -+ struct xradio_queue_stats *stats; -+ size_t capacity; -+ size_t num_queued; -+ size_t num_queued_vif[XRWL_MAX_VIFS]; -+ size_t num_pending; -+ size_t num_pending_vif[XRWL_MAX_VIFS]; -+ size_t num_sent; -+ struct xradio_queue_item *pool; -+ struct list_head queue; -+ struct list_head free_pool; -+ struct list_head pending; -+ int tx_locked_cnt; -+ int *link_map_cache[XRWL_MAX_VIFS]; -+ bool overfull; -+ spinlock_t lock; -+ u8 queue_id; -+ u8 generation; -+ struct timer_list gc; -+ unsigned long ttl; -+}; -+ -+struct xradio_queue_stats { -+ spinlock_t lock; -+ int *link_map_cache[XRWL_MAX_VIFS]; -+ int num_queued[XRWL_MAX_VIFS]; -+ size_t map_capacity; -+ wait_queue_head_t wait_link_id_empty; -+ xradio_queue_skb_dtor_t skb_dtor; -+ struct xradio_common *hw_priv; -+}; -+ -+struct xradio_txpriv { -+ u8 link_id; -+ u8 raw_link_id; -+ u8 tid; -+ u8 rate_id; -+ u8 offset; -+ u8 if_id; -+ u8 offchannel_if_id; -+ u8 use_bg_rate; -+}; -+ -+int xradio_queue_stats_init(struct xradio_queue_stats *stats, -+ size_t map_capacity, -+ xradio_queue_skb_dtor_t skb_dtor, -+ struct xradio_common *priv); -+int xradio_queue_init(struct xradio_queue *queue, -+ struct xradio_queue_stats *stats, -+ u8 queue_id, -+ size_t capacity, -+ unsigned long ttl); -+int xradio_queue_clear(struct xradio_queue *queue, int if_id); -+void xradio_queue_stats_deinit(struct xradio_queue_stats *stats); -+void xradio_queue_deinit(struct xradio_queue *queue); -+ -+size_t xradio_queue_get_num_queued(struct xradio_vif *priv, -+ struct xradio_queue *queue, -+ u32 link_id_map); -+int xradio_queue_put(struct xradio_queue *queue, -+ struct sk_buff *skb, struct xradio_txpriv *txpriv); -+int xradio_queue_get(struct xradio_queue *queue, -+ int if_id, u32 link_id_map, -+ struct wsm_tx **tx, -+ struct ieee80211_tx_info **tx_info, -+ struct xradio_txpriv **txpriv); -+ -+int xradio_queue_requeue(struct xradio_queue *queue, u32 packetID, bool check); -+ -+int xradio_queue_requeue_all(struct xradio_queue *queue); -+int xradio_queue_remove(struct xradio_queue *queue, -+ u32 packetID); -+ -+int xradio_queue_get_skb(struct xradio_queue *queue, u32 packetID, -+ struct sk_buff **skb, -+ const struct xradio_txpriv **txpriv); -+void xradio_queue_lock(struct xradio_queue *queue); -+void xradio_queue_unlock(struct xradio_queue *queue); -+bool xradio_queue_get_xmit_timestamp(struct xradio_queue *queue, -+ unsigned long *timestamp, int if_id, -+ u32 pending_frameID, u32 *Old_frame_ID); -+bool xradio_query_txpkt_timeout(struct xradio_common *hw_priv, int if_id, -+ u32 pending_pkt_id, long *timeout); -+ -+ -+bool xradio_queue_stats_is_empty(struct xradio_queue_stats *stats, -+ u32 link_id_map, int if_id); -+ -+static inline u8 xradio_queue_get_queue_id(u32 packetID) -+{ -+ return (packetID >> 16) & 0xF; -+} -+ -+static inline u8 xradio_queue_get_if_id(u32 packetID) -+{ -+ return (packetID >> 20) & 0xF; -+} -+ -+static inline u8 xradio_queue_get_link_id(u32 packetID) -+{ -+ return (packetID >> 24) & 0xF; -+} -+ -+static inline u8 xradio_queue_get_generation(u32 packetID) -+{ -+ return (packetID >> 8) & 0xFF; -+} -+ -+#endif /* XRADIO_QUEUE_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/rx.c b/drivers/net/wireless/xradio/rx.c -new file mode 100644 -index 0000000..fb8be92 ---- /dev/null -+++ b/drivers/net/wireless/xradio/rx.c -@@ -0,0 +1,414 @@ -+#include -+ -+#include "xradio.h" -+#include "rx.h" -+#include "ht.h" -+#include "p2p.h" -+#include "sta.h" -+#include "bh.h" -+#include "ap.h" -+ -+ // MRK: added copy of this tx.c function here for testing, renamed _rx -+ -+static void xradio_check_go_neg_conf_success_rx(struct xradio_common *hw_priv, -+ u8 *action) -+{ -+ if (action[2] == 0x50 && action[3] == 0x6F && action[4] == 0x9A && -+ action[5] == 0x09 && action[6] == 0x02) { -+ if(action[17] == 0) { -+ hw_priv->is_go_thru_go_neg = true; -+ } -+ else { -+ hw_priv->is_go_thru_go_neg = false; -+ } -+ } -+} -+ -+ -+static int xradio_handle_pspoll(struct xradio_vif *priv, -+ struct sk_buff *skb) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct ieee80211_sta *sta; -+ struct ieee80211_pspoll *pspoll = -+ (struct ieee80211_pspoll *) skb->data; -+ int link_id = 0; -+ u32 pspoll_mask = 0; -+ int drop = 1; -+ int i; -+ -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_AP) -+ goto done; -+ if (memcmp(priv->vif->addr, pspoll->bssid, ETH_ALEN)) -+ goto done; -+ -+ rcu_read_lock(); -+ sta = ieee80211_find_sta(priv->vif, pspoll->ta); -+ if (sta) { -+ struct xradio_sta_priv *sta_priv; -+ sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; -+ link_id = sta_priv->link_id; -+ pspoll_mask = BIT(sta_priv->link_id); -+ } -+ rcu_read_unlock(); -+ if (!link_id) -+ goto done; -+ -+ priv->pspoll_mask |= pspoll_mask; -+ drop = 0; -+ -+ /* Do not report pspols if data for given link id is -+ * queued already. */ -+ for (i = 0; i < 4; ++i) { -+ if (xradio_queue_get_num_queued(priv, -+ &hw_priv->tx_queue[i], -+ pspoll_mask)) { -+ xradio_bh_wakeup(hw_priv); -+ drop = 1; -+ break; -+ } -+ } -+ txrx_printk(XRADIO_DBG_NIY, "[RX] PSPOLL: %s\n", drop ? "local" : "fwd"); -+done: -+ return drop; -+} -+ -+ -+static void -+xradio_rx_h_ba_stat(struct xradio_vif *priv, -+ size_t hdrlen, size_t skb_len ) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_STA) -+ return; -+ if (!xradio_is_ht(&hw_priv->ht_oper)) -+ return; -+ if (!priv->setbssparams_done) -+ return; -+ -+ spin_lock_bh(&hw_priv->ba_lock); -+ hw_priv->ba_acc_rx += skb_len - hdrlen; -+ if (!(hw_priv->ba_cnt_rx || hw_priv->ba_cnt)) { -+ mod_timer(&hw_priv->ba_timer, -+ jiffies + XRADIO_BLOCK_ACK_INTERVAL); -+ } -+ hw_priv->ba_cnt_rx++; -+ spin_unlock_bh(&hw_priv->ba_lock); -+} -+ -+void xradio_rx_cb(struct xradio_vif *priv, -+ struct wsm_rx *arg, -+ struct sk_buff **skb_p) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct sk_buff *skb = *skb_p; -+ struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); -+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -+#endif -+ struct xradio_link_entry *entry = NULL; -+ unsigned long grace_period; -+ bool early_data = false; -+ size_t hdrlen = 0; -+ u8 parse_iv_len = 0; -+ -+ dev_dbg(hw_priv->pdev, "vif %d: rx, status %u flags 0x%.8x", -+ priv->if_id, arg->status, arg->flags); -+ if(ieee80211_is_deauth(frame->frame_control)) -+ dev_dbg(hw_priv->pdev, "vif %d: deauth\n", priv->if_id); -+ -+ hdr->flag = 0; -+ -+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { -+ /* STA is stopped. */ -+ goto drop; -+ } -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ xradio_frame_monitor(hw_priv,skb,false); -+#endif -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ if ((ieee80211_is_action(frame->frame_control)) -+ && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { -+ u8 *action = (u8*)&mgmt->u.action.category; -+ xradio_check_go_neg_conf_success_rx(hw_priv, action); -+ } -+#endif -+ -+ if (arg->link_id && (arg->link_id != XRADIO_LINK_ID_UNMAPPED) -+ && (arg->link_id <= XRADIO_MAX_STA_IN_AP_MODE)) { -+ entry = &priv->link_id_db[arg->link_id - 1]; -+ if (entry->status == XRADIO_LINK_SOFT && -+ ieee80211_is_data(frame->frame_control)) -+ early_data = true; -+ entry->timestamp = jiffies; -+ } -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ else if ((arg->link_id == XRADIO_LINK_ID_UNMAPPED) -+ && (priv->vif->p2p == WSM_START_MODE_P2P_GO) -+ && ieee80211_is_action(frame->frame_control) -+ && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { -+ txrx_printk(XRADIO_DBG_NIY, "[RX] Going to MAP&RESET link ID\n"); -+ -+ if (work_pending(&priv->linkid_reset_work)) -+ WARN_ON(1); -+ -+ memcpy(&priv->action_frame_sa[0], -+ ieee80211_get_SA(frame), ETH_ALEN); -+ priv->action_linkid = 0; -+ schedule_work(&priv->linkid_reset_work); -+ } -+ -+ if (arg->link_id && (arg->link_id != XRADIO_LINK_ID_UNMAPPED) -+ && (priv->vif->p2p == WSM_START_MODE_P2P_GO) -+ && ieee80211_is_action(frame->frame_control) -+ && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { -+ /* Link ID already exists for the ACTION frame. -+ * Reset and Remap */ -+ if (work_pending(&priv->linkid_reset_work)) -+ WARN_ON(1); -+ memcpy(&priv->action_frame_sa[0], -+ ieee80211_get_SA(frame), ETH_ALEN); -+ priv->action_linkid = arg->link_id; -+ schedule_work(&priv->linkid_reset_work); -+ } -+#endif -+ if (unlikely(arg->status)) { -+ if (arg->status == WSM_STATUS_MICFAILURE) { -+ dev_err(priv->hw_priv->pdev, "[RX] IF=%d, MIC failure.\n", -+ priv->if_id); -+ hdr->flag |= RX_FLAG_MMIC_ERROR; -+ } else if (arg->status == WSM_STATUS_NO_KEY_FOUND) { -+ dev_warn(priv->hw_priv->pdev, "received frame has no key status\n"); -+ //goto drop; -+ } else { -+ dev_err(priv->hw_priv->pdev, "[RX] IF=%d, Receive failure: %d.\n", -+ priv->if_id, arg->status); -+ goto drop; -+ } -+ } -+ -+ if (skb->len < sizeof(struct ieee80211_pspoll)) { -+ dev_err(priv->hw_priv->pdev, "Malformed SDU rx'ed. " -+ "Size is lesser than IEEE header.\n"); -+ goto drop; -+ } -+ -+ if (unlikely(ieee80211_is_pspoll(frame->frame_control))) -+ if (xradio_handle_pspoll(priv, skb)) -+ goto drop; -+ -+ hdr->mactime = 0; /* Not supported by WSM */ -+ hdr->band = (arg->channelNumber > 14) ? -+ NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; -+ hdr->freq = ieee80211_channel_to_frequency( -+ arg->channelNumber, -+ hdr->band); -+ -+#ifdef AP_HT_COMPAT_FIX -+ if (!priv->ht_compat_det && priv->htcap && -+ ieee80211_is_data_qos(frame->frame_control)) { -+ if(xradio_apcompat_detect(priv, arg->rxedRate)) -+ goto drop; -+ } -+#endif -+ -+ if (arg->rxedRate >= 14) { -+ hdr->encoding = RX_ENC_HT; -+ hdr->rate_idx = arg->rxedRate - 14; -+ } else if (arg->rxedRate >= 4) { -+ if (hdr->band == NL80211_BAND_5GHZ) -+ hdr->rate_idx = arg->rxedRate - 6; -+ else -+ hdr->rate_idx = arg->rxedRate - 2; -+ } else { -+ hdr->rate_idx = arg->rxedRate; -+ } -+ -+ hdr->signal = (s8)arg->rcpiRssi; -+ hdr->antenna = 0; -+ -+ hdrlen = ieee80211_hdrlen(frame->frame_control); -+ -+ if (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { -+ size_t iv_len = 0, icv_len = 0; -+ -+ hdr->flag |= RX_FLAG_DECRYPTED; -+ -+ /* Oops... There is no fast way to ask mac80211 about -+ * IV/ICV lengths. Even defines are not exposed.*/ -+ switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { -+ case WSM_RX_STATUS_WEP: -+ iv_len = 4 /* WEP_IV_LEN */; -+ icv_len = 4 /* WEP_ICV_LEN */; -+ break; -+ case WSM_RX_STATUS_TKIP: -+ iv_len = 8 /* TKIP_IV_LEN */; -+ icv_len = 4 /* TKIP_ICV_LEN */ -+ + 8 /*MICHAEL_MIC_LEN*/; -+ break; -+ case WSM_RX_STATUS_AES: -+ iv_len = 8 /* CCMP_HDR_LEN */; -+ icv_len = 8 /* CCMP_MIC_LEN */; -+ break; -+ case WSM_RX_STATUS_WAPI: -+ iv_len = 18 /* WAPI_HDR_LEN */; -+ icv_len = 16 /* WAPI_MIC_LEN */; -+ hdr->flag |= RX_FLAG_IV_STRIPPED; -+ break; -+ default: -+ WARN_ON("Unknown encryption type"); -+ goto drop; -+ } -+ -+ /* Firmware strips ICV in case of MIC failure. */ -+ if (arg->status == WSM_STATUS_MICFAILURE) { -+ icv_len = 0; -+ hdr->flag |= RX_FLAG_IV_STRIPPED; -+ } -+ -+ if (skb->len < hdrlen + iv_len + icv_len) { -+ dev_err(priv->hw_priv->pdev, "Mailformed SDU rx'ed. " -+ "Size is lesser than crypto headers.\n"); -+ goto drop; -+ } -+ -+ if (WSM_RX_STATUS_ENCRYPTION(arg->flags) == -+ WSM_RX_STATUS_TKIP) { -+ /* Remove TKIP MIC 8 bytes*/ -+ memmove(skb->data + skb->len-icv_len, -+ skb->data + skb->len-icv_len+8, 4); -+ skb_trim(skb, skb->len - 8); -+ hdr->flag |= RX_FLAG_MMIC_STRIPPED; -+ } else if (unlikely(WSM_RX_STATUS_ENCRYPTION(arg->flags) == -+ WSM_RX_STATUS_WAPI)) { -+ /* Protocols not defined in mac80211 should be -+ stripped/crypted in driver/firmware */ -+ /* Remove IV, ICV and MIC */ -+ skb_trim(skb, skb->len - icv_len); -+ memmove(skb->data + iv_len, skb->data, hdrlen); -+ skb_pull(skb, iv_len); -+ } -+ parse_iv_len = iv_len; -+ } -+ -+ if (ieee80211_is_beacon(frame->frame_control) && -+ !arg->status && -+ !memcmp(ieee80211_get_SA(frame), priv->join_bssid,ETH_ALEN)) { -+ const u8 *tim_ie; -+ u8 *ies; -+ size_t ies_len; -+ priv->disable_beacon_filter = false; -+ queue_work(hw_priv->workqueue, &priv->update_filtering_work); -+ ies = ((struct ieee80211_mgmt *) -+ (skb->data))->u.beacon.variable; -+ ies_len = skb->len - (ies - (u8 *)(skb->data)); -+ -+ tim_ie = xradio_get_ie(ies, ies_len, WLAN_EID_TIM); -+ if (tim_ie) { -+ struct ieee80211_tim_ie *tim = -+ (struct ieee80211_tim_ie *)&tim_ie[2]; -+ -+ if (priv->join_dtim_period != tim->dtim_period) { -+ priv->join_dtim_period = tim->dtim_period; -+ queue_work(hw_priv->workqueue, -+ &priv->set_beacon_wakeup_period_work); -+ } -+ } -+ if (unlikely(priv->disable_beacon_filter)) { -+ priv->disable_beacon_filter = false; -+ queue_work(hw_priv->workqueue, -+ &priv->update_filtering_work); -+ } -+ } -+#ifdef AP_HT_CAP_UPDATE -+ if (priv->mode == NL80211_IFTYPE_AP && -+ ieee80211_is_beacon(frame->frame_control) && -+ ((priv->ht_oper&HT_INFO_MASK) != 0x0011) && -+ !arg->status){ -+ u8 *ies; -+ size_t ies_len; -+ const u8 *ht_cap; -+ ies = ((struct ieee80211_mgmt *)(skb->data))->u.beacon.variable; -+ ies_len = skb->len - (ies - (u8 *)(skb->data)); -+ ht_cap = xradio_get_ie(ies, ies_len, WLAN_EID_HT_CAPABILITY); -+ if(!ht_cap) { -+ priv->ht_oper |= 0x0011; -+ queue_work(hw_priv->workqueue, &priv->ht_oper_update_work); -+ } -+ } -+#endif -+ -+#ifdef AP_HT_COMPAT_FIX -+ if (ieee80211_is_mgmt(frame->frame_control) && -+ priv->if_id == 0 && !(priv->ht_compat_det & 0x10)) { -+ xradio_remove_ht_ie(priv, skb); -+ } -+#endif -+ -+#ifdef ROAM_OFFLOAD -+ if ((ieee80211_is_beacon(frame->frame_control)||ieee80211_is_probe_resp(frame->frame_control)) && -+ !arg->status ) { -+ if (hw_priv->auto_scanning && !atomic_read(&hw_priv->scan.in_progress)) -+ hw_priv->frame_rcvd = 1; -+ -+ if (!memcmp(ieee80211_get_SA(frame), priv->join_bssid, ETH_ALEN)) { -+ if (hw_priv->beacon) -+ dev_kfree_skb(hw_priv->beacon); -+ hw_priv->beacon = skb_copy(skb, GFP_ATOMIC); -+ if (!hw_priv->beacon) -+ txrx_printk(XRADIO_DBG_ERROR, "sched_scan: own beacon storing failed\n"); -+ } -+ } -+#endif /*ROAM_OFFLOAD*/ -+ -+ //don't delay scan before next connect, yangfh. -+ if (ieee80211_is_deauth(frame->frame_control) || -+ ieee80211_is_disassoc(frame->frame_control)) -+ hw_priv->connet_time[priv->if_id] = 0; -+ -+ /* Stay awake for 1sec. after frame is received to give -+ * userspace chance to react and acquire appropriate -+ * wakelock. */ -+ if (ieee80211_is_auth(frame->frame_control)) -+ grace_period = 5 * HZ; -+ else if (ieee80211_is_deauth(frame->frame_control)) -+ grace_period = 5 * HZ; -+ else -+ grace_period = HZ; -+ -+ if (ieee80211_is_data(frame->frame_control)) -+ xradio_rx_h_ba_stat(priv, hdrlen, skb->len); -+ -+ xradio_pm_stay_awake(&hw_priv->pm_state, grace_period); -+ -+ if(xradio_realloc_resv_skb(hw_priv, *skb_p)) { -+ *skb_p = NULL; -+ return; -+ } -+ /* Try to a packet for the case dev_alloc_skb failed in bh.*/ -+ if (unlikely(early_data)) { -+ spin_lock_bh(&priv->ps_state_lock); -+ /* Double-check status with lock held */ -+ if (entry->status == XRADIO_LINK_SOFT) { -+ skb_queue_tail(&entry->rx_queue, skb); -+ dev_warn(priv->hw_priv->pdev, "***skb_queue_tail\n"); -+ } else -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ spin_unlock_bh(&priv->ps_state_lock); -+ } else { -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+ *skb_p = NULL; -+ -+ return; -+ -+drop: -+ dev_warn(priv->hw_priv->pdev, "dropped received frame\n"); -+ return; -+} -diff --git a/drivers/net/wireless/xradio/rx.h b/drivers/net/wireless/xradio/rx.h -new file mode 100644 -index 0000000..0c02b23 ---- /dev/null -+++ b/drivers/net/wireless/xradio/rx.h -@@ -0,0 +1,8 @@ -+#ifndef XRADIO_RX_H -+#define XRADIO_RX_H -+ -+void xradio_rx_cb(struct xradio_vif *priv, -+ struct wsm_rx *arg, -+ struct sk_buff **skb_p); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/scan.c b/drivers/net/wireless/xradio/scan.c -new file mode 100644 -index 0000000..a8829c0 ---- /dev/null -+++ b/drivers/net/wireless/xradio/scan.c -@@ -0,0 +1,897 @@ -+/* -+ * Scan implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include "xradio.h" -+#include "scan.h" -+#include "sta.h" -+#include "pm.h" -+ -+static void xradio_scan_restart_delayed(struct xradio_vif *priv); -+ -+static void xradio_remove_wps_p2p_ie(struct wsm_template_frame *frame) -+{ -+ u8 *ies; -+ u32 ies_len; -+ u32 ie_len; -+ u32 p2p_ie_len = 0; -+ u32 wps_ie_len = 0; -+ -+ -+ ies = &frame->skb->data[sizeof(struct ieee80211_hdr_3addr)]; -+ ies_len = frame->skb->len - sizeof(struct ieee80211_hdr_3addr); -+ while (ies_len >= 6) { -+ ie_len = ies[1] + 2; -+ ies_len -= ie_len; -+ if ((ies[0] == WLAN_EID_VENDOR_SPECIFIC) && -+ (ies[2] == 0x00 && ies[3] == 0x50 && -+ ies[4] == 0xf2 && ies[5] == 0x04)) { -+ wps_ie_len = ie_len; -+ memmove(ies, ies + ie_len, ies_len); -+ } else if ((ies[0] == WLAN_EID_VENDOR_SPECIFIC) && -+ (ies[2] == 0x50 && ies[3] == 0x6f && -+ ies[4] == 0x9a && ies[5] == 0x09)) { -+ p2p_ie_len = ie_len; -+ memmove(ies, ies + ie_len, ies_len); -+ } else { -+ ies += ie_len; -+ } -+ } -+ -+ if (p2p_ie_len || wps_ie_len) { -+ skb_trim(frame->skb, frame->skb->len - (p2p_ie_len + wps_ie_len)); -+ } -+} -+ -+static int xradio_scan_start(struct xradio_vif *priv, struct wsm_scan *scan) -+{ -+ int ret, i; -+#ifdef FPGA_SETUP -+ int tmo = 5000; -+#else -+ int tmo = 5000; -+#endif -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ -+ for (i = 0; i < scan->numOfChannels; ++i) -+ tmo += scan->ch[i].maxChannelTime + 10; -+ -+ atomic_set(&hw_priv->scan.in_progress, 1); -+ atomic_set(&hw_priv->recent_scan, 1); -+ xradio_pm_stay_awake(&hw_priv->pm_state, tmo * HZ / 1000); -+ ret = wsm_scan(hw_priv, scan, priv->if_id); -+ if (unlikely(ret)) { -+ scan_printk(XRADIO_DBG_WARN, "%s,wsm_scan failed!\n", __func__); -+ atomic_set(&hw_priv->scan.in_progress, 0); -+ xradio_scan_restart_delayed(priv); -+ } else { -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, -+ tmo * HZ / 1000); -+ } -+ return ret; -+} -+ -+#ifdef ROAM_OFFLOAD -+static int xradio_sched_scan_start(struct xradio_vif *priv, struct wsm_scan *scan) -+{ -+ int ret; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ -+ ret = wsm_scan(hw_priv, scan, priv->if_id); -+ if (unlikely(ret)) { -+ atomic_set(&hw_priv->scan.in_progress, 0); -+ scan_printk(XRADIO_DBG_WARN,"%s,wsm_scan failed!\n", __func__); -+ } -+ return ret; -+} -+#endif /*ROAM_OFFLOAD*/ -+ -+int xradio_hw_scan(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_scan_request *hw_req) -+{ -+ struct cfg80211_scan_request *req = &hw_req->req; -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, -+ }; -+ int i; -+ -+ /* Scan when P2P_GO corrupt firmware MiniAP mode */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ scan_printk(XRADIO_DBG_WARN,"%s, can't scan in AP mode!\n", __func__); -+ return -EOPNOTSUPP; -+ } -+ -+ if (hw_priv->bh_error) { -+ scan_printk(XRADIO_DBG_NIY, "Ignoring scan bh error occur!\n"); -+ return -EBUSY; -+ } -+ -+ if (work_pending(&priv->offchannel_work) || -+ (hw_priv->roc_if_id != -1)) { -+ scan_printk(XRADIO_DBG_WARN, "Offchannel work pending, " -+ "ignoring scan work %d\n", hw_priv->roc_if_id); -+ return -EBUSY; -+ } -+ -+ if (req->n_ssids == 1 && !req->ssids[0].ssid_len) -+ req->n_ssids = 0; -+ -+ scan_printk(XRADIO_DBG_NIY, "vif%d Scan request(%s-%dchs) for %d SSIDs.\n", -+ priv->if_id, (req->channels[0]->band==NL80211_BAND_2GHZ)?"2.4G":"5G", -+ req->n_channels, req->n_ssids); -+ -+ /*delay multiple ssids scan of vif0 for 3s when connnetting to a node*/ -+ if(hw_priv->connet_time[0] > 0 && req->n_ssids == 0 && priv->if_id == 0) { -+ long timeleft0 = hw_priv->connet_time[0] + SCAN_MAX_DELAY - jiffies; -+ if(jiffies >= hw_priv->connet_time[0] && timeleft0 > 0) { -+ scan_printk(XRADIO_DBG_NIY, "vif0 connetting, scan delay %ldms\n", -+ timeleft0*1000/HZ); -+ return -EBUSY; -+ } -+ hw_priv->connet_time[0] = 0; -+ } -+ -+ if (req->n_ssids > hw->wiphy->max_scan_ssids){ -+ scan_printk(XRADIO_DBG_ERROR, "%s: ssids is too much(%d)\n", -+ __func__, req->n_ssids); -+ return -EINVAL; -+ } -+ -+ /* TODO by Icenowy: so strange function call */ -+ frame.skb = ieee80211_probereq_get(hw, vif->addr, NULL, 0, 0); -+ if (!frame.skb) { -+ scan_printk(XRADIO_DBG_ERROR, "%s: ieee80211_probereq_get failed!\n", -+ __func__); -+ return -ENOMEM; -+ } -+ -+#ifdef ROAM_OFFLOAD -+ if (priv->join_status != XRADIO_JOIN_STATUS_STA) { -+ if (req->channels[0]->band == NL80211_BAND_2GHZ) -+ hw_priv->num_scanchannels = 0; -+ else -+ hw_priv->num_scanchannels = hw_priv->num_2g_channels; -+ -+ for (i=0; i < req->n_channels; i++) { -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].number = \ -+ req->channels[i]->hw_value; -+ if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR) { -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].minChannelTime = 50; -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].maxChannelTime = 110; -+ } -+ else { -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].minChannelTime = 10; -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].maxChannelTime = 40; -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].number |= \ -+ XRADIO_SCAN_TYPE_ACTIVE; -+ } -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].txPowerLevel = \ -+ req->channels[i]->max_power; -+ if (req->channels[0]->band == NL80211_BAND_5GHZ) -+ hw_priv->scan_channels[hw_priv->num_scanchannels + i].number |= \ -+ XRADIO_SCAN_BAND_5G; -+ } -+ if (req->channels[0]->band == NL80211_BAND_2GHZ) -+ hw_priv->num_2g_channels = req->n_channels; -+ else -+ hw_priv->num_5g_channels = req->n_channels; -+ } -+ hw_priv->num_scanchannels = hw_priv->num_2g_channels + hw_priv->num_5g_channels; -+#endif /*ROAM_OFFLOAD*/ -+ -+ /* will be unlocked in xradio_scan_work() */ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ if (frame.skb) { -+ int ret = 0; -+ if (priv->if_id == 0) -+ xradio_remove_wps_p2p_ie(&frame); -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ if (ret) { -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+ dev_kfree_skb(frame.skb); -+ scan_printk(XRADIO_DBG_ERROR, "%s: wsm_set_template_frame failed: %d.\n", -+ __func__, ret); -+ return ret; -+ } -+ } -+ -+ wsm_vif_lock_tx(priv); -+ -+ BUG_ON(hw_priv->scan.req); -+ hw_priv->scan.req = req; -+ hw_priv->scan.n_ssids = 0; -+ hw_priv->scan.status = 0; -+ hw_priv->scan.begin = &req->channels[0]; -+ hw_priv->scan.curr = hw_priv->scan.begin; -+ hw_priv->scan.end = &req->channels[req->n_channels]; -+ hw_priv->scan.output_power = hw_priv->output_power; -+ hw_priv->scan.if_id = priv->if_id; -+ /* TODO:COMBO: Populate BIT4 in scanflags to decide on which MAC -+ * address the SCAN request will be sent */ -+ -+ for (i = 0; i < req->n_ssids; ++i) { -+ struct wsm_ssid *dst = &hw_priv->scan.ssids[hw_priv->scan.n_ssids]; -+ BUG_ON(req->ssids[i].ssid_len > sizeof(dst->ssid)); -+ memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); -+ dst->length = req->ssids[i].ssid_len; -+ ++hw_priv->scan.n_ssids; -+ } -+ -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ if (frame.skb) -+ dev_kfree_skb(frame.skb); -+ queue_work(hw_priv->workqueue, &hw_priv->scan.work); -+ -+ return 0; -+} -+ -+#ifdef ROAM_OFFLOAD -+int xradio_hw_sched_scan_start(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct cfg80211_sched_scan_request *req, -+ struct ieee80211_sched_scan_ies *ies) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, -+ }; -+ int i; -+ -+ -+ scan_printk(XRADIO_DBG_WARN, "Scheduled scan request-->.\n"); -+ if (!priv->vif) -+ return -EINVAL; -+ -+ /* Scan when P2P_GO corrupt firmware MiniAP mode */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ scan_printk(XRADIO_DBG_WARN,"%s, can't scan in AP mode!\n", __func__); -+ return -EOPNOTSUPP; -+ } -+ -+ scan_printk(XRADIO_DBG_WARN, "Scheduled scan: n_ssids %d, ssid[0].len = %d\n", -+ req->n_ssids, req->ssids[0].ssid_len); -+ if (req->n_ssids == 1 && !req->ssids[0].ssid_len) -+ req->n_ssids = 0; -+ -+ scan_printk(XRADIO_DBG_NIY, "[SCAN] Scan request for %d SSIDs.\n", -+ req->n_ssids); -+ -+ if (req->n_ssids > hw->wiphy->max_scan_ssids) [ -+ scan_printk(XRADIO_DBG_ERROR, "%s: ssids is too much(%d)\n", -+ __func__, req->n_ssids); -+ return -EINVAL; -+ } -+ -+ frame.skb = ieee80211_probereq_get(hw, priv->vif, NULL, 0, -+ ies->ie[0], ies->len[0]); -+ if (!frame.skb) { -+ scan_printk(XRADIO_DBG_ERROR, "%s: ieee80211_probereq_get failed!\n", -+ __func__); -+ return -ENOMEM; -+ } -+ -+ /* will be unlocked in xradio_scan_work() */ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ if (frame.skb) { -+ int ret; -+ if (priv->if_id == 0) -+ xradio_remove_wps_p2p_ie(&frame); -+ ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); -+ if (0 == ret) { -+ /* Host want to be the probe responder. */ -+ ret = wsm_set_probe_responder(priv, true); -+ } -+ if (ret) { -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+ dev_kfree_skb(frame.skb); -+ scan_printk(XRADIO_DBG_ERROR, "%s: wsm_set_probe_responder failed: %d.\n", -+ __func__, ret); -+ return ret; -+ } -+ } -+ -+ wsm_lock_tx(hw_priv); -+ BUG_ON(hw_priv->scan.req); -+ hw_priv->scan.sched_req = req; -+ hw_priv->scan.n_ssids = 0; -+ hw_priv->scan.status = 0; -+ hw_priv->scan.begin = &req->channels[0]; -+ hw_priv->scan.curr = hw_priv->scan.begin; -+ hw_priv->scan.end = &req->channels[req->n_channels]; -+ hw_priv->scan.output_power = hw_priv->output_power; -+ -+ for (i = 0; i < req->n_ssids; ++i) { -+ u8 j; -+ struct wsm_ssid *dst = &hw_priv->scan.ssids[hw_priv->scan.n_ssids]; -+ BUG_ON(req->ssids[i].ssid_len > sizeof(dst->ssid)); -+ memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); -+ dst->length = req->ssids[i].ssid_len; -+ ++hw_priv->scan.n_ssids; -+ scan_printk(XRADIO_DBG_NIY, "SSID %d\n",i); -+ for(j=0; jssids[i].ssid_len; j++) -+ scan_printk(XRADIO_DBG_NIY, "0x%x\n", req->ssids[i].ssid[j]); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ if (frame.skb) -+ dev_kfree_skb(frame.skb); -+ queue_work(hw_priv->workqueue, &hw_priv->scan.swork); -+ scan_printk(XRADIO_DBG_NIY, "<-- Scheduled scan request.\n"); -+ return 0; -+} -+#endif /*ROAM_OFFLOAD*/ -+ -+void xradio_scan_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = container_of(work, -+ struct xradio_common, -+ scan.work); -+ struct xradio_vif *priv; -+ struct ieee80211_channel **it; -+ struct wsm_scan scan = { -+ .scanType = WSM_SCAN_TYPE_FOREGROUND, -+ .scanFlags = 0, /* TODO:COMBO */ -+ //.scanFlags = WSM_SCAN_FLAG_SPLIT_METHOD, /* TODO:COMBO */ -+ }; -+ bool first_run; -+ int i; -+ const u32 ProbeRequestTime = 2; -+ const u32 ChannelRemainTime = 15; -+ u32 maxChannelTime; -+ struct cfg80211_scan_info scan_info; -+ -+ -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); -+ -+ /*TODO: COMBO: introduce locking so vif is not removed in meanwhile */ -+ if (!priv) { -+ scan_printk(XRADIO_DBG_WARN, "interface removed, " -+ "ignoring scan work\n"); -+ return; -+ } -+ -+ if (priv->if_id) -+ scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1; -+ else -+ scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1; -+ -+ /* No need to set WSM_SCAN_FLAG_FORCE_BACKGROUND in BSS_LOSS work. -+ * yangfh 2015-11-11 18:45:02 */ -+ //xradio_for_each_vif(hw_priv, vif, i) { -+ // if (!vif) -+ // continue; -+ // if (vif->bss_loss_status > XRADIO_BSS_LOSS_NONE) -+ // scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND; -+ //} -+ -+ first_run = (hw_priv->scan.begin == hw_priv->scan.curr && -+ hw_priv->scan.begin != hw_priv->scan.end); -+ if (first_run) { -+ /* Firmware gets crazy if scan request is sent -+ * when STA is joined but not yet associated. -+ * Force unjoin in this case. */ -+ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) -+ xradio_join_timeout(&priv->join_timeout.work); -+ } -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ if (first_run) { -+#if 0 -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA && -+ !(priv->powersave_mode.pmMode & WSM_PSM_PS)) { -+ struct wsm_set_pm pm = priv->powersave_mode; -+ pm.pmMode = WSM_PSM_PS; -+ xradio_set_pm(priv, &pm); -+ } else -+#endif -+ if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) { -+ /* FW bug: driver has to restart p2p-dev mode -+ * after scan */ -+ xradio_disable_listening(priv); -+ } -+ } -+ -+ if (!hw_priv->scan.req || (hw_priv->scan.curr == hw_priv->scan.end)) { -+ if (hw_priv->scan.output_power != hw_priv->output_power) { -+ /* TODO:COMBO: Change when mac80211 implementation -+ * is available for output power also */ -+ WARN_ON(wsm_set_output_power(hw_priv, hw_priv->output_power * 10, -+ priv->if_id)); -+ } -+ -+#if 0 -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA && -+ !(priv->powersave_mode.pmMode & WSM_PSM_PS)) -+ xradio_set_pm(priv, &priv->powersave_mode); -+#endif -+ -+ if (hw_priv->scan.status < 0) -+ scan_printk(XRADIO_DBG_ERROR, "Scan failed (%d).\n", hw_priv->scan.status); -+ else if (hw_priv->scan.req) -+ scan_printk(XRADIO_DBG_NIY, "Scan completed.\n"); -+ else -+ scan_printk(XRADIO_DBG_NIY, "Scan canceled.\n"); -+ -+ hw_priv->scan.req = NULL; -+ xradio_scan_restart_delayed(priv); -+ wsm_unlock_tx(hw_priv); -+ mutex_unlock(&hw_priv->conf_mutex); -+ memset(&scan_info, 0, sizeof(scan_info)); -+ scan_info.aborted = hw_priv->scan.status ? 1 : 0; -+ ieee80211_scan_completed(hw_priv->hw, &scan_info); -+ up(&hw_priv->scan.lock); -+ return; -+ -+ } else { -+ struct ieee80211_channel *first = *hw_priv->scan.curr; -+ for (it = hw_priv->scan.curr + 1, i = 1; -+ it != hw_priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; -+ ++it, ++i) { -+ if ((*it)->band != first->band) -+ break; -+ if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_NO_IR) -+ break; -+ if (!(first->flags & IEEE80211_CHAN_NO_IR) && -+ (*it)->max_power != first->max_power) -+ break; -+ } -+ scan.band = first->band; -+ -+ if (hw_priv->scan.req->no_cck) -+ scan.maxTransmitRate = WSM_TRANSMIT_RATE_6; -+ else -+ scan.maxTransmitRate = WSM_TRANSMIT_RATE_1; -+ -+ /* TODO: Is it optimal? */ -+ scan.numOfProbeRequests = (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; -+ -+ scan.numOfSSIDs = hw_priv->scan.n_ssids; -+ scan.ssids = &hw_priv->scan.ssids[0]; -+ scan.numOfChannels = it - hw_priv->scan.curr; -+ /* TODO: Is it optimal? */ -+ scan.probeDelay = 100; -+ /* It is not stated in WSM specification, however -+ * FW team says that driver may not use FG scan -+ * when joined. */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ scan.scanType = WSM_SCAN_TYPE_BACKGROUND; -+ scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; -+ } -+ scan.ch = kzalloc(sizeof(struct wsm_scan_ch[it - hw_priv->scan.curr]), GFP_KERNEL); -+ if (!scan.ch) { -+ hw_priv->scan.status = -ENOMEM; -+ scan_printk(XRADIO_DBG_ERROR, "xr_kzalloc wsm_scan_ch failed.\n"); -+ goto fail; -+ } -+ maxChannelTime = (scan.numOfSSIDs * scan.numOfProbeRequests *ProbeRequestTime) + -+ ChannelRemainTime; -+ maxChannelTime = (maxChannelTime < 35) ? 35 : maxChannelTime; -+ for (i = 0; i < scan.numOfChannels; ++i) { -+ scan.ch[i].number = hw_priv->scan.curr[i]->hw_value; -+ -+ -+ if (hw_priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) { -+ scan.ch[i].minChannelTime = 50; -+ scan.ch[i].maxChannelTime = 110; -+ } else { -+ scan.ch[i].minChannelTime = 15; -+ scan.ch[i].maxChannelTime = maxChannelTime; -+ } -+ -+ -+ } -+ -+ if (!(first->flags & IEEE80211_CHAN_NO_IR) && -+ hw_priv->scan.output_power != first->max_power) { -+ hw_priv->scan.output_power = first->max_power; -+ /* TODO:COMBO: Change after mac80211 implementation -+ * complete */ -+ WARN_ON(wsm_set_output_power(hw_priv, hw_priv->scan.output_power * 10, -+ priv->if_id)); -+ } -+ -+ down(&hw_priv->scan.status_lock); -+ hw_priv->scan.status = xradio_scan_start(priv, &scan); -+ -+ kfree(scan.ch); -+ if (WARN_ON(hw_priv->scan.status)) { -+ scan_printk(XRADIO_DBG_ERROR, "scan failed, status=%d.\n", -+ hw_priv->scan.status); -+ up(&hw_priv->scan.status_lock); -+ goto fail; -+ } -+ up(&hw_priv->scan.status_lock); -+ hw_priv->scan.curr = it; -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ return; -+ -+fail: -+ hw_priv->scan.curr = hw_priv->scan.end; -+ mutex_unlock(&hw_priv->conf_mutex); -+ queue_work(hw_priv->workqueue, &hw_priv->scan.work); -+ return; -+} -+ -+#ifdef ROAM_OFFLOAD -+void xradio_sched_scan_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = container_of(work, struct xradio_common, -+ scan.swork); -+ struct wsm_scan scan; -+ struct wsm_ssid scan_ssid; -+ int i; -+ struct xradio_vif *priv = NULL; -+ -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); -+ if (unlikely(!priv)) { -+ WARN_ON(1); -+ return; -+ } -+ -+ spin_unlock(&priv->vif_lock); -+ /* Firmware gets crazy if scan request is sent -+ * when STA is joined but not yet associated. -+ * Force unjoin in this case. */ -+ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) { -+ xradio_join_timeout(&priv->join_timeout.work); -+ } -+ mutex_lock(&hw_priv->conf_mutex); -+ hw_priv->auto_scanning = 1; -+ scan.band = 0; -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) -+ scan.scanType = 3; /* auto background */ -+ else -+ scan.scanType = 2; /* auto foreground */ -+ -+ scan.scanFlags = 0x01; /* bit 0 set => forced background scan */ -+ scan.maxTransmitRate = WSM_TRANSMIT_RATE_6; -+ scan.autoScanInterval = (0xba << 24)|(30 * 1024); /* 30 seconds, -70 rssi */ -+ scan.numOfProbeRequests = 1; -+ //scan.numOfChannels = 11; -+ scan.numOfChannels = hw_priv->num_scanchannels; -+ scan.numOfSSIDs = 1; -+ scan.probeDelay = 100; -+ scan_ssid.length = priv->ssid_length; -+ memcpy(scan_ssid.ssid, priv->ssid, priv->ssid_length); -+ scan.ssids = &scan_ssid; -+ -+ scan.ch = xr_kzalloc(sizeof(struct wsm_scan_ch[scan.numOfChannels]), false); -+ if (!scan.ch) { -+ scan_printk(XRADIO_DBG_ERROR, "xr_kzalloc wsm_scan_ch failed.\n"); -+ hw_priv->scan.status = -ENOMEM; -+ goto fail; -+ } -+ -+ for (i = 0; i < scan.numOfChannels; i++) { -+ scan.ch[i].number = hw_priv->scan_channels[i].number; -+ scan.ch[i].minChannelTime = hw_priv->scan_channels[i].minChannelTime; -+ scan.ch[i].maxChannelTime = hw_priv->scan_channels[i].maxChannelTime; -+ scan.ch[i].txPowerLevel = hw_priv->scan_channels[i].txPowerLevel; -+ } -+ -+#if 0 -+ for (i = 1; i <= scan.numOfChannels; i++) { -+ scan.ch[i-1].number = i; -+ scan.ch[i-1].minChannelTime = 10; -+ scan.ch[i-1].maxChannelTime = 40; -+ } -+#endif -+ -+ hw_priv->scan.status = xradio_sched_scan_start(priv, &scan); -+ kfree(scan.ch); -+ if (hw_priv->scan.status) { -+ scan_printk(XRADIO_DBG_ERROR, "scan failed, status=%d.\n", -+ hw_priv->scan.status); -+ goto fail; -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ return; -+ -+fail: -+ mutex_unlock(&hw_priv->conf_mutex); -+ queue_work(hw_priv->workqueue, &hw_priv->scan.swork); -+ return; -+} -+ -+void xradio_hw_sched_scan_stop(struct xradio_common *hw_priv) -+{ -+ struct xradio_vif *priv = NULL; -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv,hw_priv->scan.if_id); -+ if (unlikely(!priv)) -+ return; -+ -+ spin_unlock(&priv->vif_lock); -+ wsm_stop_scan(hw_priv, priv->if_id); -+ -+ return; -+} -+#endif /*ROAM_OFFLOAD*/ -+ -+ -+static void xradio_scan_restart_delayed(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ -+ if (priv->delayed_link_loss) { -+ int tmo = hw_priv->scan.direct_probe ? 0 : priv->cqm_beacon_loss_count; -+ -+ priv->delayed_link_loss = 0; -+ /* Restart beacon loss timer and requeue -+ BSS loss work. */ -+ scan_printk(XRADIO_DBG_WARN, "[CQM] Requeue BSS loss in %d " -+ "beacons.\n", tmo); -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ queue_delayed_work(hw_priv->workqueue, &priv->bss_loss_work, -+ tmo * HZ / 10); -+ -+ } -+ -+ /* FW bug: driver has to restart p2p-dev mode after scan. */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) { -+ /*xradio_enable_listening(priv);*/ -+ WARN_ON(1); -+ xradio_update_filtering(priv); -+ scan_printk(XRADIO_DBG_WARN, "driver has to restart " -+ "p2p-dev mode after scan"); -+ } -+ -+ if (atomic_xchg(&priv->delayed_unjoin, 0)) { -+ if (queue_work(hw_priv->workqueue, &priv->unjoin_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+} -+ -+static void xradio_scan_complete(struct xradio_common *hw_priv, int if_id) -+{ -+ struct xradio_vif *priv; -+ atomic_xchg(&hw_priv->recent_scan, 0); -+ -+ -+ if (hw_priv->scan.direct_probe) { -+ mutex_lock(&hw_priv->conf_mutex); -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, if_id); -+ if (priv) { -+ scan_printk(XRADIO_DBG_MSG, "Direct probe complete.\n"); -+ xradio_scan_restart_delayed(priv); -+ } else { -+ scan_printk(XRADIO_DBG_MSG, "Direct probe complete without interface!\n"); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ hw_priv->scan.direct_probe = 0; -+ up(&hw_priv->scan.lock); -+ wsm_unlock_tx(hw_priv); -+ } else { -+ xradio_scan_work(&hw_priv->scan.work); -+ } -+} -+ -+void xradio_scan_complete_cb(struct xradio_common *hw_priv, -+ struct wsm_scan_complete *arg) -+{ -+ struct xradio_vif *priv = xrwl_hwpriv_to_vifpriv(hw_priv, -+ hw_priv->scan.if_id); -+ -+ -+ if (unlikely(!priv)) -+ return; -+ -+#ifdef ROAM_OFFLOAD -+ if (hw_priv->auto_scanning) -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, 0); -+#endif /*ROAM_OFFLOAD*/ -+ -+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { -+ /* STA is stopped. */ -+ spin_unlock(&priv->vif_lock); -+ scan_printk(XRADIO_DBG_WARN, "%s: priv->mode UNSPECIFIED.\n", __func__); -+ return; -+ } -+ spin_unlock(&priv->vif_lock); -+ -+ /* -+ if(hw_priv->scan.status == -ETIMEDOUT) -+ scan_printk(XRADIO_DBG_WARN, "Scan timeout already occured. " -+ "Don't cancel work"); -+ if ((hw_priv->scan.status != -ETIMEDOUT) && -+ (cancel_delayed_work_sync(&hw_priv->scan.timeout) > 0)) { -+ hw_priv->scan.status = 1; -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, 0); -+ } -+ */ // should not involve status as a condition -+ -+ if (cancel_delayed_work_sync(&hw_priv->scan.timeout) > 0) { -+ down(&hw_priv->scan.status_lock); -+ hw_priv->scan.status = 1; -+ up(&hw_priv->scan.status_lock); -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, 0); -+ } -+} -+ -+void xradio_scan_timeout(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, scan.timeout.work); -+ -+ -+ if (likely(atomic_xchg(&hw_priv->scan.in_progress, 0))) { -+ if (hw_priv->scan.status > 0) -+ hw_priv->scan.status = 0; -+ else if (!hw_priv->scan.status) { -+ scan_printk(XRADIO_DBG_WARN, "Timeout waiting for scan " -+ "complete notification.\n"); -+ hw_priv->scan.status = -ETIMEDOUT; -+ hw_priv->scan.curr = hw_priv->scan.end; -+ WARN_ON(wsm_stop_scan(hw_priv, hw_priv->scan.if_id ? 1 : 0)); -+ } -+ xradio_scan_complete(hw_priv, hw_priv->scan.if_id); -+#ifdef ROAM_OFFLOAD -+ } else if (hw_priv->auto_scanning) { -+ hw_priv->auto_scanning = 0; -+ ieee80211_sched_scan_results(hw_priv->hw); -+#endif /*ROAM_OFFLOAD*/ -+ } -+} -+ -+void xradio_probe_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, scan.probe_work.work); -+ struct xradio_vif *priv; -+ u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queueId]; -+ const struct xradio_txpriv *txpriv; -+ struct wsm_tx *wsm; -+ struct wsm_template_frame frame = { -+ .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, -+ }; -+ struct wsm_ssid ssids[1] = {{ -+ .length = 0, -+ } }; -+ struct wsm_scan_ch ch[1] = {{ -+ .minChannelTime = 0, -+ .maxChannelTime = 10, -+ } }; -+ struct wsm_scan scan = { -+ .scanType = WSM_SCAN_TYPE_FOREGROUND, -+ .numOfProbeRequests = 1, -+ .probeDelay = 0, -+ .numOfChannels = 1, -+ .ssids = ssids, -+ .ch = ch, -+ }; -+ u8 *ies; -+ size_t ies_len; -+ int ret = 1; -+ scan_printk(XRADIO_DBG_MSG, "%s:Direct probe.\n", __func__); -+ -+ BUG_ON(queueId >= 4); -+ BUG_ON(!hw_priv->channel); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ if (unlikely(down_trylock(&hw_priv->scan.lock))) { -+ /* Scan is already in progress. Requeue self. */ -+ schedule(); -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.probe_work, -+ HZ / 10); -+ mutex_unlock(&hw_priv->conf_mutex); -+ return; -+ } -+ -+ if (xradio_queue_get_skb(queue, hw_priv->pending_frame_id, &frame.skb, &txpriv)) { -+ up(&hw_priv->scan.lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ wsm_unlock_tx(hw_priv); -+ scan_printk(XRADIO_DBG_ERROR, "%s:xradio_queue_get_skb error!\n", __func__); -+ return; -+ } -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, txpriv->if_id); -+ if (!priv) { -+ up(&hw_priv->scan.lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ scan_printk(XRADIO_DBG_ERROR, "%s:priv error!\n", __func__); -+ return; -+ } -+ wsm = (struct wsm_tx *)frame.skb->data; -+ scan.maxTransmitRate = wsm->maxTxRate; -+ scan.band = (hw_priv->channel->band == NL80211_BAND_5GHZ) ? -+ WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ scan.scanType = WSM_SCAN_TYPE_BACKGROUND; -+ scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; -+ if (priv->if_id) -+ scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1; -+ else -+ scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1; -+ } -+ -+ /* No need to set WSM_SCAN_FLAG_FORCE_BACKGROUND in BSS_LOSS work. -+ * yangfh 2015-11-11 18:45:02 */ -+ //xradio_for_each_vif(hw_priv, vif, i) { -+ // if (!vif) -+ // continue; -+ // if (vif->bss_loss_status > XRADIO_BSS_LOSS_NONE) -+ // scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND; -+ //} -+ -+ ch[0].number = hw_priv->channel->hw_value; -+ skb_pull(frame.skb, txpriv->offset); -+ ies = &frame.skb->data[sizeof(struct ieee80211_hdr_3addr)]; -+ ies_len = frame.skb->len - sizeof(struct ieee80211_hdr_3addr); -+ -+ if (ies_len) { -+ u8 *ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len); -+ if (ssidie && ssidie[1] && ssidie[1] <= sizeof(ssids[0].ssid)) { -+ u8 *nextie = &ssidie[2 + ssidie[1]]; -+ /* Remove SSID from the IE list. It has to be provided -+ * as a separate argument in xradio_scan_start call */ -+ -+ /* Store SSID localy */ -+ ssids[0].length = ssidie[1]; -+ memcpy(ssids[0].ssid, &ssidie[2], ssids[0].length); -+ scan.numOfSSIDs = 1; -+ -+ /* Remove SSID from IE list */ -+ ssidie[1] = 0; -+ memmove(&ssidie[2], nextie, &ies[ies_len] - nextie); -+ skb_trim(frame.skb, frame.skb->len - ssids[0].length); -+ } -+ } -+ -+ if (priv->if_id == 0) -+ xradio_remove_wps_p2p_ie(&frame); -+ -+ /* FW bug: driver has to restart p2p-dev mode after scan */ -+ if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) { -+ WARN_ON(1); -+ /*xradio_disable_listening(priv);*/ -+ } -+ ret = WARN_ON(wsm_set_template_frame(hw_priv, &frame, -+ priv->if_id)); -+ -+ hw_priv->scan.direct_probe = 1; -+ hw_priv->scan.if_id = priv->if_id; -+ if (!ret) { -+ wsm_flush_tx(hw_priv); -+ ret = WARN_ON(xradio_scan_start(priv, &scan)); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ skb_push(frame.skb, txpriv->offset); -+ if (!ret) -+ IEEE80211_SKB_CB(frame.skb)->flags |= IEEE80211_TX_STAT_ACK; -+ -+ BUG_ON(xradio_queue_remove(queue, hw_priv->pending_frame_id)); -+ -+ if (ret) { -+ hw_priv->scan.direct_probe = 0; -+ up(&hw_priv->scan.lock); -+ wsm_unlock_tx(hw_priv); -+ } -+ -+ return; -+} -diff --git a/drivers/net/wireless/xradio/scan.h b/drivers/net/wireless/xradio/scan.h -new file mode 100644 -index 0000000..5c520ed ---- /dev/null -+++ b/drivers/net/wireless/xradio/scan.h -@@ -0,0 +1,71 @@ -+/* -+ * Scan interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+ -+#ifndef SCAN_H_INCLUDED -+#define SCAN_H_INCLUDED -+ -+#include -+#include "wsm.h" -+ -+/* external */ struct sk_buff; -+/* external */ struct cfg80211_scan_request; -+/* external */ struct ieee80211_channel; -+/* external */ struct ieee80211_hw; -+/* external */ struct work_struct; -+ -+#define SCAN_MAX_DELAY (3*HZ) //3s, add by yangfh for connect -+ -+struct xradio_scan { -+ struct semaphore lock; -+ struct work_struct work; -+#ifdef ROAM_OFFLOAD -+ struct work_struct swork; /* scheduled scan work */ -+ struct cfg80211_sched_scan_request *sched_req; -+#endif /*ROAM_OFFLOAD*/ -+ struct delayed_work timeout; -+ struct cfg80211_scan_request *req; -+ struct ieee80211_channel **begin; -+ struct ieee80211_channel **curr; -+ struct ieee80211_channel **end; -+ struct wsm_ssid ssids[WSM_SCAN_MAX_NUM_OF_SSIDS]; -+ int output_power; -+ int n_ssids; -+ //add by liwei, for h64 ping WS550 BUG -+ struct semaphore status_lock; -+ int status; -+ atomic_t in_progress; -+ /* Direct probe requests workaround */ -+ struct delayed_work probe_work; -+ int direct_probe; -+ u8 if_id; -+}; -+ -+int xradio_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, -+ struct ieee80211_scan_request *req); -+#ifdef ROAM_OFFLOAD -+int xradio_hw_sched_scan_start(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct cfg80211_sched_scan_request *req, -+ struct ieee80211_sched_scan_ies *ies); -+void xradio_hw_sched_scan_stop(struct xradio_common *priv); -+void xradio_sched_scan_work(struct work_struct *work); -+#endif /*ROAM_OFFLOAD*/ -+void xradio_scan_work(struct work_struct *work); -+void xradio_scan_timeout(struct work_struct *work); -+void xradio_scan_complete_cb(struct xradio_common *priv, -+ struct wsm_scan_complete *arg); -+ -+/* ******************************************************************** */ -+/* Raw probe requests TX workaround */ -+void xradio_probe_work(struct work_struct *work); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/sdio.c b/drivers/net/wireless/xradio/sdio.c -new file mode 100644 -index 0000000..13d4eb5 ---- /dev/null -+++ b/drivers/net/wireless/xradio/sdio.c -@@ -0,0 +1,246 @@ -+/* -+ * SDIO driver for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "sdio.h" -+#include "main.h" -+ -+/* sdio vendor id and device id*/ -+#define SDIO_VENDOR_ID_XRADIO 0x0020 -+#define SDIO_DEVICE_ID_XRADIO 0x2281 -+static const struct sdio_device_id xradio_sdio_ids[] = { -+ { SDIO_DEVICE(SDIO_VENDOR_ID_XRADIO, SDIO_DEVICE_ID_XRADIO) }, -+ //{ SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) }, -+ { /* end: all zeroes */ }, -+}; -+ -+/* sbus_ops implemetation */ -+int sdio_data_read(struct xradio_common* self, unsigned int addr, -+ void *dst, int count) -+{ -+ int ret = sdio_memcpy_fromio(self->sdio_func, dst, addr, count); -+// printk("sdio_memcpy_fromio 0x%x:%d ret %d\n", addr, count, ret); -+// print_hex_dump_bytes("sdio read ", 0, dst, min(count,32)); -+ return ret; -+} -+ -+int sdio_data_write(struct xradio_common* self, unsigned int addr, -+ const void *src, int count) -+{ -+ int ret = sdio_memcpy_toio(self->sdio_func, addr, (void *)src, count); -+// printk("sdio_memcpy_toio 0x%x:%d ret %d\n", addr, count, ret); -+// print_hex_dump_bytes("sdio write", 0, src, min(count,32)); -+ return ret; -+} -+ -+void sdio_lock(struct xradio_common* self) -+{ -+ sdio_claim_host(self->sdio_func); -+} -+ -+void sdio_unlock(struct xradio_common *self) -+{ -+ sdio_release_host(self->sdio_func); -+} -+ -+size_t sdio_align_len(struct xradio_common *self, size_t size) -+{ -+ return sdio_align_size(self->sdio_func, size); -+} -+ -+int sdio_set_blk_size(struct xradio_common *self, size_t size) -+{ -+ return sdio_set_block_size(self->sdio_func, size); -+} -+ -+extern void xradio_irq_handler(struct xradio_common*); -+ -+static irqreturn_t sdio_irq_handler(int irq, void *dev_id) -+{ -+ struct sdio_func *func = (struct sdio_func*) dev_id; -+ struct xradio_common *self = sdio_get_drvdata(func); -+ if (self != NULL) -+ xradio_irq_handler(self); -+ return IRQ_HANDLED; -+} -+ -+static int sdio_enableint(struct sdio_func* func) -+{ -+ int ret = 0; -+ u8 cccr; -+ int func_num; -+ -+ sdio_claim_host(func); -+ -+ /* Hack to access Fuction-0 */ -+ func_num = func->num; -+ func->num = 0; -+ cccr = sdio_readb(func, SDIO_CCCR_IENx, &ret); -+ cccr |= BIT(0); /* Master interrupt enable ... */ -+ cccr |= BIT(func_num); /* ... for our function */ -+ sdio_writeb(func, cccr, SDIO_CCCR_IENx, &ret); -+ -+ /* Restore the WLAN function number */ -+ func->num = func_num; -+ -+ sdio_release_host(func); -+ -+ return ret; -+} -+ -+int sdio_pm(struct xradio_common *self, bool suspend) -+{ -+ int ret = 0; -+ if (suspend) { -+ /* Notify SDIO that XRADIO will remain powered during suspend */ -+ ret = sdio_set_host_pm_flags(self->sdio_func, MMC_PM_KEEP_POWER); -+ if (ret) -+ dev_dbg(&self->sdio_func->dev, "Error setting SDIO pm flags: %i\n", ret); -+ } -+ -+ return ret; -+} -+ -+static const struct of_device_id xradio_sdio_of_match_table[] = { -+ { .compatible = "xradio,xr819" }, -+ { } -+}; -+ -+static int xradio_probe_of(struct sdio_func *func) -+{ -+ struct device *dev = &func->dev; -+ struct device_node *np = dev->of_node; -+ const struct of_device_id *of_id; -+ int irq; -+ int ret; -+ -+ of_id = of_match_node(xradio_sdio_of_match_table, np); -+ if (!of_id) -+ return -ENODEV; -+ -+ //pdev_data->family = of_id->data; -+ -+ irq = irq_of_parse_and_map(np, 0); -+ if (!irq) { -+ dev_err(dev, "No irq in platform data\n"); -+ return -EINVAL; -+ } -+ -+ ret = devm_request_irq(dev, irq, sdio_irq_handler, 0, "xradio", func); -+ if (ret) { -+ dev_err(dev, "Failed to request irq_wakeup.\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* Probe Function to be called by SDIO stack when device is discovered */ -+static int sdio_probe(struct sdio_func *func, -+ const struct sdio_device_id *id) -+{ -+ dev_dbg(&func->dev, "XRadio Device:sdio clk=%d\n", -+ func->card->host->ios.clock); -+ dev_dbg(&func->dev, "sdio func->class=%x\n", func->class); -+ dev_dbg(&func->dev, "sdio_vendor: 0x%04x\n", func->vendor); -+ dev_dbg(&func->dev, "sdio_device: 0x%04x\n", func->device); -+ dev_dbg(&func->dev, "Function#: 0x%04x\n", func->num); -+ -+#if 0 //for odly and sdly debug. -+{ -+ u32 sdio_param = 0; -+ sdio_param = readl(__io_address(0x01c20088)); -+ sdio_param &= ~(0xf<<8); -+ sdio_param |= 3<<8; -+ sdio_param &= ~(0xf<<20); -+ sdio_param |= s_dly<<20; -+ writel(sdio_param, __io_address(0x01c20088)); -+ sbus_printk(XRADIO_DBG_ALWY, "%s: 0x01c20088=0x%08x\n", __func__, sdio_param); -+} -+#endif -+ -+ xradio_probe_of(func); -+ -+ func->card->quirks |= MMC_QUIRK_BROKEN_BYTE_MODE_512; -+ sdio_claim_host(func); -+ sdio_enable_func(func); -+ sdio_release_host(func); -+ -+ sdio_enableint(func); -+ -+ xradio_core_init(func); -+ -+ try_module_get(func->dev.driver->owner); -+ return 0; -+} -+/* Disconnect Function to be called by SDIO stack when -+ * device is disconnected */ -+static void sdio_remove(struct sdio_func *func) -+{ -+ sdio_claim_host(func); -+ sdio_disable_func(func); -+ sdio_release_host(func); -+ module_put(func->dev.driver->owner); -+} -+ -+static int sdio_suspend(struct device *dev) -+{ -+ int ret = 0; -+ /* -+ struct sdio_func *func = dev_to_sdio_func(dev); -+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); -+ if (ret) -+ sbus_printk(XRADIO_DBG_ERROR, "set MMC_PM_KEEP_POWER error\n"); -+ */ -+ return ret; -+} -+ -+static int sdio_resume(struct device *dev) -+{ -+ return 0; -+} -+ -+static const struct dev_pm_ops sdio_pm_ops = { -+ .suspend = sdio_suspend, -+ .resume = sdio_resume, -+}; -+ -+static struct sdio_driver sdio_driver = { -+ .name = "xradio_wlan", -+ .id_table = xradio_sdio_ids, -+ .probe = sdio_probe, -+ .remove = sdio_remove, -+ .drv = { -+ .owner = THIS_MODULE, -+ .pm = &sdio_pm_ops, -+ } -+}; -+ -+ -+int xradio_sdio_register(){ -+ return sdio_register_driver(&sdio_driver); -+} -+ -+void xradio_sdio_unregister(){ -+ sdio_unregister_driver(&sdio_driver); -+} -+ -+MODULE_DEVICE_TABLE(sdio, xradio_sdio_ids); -diff --git a/drivers/net/wireless/xradio/sdio.h b/drivers/net/wireless/xradio/sdio.h -new file mode 100644 -index 0000000..ea3c45a ---- /dev/null -+++ b/drivers/net/wireless/xradio/sdio.h -@@ -0,0 +1,17 @@ -+#ifndef __XRADIO_SDIO_H -+#define __XRADIO_SDIO_H -+ -+size_t sdio_align_len(struct xradio_common *self, size_t size); -+void sdio_lock(struct xradio_common *self); -+void sdio_unlock(struct xradio_common *self); -+int sdio_set_blk_size(struct xradio_common *self, size_t size); -+int sdio_data_read(struct xradio_common *self, unsigned int addr, void *dst, -+ int count); -+int sdio_data_write(struct xradio_common *self, unsigned int addr, const void *src, -+ int count); -+int sdio_pm(struct xradio_common *self, bool suspend); -+ -+int xradio_sdio_register(void); -+void xradio_sdio_unregister(void); -+ -+#endif -diff --git a/drivers/net/wireless/xradio/sta.c b/drivers/net/wireless/xradio/sta.c -new file mode 100644 -index 0000000..5e9d8a2 ---- /dev/null -+++ b/drivers/net/wireless/xradio/sta.c -@@ -0,0 +1,2199 @@ -+/* -+ * STA APIs for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "sta.h" -+#include "ap.h" -+#include "keys.h" -+#include "fwio.h" -+#include "bh.h" -+#include "wsm.h" -+#ifdef ROAM_OFFLOAD -+#include -+#endif /*ROAM_OFFLOAD*/ -+ -+#include "net/mac80211.h" -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+#include -+#endif -+ -+#define WEP_ENCRYPT_HDR_SIZE 4 -+#define WEP_ENCRYPT_TAIL_SIZE 4 -+#define WPA_ENCRYPT_HDR_SIZE 8 -+#define WPA_ENCRYPT_TAIL_SIZE 12 -+#define WPA2_ENCRYPT_HDR_SIZE 8 -+#define WPA2_ENCRYPT_TAIL_SIZE 8 -+#define WAPI_ENCRYPT_HDR_SIZE 18 -+#define WAPI_ENCRYPT_TAIL_SIZE 16 -+#define MAX_ARP_REPLY_TEMPLATE_SIZE 120 -+ -+static inline void __xradio_free_event_queue(struct list_head *list) -+{ -+ while (!list_empty(list)) { -+ struct xradio_wsm_event *event = -+ list_first_entry(list, struct xradio_wsm_event,link); -+ list_del(&event->link); -+ kfree(event); -+ } -+} -+ -+static inline void __xradio_bf_configure(struct xradio_vif *priv) -+{ -+ priv->bf_table.numOfIEs = __cpu_to_le32(3); -+ priv->bf_table.entry[0].ieId = WLAN_EID_VENDOR_SPECIFIC; -+ priv->bf_table.entry[0].actionFlags = -+ WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED; -+ -+ priv->bf_table.entry[0].oui[0] = 0x50; -+ priv->bf_table.entry[0].oui[1] = 0x6F; -+ priv->bf_table.entry[0].oui[2] = 0x9A; -+ -+ priv->bf_table.entry[1].ieId = WLAN_EID_ERP_INFO; -+ priv->bf_table.entry[1].actionFlags = -+ WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED; -+ -+ priv->bf_table.entry[2].ieId = WLAN_EID_HT_OPERATION; -+ priv->bf_table.entry[2].actionFlags = -+ WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED; -+ -+ priv->bf_control.enabled = WSM_BEACON_FILTER_ENABLE; -+} -+ -+/* ******************************************************************** */ -+/* STA API */ -+ -+int xradio_start(struct ieee80211_hw *dev) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ int ret = 0; -+ -+ -+ if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, -+ hw_priv->driver_ready, 3*HZ) <= 0) { -+ wiphy_err(dev->wiphy, "driver is not ready!\n"); -+ return -ETIMEDOUT; -+ } -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ memcpy(hw_priv->mac_addr, dev->wiphy->perm_addr, ETH_ALEN); -+ hw_priv->softled_state = 0; -+ -+ ret = xradio_setup_mac(hw_priv); -+ if (WARN_ON(ret)) { -+ wiphy_err(dev->wiphy, "xradio_setup_mac failed(%d)\n", ret); -+ goto out; -+ } -+ -+out: -+ mutex_unlock(&hw_priv->conf_mutex); -+ return ret; -+} -+ -+void xradio_stop(struct ieee80211_hw *dev) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = NULL; -+ LIST_HEAD(list); -+ int i; -+ -+ wsm_lock_tx(hw_priv); -+ while (down_trylock(&hw_priv->scan.lock)) { -+ /* Scan is in progress. Force it to stop. */ -+ hw_priv->scan.req = NULL; -+ schedule(); -+ } -+ up(&hw_priv->scan.lock); -+ -+ cancel_delayed_work_sync(&hw_priv->scan.probe_work); -+ cancel_delayed_work_sync(&hw_priv->scan.timeout); -+ flush_workqueue(hw_priv->workqueue); -+ del_timer_sync(&hw_priv->ba_timer); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ hw_priv->softled_state = 0; -+ /* xradio_set_leds(hw_priv); */ -+ -+ spin_lock(&hw_priv->event_queue_lock); -+ list_splice_init(&hw_priv->event_queue, &list); -+ spin_unlock(&hw_priv->event_queue_lock); -+ __xradio_free_event_queue(&list); -+ -+ for (i = 0; i < 4; i++) -+ xradio_queue_clear(&hw_priv->tx_queue[i], XRWL_ALL_IFS); -+ -+ /* HACK! */ -+ if (atomic_xchg(&hw_priv->tx_lock, 1) != 1) -+ wiphy_debug(dev->wiphy, "TX is force-unlocked due to stop request.\n"); -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ priv->mode = NL80211_IFTYPE_UNSPECIFIED; -+ priv->listening = false; -+ priv->delayed_link_loss = 0; -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ cancel_delayed_work_sync(&priv->join_timeout); -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ cancel_delayed_work_sync(&priv->link_id_gc_work); -+ del_timer_sync(&priv->mcast_timeout); -+ } -+ -+ wsm_unlock_tx(hw_priv); -+ -+ mutex_unlock(&hw_priv->conf_mutex); -+} -+ -+int xradio_add_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif) -+{ -+ int ret; -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv; -+ struct xradio_vif **drv_priv = (void *)vif->drv_priv; -+ int i; -+ if (atomic_read(&hw_priv->num_vifs) >= XRWL_MAX_VIFS) -+ return -EOPNOTSUPP; -+ -+ if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, -+ hw_priv->driver_ready, 3*HZ) <= 0) { -+ wiphy_err(dev->wiphy, "driver is not ready!\n"); -+ return -ETIMEDOUT; -+ } -+ -+ /* fix the problem that when connected,then deauth */ -+ vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; -+ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; -+ -+ priv = xrwl_get_vif_from_ieee80211(vif); -+ atomic_set(&priv->enabled, 0); -+ -+ *drv_priv = priv; -+ /* __le32 auto_calibration_mode = __cpu_to_le32(1); */ -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ priv->mode = vif->type; -+ -+ spin_lock(&hw_priv->vif_list_lock); -+ if (atomic_read(&hw_priv->num_vifs) < XRWL_MAX_VIFS) { -+ for (i = 0; i < XRWL_MAX_VIFS; i++) -+ if (!memcmp(vif->addr, hw_priv->addresses[i].addr, ETH_ALEN)) -+ break; -+ if (i == XRWL_MAX_VIFS) { -+ spin_unlock(&hw_priv->vif_list_lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ return -EINVAL; -+ } -+ priv->if_id = i; -+ -+ hw_priv->if_id_slot |= BIT(priv->if_id); -+ priv->hw_priv = hw_priv; -+ priv->hw = dev; -+ priv->vif = vif; -+ hw_priv->vif_list[priv->if_id] = vif; -+ atomic_inc(&hw_priv->num_vifs); -+ } else { -+ spin_unlock(&hw_priv->vif_list_lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+ return -EOPNOTSUPP; -+ } -+ spin_unlock(&hw_priv->vif_list_lock); -+ /* TODO:COMBO :Check if MAC address matches the one expected by FW */ -+ memcpy(hw_priv->mac_addr, vif->addr, ETH_ALEN); -+ -+ /* Enable auto-calibration */ -+ /* Exception in subsequent channel switch; disabled. -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE, -+ &auto_calibration_mode, sizeof(auto_calibration_mode))); -+ */ -+ wiphy_debug(dev->wiphy, "Interface ID:%d of type:%d added\n", priv->if_id, priv->mode); -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ xradio_vif_setup(priv); -+ -+ ret = WARN_ON(xradio_setup_mac_pvif(priv)); -+ -+ return ret; -+} -+ -+void xradio_remove_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct wsm_reset reset = { -+ .reset_statistics = true, -+ }; -+ int i; -+ bool is_htcapie = false; -+ struct xradio_vif *tmp_priv; -+ -+ wiphy_warn(dev->wiphy, "!!! vif_id=%d\n", priv->if_id); -+ atomic_set(&priv->enabled, 0); -+ down(&hw_priv->scan.lock); -+ if(priv->join_status == XRADIO_JOIN_STATUS_STA){ -+ if (atomic_xchg(&priv->delayed_unjoin, 0)) { -+ wsm_unlock_tx(hw_priv); -+ wiphy_err(dev->wiphy, "delayed_unjoin exist!\n"); -+ } -+ cancel_work_sync(&priv->unjoin_work); -+ wsm_lock_tx(hw_priv); -+ xradio_unjoin_work(&priv->unjoin_work); -+ } -+ mutex_lock(&hw_priv->conf_mutex); -+ xradio_tx_queues_lock(hw_priv); -+ wsm_lock_tx(hw_priv); -+ switch (priv->join_status) { -+ case XRADIO_JOIN_STATUS_AP: -+ for (i = 0; priv->link_id_map; ++i) { -+ if (priv->link_id_map & BIT(i)) { -+ xrwl_unmap_link(priv, i); -+ priv->link_id_map &= ~BIT(i); -+ } -+ } -+ memset(priv->link_id_db, 0, -+ sizeof(priv->link_id_db)); -+ priv->sta_asleep_mask = 0; -+ priv->enable_beacon = false; -+ priv->tx_multicast = false; -+ priv->aid0_bit_set = false; -+ priv->buffered_multicasts = false; -+ priv->pspoll_mask = 0; -+ reset.link_id = 0; -+ wsm_reset(hw_priv, &reset, priv->if_id); -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ xradio_for_each_vif(hw_priv, tmp_priv, i) { -+ if (!tmp_priv) -+ continue; -+ if ((tmp_priv->join_status == XRADIO_JOIN_STATUS_STA) && tmp_priv->htcap) -+ is_htcapie = true; -+ } -+ -+ if (is_htcapie) { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11N_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11N_THROTTLE; -+ sta_printk(XRADIO_DBG_NIY, "AP REMOVE HTCAP 11N %d\n",hw_priv->vif0_throttle); -+ } else { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ sta_printk(XRADIO_DBG_NIY, "AP REMOVE 11BG %d\n",hw_priv->vif0_throttle); -+ } -+ break; -+ case XRADIO_JOIN_STATUS_MONITOR: -+ xradio_disable_listening(priv); -+ break; -+ default: -+ break; -+ } -+ /* TODO:COMBO: Change Queue Module */ -+ __xradio_flush(hw_priv, false, priv->if_id); -+ -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ cancel_delayed_work_sync(&priv->link_id_gc_work); -+ cancel_delayed_work_sync(&priv->join_timeout); -+ cancel_delayed_work_sync(&priv->set_cts_work); -+ cancel_delayed_work_sync(&priv->pending_offchanneltx_work); -+ -+ del_timer_sync(&priv->mcast_timeout); -+ /* TODO:COMBO: May be reset of these variables "delayed_link_loss and -+ * join_status to default can be removed as dev_priv will be freed by -+ * mac80211 */ -+ priv->delayed_link_loss = 0; -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ wsm_unlock_tx(hw_priv); -+ -+ if ((priv->if_id ==1) && (priv->mode == NL80211_IFTYPE_AP -+ || priv->mode == NL80211_IFTYPE_P2P_GO)) { -+ hw_priv->is_go_thru_go_neg = false; -+ } -+ spin_lock(&hw_priv->vif_list_lock); -+ spin_lock(&priv->vif_lock); -+ hw_priv->vif_list[priv->if_id] = NULL; -+ hw_priv->if_id_slot &= (~BIT(priv->if_id)); -+ atomic_dec(&hw_priv->num_vifs); -+ if (atomic_read(&hw_priv->num_vifs) == 0) { -+ xradio_free_keys(hw_priv); -+ memset(hw_priv->mac_addr, 0, ETH_ALEN); -+ } -+ spin_unlock(&priv->vif_lock); -+ spin_unlock(&hw_priv->vif_list_lock); -+ priv->listening = false; -+ -+ xradio_tx_queues_unlock(hw_priv); -+ mutex_unlock(&hw_priv->conf_mutex); -+ -+ if (atomic_read(&hw_priv->num_vifs) == 0) -+ flush_workqueue(hw_priv->workqueue); -+ memset(priv, 0, sizeof(struct xradio_vif)); -+ up(&hw_priv->scan.lock); -+} -+ -+int xradio_change_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ enum nl80211_iftype new_type, -+ bool p2p) -+{ -+ int ret = 0; -+ wiphy_debug(dev->wiphy, "changing interface type; new type=%d(%d), p2p=%d(%d)\n", -+ new_type, vif->type, p2p, vif->p2p); -+ if (new_type != vif->type || vif->p2p != p2p) { -+ xradio_remove_interface(dev, vif); -+ vif->type = new_type; -+ vif->p2p = p2p; -+ ret = xradio_add_interface(dev, vif); -+ } -+ -+ return ret; -+} -+ -+int xradio_config(struct ieee80211_hw *dev, u32 changed) -+{ -+ int ret = 0; -+ struct xradio_common *hw_priv = dev->priv; -+ struct ieee80211_conf *conf = &dev->conf; -+ /* TODO:COMBO: adjust to multi vif interface -+ * IEEE80211_CONF_CHANGE_IDLE is still handled per xradio_vif*/ -+ int if_id = 0; -+ struct xradio_vif *priv; -+ -+ -+ if (changed & -+ (IEEE80211_CONF_CHANGE_MONITOR|IEEE80211_CONF_CHANGE_IDLE)) { -+ /* TBD: It looks like it's transparent -+ * there's a monitor interface present -- use this -+ * to determine for example whether to calculate -+ * timestamps for packets or not, do not use instead -+ * of filter flags! */ -+ wiphy_debug(dev->wiphy, "ignore IEEE80211_CONF_CHANGE_MONITOR (%d)" -+ "IEEE80211_CONF_CHANGE_IDLE (%d)\n", -+ (changed & IEEE80211_CONF_CHANGE_MONITOR) ? 1 : 0, -+ (changed & IEEE80211_CONF_CHANGE_IDLE) ? 1 : 0); -+ return ret; -+ } -+ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); -+ /* TODO: IEEE80211_CONF_CHANGE_QOS */ -+ /* TODO:COMBO:Change when support is available mac80211*/ -+ if (changed & IEEE80211_CONF_CHANGE_POWER) { -+ /*hw_priv->output_power = conf->power_level;*/ -+ hw_priv->output_power = 20; -+ wiphy_debug(dev->wiphy, "Config Tx power=%d, but real=%d\n", -+ conf->power_level, hw_priv->output_power); -+ WARN_ON(wsm_set_output_power(hw_priv, hw_priv->output_power * 10, if_id)); -+ } -+ -+ if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) && -+ (hw_priv->channel != conf->chandef.chan)) { -+ /* Switch Channel commented for CC Mode */ -+ struct ieee80211_channel *ch = conf->chandef.chan; -+ wiphy_debug(dev->wiphy, "Freq %d (wsm ch: %d).\n", -+ ch->center_freq, ch->hw_value); -+ /* Earlier there was a call to __xradio_flush(). -+ Removed as deemed unnecessary */ -+ hw_priv->channel = ch; -+ hw_priv->channel_changed = 1; -+ } -+ -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+ return ret; -+} -+ -+void xradio_update_filtering(struct xradio_vif *priv) -+{ -+ int ret; -+ bool bssid_filtering = !priv->rx_filter.bssid; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ static struct wsm_beacon_filter_control bf_disabled = { -+ .enabled = 0, -+ .bcn_count = 1, -+ }; -+ bool ap_mode = 0; -+ static struct wsm_beacon_filter_table bf_table_auto = { -+ .numOfIEs = __cpu_to_le32(2), -+ .entry[0].ieId = WLAN_EID_VENDOR_SPECIFIC, -+ .entry[0].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED, -+ .entry[0].oui[0] = 0x50, -+ .entry[0].oui[1] = 0x6F, -+ .entry[0].oui[2] = 0x9A, -+ -+ .entry[1].ieId = WLAN_EID_HT_OPERATION, -+ .entry[1].actionFlags = WSM_BEACON_FILTER_IE_HAS_CHANGED | -+ WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT | -+ WSM_BEACON_FILTER_IE_HAS_APPEARED, -+ }; -+ static struct wsm_beacon_filter_control bf_auto = { -+ .enabled = WSM_BEACON_FILTER_ENABLE | -+ WSM_BEACON_FILTER_AUTO_ERP, -+ .bcn_count = 1, -+ }; -+ -+ -+ bf_auto.bcn_count = priv->bf_control.bcn_count; -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_PASSIVE) -+ return; -+ else if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) -+ bssid_filtering = false; -+ -+ if (priv->vif && (priv->vif->type == NL80211_IFTYPE_AP)) -+ ap_mode = true; -+ /* -+ * When acting as p2p client being connected to p2p GO, in order to -+ * receive frames from a different p2p device, turn off bssid filter. -+ * -+ * WARNING: FW dependency! -+ * This can only be used with FW WSM371 and its successors. -+ * In that FW version even with bssid filter turned off, -+ * device will block most of the unwanted frames. -+ */ -+ if (priv->vif && priv->vif->p2p) -+ bssid_filtering = false; -+ -+ ret = wsm_set_rx_filter(hw_priv, &priv->rx_filter, priv->if_id); -+ if (!ret && !ap_mode) { -+ if (priv->vif) { -+ if (priv->vif->p2p || NL80211_IFTYPE_STATION != priv->vif->type) -+ ret = wsm_set_beacon_filter_table(hw_priv, &priv->bf_table, priv->if_id); -+ else -+ ret = wsm_set_beacon_filter_table(hw_priv, &bf_table_auto, priv->if_id); -+ } else -+ WARN_ON(1); -+ } -+ if (!ret && !ap_mode) { -+ if (priv->disable_beacon_filter) -+ ret = wsm_beacon_filter_control(hw_priv, &bf_disabled, priv->if_id); -+ else { -+ if (priv->vif) { -+ if (priv->vif->p2p || NL80211_IFTYPE_STATION != priv->vif->type) -+ ret = wsm_beacon_filter_control(hw_priv, &priv->bf_control, -+ priv->if_id); -+ else -+ ret = wsm_beacon_filter_control(hw_priv, &bf_auto, priv->if_id); -+ } else -+ WARN_ON(1); -+ } -+ } -+ -+ if (!ret) -+ ret = wsm_set_bssid_filtering(hw_priv, bssid_filtering, priv->if_id); -+#if 0 -+ if (!ret) { -+ ret = wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); -+ } -+#endif -+ if (ret) -+ wiphy_debug(priv->hw_priv->hw->wiphy, "Update filtering failed: %d.\n", ret); -+ return; -+} -+ -+void xradio_update_filtering_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, -+ update_filtering_work); -+ -+ xradio_update_filtering(priv); -+} -+ -+void xradio_set_beacon_wakeup_period_work(struct work_struct *work) -+{ -+ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, set_beacon_wakeup_period_work); -+ -+ -+#ifdef XRADIO_USE_LONG_DTIM_PERIOD -+{ -+ int join_dtim_period_extend; -+ if (priv->join_dtim_period <= 3) { -+ join_dtim_period_extend = priv->join_dtim_period * 3; -+ } else if (priv->join_dtim_period <= 5) { -+ join_dtim_period_extend = priv->join_dtim_period * 2; -+ } else { -+ join_dtim_period_extend = priv->join_dtim_period; -+ } -+ WARN_ON(wsm_set_beacon_wakeup_period(priv->hw_priv, -+ priv->beacon_int * join_dtim_period_extend > -+ MAX_BEACON_SKIP_TIME_MS ? 1 : join_dtim_period_extend, -+ 0, priv->if_id)); -+} -+#else -+ WARN_ON(wsm_set_beacon_wakeup_period(priv->hw_priv, -+ priv->beacon_int * priv->join_dtim_period > -+ MAX_BEACON_SKIP_TIME_MS ? 1 :priv->join_dtim_period, -+ 0, priv->if_id)); -+#endif -+} -+ -+u64 xradio_prepare_multicast(struct ieee80211_hw *hw, -+ struct netdev_hw_addr_list *mc_list) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = NULL; -+ static u8 broadcast_ipv6[ETH_ALEN] = { -+ 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 -+ }; -+ static u8 broadcast_ipv4[ETH_ALEN] = { -+ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x01 -+ }; -+ -+ int i= 0; -+ xradio_for_each_vif(hw_priv,priv,i) { -+ struct netdev_hw_addr *ha = NULL; -+ int count = 0; -+ if ((!priv)) -+ continue; -+ -+ /* Disable multicast filtering */ -+ priv->has_multicast_subscription = false; -+ memset(&priv->multicast_filter, 0x00, sizeof(priv->multicast_filter)); -+ if (netdev_hw_addr_list_count(mc_list) > WSM_MAX_GRP_ADDRTABLE_ENTRIES) -+ return 0; -+ -+ /* Enable if requested */ -+ netdev_hw_addr_list_for_each(ha, mc_list) { -+ sta_printk(XRADIO_DBG_MSG, "multicast: %pM\n", ha->addr); -+ memcpy(&priv->multicast_filter.macAddress[count], ha->addr, ETH_ALEN); -+ if (memcmp(ha->addr, broadcast_ipv4, ETH_ALEN) && -+ memcmp(ha->addr, broadcast_ipv6, ETH_ALEN)) -+ priv->has_multicast_subscription = true; -+ count++; -+ } -+ if (count) { -+ priv->multicast_filter.enable = __cpu_to_le32(1); -+ priv->multicast_filter.numOfAddresses = __cpu_to_le32(count); -+ } -+ } -+ return netdev_hw_addr_list_count(mc_list); -+} -+ -+void xradio_configure_filter(struct ieee80211_hw *hw, -+ unsigned int changed_flags, -+ unsigned int *total_flags, -+ u64 multicast) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = NULL; -+ int i = 0; -+ -+ /* delete umac warning */ -+ if (hw_priv->vif_list[0] == NULL && hw_priv->vif_list[1] == NULL) -+ -+ *total_flags &= ~(1<<31); -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if(NULL == priv) -+ continue; -+ -+#if 0 -+ bool listening = !!(*total_flags & -+ (FIF_PROMISC_IN_BSS | -+ FIF_OTHER_BSS | -+ FIF_BCN_PRBRESP_PROMISC | -+ FIF_PROBE_REQ)); -+#endif -+ -+ *total_flags &= FIF_OTHER_BSS | -+ FIF_FCSFAIL | -+ FIF_BCN_PRBRESP_PROMISC | -+ FIF_PROBE_REQ; -+ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ priv->rx_filter.promiscuous = 0; -+ priv->rx_filter.bssid = (*total_flags & -+ (FIF_OTHER_BSS | FIF_PROBE_REQ)) ? 1 : 0; -+ priv->rx_filter.fcs = (*total_flags & FIF_FCSFAIL) ? 1 : 0; -+ priv->bf_control.bcn_count = (*total_flags & -+ (FIF_BCN_PRBRESP_PROMISC | -+ FIF_PROBE_REQ)) ? 1 : 0; -+ -+ /*add for handle ap FIF_PROBE_REQ message,*/ -+ priv->rx_filter.promiscuous = 0; -+ priv->rx_filter.fcs = 0; -+ if(NL80211_IFTYPE_AP == priv->vif->type){ -+ priv->bf_control.bcn_count = 1; -+ priv->rx_filter.bssid = 1; -+ }else{ -+ priv->bf_control.bcn_count = 0; -+ priv->rx_filter.bssid = 0; -+ } -+#if 0 -+ if (priv->listening ^ listening) { -+ priv->listening = listening; -+ wsm_lock_tx(hw_priv); -+ xradio_update_listening(priv, listening); -+ wsm_unlock_tx(hw_priv); -+ } -+#endif -+ xradio_update_filtering(priv); -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+ } -+} -+ -+int xradio_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, -+ u16 queue, const struct ieee80211_tx_queue_params *params) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ int ret = 0; -+ /* To prevent re-applying PM request OID again and again*/ -+ bool old_uapsdFlags; -+ -+ wiphy_debug(dev->wiphy, "vif %d, configuring tx\n", priv->if_id); -+ -+ if (WARN_ON(!priv)) -+ return -EOPNOTSUPP; -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ -+ if (queue < dev->queues) { -+ old_uapsdFlags = priv->uapsd_info.uapsdFlags; -+ -+ WSM_TX_QUEUE_SET(&priv->tx_queue_params, queue, 0, 0, 0); -+ ret = wsm_set_tx_queue_params(hw_priv, -+ &priv->tx_queue_params.params[queue], -+ queue, priv->if_id); -+ if (ret) { -+ wiphy_err(dev->wiphy, "wsm_set_tx_queue_params failed!\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ WSM_EDCA_SET(&priv->edca, queue, params->aifs, -+ params->cw_min, params->cw_max, -+ params->txop, 0xc8, params->uapsd); -+ /* sta role is not support the uapsd */ -+ if (priv->mode == NL80211_IFTYPE_STATION || -+ priv->mode == NL80211_IFTYPE_P2P_CLIENT) -+ priv->edca.params[queue].uapsdEnable = 0; -+ -+ ret = wsm_set_edca_params(hw_priv, &priv->edca, priv->if_id); -+ if (ret) { -+ wiphy_err(dev->wiphy, "wsm_set_edca_params failed!\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ if (priv->mode == NL80211_IFTYPE_STATION) { -+ ret = xradio_set_uapsd_param(priv, &priv->edca); -+ if (!ret && priv->setbssparams_done && -+ (priv->join_status == XRADIO_JOIN_STATUS_STA) && -+ (old_uapsdFlags != priv->uapsd_info.uapsdFlags)) -+ xradio_set_pm(priv, &priv->powersave_mode); -+ } -+ } else { -+ wiphy_err(dev->wiphy, "queue is to large!\n"); -+ ret = -EINVAL; -+ } -+ -+out: -+ mutex_unlock(&hw_priv->conf_mutex); -+ return ret; -+} -+ -+int xradio_get_stats(struct ieee80211_hw *dev, -+ struct ieee80211_low_level_stats *stats) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ -+ memcpy(stats, &hw_priv->stats, sizeof(*stats)); -+ return 0; -+} -+ -+/* -+int xradio_get_tx_stats(struct ieee80211_hw *dev, -+ struct ieee80211_tx_queue_stats *stats) -+{ -+ int i; -+ struct xradio_common *priv = dev->priv; -+ -+ for (i = 0; i < dev->queues; ++i) -+ xradio_queue_get_stats(&priv->tx_queue[i], &stats[i]); -+ -+ return 0; -+} -+*/ -+ -+int xradio_set_pm(struct xradio_vif *priv, const struct wsm_set_pm *arg) -+{ -+ struct wsm_set_pm pm = *arg; -+ -+ if (priv->uapsd_info.uapsdFlags != 0) -+ pm.pmMode &= ~WSM_PSM_FAST_PS_FLAG; -+ -+ if (memcmp(&pm, &priv->firmware_ps_mode, sizeof(struct wsm_set_pm))) { -+ priv->firmware_ps_mode = pm; -+ return wsm_set_pm(priv->hw_priv, &pm, priv->if_id); -+ } else { -+ return 0; -+ } -+} -+ -+void xradio_wep_key_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = container_of(work, struct xradio_vif , wep_key_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queueId]; -+ __le32 wep_default_key_id = __cpu_to_le32(priv->wep_default_key_id); -+ -+ -+ BUG_ON(queueId >= 4); -+ -+ sta_printk(XRADIO_DBG_MSG, "Setting default WEP key: %d\n", -+ priv->wep_default_key_id); -+ -+ wsm_flush_tx(hw_priv); -+ WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, -+ &wep_default_key_id, sizeof(wep_default_key_id), -+ priv->if_id)); -+ -+ xradio_queue_requeue(queue, hw_priv->pending_frame_id, true); -+ -+ wsm_unlock_tx(hw_priv); -+} -+ -+int xradio_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ int ret = 0; -+ __le32 val32; -+ struct xradio_vif *priv = NULL; -+ int i =0; -+ int if_id; -+ -+ -+ xradio_for_each_vif(hw_priv,priv,i) { -+ if (!priv) -+ continue; -+ if_id = priv->if_id; -+ -+ if (value != (u32) -1) -+ val32 = __cpu_to_le32(value); -+ else -+ val32 = 0; /* disabled */ -+ -+ /* mutex_lock(&priv->conf_mutex); */ -+ ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_RTS_THRESHOLD, -+ &val32, sizeof(val32), if_id)); -+ /* mutex_unlock(&priv->conf_mutex); */ -+ } -+ return ret; -+} -+ -+/* TODO: COMBO: Flush only a particular interface specific parts */ -+int __xradio_flush(struct xradio_common *hw_priv, bool drop, int if_id) -+{ -+ int i, ret; -+ struct xradio_vif *priv = -+ __xrwl_hwpriv_to_vifpriv(hw_priv, if_id); -+ -+ -+ for (;;) { -+ /* TODO: correct flush handling is required when dev_stop. -+ * Temporary workaround: 2s -+ */ -+ if (drop) { -+ for (i = 0; i < 4; ++i) -+ xradio_queue_clear(&hw_priv->tx_queue[i],if_id); -+ } else if(!hw_priv->bh_error){ -+ ret = wait_event_timeout( -+ hw_priv->tx_queue_stats.wait_link_id_empty, -+ xradio_queue_stats_is_empty(&hw_priv->tx_queue_stats, -1, if_id), -+ 2 * HZ); -+ } else { //add by yangfh, don't wait when bh error -+ sta_printk(XRADIO_DBG_ERROR, " %s:bh_error occur.\n", __func__); -+ ret = -1; -+ break; -+ } -+ -+ if (!drop && unlikely(ret <= 0)) { -+ sta_printk(XRADIO_DBG_ERROR, " %s: timeout...\n", __func__); -+ ret = -ETIMEDOUT; -+ break; -+ } else { -+ ret = 0; -+ } -+ -+ wsm_vif_lock_tx(priv); -+ if (unlikely(!xradio_queue_stats_is_empty(&hw_priv->tx_queue_stats, -+ -1, if_id))) { -+ /* Highly unlekely: WSM requeued frames. */ -+ wsm_unlock_tx(hw_priv); -+ continue; -+ } -+ wsm_unlock_tx(hw_priv); -+ break; -+ } -+ return ret; -+} -+ -+void xradio_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) -+{ -+ //struct xradio_vif *priv = NULL; -+ struct xradio_common *hw_priv = hw->priv; -+ int i = 0; -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ -+ /*TODO:COMBO: reenable this part of code when flush callback -+ * is implemented per vif */ -+ /*switch (hw_priv->mode) { -+ case NL80211_IFTYPE_MONITOR: -+ drop = true; -+ break; -+ case NL80211_IFTYPE_AP: -+ if (!hw_priv->enable_beacon) -+ drop = true; -+ break; -+ }*/ -+ -+ //if (!(hw_priv->if_id_slot & BIT(priv->if_id))) -+ // return; -+ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if(NULL == priv) -+ continue; -+ if ((hw_priv->if_id_slot & BIT(priv->if_id))) -+ __xradio_flush(hw_priv, drop, priv->if_id); -+ } -+ return; -+} -+ -+int xradio_remain_on_channel(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_channel *chan, -+ int duration, enum ieee80211_roc_type type) -+{ -+ int ret = 0; -+ struct xradio_common *hw_priv = hw->priv; -+ struct xradio_vif *priv = NULL; -+ int i = 0; -+ int if_id; -+#ifdef TES_P2P_0002_ROC_RESTART -+ struct timeval TES_P2P_0002_tmval; -+#endif -+ -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ do_gettimeofday(&TES_P2P_0002_tmval); -+ TES_P2P_0002_roc_dur = (s32)duration; -+ TES_P2P_0002_roc_sec = (s32)TES_P2P_0002_tmval.tv_sec; -+ TES_P2P_0002_roc_usec = (s32)TES_P2P_0002_tmval.tv_usec; -+#endif -+ -+ down(&hw_priv->scan.lock); -+ mutex_lock(&hw_priv->conf_mutex); -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if(NULL == priv) -+ continue; -+ if_id = priv->if_id; -+ -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "ROC IN %d ch %d\n", -+ priv->if_id, chan->hw_value); -+#endif -+ /* default only p2p interface if_id can remain on */ -+ if((priv->if_id == 0) || (priv->if_id == 1)) -+ continue; -+ hw_priv->roc_if_id = priv->if_id; -+ ret = WARN_ON(__xradio_flush(hw_priv, false, if_id)); -+ xradio_enable_listening(priv, chan); -+ -+ if (!ret) { -+ atomic_set(&hw_priv->remain_on_channel, 1); -+ queue_delayed_work(hw_priv->workqueue, &hw_priv->rem_chan_timeout, -+ duration * HZ / 1000); -+ priv->join_status = XRADIO_JOIN_STATUS_MONITOR; -+ ieee80211_ready_on_channel(hw); -+ } else { -+ hw_priv->roc_if_id = -1; -+ up(&hw_priv->scan.lock); -+ } -+ -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "ROC OUT %d\n", priv->if_id); -+#endif -+ } -+ /* set the channel to supplied ieee80211_channel pointer, if it -+ is not set. This is to remove the crash while sending a probe res -+ in listen state. Later channel will updated on -+ IEEE80211_CONF_CHANGE_CHANNEL event*/ -+ if(!hw_priv->channel) { -+ hw_priv->channel = chan; -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ return ret; -+} -+ -+int xradio_cancel_remain_on_channel(struct ieee80211_hw *hw) -+{ -+ struct xradio_common *hw_priv = hw->priv; -+ -+ -+ sta_printk(XRADIO_DBG_NIY, "Cancel remain on channel\n"); -+#ifdef TES_P2P_0002_ROC_RESTART -+ if (TES_P2P_0002_state == TES_P2P_0002_STATE_GET_PKTID) { -+ TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; -+ sta_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_IDLE][Cancel ROC]\n"); -+ } -+#endif -+ -+ if (atomic_read(&hw_priv->remain_on_channel)) -+ cancel_delayed_work_sync(&hw_priv->rem_chan_timeout); -+ -+ if (atomic_read(&hw_priv->remain_on_channel)) -+ xradio_rem_chan_timeout(&hw_priv->rem_chan_timeout.work); -+ -+ return 0; -+} -+ -+/* ******************************************************************** */ -+/* WSM callbacks */ -+ -+void xradio_channel_switch_cb(struct xradio_common *hw_priv) -+{ -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_free_event_queue(struct xradio_common *hw_priv) -+{ -+ LIST_HEAD(list); -+ -+ -+ spin_lock(&hw_priv->event_queue_lock); -+ list_splice_init(&hw_priv->event_queue, &list); -+ spin_unlock(&hw_priv->event_queue_lock); -+ -+ __xradio_free_event_queue(&list); -+} -+ -+void xradio_event_handler(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, event_handler); -+ struct xradio_vif *priv; -+ struct xradio_wsm_event *event; -+ LIST_HEAD(list); -+ -+ -+ spin_lock(&hw_priv->event_queue_lock); -+ list_splice_init(&hw_priv->event_queue, &list); -+ spin_unlock(&hw_priv->event_queue_lock); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ list_for_each_entry(event, &list, link) { -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, event->if_id); -+ if (!priv) { -+ sta_printk(XRADIO_DBG_WARN, "[CQM] Event for non existing " -+ "interface, ignoring.\n"); -+ continue; -+ } -+ switch (event->evt.eventId) { -+ case WSM_EVENT_ERROR: -+ /* I even don't know what is it about.. */ -+ //STUB(); -+ break; -+ case WSM_EVENT_BSS_LOST: -+ { -+ spin_lock(&priv->bss_loss_lock); -+ if (priv->bss_loss_status > XRADIO_BSS_LOSS_NONE) { -+ spin_unlock(&priv->bss_loss_lock); -+ break; -+ } -+ priv->bss_loss_status = XRADIO_BSS_LOSS_CHECKING; -+ spin_unlock(&priv->bss_loss_lock); -+ sta_printk(XRADIO_DBG_WARN, "[CQM] BSS lost, Beacon miss=%d, event=%x.\n", -+ (event->evt.eventData>>8)&0xff, event->evt.eventData&0xff); -+ -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ if (!down_trylock(&hw_priv->scan.lock)) { -+ up(&hw_priv->scan.lock); -+ priv->delayed_link_loss = 0; -+ queue_delayed_work(hw_priv->workqueue, -+ &priv->bss_loss_work, HZ/10); //100ms -+ } else { -+ /* Scan is in progress. Delay reporting. */ -+ /* Scan complete will trigger bss_loss_work */ -+ priv->delayed_link_loss = 1; -+ /* Also we're starting watchdog. */ -+ queue_delayed_work(hw_priv->workqueue, -+ &priv->bss_loss_work, 10 * HZ); -+ } -+ break; -+ } -+ case WSM_EVENT_BSS_REGAINED: -+ { -+ sta_printk(XRADIO_DBG_WARN, "[CQM] BSS regained.\n"); -+ priv->delayed_link_loss = 0; -+ spin_lock(&priv->bss_loss_lock); -+ priv->bss_loss_status = XRADIO_BSS_LOSS_NONE; -+ spin_unlock(&priv->bss_loss_lock); -+ cancel_delayed_work_sync(&priv->bss_loss_work); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ break; -+ } -+ case WSM_EVENT_RADAR_DETECTED: -+ //STUB(); -+ break; -+ case WSM_EVENT_RCPI_RSSI: -+ { -+ /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 -+ * RSSI = RCPI / 2 - 110 */ -+ int rcpiRssi = (int)(event->evt.eventData & 0xFF); -+ int cqm_evt; -+ if (priv->cqm_use_rssi) -+ rcpiRssi = (s8)rcpiRssi; -+ else -+ rcpiRssi = rcpiRssi / 2 - 110; -+ -+ cqm_evt = (rcpiRssi <= priv->cqm_rssi_thold) ? -+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW : -+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; -+ sta_printk(XRADIO_DBG_NIY, "[CQM] RSSI event: %d", rcpiRssi); -+ ieee80211_cqm_rssi_notify(priv->vif, -+ cqm_evt, -+ 0, -+ GFP_KERNEL); -+ break; -+ } -+ case WSM_EVENT_BT_INACTIVE: -+ //STUB(); -+ break; -+ case WSM_EVENT_BT_ACTIVE: -+ //STUB(); -+ break; -+ case WSM_EVENT_INACTIVITY: -+ { -+ int link_id = ffs((u32)(event->evt.eventData)) - 1; -+ struct sk_buff *skb; -+ struct ieee80211_mgmt *deauth; -+ struct xradio_link_entry *entry = NULL; -+ -+ sta_printk(XRADIO_DBG_WARN, "Inactivity Event Recieved for " -+ "link_id %d\n", link_id); -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ break; -+ skb_reserve(skb, 64); -+ xrwl_unmap_link(priv, link_id); -+ deauth = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ WARN_ON(!deauth); -+ entry = &priv->link_id_db[link_id - 1]; -+ deauth->duration = 0; -+ memcpy(deauth->da, priv->vif->addr, ETH_ALEN); -+ memcpy(deauth->sa, entry->mac/*priv->link_id_db[i].mac*/, ETH_ALEN); -+ memcpy(deauth->bssid, priv->vif->addr, ETH_ALEN); -+ deauth->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | -+ IEEE80211_STYPE_DEAUTH | -+ IEEE80211_FCTL_TODS); -+ deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING; -+ deauth->seq_ctrl = 0; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ sta_printk(XRADIO_DBG_WARN, " Inactivity Deauth Frame sent for MAC SA %pM \t and DA %pM\n", deauth->sa, deauth->da); -+ queue_work(priv->hw_priv->workqueue, &priv->set_tim_work); -+ break; -+ } -+ case WSM_EVENT_PS_MODE_ERROR: -+ { -+ if (!priv->uapsd_info.uapsdFlags && -+ (priv->user_pm_mode != WSM_PSM_PS)) -+ { -+ struct wsm_set_pm pm = priv->powersave_mode; -+ int ret = 0; -+ -+ priv->powersave_mode.pmMode = WSM_PSM_ACTIVE; -+ ret = xradio_set_pm (priv, &priv->powersave_mode); -+ if(ret) -+ priv->powersave_mode = pm; -+ } -+ break; -+ } -+ } -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ __xradio_free_event_queue(&list); -+} -+ -+void xradio_bss_loss_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, bss_loss_work.work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int timeout; /* in beacons */ -+ -+ -+ timeout = priv->cqm_link_loss_count - priv->cqm_beacon_loss_count; -+ /* Skip the confimration procedure in P2P case */ -+ if (priv->vif->p2p) -+ goto report; -+ -+ spin_lock(&priv->bss_loss_lock); -+ if (priv->bss_loss_status == XRADIO_BSS_LOSS_CONFIRMING) { -+ //do loss report next time. -+ priv->bss_loss_status = XRADIO_BSS_LOSS_CONFIRMED; -+ spin_unlock(&priv->bss_loss_lock); -+ //wait for more 1s to loss confirm. -+ queue_delayed_work(hw_priv->workqueue, &priv->bss_loss_work, 1 * HZ); -+ return; -+ } else if (priv->bss_loss_status == XRADIO_BSS_LOSS_NONE) { -+ spin_unlock(&priv->bss_loss_lock); -+ //link is alive. -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ return; -+ } else if (priv->bss_loss_status == XRADIO_BSS_LOSS_CHECKING) { -+ /* it mean no confirming packets, just report loss. */ -+ } -+ spin_unlock(&priv->bss_loss_lock); -+ -+report: -+ if (priv->cqm_beacon_loss_count) { -+ sta_printk(XRADIO_DBG_WARN, "[CQM] Beacon loss.\n"); -+ if (timeout <= 0) -+ timeout = 0; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //ieee80211_cqm_beacon_miss_notify(priv->vif, GFP_KERNEL); -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ } else { -+ timeout = 0; -+ } -+ -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ queue_delayed_work(hw_priv->workqueue, &priv->connection_loss_work, -+ timeout * HZ / 10); -+ -+ spin_lock(&priv->bss_loss_lock); -+ priv->bss_loss_status = XRADIO_BSS_LOSS_NONE; -+ spin_unlock(&priv->bss_loss_lock); -+} -+ -+void xradio_connection_loss_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, connection_loss_work.work); -+ sta_printk(XRADIO_DBG_ERROR, "[CQM] if%d Reporting connection loss.\n", -+ priv->if_id); -+ ieee80211_connection_loss(priv->vif); -+} -+ -+void xradio_tx_failure_work(struct work_struct *work) -+{ -+ //struct xradio_vif *priv = -+ // container_of(work, struct xradio_vif, tx_failure_work); -+ sta_printk(XRADIO_DBG_WARN, "[CQM] Reporting TX failure.\n"); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ //ieee80211_cqm_tx_fail_notify(priv->vif, GFP_KERNEL); -+#else /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ //(void)priv; -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+} -+ -+/* Internal API */ -+int xradio_setup_mac(struct xradio_common *hw_priv) -+{ -+ int ret = 0, if_id; -+ -+ -+ if (hw_priv->sdd) { -+ struct wsm_configuration cfg = { -+ .dot11StationId = &hw_priv->mac_addr[0], -+ .dpdData = hw_priv->sdd->data, -+ .dpdData_size = hw_priv->sdd->size, -+ }; -+ for (if_id = 0; if_id < xrwl_get_nr_hw_ifaces(hw_priv); -+ if_id++) { -+ /* Set low-power mode. */ -+ ret |= WARN_ON(wsm_configuration(hw_priv, &cfg, -+ if_id)); -+ } -+ /* wsm_configuration only once, so release it */ -+ release_firmware(hw_priv->sdd); -+ hw_priv->sdd = NULL; -+ } -+ -+ /* BUG:TX output power is not set untill config_xradio is called. -+ * This would lead to 0 power set in fw and would effect scan & p2p-find -+ * Setting to default value here from sdd which would be overwritten when -+ * we make connection to AP.This value is used only during scan & p2p-ops -+ * untill AP connection is made */ -+ /*BUG:TX output power: Hardcoding to 20dbm if CCX is not enabled*/ -+ /*TODO: This might change*/ -+ if (!hw_priv->output_power) -+ hw_priv->output_power=20; -+ sta_printk(XRADIO_DBG_MSG, "%s output power %d\n",__func__,hw_priv->output_power); -+ -+ return ret; -+} -+ -+void xradio_pending_offchanneltx_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, pending_offchanneltx_work.work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ -+ mutex_lock(&hw_priv->conf_mutex); -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "OFFCHAN PEND IN\n"); -+#endif -+ xradio_disable_listening(priv); -+ hw_priv->roc_if_id = -1; -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "OFFCHAN PEND OUT\n"); -+#endif -+ up(&hw_priv->scan.lock); -+ mutex_unlock(&hw_priv->conf_mutex); -+} -+ -+void xradio_offchannel_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, offchannel_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queueId]; -+ -+ -+ BUG_ON(queueId >= 4); -+ BUG_ON(!hw_priv->channel); -+ -+ if (unlikely(down_trylock(&hw_priv->scan.lock))) { -+ int ret; -+ sta_printk(XRADIO_DBG_ERROR, "xradio_offchannel_work***** drop frame\n"); -+ ret = xradio_queue_remove(queue, hw_priv->pending_frame_id); -+ if (ret) -+ sta_printk(XRADIO_DBG_ERROR, "xradio_offchannel_work: " -+ "queue_remove failed %d\n", ret); -+ wsm_unlock_tx(hw_priv); -+ //workaround by yangfh -+ up(&hw_priv->scan.lock); -+ ieee80211_connection_loss(priv->vif); -+ sta_printk(XRADIO_DBG_ERROR,"lock %d\n", hw_priv->scan.lock.count); -+ -+ return; -+ } -+ mutex_lock(&hw_priv->conf_mutex); -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "OFFCHAN WORK IN %d\n", priv->if_id); -+#endif -+ hw_priv->roc_if_id = priv->if_id; -+ if (likely(!priv->join_status)) { -+ wsm_vif_flush_tx(priv); -+ xradio_enable_listening(priv, hw_priv->channel); -+ /* xradio_update_filtering(priv); */ -+ } -+ if (unlikely(!priv->join_status)) -+ xradio_queue_remove(queue, hw_priv->pending_frame_id); -+ else -+ xradio_queue_requeue(queue, hw_priv->pending_frame_id, false); -+ -+ queue_delayed_work(hw_priv->workqueue, -+ &priv->pending_offchanneltx_work, 204 * HZ/1000); -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_WARN, "OFFCHAN WORK OUT %d\n", priv->if_id); -+#endif -+ mutex_unlock(&hw_priv->conf_mutex); -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_join_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, join_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queueId]; -+ const struct xradio_txpriv *txpriv = NULL; -+ struct sk_buff *skb = NULL; -+ const struct wsm_tx *wsm; -+ const struct ieee80211_hdr *frame; -+ const u8 *bssid; -+ struct cfg80211_bss *bss; -+ const u8 *ssidie; -+ const u8 *dtimie; -+ const struct ieee80211_tim_ie *tim = NULL; -+ struct wsm_protected_mgmt_policy mgmt_policy; -+ //struct wsm_reset reset = { -+ // .reset_statistics = true, -+ //}; -+ -+ -+ -+ BUG_ON(queueId >= 4); -+ if (xradio_queue_get_skb(queue, hw_priv->pending_frame_id, -+ &skb, &txpriv)) { -+ wsm_unlock_tx(hw_priv); -+ return; -+ } -+ wsm = (struct wsm_tx *)&skb->data[0]; -+ frame = (struct ieee80211_hdr *)&skb->data[txpriv->offset]; -+ bssid = &frame->addr1[0]; /* AP SSID in a 802.11 frame */ -+ -+ BUG_ON(!wsm); -+ BUG_ON(!hw_priv->channel); -+ -+ if (unlikely(priv->join_status)) { -+ sta_printk(XRADIO_DBG_WARN, "%s, pre join_status=%d.\n", -+ __func__, priv->join_status); -+ wsm_lock_tx(hw_priv); -+ xradio_unjoin_work(&priv->unjoin_work); -+ } -+ -+ cancel_delayed_work_sync(&priv->join_timeout); -+ -+ bss = cfg80211_get_bss(hw_priv->hw->wiphy, hw_priv->channel, -+ bssid, NULL, 0, 0, 0); -+ if (!bss) { -+ xradio_queue_remove(queue, hw_priv->pending_frame_id); -+ wsm_unlock_tx(hw_priv); -+ return; -+ } -+ ssidie = cfg80211_find_ie(WLAN_EID_SSID, -+ bss->ies->data, -+ bss->ies->len); -+ dtimie = cfg80211_find_ie(WLAN_EID_TIM, -+ bss->ies->data, -+ bss->ies->len); -+ if (dtimie) -+ tim = (struct ieee80211_tim_ie *)&dtimie[2]; -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ { -+ struct wsm_join join = { -+ .mode = (bss->capability & WLAN_CAPABILITY_IBSS) ? -+ WSM_JOIN_MODE_IBSS : WSM_JOIN_MODE_BSS, -+ /* default changed to LONG, by HuangLu, fix 2/5.5/11m tx fail*/ -+ .preambleType = WSM_JOIN_PREAMBLE_LONG, -+ .probeForJoin = 1, -+ /* dtimPeriod will be updated after association */ -+ .dtimPeriod = 1, -+ .beaconInterval = bss->beacon_interval, -+ }; -+ -+ if (priv->if_id) -+ join.flags |= WSM_FLAG_MAC_INSTANCE_1; -+ else -+ join.flags &= ~WSM_FLAG_MAC_INSTANCE_1; -+ -+ /* BT Coex related changes */ -+ if (hw_priv->is_BT_Present) { -+ if (((hw_priv->conf_listen_interval * 100) % -+ bss->beacon_interval) == 0) -+ priv->listen_interval = -+ ((hw_priv->conf_listen_interval * 100) / -+ bss->beacon_interval); -+ else -+ priv->listen_interval = -+ ((hw_priv->conf_listen_interval * 100) / -+ bss->beacon_interval + 1); -+ } -+ -+ if (tim && tim->dtim_period > 1) { -+ join.dtimPeriod = tim->dtim_period; -+ priv->join_dtim_period = tim->dtim_period; -+ } -+ priv->beacon_int = bss->beacon_interval; -+ sta_printk(XRADIO_DBG_NIY, "Join DTIM: %d, interval: %d\n", -+ join.dtimPeriod, priv->beacon_int); -+ -+ hw_priv->is_go_thru_go_neg = false; -+ join.channelNumber = hw_priv->channel->hw_value; -+ -+ /* basicRateSet will be updated after association. -+ Currently these values are hardcoded */ -+ if (hw_priv->channel->band == NL80211_BAND_5GHZ) { -+ join.band = WSM_PHY_BAND_5G; -+ join.basicRateSet = 64; /*6 mbps*/ -+ }else{ -+ join.band = WSM_PHY_BAND_2_4G; -+ join.basicRateSet = 7; /*1, 2, 5.5 mbps*/ -+ } -+ memcpy(&join.bssid[0], bssid, sizeof(join.bssid)); -+ memcpy(&priv->join_bssid[0], bssid, sizeof(priv->join_bssid)); -+ -+ if (ssidie) { -+ join.ssidLength = ssidie[1]; -+ if (WARN_ON(join.ssidLength > sizeof(join.ssid))) -+ join.ssidLength = sizeof(join.ssid); -+ memcpy(&join.ssid[0], &ssidie[2], join.ssidLength); -+ if(strstr(&join.ssid[0],"5.1.4")) -+ msleep(200); -+#ifdef ROAM_OFFLOAD -+ if((priv->vif->type == NL80211_IFTYPE_STATION)) { -+ priv->ssid_length = join.ssidLength; -+ memcpy(priv->ssid, &join.ssid[0], priv->ssid_length); -+ } -+#endif /*ROAM_OFFLOAD*/ -+ } -+ -+ if (priv->vif->p2p) { -+ join.flags |= WSM_JOIN_FLAGS_P2P_GO; -+ join.basicRateSet = -+ xradio_rate_mask_to_wsm(hw_priv, 0xFF0); -+ } -+ -+ wsm_flush_tx(hw_priv); -+ -+ /* Queue unjoin if not associated in 3 sec. */ -+ queue_delayed_work(hw_priv->workqueue, -+ &priv->join_timeout, 3 * HZ); -+ /*Stay Awake for Join Timeout*/ -+ xradio_pm_stay_awake(&hw_priv->pm_state, 3 * HZ); -+ -+ xradio_disable_listening(priv); -+ -+ //WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id)); -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ 0, hw_priv->ba_tid_mask, priv->if_id)); -+ spin_lock_bh(&hw_priv->ba_lock); -+ hw_priv->ba_ena = false; -+ hw_priv->ba_cnt = 0; -+ hw_priv->ba_acc = 0; -+ hw_priv->ba_hist = 0; -+ hw_priv->ba_cnt_rx = 0; -+ hw_priv->ba_acc_rx = 0; -+ spin_unlock_bh(&hw_priv->ba_lock); -+ -+ mgmt_policy.protectedMgmtEnable = 0; -+ mgmt_policy.unprotectedMgmtFramesAllowed = 1; -+ mgmt_policy.encryptionForAuthFrame = 1; -+ wsm_set_protected_mgmt_policy(hw_priv, &mgmt_policy, priv->if_id); -+ -+ if (wsm_join(hw_priv, &join, priv->if_id)) { -+ memset(&priv->join_bssid[0], -+ 0, sizeof(priv->join_bssid)); -+ xradio_queue_remove(queue, hw_priv->pending_frame_id); -+ cancel_delayed_work_sync(&priv->join_timeout); -+ } else { -+ /* Upload keys */ -+ xradio_queue_requeue(queue, hw_priv->pending_frame_id, -+ true); -+ priv->join_status = XRADIO_JOIN_STATUS_STA; -+ -+ /* Due to beacon filtering it is possible that the -+ * AP's beacon is not known for the mac80211 stack. -+ * Disable filtering temporary to make sure the stack -+ * receives at least one */ -+ priv->disable_beacon_filter = true; -+ -+ } -+ xradio_update_filtering(priv); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ cfg80211_put_bss(hw_priv->hw->wiphy,bss); -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_join_timeout(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, join_timeout.work); -+ sta_printk(XRADIO_DBG_WARN, "[WSM] Issue unjoin command (TMO).\n"); -+ wsm_lock_tx(priv->hw_priv); -+ xradio_unjoin_work(&priv->unjoin_work); -+} -+ -+void xradio_unjoin_work(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, unjoin_work); -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ struct wsm_reset reset = { -+ .reset_statistics = true, -+ }; -+ bool is_htcapie = false; -+ int i; -+ struct xradio_vif *tmp_priv; -+ -+ //add by yangfh. -+ hw_priv->connet_time[priv->if_id] = 0; -+#ifdef AP_HT_COMPAT_FIX -+ priv->ht_compat_det &= ~1; -+ priv->ht_compat_cnt = 0; -+#endif -+ -+ del_timer_sync(&hw_priv->ba_timer); -+ mutex_lock(&hw_priv->conf_mutex); -+ if (unlikely(atomic_read(&hw_priv->scan.in_progress))) { -+ if (atomic_xchg(&priv->delayed_unjoin, 1)) { -+ sta_printk(XRADIO_DBG_NIY, -+ "%s: Delayed unjoin " -+ "is already scheduled.\n", -+ __func__); -+ wsm_unlock_tx(hw_priv); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ return; -+ } -+ -+ if (priv->join_status && -+ priv->join_status > XRADIO_JOIN_STATUS_STA) { -+ sta_printk(XRADIO_DBG_ERROR, -+ "%s: Unexpected: join status: %d\n", -+ __func__, priv->join_status); -+ BUG_ON(1); -+ } -+ if (priv->join_status) { -+ cancel_work_sync(&priv->update_filtering_work); -+ cancel_work_sync(&priv->set_beacon_wakeup_period_work); -+ memset(&priv->join_bssid[0], 0, sizeof(priv->join_bssid)); -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ -+ /* Unjoin is a reset. */ -+ wsm_flush_tx(hw_priv); -+ WARN_ON(wsm_keep_alive_period(hw_priv, 0, priv->if_id)); -+ WARN_ON(wsm_reset(hw_priv, &reset, priv->if_id)); -+ WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, priv->if_id)); -+ WARN_ON(wsm_set_output_power(hw_priv, -+ hw_priv->output_power * 10, priv->if_id)); -+ priv->join_dtim_period = 0; -+ priv->cipherType = 0; -+ WARN_ON(xradio_setup_mac_pvif(priv)); -+ xradio_free_event_queue(hw_priv); -+ cancel_work_sync(&hw_priv->event_handler); -+ cancel_delayed_work_sync(&priv->connection_loss_work); -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ 0, hw_priv->ba_tid_mask, priv->if_id)); -+ priv->disable_beacon_filter = false; -+ xradio_update_filtering(priv); -+ priv->setbssparams_done = false; -+ memset(&priv->association_mode, 0, -+ sizeof(priv->association_mode)); -+ memset(&priv->bss_params, 0, sizeof(priv->bss_params)); -+ memset(&priv->firmware_ps_mode, 0, -+ sizeof(priv->firmware_ps_mode)); -+ priv->htcap = false; -+ xradio_for_each_vif(hw_priv, tmp_priv, i) { -+ if (!tmp_priv) -+ continue; -+ if ((tmp_priv->join_status == XRADIO_JOIN_STATUS_STA) && tmp_priv->htcap) -+ is_htcapie = true; -+ } -+ -+ if (is_htcapie) { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11N_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11N_THROTTLE; -+ sta_printk(XRADIO_DBG_NIY, "UNJOIN HTCAP 11N %d\n",hw_priv->vif0_throttle); -+ } else { -+ hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; -+ hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; -+ sta_printk(XRADIO_DBG_NIY, "UNJOIN 11BG %d\n",hw_priv->vif0_throttle); -+ } -+ sta_printk(XRADIO_DBG_NIY, "Unjoin.\n"); -+ } -+ mutex_unlock(&hw_priv->conf_mutex); -+ wsm_unlock_tx(hw_priv); -+} -+ -+int xradio_enable_listening(struct xradio_vif *priv, -+ struct ieee80211_channel *chan) -+{ -+ /* TODO:COMBO: Channel is common to HW currently in mac80211. -+ Change the code below once channel is made per VIF */ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ struct wsm_start start = { -+ .mode = WSM_START_MODE_P2P_DEV | (priv->if_id << 4), -+ .band = (chan->band == NL80211_BAND_5GHZ) ? -+ WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G, -+ .channelNumber = chan->hw_value, -+ .beaconInterval = 100, -+ .DTIMPeriod = 1, -+ .probeDelay = 0, -+ .basicRateSet = 0x0F, -+ }; -+ -+ -+ if(priv->if_id != 2) { -+ WARN_ON(priv->join_status > XRADIO_JOIN_STATUS_MONITOR); -+ return 0; -+ } -+ if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) -+ return 0; -+ if (priv->join_status == XRADIO_JOIN_STATUS_PASSIVE) -+ priv->join_status = XRADIO_JOIN_STATUS_MONITOR; -+ -+ WARN_ON(priv->join_status > XRADIO_JOIN_STATUS_MONITOR); -+ -+ return wsm_start(hw_priv, &start, XRWL_GENERIC_IF_ID); -+} -+ -+int xradio_disable_listening(struct xradio_vif *priv) -+{ -+ int ret; -+ struct wsm_reset reset = { -+ .reset_statistics = true, -+ }; -+ -+ -+ if(priv->if_id != 2) { -+ WARN_ON(priv->join_status > XRADIO_JOIN_STATUS_MONITOR); -+ return 0; -+ } -+ priv->join_status = XRADIO_JOIN_STATUS_PASSIVE; -+ -+ WARN_ON(priv->join_status > XRADIO_JOIN_STATUS_MONITOR); -+ -+ if (priv->hw_priv->roc_if_id == -1) -+ return 0; -+ -+ ret = wsm_reset(priv->hw_priv, &reset, XRWL_GENERIC_IF_ID); -+ return ret; -+} -+ -+/* TODO:COMBO:UAPSD will be supported only on one interface */ -+int xradio_set_uapsd_param(struct xradio_vif *priv, -+ const struct wsm_edca_params *arg) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int ret; -+ u16 uapsdFlags = 0; -+ -+ -+ /* Here's the mapping AC [queue, bit] -+ VO [0,3], VI [1, 2], BE [2, 1], BK [3, 0]*/ -+ -+ if (arg->params[0].uapsdEnable) -+ uapsdFlags |= 1 << 3; -+ -+ if (arg->params[1].uapsdEnable) -+ uapsdFlags |= 1 << 2; -+ -+ if (arg->params[2].uapsdEnable) -+ uapsdFlags |= 1 << 1; -+ -+ if (arg->params[3].uapsdEnable) -+ uapsdFlags |= 1; -+ -+ /* Currently pseudo U-APSD operation is not supported, so setting -+ * MinAutoTriggerInterval, MaxAutoTriggerInterval and -+ * AutoTriggerStep to 0 */ -+ -+ priv->uapsd_info.uapsdFlags = cpu_to_le16(uapsdFlags); -+ priv->uapsd_info.minAutoTriggerInterval = 0; -+ priv->uapsd_info.maxAutoTriggerInterval = 0; -+ priv->uapsd_info.autoTriggerStep = 0; -+ -+ ret = wsm_set_uapsd_info(hw_priv, &priv->uapsd_info, -+ priv->if_id); -+ return ret; -+} -+ -+void xradio_ba_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, ba_work); -+ u8 tx_ba_tid_mask; -+ -+ -+ /* TODO:COMBO: reenable this part of code */ -+/* if (priv->join_status != XRADIO_JOIN_STATUS_STA) -+ return; -+ if (!priv->setbssparams_done) -+ return;*/ -+ -+ sta_printk(XRADIO_DBG_WARN, "BA work****\n"); -+ spin_lock_bh(&hw_priv->ba_lock); -+// tx_ba_tid_mask = hw_priv->ba_ena ? hw_priv->ba_tid_mask : 0; -+ tx_ba_tid_mask = hw_priv->ba_tid_mask; -+ spin_unlock_bh(&hw_priv->ba_lock); -+ -+ wsm_lock_tx(hw_priv); -+ -+ WARN_ON(wsm_set_block_ack_policy(hw_priv, -+ tx_ba_tid_mask, hw_priv->ba_tid_mask, -1)); /*TODO:COMBO*/ -+ -+ wsm_unlock_tx(hw_priv); -+} -+ -+void xradio_ba_timer(struct timer_list *t) -+{ -+ struct xradio_common *hw_priv = from_timer(hw_priv, t, ba_timer); -+ bool ba_ena; -+ -+ -+ spin_lock_bh(&hw_priv->ba_lock); -+ -+ if (atomic_read(&hw_priv->scan.in_progress)) { -+ hw_priv->ba_cnt = 0; -+ hw_priv->ba_acc = 0; -+ hw_priv->ba_cnt_rx = 0; -+ hw_priv->ba_acc_rx = 0; -+ goto skip_statistic_update; -+ } -+ -+ if (hw_priv->ba_cnt >= XRADIO_BLOCK_ACK_CNT && -+ (hw_priv->ba_acc / hw_priv->ba_cnt >= XRADIO_BLOCK_ACK_THLD || -+ (hw_priv->ba_cnt_rx >= XRADIO_BLOCK_ACK_CNT && -+ hw_priv->ba_acc_rx / hw_priv->ba_cnt_rx >= -+ XRADIO_BLOCK_ACK_THLD))) -+ ba_ena = true; -+ else -+ ba_ena = false; -+ -+ hw_priv->ba_cnt = 0; -+ hw_priv->ba_acc = 0; -+ hw_priv->ba_cnt_rx = 0; -+ hw_priv->ba_acc_rx = 0; -+ -+ if (ba_ena != hw_priv->ba_ena) { -+ if (ba_ena || ++hw_priv->ba_hist >= XRADIO_BLOCK_ACK_HIST) { -+ hw_priv->ba_ena = ba_ena; -+ hw_priv->ba_hist = 0; -+#if 0 -+ sta_printk(XRADIO_DBG_NIY, "%s block ACK:\n", -+ ba_ena ? "enable" : "disable"); -+ queue_work(hw_priv->workqueue, &hw_priv->ba_work); -+#endif -+ } -+ } else if (hw_priv->ba_hist) -+ --hw_priv->ba_hist; -+ -+skip_statistic_update: -+ spin_unlock_bh(&hw_priv->ba_lock); -+} -+ -+int xradio_vif_setup(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ int ret = 0; -+ -+ -+ //reset channel change flag, yangfh 2015-5-15 17:12:14 -+ hw_priv->channel_changed = 0; -+ /* Setup per vif workitems and locks */ -+ spin_lock_init(&priv->vif_lock); -+ INIT_WORK(&priv->join_work, xradio_join_work); -+ INIT_DELAYED_WORK(&priv->join_timeout, xradio_join_timeout); -+ INIT_WORK(&priv->unjoin_work, xradio_unjoin_work); -+ INIT_WORK(&priv->wep_key_work, xradio_wep_key_work); -+ INIT_WORK(&priv->offchannel_work, xradio_offchannel_work); -+ INIT_DELAYED_WORK(&priv->bss_loss_work, xradio_bss_loss_work); -+ INIT_DELAYED_WORK(&priv->connection_loss_work, xradio_connection_loss_work); -+ priv->bss_loss_status = XRADIO_BSS_LOSS_NONE; -+ spin_lock_init(&priv->bss_loss_lock); -+ INIT_WORK(&priv->tx_failure_work, xradio_tx_failure_work); -+ spin_lock_init(&priv->ps_state_lock); -+ INIT_DELAYED_WORK(&priv->set_cts_work, xradio_set_cts_work); -+ INIT_WORK(&priv->set_tim_work, xradio_set_tim_work); -+ INIT_WORK(&priv->multicast_start_work, xradio_multicast_start_work); -+ INIT_WORK(&priv->multicast_stop_work, xradio_multicast_stop_work); -+ INIT_WORK(&priv->link_id_work, xradio_link_id_work); -+ INIT_DELAYED_WORK(&priv->link_id_gc_work, xradio_link_id_gc_work); -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ INIT_WORK(&priv->linkid_reset_work, xradio_link_id_reset); -+#endif -+ INIT_WORK(&priv->update_filtering_work, xradio_update_filtering_work); -+ INIT_DELAYED_WORK(&priv->pending_offchanneltx_work, -+ xradio_pending_offchanneltx_work); -+ INIT_WORK(&priv->set_beacon_wakeup_period_work, -+ xradio_set_beacon_wakeup_period_work); -+#ifdef AP_HT_CAP_UPDATE -+ INIT_WORK(&priv->ht_oper_update_work, xradio_ht_oper_update_work); -+#endif -+ timer_setup(&priv->mcast_timeout, xradio_mcast_timeout, 0); -+ priv->setbssparams_done = false; -+ priv->power_set_true = 0; -+ priv->user_power_set_true = 0; -+ priv->user_pm_mode = 0; -+ -+ /* Initialising the broadcast filter */ -+ memset(priv->broadcast_filter.MacAddr, 0xFF, ETH_ALEN); -+ priv->broadcast_filter.nummacaddr = 1; -+ priv->broadcast_filter.address_mode = 1; -+ priv->broadcast_filter.filter_mode = 1; -+ priv->htcap = false; -+#ifdef AP_HT_COMPAT_FIX -+ priv->ht_compat_det = 0; -+ priv->ht_compat_cnt = 0; -+#endif -+ -+ sta_printk(XRADIO_DBG_ALWY, "!!!%s: id=%d, type=%d, p2p=%d\n", -+ __func__, priv->if_id, priv->vif->type, priv->vif->p2p); -+ -+ atomic_set(&priv->enabled, 1); -+ -+ /* default EDCA */ -+ WSM_EDCA_SET(&priv->edca, 0, 0x0002, 0x0003, 0x0007, -+ 47, 0xc8, false); -+ WSM_EDCA_SET(&priv->edca, 1, 0x0002, 0x0007, 0x000f, -+ 94, 0xc8, false); -+ -+// if(priv->vif->p2p == true) { -+ WSM_EDCA_SET(&priv->edca, 2, 0x0002, 0x0003, 0x0007, -+ 0, 0xc8, false); -+ sta_printk(XRADIO_DBG_MSG, "EDCA params Best effort for sta/p2p is " \ -+ "aifs=%u, cw_min=%u, cw_max=%u \n", -+ priv->edca.params[2].aifns, priv->edca.params[2].cwMin, -+ priv->edca.params[2].cwMax); -+#if 0 -+ }else { -+ WSM_EDCA_SET(&priv->edca, 2, 0x0003, 0x000f, 0x03ff, -+ 0, 0xc8, false); -+ sta_printk(XRADIO_DBG_MSG, "EDCA params Best effort for sta is " \ -+ "aifs=%u, cw_min=%u, cw_max=%u \n", -+ priv->edca.params[2].aifns, priv->edca.params[2].cwMin, -+ priv->edca.params[2].cwMax); -+ } -+#endif -+ WSM_EDCA_SET(&priv->edca, 3, 0x0007, 0x000f, 0x03ff, -+ 0, 0xc8, false); -+ -+ ret = wsm_set_edca_params(hw_priv, &priv->edca, priv->if_id); -+ if (WARN_ON(ret)) -+ goto out; -+ -+ ret = xradio_set_uapsd_param(priv, &priv->edca); -+ if (WARN_ON(ret)) -+ goto out; -+ -+ memset(priv->bssid, ~0, ETH_ALEN); -+ priv->wep_default_key_id = -1; -+ priv->cipherType = 0; -+ priv->cqm_link_loss_count = XRADIO_LINK_LOSS_THOLD_DEF; -+ priv->cqm_beacon_loss_count = XRADIO_BSS_LOSS_THOLD_DEF; -+ -+ /* Temporary configuration - beacon filter table */ -+ __xradio_bf_configure(priv); -+ -+out: -+ return ret; -+} -+ -+int xradio_setup_mac_pvif(struct xradio_vif *priv) -+{ -+ int ret = 0; -+ /* NOTE: There is a bug in FW: it reports signal -+ * as RSSI if RSSI subscription is enabled. -+ * It's not enough to set WSM_RCPI_RSSI_USE_RSSI. */ -+ /* NOTE2: RSSI based reports have been switched to RCPI, since -+ * FW has a bug and RSSI reported values are not stable, -+ * what can leads to signal level oscilations in user-end applications */ -+ struct wsm_rcpi_rssi_threshold threshold = { -+ .rssiRcpiMode = WSM_RCPI_RSSI_THRESHOLD_ENABLE | -+ WSM_RCPI_RSSI_DONT_USE_UPPER | -+ WSM_RCPI_RSSI_DONT_USE_LOWER, -+ .rollingAverageCount = 16, -+ }; -+ -+ -+ /* Remember the decission here to make sure, we will handle -+ * the RCPI/RSSI value correctly on WSM_EVENT_RCPI_RSS */ -+ if (threshold.rssiRcpiMode & WSM_RCPI_RSSI_USE_RSSI) -+ priv->cqm_use_rssi = true; -+ -+ -+ /* Configure RSSI/SCPI reporting as RSSI. */ -+ ret = wsm_set_rcpi_rssi_threshold(priv->hw_priv, &threshold, priv->if_id); -+ return ret; -+} -+ -+void xradio_rem_chan_timeout(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, rem_chan_timeout.work); -+ int ret, if_id; -+ struct xradio_vif *priv; -+ -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ if(TES_P2P_0002_state == TES_P2P_0002_STATE_GET_PKTID) { -+ sta_printk(XRADIO_DBG_WARN, "[Restart rem_chan_timeout:Timeout]\n"); -+ return; -+ } -+#endif -+ -+ if (atomic_read(&hw_priv->remain_on_channel) == 0) { -+ return; -+ } -+ ieee80211_remain_on_channel_expired(hw_priv->hw); -+ -+ mutex_lock(&hw_priv->conf_mutex); -+ if_id = hw_priv->roc_if_id; -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_ERROR, "ROC TO IN %d\n", if_id); -+#endif -+ priv = __xrwl_hwpriv_to_vifpriv(hw_priv, if_id); -+ ret = WARN_ON(__xradio_flush(hw_priv, false, if_id)); -+ if (!ret) { -+ xradio_disable_listening(priv); -+ } -+ atomic_set(&hw_priv->remain_on_channel, 0); -+ hw_priv->roc_if_id = -1; -+ -+#ifdef ROC_DEBUG -+ sta_printk(XRADIO_DBG_ERROR, "ROC TO OUT %d\n", if_id); -+#endif -+ -+ mutex_unlock(&hw_priv->conf_mutex); -+ up(&hw_priv->scan.lock); -+} -+const u8 *xradio_get_ie(u8 *start, size_t len, u8 ie) -+{ -+ u8 *end, *pos; -+ -+ -+ pos = start; -+ if (pos == NULL) -+ return NULL; -+ end = pos + len; -+ -+ while (pos + 1 < end) { -+ if (pos + 2 + pos[1] > end) -+ break; -+ if (pos[0] == ie) -+ return pos; -+ pos += 2 + pos[1]; -+ } -+ -+ return NULL; -+} -+ -+/** -+ * xradio_set_macaddrfilter -called when tesmode command -+ * is for setting mac address filter -+ * -+ * @hw: the hardware -+ * @data: incoming data -+ * -+ * Returns: 0 on success or non zero value on failure -+ */ -+int xradio_set_macaddrfilter(struct xradio_common *hw_priv, struct xradio_vif *priv, u8 *data) -+{ -+ struct wsm_mac_addr_filter *mac_addr_filter = NULL; -+ struct wsm_mac_addr_info *addr_info = NULL; -+ u8 action_mode = 0, no_of_mac_addr = 0, i = 0; -+ int ret = 0; -+ u16 macaddrfiltersize = 0; -+ -+ -+ /* Retrieving Action Mode */ -+ action_mode = data[0]; -+ /* Retrieving number of address entries */ -+ no_of_mac_addr = data[1]; -+ -+ addr_info = (struct wsm_mac_addr_info *)&data[2]; -+ -+ /* Computing sizeof Mac addr filter */ -+ macaddrfiltersize = sizeof(*mac_addr_filter) + \ -+ (no_of_mac_addr * sizeof(struct wsm_mac_addr_info)); -+ -+ mac_addr_filter = kzalloc(macaddrfiltersize, GFP_KERNEL); -+ if (!mac_addr_filter) { -+ ret = -ENOMEM; -+ goto exit_p; -+ } -+ mac_addr_filter->action_mode = action_mode; -+ mac_addr_filter->numfilter = no_of_mac_addr; -+ -+ for (i = 0; i < no_of_mac_addr; i++) { -+ mac_addr_filter->macaddrfilter[i].address_mode = \ -+ addr_info[i].address_mode; -+ memcpy(mac_addr_filter->macaddrfilter[i].MacAddr, \ -+ addr_info[i].MacAddr , ETH_ALEN); -+ mac_addr_filter->macaddrfilter[i].filter_mode = \ -+ addr_info[i].filter_mode; -+ } -+ ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_MAC_ADDR_FILTER, \ -+ mac_addr_filter, macaddrfiltersize, priv->if_id)); -+ -+ kfree(mac_addr_filter); -+exit_p: -+ return ret; -+} -+ -+/** -+ * xradio_set_arpreply -called for creating and -+ * configuring arp response template frame -+ * -+ * @hw: the hardware -+ * -+ * Returns: 0 on success or non zero value on failure -+ */ -+int xradio_set_arpreply(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -+{ -+ struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); -+ struct xradio_common *hw_priv = (struct xradio_common *)hw->priv; -+ u32 framehdrlen, encrypthdr, encrypttailsize, framebdylen = 0; -+ bool encrypt = false; -+ int ret = 0; -+ u8 *template_frame = NULL; -+ struct ieee80211_hdr_3addr *dot11hdr = NULL; -+ struct ieee80211_snap_hdr *snaphdr = NULL; -+ struct arphdr *arp_hdr = NULL; -+ -+ -+ template_frame = kzalloc(MAX_ARP_REPLY_TEMPLATE_SIZE, GFP_KERNEL); -+ if (!template_frame) { -+ sta_printk(XRADIO_DBG_ERROR, "Template frame memory failed\n"); -+ ret = -ENOMEM; -+ goto exit_p; -+ } -+ dot11hdr = (struct ieee80211_hdr_3addr *)&template_frame[4]; -+ -+ framehdrlen = sizeof(*dot11hdr); -+ if ((priv->vif->type == NL80211_IFTYPE_AP) && priv->vif->p2p) -+ priv->cipherType = WLAN_CIPHER_SUITE_CCMP; -+ switch (priv->cipherType) { -+ -+ case WLAN_CIPHER_SUITE_WEP40: -+ case WLAN_CIPHER_SUITE_WEP104: -+ sta_printk(XRADIO_DBG_NIY, "WEP\n"); -+ encrypthdr = WEP_ENCRYPT_HDR_SIZE; -+ encrypttailsize = WEP_ENCRYPT_TAIL_SIZE; -+ encrypt = 1; -+ break; -+ -+ -+ case WLAN_CIPHER_SUITE_TKIP: -+ sta_printk(XRADIO_DBG_NIY, "WPA\n"); -+ encrypthdr = WPA_ENCRYPT_HDR_SIZE; -+ encrypttailsize = WPA_ENCRYPT_TAIL_SIZE; -+ encrypt = 1; -+ break; -+ -+ case WLAN_CIPHER_SUITE_CCMP: -+ sta_printk(XRADIO_DBG_NIY, "WPA2\n"); -+ encrypthdr = WPA2_ENCRYPT_HDR_SIZE; -+ encrypttailsize = WPA2_ENCRYPT_TAIL_SIZE; -+ encrypt = 1; -+ break; -+ -+ case WLAN_CIPHER_SUITE_SMS4: -+ sta_printk(XRADIO_DBG_NIY, "WAPI\n"); -+ encrypthdr = WAPI_ENCRYPT_HDR_SIZE; -+ encrypttailsize = WAPI_ENCRYPT_TAIL_SIZE; -+ encrypt = 1; -+ break; -+ -+ default: -+ encrypthdr = 0; -+ encrypttailsize = 0; -+ encrypt = 0; -+ break; -+ } -+ -+ framehdrlen += encrypthdr; -+ /* Filling the 802.11 Hdr */ -+ dot11hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA); -+ if (priv->vif->type == NL80211_IFTYPE_STATION) -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_TODS); -+ else -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_FROMDS); -+ -+ if (encrypt) -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_WEP); -+ -+ if (priv->vif->bss_conf.qos) { -+ sta_printk(XRADIO_DBG_NIY, "QOS Enabled\n"); -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_QOS_DATAGRP); -+ *(u16 *)(dot11hdr + 1) = 0x0; -+ framehdrlen += 2; -+ } else { -+ dot11hdr->frame_control |= cpu_to_le16(IEEE80211_STYPE_DATA); -+ } -+ -+ memcpy(dot11hdr->addr1, priv->vif->bss_conf.bssid, ETH_ALEN); -+ memcpy(dot11hdr->addr2, priv->vif->addr, ETH_ALEN); -+ memcpy(dot11hdr->addr3, priv->vif->bss_conf.bssid, ETH_ALEN); -+ -+ /* Filling the LLC/SNAP Hdr */ -+ snaphdr = (struct ieee80211_snap_hdr *)((u8 *)dot11hdr + framehdrlen); -+ memcpy(snaphdr, (struct ieee80211_snap_hdr *)rfc1042_header, \ -+ sizeof(*snaphdr)); -+ *(u16 *)(++snaphdr) = cpu_to_be16(ETH_P_ARP); -+ /* Updating the framebdylen with snaphdr and LLC hdr size */ -+ framebdylen = sizeof(*snaphdr) + 2; -+ -+ /* Filling the ARP Reply Payload */ -+ arp_hdr = (struct arphdr *)((u8 *)dot11hdr + framehdrlen + framebdylen); -+ arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER); -+ arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP); -+ arp_hdr->ar_hln = ETH_ALEN; -+ arp_hdr->ar_pln = 4; -+ arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY); -+ -+ /* Updating the frmbdylen with Arp Reply Hdr and Arp payload size(20) */ -+ framebdylen += sizeof(*arp_hdr) + 20; -+ -+ /* Updating the framebdylen with Encryption Tail Size */ -+ framebdylen += encrypttailsize; -+ -+ /* Filling the Template Frame Hdr */ -+ template_frame[0] = WSM_FRAME_TYPE_ARP_REPLY; /* Template frame type */ -+ template_frame[1] = 0xFF; /* Rate to be fixed */ -+ ((u16 *)&template_frame[2])[0] = framehdrlen + framebdylen; -+ -+ ret = WARN_ON(wsm_write_mib(hw_priv, WSM_MIB_ID_TEMPLATE_FRAME, \ -+ template_frame, (framehdrlen+framebdylen+4), -+ priv->if_id)); -+ kfree(template_frame); -+exit_p: -+ return ret; -+} -+ -+#ifdef ROAM_OFFLOAD -+/** -+ * xradio_testmode_event -send asynchronous event -+ * to userspace -+ * -+ * @wiphy: the wiphy -+ * @msg_id: XR msg ID -+ * @data: data to be sent -+ * @len: data length -+ * @gfp: allocation flag -+ * -+ * Returns: 0 on success or non zero value on failure -+ */ -+int xradio_testmode_event(struct wiphy *wiphy, const u32 msg_id, -+ const void *data, int len, gfp_t gfp) -+{ -+ struct sk_buff *skb = NULL; -+ -+ -+ skb = cfg80211_testmode_alloc_event_skb(wiphy, -+ nla_total_size(len+sizeof(msg_id)), gfp); -+ -+ if (!skb) -+ return -ENOMEM; -+ -+ cfg80211_testmode_event(skb, gfp); -+ return 0; -+} -+#endif /*ROAM_OFFLOAD*/ -diff --git a/drivers/net/wireless/xradio/sta.h b/drivers/net/wireless/xradio/sta.h -new file mode 100644 -index 0000000..42ea2f6 ---- /dev/null -+++ b/drivers/net/wireless/xradio/sta.h -@@ -0,0 +1,122 @@ -+/* -+ * sta interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#ifndef STA_H_INCLUDED -+#define STA_H_INCLUDED -+ -+ -+#ifdef XRADIO_USE_LONG_KEEP_ALIVE_PERIOD -+#define XRADIO_KEEP_ALIVE_PERIOD (28) -+#else -+/*For Samsung, it is defined as 4*/ -+#define XRADIO_KEEP_ALIVE_PERIOD (4) -+#endif -+ -+#ifdef XRADIO_USE_LONG_DTIM_PERIOD -+#define XRADIO_BSS_LOSS_THOLD_DEF 30 -+#define XRADIO_LINK_LOSS_THOLD_DEF 50 -+#else -+#define XRADIO_BSS_LOSS_THOLD_DEF 20 -+#define XRADIO_LINK_LOSS_THOLD_DEF 40 -+#endif -+ -+/* ******************************************************************** */ -+/* mac80211 API */ -+ -+int xradio_start(struct ieee80211_hw *dev); -+void xradio_stop(struct ieee80211_hw *dev); -+int xradio_add_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif); -+void xradio_remove_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif); -+int xradio_change_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ enum nl80211_iftype new_type, -+ bool p2p); -+int xradio_config(struct ieee80211_hw *dev, u32 changed); -+int xradio_change_interface(struct ieee80211_hw *dev, -+ struct ieee80211_vif *vif, -+ enum nl80211_iftype new_type, -+ bool p2p); -+void xradio_configure_filter(struct ieee80211_hw *dev, -+ unsigned int changed_flags, -+ unsigned int *total_flags, -+ u64 multicast); -+int xradio_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, -+ u16 queue, const struct ieee80211_tx_queue_params *params); -+int xradio_get_stats(struct ieee80211_hw *dev, -+ struct ieee80211_low_level_stats *stats); -+/* Not more a part of interface? -+int xradio_get_tx_stats(struct ieee80211_hw *dev, -+ struct ieee80211_tx_queue_stats *stats); -+*/ -+int xradio_set_rts_threshold(struct ieee80211_hw *hw, u32 value); -+ -+void xradio_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); -+ -+ -+int xradio_remain_on_channel(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_channel *chan, -+ int duration, enum ieee80211_roc_type type); -+int xradio_cancel_remain_on_channel(struct ieee80211_hw *hw); -+int xradio_set_arpreply(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -+u64 xradio_prepare_multicast(struct ieee80211_hw *hw, -+ struct netdev_hw_addr_list *mc_list); -+int xradio_set_pm(struct xradio_vif *priv, const struct wsm_set_pm *arg); -+void xradio_set_data_filter(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ void *data, -+ int len); -+ -+/* ******************************************************************** */ -+/* WSM callbacks */ -+ -+/* void xradio_set_pm_complete_cb(struct xradio_common *hw_priv, -+ struct wsm_set_pm_complete *arg); */ -+void xradio_channel_switch_cb(struct xradio_common *hw_priv); -+ -+/* ******************************************************************** */ -+/* WSM events */ -+ -+void xradio_free_event_queue(struct xradio_common *hw_priv); -+void xradio_event_handler(struct work_struct *work); -+void xradio_bss_loss_work(struct work_struct *work); -+void xradio_connection_loss_work(struct work_struct *work); -+void xradio_keep_alive_work(struct work_struct *work); -+void xradio_tx_failure_work(struct work_struct *work); -+ -+/* ******************************************************************** */ -+/* Internal API */ -+ -+int xradio_setup_mac(struct xradio_common *hw_priv); -+void xradio_join_work(struct work_struct *work); -+void xradio_join_timeout(struct work_struct *work); -+void xradio_unjoin_work(struct work_struct *work); -+void xradio_offchannel_work(struct work_struct *work); -+void xradio_wep_key_work(struct work_struct *work); -+void xradio_update_filtering(struct xradio_vif *priv); -+void xradio_update_filtering_work(struct work_struct *work); -+int __xradio_flush(struct xradio_common *hw_priv, bool drop, int if_id); -+void xradio_set_beacon_wakeup_period_work(struct work_struct *work); -+int xradio_enable_listening(struct xradio_vif *priv, struct ieee80211_channel *chan); -+int xradio_disable_listening(struct xradio_vif *priv); -+int xradio_set_uapsd_param(struct xradio_vif *priv, const struct wsm_edca_params *arg); -+void xradio_ba_work(struct work_struct *work); -+void xradio_ba_timer(struct timer_list *t); -+const u8 *xradio_get_ie(u8 *start, size_t len, u8 ie); -+int xradio_vif_setup(struct xradio_vif *priv); -+int xradio_setup_mac_pvif(struct xradio_vif *priv); -+void xradio_iterate_vifs(void *data, u8 *mac, struct ieee80211_vif *vif); -+void xradio_rem_chan_timeout(struct work_struct *work); -+int xradio_set_macaddrfilter(struct xradio_common *hw_priv, struct xradio_vif *priv, u8 *data); -+#ifdef ROAM_OFFLOAD -+int xradio_testmode_event(struct wiphy *wiphy, const u32 msg_id, -+ const void *data, int len, gfp_t gfp); -+#endif /*ROAM_OFFLOAD*/ -+#endif -diff --git a/drivers/net/wireless/xradio/tx.c b/drivers/net/wireless/xradio/tx.c -new file mode 100644 -index 0000000..72c04ef ---- /dev/null -+++ b/drivers/net/wireless/xradio/tx.c -@@ -0,0 +1,1455 @@ -+/* -+ * Datapath implementation for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "wsm.h" -+#include "bh.h" -+#include "ap.h" -+#include "sta.h" -+#include "sdio.h" -+#include "common.h" -+#include "p2p.h" -+ -+#define B_RATE_INDEX 0 //11b rate for important short frames in 2.4G. -+#define AG_RATE_INDEX 6 //11a/g rate for important short frames in 5G. -+#define XRADIO_INVALID_RATE_ID (0xFF) -+ -+/* rate should fall quickly to avoid dropping frames by aps. -+ * Add by yangfh 2014-9-22 13:39:57 -+ */ -+#define HIGH_RATE_MAX_RETRY 7 -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+#include -+#endif -+ -+//for test yangfh -+extern u32 tx_retrylimit; -+extern u32 tx_over_limit; -+extern u32 tx_lower_limit; -+extern int retry_mis; -+ -+static const struct ieee80211_rate * -+xradio_get_tx_rate(const struct xradio_common *hw_priv, -+ const struct ieee80211_tx_rate *rate); -+ -+/* ******************************************************************** */ -+/* TX policy cache implementation */ -+ -+static void tx_policy_dump(struct tx_policy *policy) -+{ -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] " -+ "%.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X" -+ "%.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X" -+ "%.1X%.1X%.1X%.1X%.1X%.1X%.1X%.1X: %d\n", -+ policy->raw[0] & 0x0F, policy->raw[0] >> 4, -+ policy->raw[1] & 0x0F, policy->raw[1] >> 4, -+ policy->raw[2] & 0x0F, policy->raw[2] >> 4, -+ policy->raw[3] & 0x0F, policy->raw[3] >> 4, -+ policy->raw[4] & 0x0F, policy->raw[4] >> 4, -+ policy->raw[5] & 0x0F, policy->raw[5] >> 4, -+ policy->raw[6] & 0x0F, policy->raw[6] >> 4, -+ policy->raw[7] & 0x0F, policy->raw[7] >> 4, -+ policy->raw[8] & 0x0F, policy->raw[8] >> 4, -+ policy->raw[9] & 0x0F, policy->raw[9] >> 4, -+ policy->raw[10] & 0x0F, policy->raw[10] >> 4, -+ policy->raw[11] & 0x0F, policy->raw[11] >> 4, -+ policy->defined); -+} -+ -+static void xradio_check_go_neg_conf_success(struct xradio_common *hw_priv, -+ u8 *action) -+{ -+ if (action[2] == 0x50 && action[3] == 0x6F && action[4] == 0x9A && -+ action[5] == 0x09 && action[6] == 0x02) { -+ if(action[17] == 0) { -+ hw_priv->is_go_thru_go_neg = true; -+ } -+ else { -+ hw_priv->is_go_thru_go_neg = false; -+ } -+ } -+} -+ -+static void xradio_check_prov_desc_req(struct xradio_common *hw_priv, -+ u8 *action) -+{ -+ if (action[2] == 0x50 && action[3] == 0x6F && action[4] == 0x9A && -+ action[5] == 0x09 && action[6] == 0x07) { -+ hw_priv->is_go_thru_go_neg = false; -+ } -+} -+ -+//modified by yangfh -+static void tx_policy_build(const struct xradio_common *hw_priv, -+ /* [out] */ struct tx_policy *policy, -+ struct ieee80211_tx_rate *rates, size_t count) -+{ -+ int i, j; -+ struct ieee80211_rate * tmp_rate = NULL; -+ unsigned limit = hw_priv->short_frame_max_tx_count; -+ unsigned max_rates_cnt = count; -+ unsigned total = 0; -+ BUG_ON(rates[0].idx < 0); -+ memset(policy, 0, sizeof(*policy)); -+ -+ -+ txrx_printk(XRADIO_DBG_NIY,"============================"); -+#if 0 -+ //debug yangfh -+ for (i = 0; i < count; ++i) { -+ if(rates[i].idx>=0) { -+ tmp_rate = xradio_get_tx_rate(hw_priv, &rates[i]); -+ txrx_printk(XRADIO_DBG_NIY,"[TX policy] Org %d.%dMps=%d", -+ tmp_rate->bitrate/10, tmp_rate->bitrate%10, rates[i].count); -+ } -+ } -+ txrx_printk(XRADIO_DBG_NIY,"----------------------------"); -+#endif -+ -+ /* minstrel is buggy a little bit, so distille -+ * incoming rates first. -+ */ -+ /* Sort rates in descending order. */ -+ total = rates[0].count; -+ for (i = 1; i < count; ++i) { -+ if (rates[i].idx > rates[i-1].idx) { -+ rates[i].idx = rates[i-1].idx>0?(rates[i-1].idx-1):-1; -+ } -+ if (rates[i].idx < 0 || i>=limit) { -+ count = i; -+ break; -+ } else { -+ total += rates[i].count; -+ } -+ } -+ -+ /* Add lowest rate to the end when 11a/n. -+ * Don't apply in 11b/g because p2p unsupport 1Mbps. -+ * TODO: it's better to do this in rate control of mac80211. -+ */ -+ if (((rates[0].flags & IEEE80211_TX_RC_MCS) || -+ hw_priv->channel->band == NL80211_BAND_5GHZ) && -+ count < max_rates_cnt && rates[count-1].idx != 0) { -+ rates[count].idx = 0; -+ rates[count].count = rates[0].count; -+ rates[count].flags = rates[0].flags; -+ total += rates[count].count; -+ count++; -+ } -+ -+ /* adjust tx count to limit, rates should fall quickly -+ * and lower rates should be more retry, because reorder -+ * buffer of reciever will be timeout and clear probably. -+ */ -+ if (count < 2) { -+ rates[0].count = limit; -+ total = limit; -+ } else { -+ u8 end_retry = 0; //the retry should be add to last rate. -+ if (limit > HIGH_RATE_MAX_RETRY) { -+ end_retry = limit - HIGH_RATE_MAX_RETRY; -+ limit = HIGH_RATE_MAX_RETRY; -+ } -+ for (i = 0; (limit != total) && (i < 100); ++i) { //i<100 to avoid dead loop -+ j = i % count; -+ if(limit < total) { -+ total += (rates[j].count > 1? -1 : 0); -+ rates[j].count += (rates[j].count > 1? -1 : 0); -+ } else { -+ j = count - 1 - j; -+ if (rates[j].count > 0) { -+ total++; -+ rates[j].count++; -+ } -+ } -+ } -+ if (end_retry) { -+ rates[count-1].count += end_retry; -+ limit += end_retry; -+ } -+ } -+ -+ /* Eliminate duplicates. */ -+ total = rates[0].count; -+ for (i = 0, j = 1; j < count; ++j) { -+ if (rates[j].idx == rates[i].idx) { -+ rates[i].count += rates[j].count; -+ } else if (rates[j].idx > rates[i].idx) { -+ break; -+ } else { -+ ++i; -+ if (i != j) -+ rates[i] = rates[j]; -+ } -+ total += rates[j].count; -+ } -+ count = i + 1; -+ -+ /* Re-fill policy trying to keep every requested rate and with -+ * respect to the global max tx retransmission count. -+ */ -+ if (limit < count) -+ limit = count; -+ if (total > limit) { -+ for (i = 0; i < count; ++i) { -+ int left = count - i - 1; -+ if (rates[i].count > limit - left) -+ rates[i].count = limit - left; -+ limit -= rates[i].count; -+ } -+ } -+ -+ /* HACK!!! Device has problems (at least) switching from -+ * 54Mbps CTS to 1Mbps. This switch takes enormous amount -+ * of time (100-200 ms), leading to valuable throughput drop. -+ * As a workaround, additional g-rates are injected to the -+ * policy. -+ */ -+ if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) && -+ rates[0].idx > 4 && rates[0].count > 2 && -+ rates[1].idx < 2) { -+ /* ">> 1" is an equivalent of "/ 2", but faster */ -+ int mid_rate = (rates[0].idx + 4) >> 1; -+ -+ /* Decrease number of retries for the initial rate */ -+ rates[0].count -= 2; -+ -+ if (mid_rate != 4) { -+ /* Keep fallback rate at 1Mbps. */ -+ rates[3] = rates[1]; -+ -+ /* Inject 1 transmission on lowest g-rate */ -+ rates[2].idx = 4; -+ rates[2].count = 1; -+ rates[2].flags = rates[1].flags; -+ -+ /* Inject 1 transmission on mid-rate */ -+ rates[1].idx = mid_rate; -+ rates[1].count = 1; -+ -+ /* Fallback to 1 Mbps is a really bad thing, -+ * so let's try to increase probability of -+ * successful transmission on the lowest g rate -+ * even more */ -+ if (rates[0].count >= 3) { -+ --rates[0].count; -+ ++rates[2].count; -+ } -+ -+ /* Adjust amount of rates defined */ -+ count += 2; -+ } else { -+ /* Keep fallback rate at 1Mbps. */ -+ rates[2] = rates[1]; -+ -+ /* Inject 2 transmissions on lowest g-rate */ -+ rates[1].idx = 4; -+ rates[1].count = 2; -+ -+ /* Adjust amount of rates defined */ -+ count += 1; -+ } -+ } -+ -+ tmp_rate = (struct ieee80211_rate *)xradio_get_tx_rate(hw_priv, &rates[0]); -+ if(tmp_rate) -+ policy->defined = tmp_rate->hw_value + 1; -+ -+ for (i = 0; i < count; ++i) { -+ register unsigned rateid, off, shift, retries; -+ -+ tmp_rate = (struct ieee80211_rate *)xradio_get_tx_rate(hw_priv, &rates[i]); -+ if(tmp_rate) { -+ rateid = tmp_rate->hw_value; -+ } else { -+ break; -+ } -+ off = rateid >> 3; /* eq. rateid / 8 */ -+ shift = (rateid & 0x07) << 2; /* eq. (rateid % 8) * 4 */ -+ -+ retries = rates[i].count; -+ if (unlikely(retries > 0x0F)) -+ rates[i].count = retries = 0x0F; -+ policy->tbl[off] |= __cpu_to_le32(retries << shift); -+ policy->retry_count += retries; -+ txrx_printk(XRADIO_DBG_NIY,"[TX policy] %d.%dMps=%d", -+ tmp_rate->bitrate/10, tmp_rate->bitrate%10, retries); -+ } -+ -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] Dst Policy (%d): " \ -+ "%d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n", -+ count, -+ rates[0].idx, rates[0].count, -+ rates[1].idx, rates[1].count, -+ rates[2].idx, rates[2].count, -+ rates[3].idx, rates[3].count, -+ rates[4].idx, rates[4].count); -+} -+ -+static inline bool tx_policy_is_equal(const struct tx_policy *wanted, -+ const struct tx_policy *cached) -+{ -+ size_t count = wanted->defined >> 1; -+ -+ if (wanted->defined > cached->defined) -+ return false; -+ if (count) { -+ if (memcmp(wanted->raw, cached->raw, count)) -+ return false; -+ } -+ if (wanted->defined & 1) { -+ if ((wanted->raw[count] & 0x0F) != (cached->raw[count] & 0x0F)) -+ return false; -+ } -+ return true; -+} -+ -+static int tx_policy_find(struct tx_policy_cache *cache, -+ const struct tx_policy *wanted) -+{ -+ /* O(n) complexity. Not so good, but there's only 8 entries in -+ * the cache. -+ * Also lru helps to reduce search time. */ -+ struct tx_policy_cache_entry *it; -+ /* Search for policy in "used" list */ -+ list_for_each_entry(it, &cache->used, link) { -+ if (tx_policy_is_equal(wanted, &it->policy)) -+ return it - cache->cache; -+ } -+ /* Then - in "free list" */ -+ list_for_each_entry(it, &cache->free, link) { -+ if (tx_policy_is_equal(wanted, &it->policy)) -+ return it - cache->cache; -+ } -+ return -1; -+} -+ -+static inline void tx_policy_use(struct tx_policy_cache *cache, -+ struct tx_policy_cache_entry *entry) -+{ -+ ++entry->policy.usage_count; -+ list_move(&entry->link, &cache->used); -+} -+ -+static inline int tx_policy_release(struct tx_policy_cache *cache, -+ struct tx_policy_cache_entry *entry) -+{ -+ int ret = --entry->policy.usage_count; -+ if (!ret) -+ list_move(&entry->link, &cache->free); -+ return ret; -+} -+ -+/* ******************************************************************** */ -+/* External TX policy cache API */ -+ -+void tx_policy_init(struct xradio_common *hw_priv) -+{ -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ int i; -+ -+ memset(cache, 0, sizeof(*cache)); -+ -+ spin_lock_init(&cache->lock); -+ INIT_LIST_HEAD(&cache->used); -+ INIT_LIST_HEAD(&cache->free); -+ -+ for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) -+ list_add(&cache->cache[i].link, &cache->free); -+} -+ -+static int tx_policy_get(struct xradio_common *hw_priv, -+ struct ieee80211_tx_rate *rates, -+ u8 use_bg_rate, bool *renew) -+{ -+ int idx; -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ struct tx_policy wanted; -+ -+ -+ if(use_bg_rate) { -+ u8 rate = (u8)(use_bg_rate & 0x3f); -+ u8 shitf = ((rate&0x7)<<2); -+ u8 off = (rate>>3); -+ memset(&wanted, 0, sizeof(wanted)); -+ wanted.defined = rate + 1; -+ wanted.retry_count = (hw_priv->short_frame_max_tx_count&0xf); -+ wanted.tbl[off] = wanted.retry_count<lock); -+ idx = tx_policy_find(cache, &wanted); -+ if (idx >= 0) { -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] Used TX policy: %d\n", -+ idx); -+ *renew = false; -+ } else { -+ struct tx_policy_cache_entry *entry; -+ if (WARN_ON_ONCE(list_empty(&cache->free))) { -+ spin_unlock_bh(&cache->lock); -+ txrx_printk(XRADIO_DBG_ERROR, "[TX policy] no policy cache\n"); -+ return XRADIO_INVALID_RATE_ID; -+ } -+ /* If policy is not found create a new one -+ * using the oldest entry in "free" list */ -+ *renew = true; -+ entry = list_entry(cache->free.prev, -+ struct tx_policy_cache_entry, link); -+ entry->policy = wanted; -+ idx = entry - cache->cache; -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] New TX policy: %d\n", -+ idx); -+ tx_policy_dump(&entry->policy); -+ } -+ tx_policy_use(cache, &cache->cache[idx]); -+ if (unlikely(list_empty(&cache->free))) { -+ /* Lock TX queues. */ -+ txrx_printk(XRADIO_DBG_WARN, "[TX policy] policy cache used up\n"); -+ xradio_tx_queues_lock(hw_priv); -+ } -+ spin_unlock_bh(&cache->lock); -+ -+ return idx; -+} -+ -+static void tx_policy_put(struct xradio_common *hw_priv, int idx) -+{ -+ int usage, locked; -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ -+ spin_lock_bh(&cache->lock); -+ locked = list_empty(&cache->free); -+ usage = tx_policy_release(cache, &cache->cache[idx]); -+ if (unlikely(locked) && !usage) { -+ /* Unlock TX queues. */ -+ xradio_tx_queues_unlock(hw_priv); -+ } -+ spin_unlock_bh(&cache->lock); -+} -+ -+/* -+bool tx_policy_cache_full(struct xradio_common *hw_priv) -+{ -+ bool ret; -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ spin_lock_bh(&cache->lock); -+ ret = list_empty(&cache->free); -+ spin_unlock_bh(&cache->lock); -+ return ret; -+} -+*/ -+extern u32 policy_upload; -+extern u32 policy_num; -+static int tx_policy_upload(struct xradio_common *hw_priv) -+{ -+ struct tx_policy_cache *cache = &hw_priv->tx_policy_cache; -+ int i; -+ struct wsm_set_tx_rate_retry_policy arg = { -+ .hdr = { -+ .numTxRatePolicies = 0, -+ } -+ }; -+ int if_id = 0; -+ -+ spin_lock_bh(&cache->lock); -+ /* Upload only modified entries. */ -+ for (i = 0; i < TX_POLICY_CACHE_SIZE; ++i) { -+ struct tx_policy *src = &cache->cache[i].policy; -+ if (src->retry_count && !src->uploaded) { -+ struct wsm_set_tx_rate_retry_policy_policy *dst = -+ &arg.tbl[arg.hdr.numTxRatePolicies]; -+ dst->policyIndex = i; -+ dst->shortRetryCount = hw_priv->short_frame_max_tx_count-1; -+ //only RTS need use longRetryCount, should be short_frame. -+ dst->longRetryCount = hw_priv->short_frame_max_tx_count-1; -+ -+ /* BIT(2) - Terminate retries when Tx rate retry policy -+ * finishes. -+ * BIT(3) - Count initial frame transmission as part of -+ * rate retry counting but not as a retry -+ * attempt */ -+ dst->policyFlags = BIT(2) | BIT(3); -+ memcpy(dst->rateCountIndices, src->tbl, -+ sizeof(dst->rateCountIndices)); -+ src->uploaded = 1; -+ ++arg.hdr.numTxRatePolicies; -+ } -+ } -+ spin_unlock_bh(&cache->lock); -+ atomic_set(&hw_priv->upload_count, 0); -+ -+ txrx_printk(XRADIO_DBG_MSG, "[TX policy] Upload %d policies\n", -+ arg.hdr.numTxRatePolicies); -+ -+ /*TODO: COMBO*/ -+ return wsm_set_tx_rate_retry_policy(hw_priv, &arg, if_id); -+} -+ -+void tx_policy_upload_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, tx_policy_upload_work); -+ -+ WARN_ON(tx_policy_upload(hw_priv)); -+ wsm_unlock_tx(hw_priv); -+} -+ -+/* ******************************************************************** */ -+/* xradio TX implementation */ -+ -+struct xradio_txinfo { -+ struct sk_buff *skb; -+ unsigned queue; -+ struct ieee80211_tx_info *tx_info; -+ const struct ieee80211_rate *rate; -+ struct ieee80211_hdr *hdr; -+ size_t hdrlen; -+ const u8 *da; -+ struct xradio_sta_priv *sta_priv; -+ struct xradio_txpriv txpriv; -+}; -+ -+u32 xradio_rate_mask_to_wsm(struct xradio_common *hw_priv, u32 rates) -+{ -+ u32 ret = 0; -+ int i; -+ u32 n_bitrates = -+ hw_priv->hw->wiphy->bands[hw_priv->channel->band]->n_bitrates; -+ struct ieee80211_rate * bitrates = -+ hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates; -+ -+ for (i = 0; i < n_bitrates; ++i) { -+ if (rates & BIT(i)) -+ ret |= BIT(bitrates[i].hw_value); -+ } -+ return ret; -+} -+ -+static const struct ieee80211_rate * -+xradio_get_tx_rate(const struct xradio_common *hw_priv, -+ const struct ieee80211_tx_rate *rate) -+{ -+ if (rate->idx < 0) -+ return NULL; -+ if (rate->flags & IEEE80211_TX_RC_MCS) -+ return &hw_priv->mcs_rates[rate->idx]; -+ return &hw_priv->hw->wiphy->bands[hw_priv->channel->band]-> -+ bitrates[rate->idx]; -+} -+ -+inline static s8 -+xradio_get_rate_idx(const struct xradio_common *hw_priv, u8 flag, u16 hw_value) -+{ -+ s16 ret = (s16)hw_value; -+ if(flag & IEEE80211_TX_RC_MCS) { //11n -+ if(hw_value <= hw_priv->mcs_rates[7].hw_value && -+ hw_value >= hw_priv->mcs_rates[0].hw_value) -+ ret -= hw_priv->mcs_rates[0].hw_value; -+ else -+ ret = -1; -+ } else { //11b/g -+ if(hw_value>5 && hw_valuemcs_rates[0].hw_value) { -+ ret -= hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates[0].hw_value; -+ if(hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates[0].hw_value<5) //11a -+ ret -= 2; -+ } else if(hw_value<4) { -+ ret -= hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates[0].hw_value; -+ } else { -+ ret = -1; -+ } -+ } -+ return (s8)ret; -+} -+ -+static int -+xradio_tx_h_calc_link_ids(struct xradio_vif *priv, -+ struct ieee80211_tx_control *control, -+ struct xradio_txinfo *t) -+{ -+ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ if ((t->tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || -+ (hw_priv->roc_if_id == priv->if_id)) -+ t->txpriv.offchannel_if_id = 2; -+ else -+ t->txpriv.offchannel_if_id = 0; -+ -+ if (likely(control->sta && t->sta_priv->link_id)) -+ t->txpriv.raw_link_id = -+ t->txpriv.link_id = -+ t->sta_priv->link_id; -+ else if (priv->mode != NL80211_IFTYPE_AP) -+ t->txpriv.raw_link_id = -+ t->txpriv.link_id = 0; -+ else if (is_multicast_ether_addr(t->da)) { -+ if (priv->enable_beacon) { -+ t->txpriv.raw_link_id = 0; -+ t->txpriv.link_id = priv->link_id_after_dtim; -+ } else { -+ t->txpriv.raw_link_id = 0; -+ t->txpriv.link_id = 0; -+ } -+ } else { -+ t->txpriv.link_id = -+ xradio_find_link_id(priv, t->da); -+ /* Do not assign valid link id for deauth/disassoc frame being -+ transmitted to an unassociated STA */ -+ if (!(t->txpriv.link_id) && -+ (ieee80211_is_deauth(t->hdr->frame_control) || -+ ieee80211_is_disassoc(t->hdr->frame_control))) { -+ t->txpriv.link_id = 0; -+ } else { -+ if (!t->txpriv.link_id) -+ t->txpriv.link_id = xradio_alloc_link_id(priv, t->da); -+ if (!t->txpriv.link_id) { -+ txrx_printk(XRADIO_DBG_ERROR, -+ "%s: No more link IDs available.\n", __func__); -+ return -ENOENT; -+ } -+ } -+ t->txpriv.raw_link_id = t->txpriv.link_id; -+ } -+ if (t->txpriv.raw_link_id) -+ priv->link_id_db[t->txpriv.raw_link_id - 1].timestamp = -+ jiffies; -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ if (control->sta && -+ (control->sta->uapsd_queues & BIT(t->queue))) -+ t->txpriv.link_id = priv->link_id_uapsd; -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ return 0; -+} -+ -+static void -+xradio_tx_h_pm(struct xradio_vif *priv, -+ struct xradio_txinfo *t) -+{ -+ if (unlikely(ieee80211_is_auth(t->hdr->frame_control))) { -+ u32 mask = ~BIT(t->txpriv.raw_link_id); -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->sta_asleep_mask &= mask; -+ priv->pspoll_mask &= mask; -+ spin_unlock_bh(&priv->ps_state_lock); -+ } -+} -+ -+static void -+xradio_tx_h_calc_tid(struct xradio_vif *priv, -+ struct xradio_txinfo *t) -+{ -+ if (ieee80211_is_data_qos(t->hdr->frame_control)) { -+ u8 *qos = ieee80211_get_qos_ctl(t->hdr); -+ t->txpriv.tid = qos[0] & IEEE80211_QOS_CTL_TID_MASK; -+ } else if (ieee80211_is_data(t->hdr->frame_control)) { -+ t->txpriv.tid = 0; -+ } -+} -+ -+/* IV/ICV injection. */ -+/* TODO: Quite unoptimal. It's better co modify mac80211 -+ * to reserve space for IV */ -+static int -+xradio_tx_h_crypt(struct xradio_vif *priv, -+ struct xradio_txinfo *t) -+{ -+ size_t iv_len; -+ size_t icv_len; -+ u8 *icv; -+ -+ if (!t->tx_info->control.hw_key || -+ !(t->hdr->frame_control & -+ __cpu_to_le32(IEEE80211_FCTL_PROTECTED))) -+ return 0; -+ -+ iv_len = t->tx_info->control.hw_key->iv_len; -+ icv_len = t->tx_info->control.hw_key->icv_len; -+ -+ if (t->tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) -+ icv_len += 8; /* MIC */ -+ -+ if (unlikely((skb_headroom(t->skb) + skb_tailroom(t->skb) < -+ iv_len + icv_len + WSM_TX_EXTRA_HEADROOM) || -+ (skb_headroom(t->skb) < -+ iv_len + WSM_TX_EXTRA_HEADROOM))) { -+ dev_dbg(priv->hw_priv->pdev, -+ "no space allocated for crypto headers.\n" -+ "headroom: %d, tailroom: %d, " -+ "req_headroom: %d, req_tailroom: %d\n" -+ "Please fix it in xradio_get_skb().\n", -+ skb_headroom(t->skb), skb_tailroom(t->skb), -+ iv_len + WSM_TX_EXTRA_HEADROOM, icv_len); -+ return -ENOMEM; -+ } else if (unlikely(skb_tailroom(t->skb) < icv_len)) { -+ size_t offset = icv_len - skb_tailroom(t->skb); -+ u8 *p; -+ dev_dbg(priv->hw_priv->pdev, -+ "Slowpath: tailroom is not big enough. " -+ "Req: %d, got: %d.\n", -+ icv_len, skb_tailroom(t->skb)); -+ -+ p = skb_push(t->skb, offset); -+ memmove(p, &p[offset], t->skb->len - offset); -+ skb_trim(t->skb, t->skb->len - offset); -+ } -+ /* ccmp pkt from umac to driver,it has iv room,,so ccmp pkt do not add iv room */ -+ if (t->tx_info->control.hw_key->cipher != WLAN_CIPHER_SUITE_CCMP){ -+ u8 *newhdr; -+ newhdr = skb_push(t->skb, iv_len); -+ memmove(newhdr, newhdr + iv_len, t->hdrlen); -+ t->hdr = (struct ieee80211_hdr *) newhdr; -+ } -+ t->hdrlen += iv_len; -+ icv = skb_put(t->skb, icv_len); -+ -+ return 0; -+} -+ -+static int -+xradio_tx_h_align(struct xradio_vif *priv, struct xradio_txinfo *t, -+ u8 *flags) -+{ -+ size_t offset = (size_t)t->skb->data & 3; -+ u8 *newhdr;//add by dingxh -+ -+ -+ if (!offset) -+ return 0; -+ -+ if (skb_headroom(t->skb) < offset) { -+ txrx_printk(XRADIO_DBG_ERROR, -+ "Bug: no space allocated " -+ "for DMA alignment.\n" -+ "headroom: %d\n", -+ skb_headroom(t->skb)); -+ return -ENOMEM; -+ } -+ //offset = 1or3 process add by dingxh -+ if (offset & 1) { -+ newhdr = skb_push(t->skb, offset); -+ memmove(newhdr, newhdr + offset, t->skb->len-offset); -+ skb_trim(t->skb, t->skb->len-offset); -+ t->hdr = (struct ieee80211_hdr *) newhdr; -+ return 0; -+ } -+ //add by dingxh -+ //offset=2 process -+ skb_push(t->skb, offset); -+ t->hdrlen += offset; -+ t->txpriv.offset += offset; -+ *flags |= WSM_TX_2BYTES_SHIFT; -+ return 0; -+} -+ -+static int -+xradio_tx_h_action(struct xradio_vif *priv, struct xradio_txinfo *t) -+{ -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)t->hdr; -+ -+ if (ieee80211_is_action(t->hdr->frame_control) && -+ mgmt->u.action.category == WLAN_CATEGORY_BACK) -+ return 1; -+ else -+ return 0; -+} -+ -+/* Add WSM header */ -+static struct wsm_tx * -+xradio_tx_h_wsm(struct xradio_vif *priv, struct xradio_txinfo *t) -+{ -+ struct wsm_tx *wsm; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ if (skb_headroom(t->skb) < sizeof(struct wsm_tx)) { -+ txrx_printk(XRADIO_DBG_ERROR, -+ "Bug: no space allocated " -+ "for WSM header.\n" -+ "headroom: %d\n", -+ skb_headroom(t->skb)); -+ return NULL; -+ } -+ -+ wsm = (struct wsm_tx *)skb_push(t->skb, sizeof(struct wsm_tx)); -+ t->txpriv.offset += sizeof(struct wsm_tx); -+ memset(wsm, 0, sizeof(*wsm)); -+ wsm->hdr.len = __cpu_to_le16(t->skb->len); -+ wsm->hdr.id = __cpu_to_le16(0x0004); -+ wsm->queueId = (t->txpriv.raw_link_id << 2) | wsm_queue_id_to_wsm(t->queue); -+ if (wsm->hdr.len > hw_priv->wsm_caps.sizeInpChBuf) { -+ txrx_printk(XRADIO_DBG_ERROR,"%s,msg length too big=%d\n", -+ __func__, wsm->hdr.len); -+ wsm = NULL; -+ } -+ -+ return wsm; -+} -+ -+/* BT Coex specific handling */ -+static void -+xradio_tx_h_bt(struct xradio_vif *priv, struct xradio_txinfo *t, struct wsm_tx *wsm) -+{ -+ u8 priority = 0; -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ if (!hw_priv->is_BT_Present) -+ return; -+ -+ if (unlikely(ieee80211_is_nullfunc(t->hdr->frame_control))) -+ priority = WSM_EPTA_PRIORITY_MGT; -+ else if (ieee80211_is_data(t->hdr->frame_control)) { -+ /* Skip LLC SNAP header (+6) */ -+ u8 *payload = &t->skb->data[t->hdrlen]; -+ u16 *ethertype = (u16 *) &payload[6]; -+ if (unlikely(*ethertype == __be16_to_cpu(ETH_P_PAE))) -+ priority = WSM_EPTA_PRIORITY_EAPOL; -+ } else if (unlikely(ieee80211_is_assoc_req(t->hdr->frame_control) || -+ ieee80211_is_reassoc_req(t->hdr->frame_control))) { -+ struct ieee80211_mgmt *mgt_frame = -+ (struct ieee80211_mgmt *)t->hdr; -+ -+ if (mgt_frame->u.assoc_req.listen_interval < -+ priv->listen_interval) { -+ txrx_printk(XRADIO_DBG_MSG, -+ "Modified Listen Interval to %d from %d\n", -+ priv->listen_interval, -+ mgt_frame->u.assoc_req.listen_interval); -+ /* Replace listen interval derieved from -+ * the one read from SDD */ -+ mgt_frame->u.assoc_req.listen_interval = -+ priv->listen_interval; -+ } -+ } -+ -+ if (likely(!priority)) { -+ if (ieee80211_is_action(t->hdr->frame_control)) -+ priority = WSM_EPTA_PRIORITY_ACTION; -+ else if (ieee80211_is_mgmt(t->hdr->frame_control)) -+ priority = WSM_EPTA_PRIORITY_MGT; -+ else if ((wsm->queueId == WSM_QUEUE_VOICE)) -+ priority = WSM_EPTA_PRIORITY_VOICE; -+ else if ((wsm->queueId == WSM_QUEUE_VIDEO)) -+ priority = WSM_EPTA_PRIORITY_VIDEO; -+ else -+ priority = WSM_EPTA_PRIORITY_DATA; -+ } -+ -+ txrx_printk(XRADIO_DBG_MSG, "[TX] EPTA priority %d.\n", -+ priority); -+ -+ wsm->flags |= priority << 1; -+} -+ -+static int -+xradio_tx_h_rate_policy(struct xradio_common *hw_priv, struct xradio_txinfo *t, -+ struct wsm_tx *wsm) -+{ -+ bool tx_policy_renew = false; -+ struct xradio_vif *priv = -+ xrwl_get_vif_from_ieee80211(t->tx_info->control.vif); -+ -+ t->txpriv.rate_id = tx_policy_get(hw_priv, -+ t->tx_info->control.rates, t->txpriv.use_bg_rate, -+ &tx_policy_renew); -+ if (t->txpriv.rate_id == XRADIO_INVALID_RATE_ID) -+ return -EFAULT; -+ -+ wsm->flags |= t->txpriv.rate_id << 4; -+ t->rate = xradio_get_tx_rate(hw_priv, &t->tx_info->control.rates[0]); -+ if (t->txpriv.use_bg_rate) -+ wsm->maxTxRate = (u8)(t->txpriv.use_bg_rate & 0x3f); -+ else -+ wsm->maxTxRate = t->rate->hw_value; -+ -+ if (t->rate->flags & IEEE80211_TX_RC_MCS) { -+ if (priv->association_mode.greenfieldMode) -+ wsm->htTxParameters |= -+ __cpu_to_le32(WSM_HT_TX_GREENFIELD); -+ else -+ wsm->htTxParameters |= -+ __cpu_to_le32(WSM_HT_TX_MIXED); -+ } -+ -+ if (tx_policy_renew) { -+ txrx_printk(XRADIO_DBG_MSG, "[TX] TX policy renew.\n"); -+ /* It's not so optimal to stop TX queues every now and then. -+ * Maybe it's better to reimplement task scheduling with -+ * a counter. */ -+ /* xradio_tx_queues_lock(priv); */ -+ /* Definetly better. TODO. */ -+ if (atomic_add_return(1, &hw_priv->upload_count) == 1) { -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, -+ &hw_priv->tx_policy_upload_work) <= 0) { -+ atomic_set(&hw_priv->upload_count, 0); -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+ } -+ return 0; -+} -+ -+static bool -+xradio_tx_h_pm_state(struct xradio_vif *priv, struct xradio_txinfo *t) -+{ -+ int was_buffered = 1; -+ -+ -+ if (t->txpriv.link_id == priv->link_id_after_dtim && -+ !priv->buffered_multicasts) { -+ priv->buffered_multicasts = true; -+ if (priv->sta_asleep_mask) -+ queue_work(priv->hw_priv->workqueue, -+ &priv->multicast_start_work); -+ } -+ -+ if (t->txpriv.raw_link_id && t->txpriv.tid < XRADIO_MAX_TID) -+ was_buffered = priv->link_id_db[t->txpriv.raw_link_id - 1] -+ .buffered[t->txpriv.tid]++; -+ -+ return !was_buffered; -+} -+ -+static void -+xradio_tx_h_ba_stat(struct xradio_vif *priv, -+ struct xradio_txinfo *t) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ -+ if (priv->join_status != XRADIO_JOIN_STATUS_STA) -+ return; -+ if (!xradio_is_ht(&hw_priv->ht_oper)) -+ return; -+ if (!priv->setbssparams_done) -+ return; -+ if (!ieee80211_is_data(t->hdr->frame_control)) -+ return; -+ -+ spin_lock_bh(&hw_priv->ba_lock); -+ hw_priv->ba_acc += t->skb->len - t->hdrlen; -+ if (!(hw_priv->ba_cnt_rx || hw_priv->ba_cnt)) { -+ mod_timer(&hw_priv->ba_timer, -+ jiffies + XRADIO_BLOCK_ACK_INTERVAL); -+ } -+ hw_priv->ba_cnt++; -+ spin_unlock_bh(&hw_priv->ba_lock); -+} -+ -+static int -+xradio_tx_h_skb_pad(struct xradio_common *priv, -+ struct wsm_tx *wsm, -+ struct sk_buff *skb) -+{ -+ size_t len = __le16_to_cpu(wsm->hdr.len); -+ size_t padded_len = sdio_align_len(priv, len); -+ -+ -+ if (WARN_ON(skb_padto(skb, padded_len) != 0)) { -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+void xradio_tx(struct ieee80211_hw *dev, struct ieee80211_tx_control *control, struct sk_buff *skb) -+{ -+ struct xradio_common *hw_priv = dev->priv; -+ struct xradio_txinfo t = { -+ .skb = skb, -+ .queue = skb_get_queue_mapping(skb), -+ .tx_info = IEEE80211_SKB_CB(skb), -+ .hdr = (struct ieee80211_hdr *)skb->data, -+ .txpriv.tid = XRADIO_MAX_TID, -+ .txpriv.rate_id = XRADIO_INVALID_RATE_ID, -+ .txpriv.use_bg_rate = 0, -+ }; -+ struct ieee80211_sta *sta; -+ struct wsm_tx *wsm; -+ bool tid_update = 0; -+ u8 flags = 0; -+ int ret = 0; -+ struct xradio_vif *priv; -+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; -+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; -+ -+ if (!skb->data) -+ BUG_ON(1); -+ -+ if (!(t.tx_info->control.vif)) { -+ ret = __LINE__; -+ goto drop; -+ } -+ priv = xrwl_get_vif_from_ieee80211(t.tx_info->control.vif); -+ if (!priv) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ if (atomic_read(&priv->enabled) == 0) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ //dhcp and 80211 frames are important, use b/g rate and delay scan. -+ //it can make sense, such as accelerate connect. -+ if (ieee80211_is_auth(frame->frame_control)) { -+ hw_priv->connet_time[priv->if_id] = jiffies; -+ } else if (ieee80211_is_data_present(frame->frame_control)) { -+ /* since Umac had already alloc IV space in ccmp skb, so we need to add this iv_len as the new offset to LLC */ -+ u8* llc = NULL; -+ if(t.tx_info->control.hw_key && -+ (t.hdr->frame_control & __cpu_to_le32(IEEE80211_FCTL_PROTECTED)) && -+ (t.tx_info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP)) -+ llc = skb->data+ieee80211_hdrlen(frame->frame_control) + t.tx_info->control.hw_key->iv_len; -+ else -+ llc = skb->data+ieee80211_hdrlen(frame->frame_control); -+ if (is_dhcp(llc) || is_8021x(llc)) { -+ t.txpriv.use_bg_rate = -+ hw_priv->hw->wiphy->bands[hw_priv->channel->band]->bitrates[0].hw_value; -+ if (priv->vif->p2p) -+ t.txpriv.use_bg_rate = AG_RATE_INDEX; -+ t.txpriv.use_bg_rate |= 0x80; -+ } -+ if (t.txpriv.use_bg_rate){ -+ hw_priv->connet_time[priv->if_id] = jiffies; -+ } -+ } else if (ieee80211_is_deauth(frame->frame_control) || -+ ieee80211_is_disassoc(frame->frame_control)) { -+ hw_priv->connet_time[priv->if_id] = 0; -+ } -+ -+#ifdef AP_HT_COMPAT_FIX -+ if (ieee80211_is_assoc_req(frame->frame_control) && -+ priv->if_id == 0 && !(priv->ht_compat_det & 0x10)) { -+ xradio_remove_ht_ie(priv, skb); -+ } -+#endif -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+ xradio_frame_monitor(hw_priv,skb,true); -+#endif -+ -+ if (ieee80211_is_action(frame->frame_control) && -+ mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { -+ u8 *action = (u8*)&mgmt->u.action.category; -+ xradio_check_go_neg_conf_success(hw_priv, action); -+ xradio_check_prov_desc_req(hw_priv, action); -+ } -+ -+ t.txpriv.if_id = priv->if_id; -+ t.hdrlen = ieee80211_hdrlen(t.hdr->frame_control); -+ t.da = ieee80211_get_DA(t.hdr); -+ t.sta_priv = -+ (struct xradio_sta_priv *)&control->sta->drv_priv; -+ -+ if (WARN_ON(t.queue >= 4)) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ //spin_lock_bh(&hw_priv->tx_queue[t.queue].lock); -+ //if ((priv->if_id == 0) && -+ // (hw_priv->tx_queue[t.queue].num_queued_vif[0] >= -+ // hw_priv->vif0_throttle)) { -+ // spin_unlock_bh(&hw_priv->tx_queue[t.queue].lock); -+ // -+ // ret = __LINE__; -+ // goto drop; -+ //} else if ((priv->if_id == 1) && -+ // (hw_priv->tx_queue[t.queue].num_queued_vif[1] >= -+ // hw_priv->vif1_throttle)) { -+ // spin_unlock_bh(&hw_priv->tx_queue[t.queue].lock); -+ // -+ // ret = __LINE__; -+ // goto drop; -+ //} -+ //spin_unlock_bh(&hw_priv->tx_queue[t.queue].lock); -+ -+ ret = xradio_tx_h_calc_link_ids(priv, control, &t); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ dev_dbg(hw_priv->pdev, "vif %d: tx, %d bytes queue %d, link_id %d(%d).\n", -+ priv->if_id, skb->len, t.queue, t.txpriv.link_id, t.txpriv.raw_link_id); -+ if(ieee80211_is_assoc_resp(frame->frame_control)){ -+ dev_dbg(hw_priv->pdev, "vif %d: association response\n", priv->if_id); -+ } -+ -+ xradio_tx_h_pm(priv, &t); -+ xradio_tx_h_calc_tid(priv, &t); -+ ret = xradio_tx_h_crypt(priv, &t); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ ret = xradio_tx_h_align(priv, &t, &flags); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ ret = xradio_tx_h_action(priv, &t); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ wsm = xradio_tx_h_wsm(priv, &t); -+ if (!wsm) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ wsm->flags |= flags; -+ xradio_tx_h_bt(priv, &t, wsm); -+ ret = xradio_tx_h_rate_policy(hw_priv, &t, wsm); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ ret = xradio_tx_h_skb_pad(hw_priv, wsm, skb); -+ if (ret) { -+ ret = __LINE__; -+ goto drop; -+ } -+ -+ rcu_read_lock(); -+ sta = rcu_dereference(control->sta); -+ -+ xradio_tx_h_ba_stat(priv, &t); -+ spin_lock_bh(&priv->ps_state_lock); -+ { -+ tid_update = xradio_tx_h_pm_state(priv, &t); -+ BUG_ON(xradio_queue_put(&hw_priv->tx_queue[t.queue], -+ t.skb, &t.txpriv)); -+#ifdef ROC_DEBUG -+ txrx_printk(XRADIO_DBG_ERROR, "QPUT %x, %pM, if_id - %d\n", -+ t.hdr->frame_control, t.da, priv->if_id); -+#endif -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ if (tid_update && sta) -+ ieee80211_sta_set_buffered(sta, -+ t.txpriv.tid, true); -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+ -+ rcu_read_unlock(); -+ -+ xradio_bh_wakeup(hw_priv); -+ -+ return; -+ -+drop: -+ dev_dbg(hw_priv->pdev, "dropped tx at line %d, fctl=0x%04x.\n", ret, frame->frame_control); -+ xradio_skb_dtor(hw_priv, skb, &t.txpriv); -+ return; -+} -+ -+void xradio_tx_confirm_cb(struct xradio_common *hw_priv, -+ struct wsm_tx_confirm *arg) -+{ -+ u8 queue_id = xradio_queue_get_queue_id(arg->packetID); -+ struct xradio_queue *queue = &hw_priv->tx_queue[queue_id]; -+ struct sk_buff *skb; -+ const struct xradio_txpriv *txpriv; -+ struct xradio_vif *priv; -+ u32 feedback_retry = 0; -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, arg->if_id); -+ if (unlikely(!priv)) -+ return; -+ -+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { -+ /* STA is stopped. */ -+ spin_unlock(&priv->vif_lock); -+ return; -+ } -+ -+ if (WARN_ON(queue_id >= 4)) { -+ spin_unlock(&priv->vif_lock); -+ return; -+ } -+ -+ dev_dbg(hw_priv->pdev, "vif %d: tx confirm status=%d, retry=%d, lastRate=%d\n", -+ priv->if_id, arg->status, arg->ackFailures, arg->txedRate); -+ -+ if ((arg->status == WSM_REQUEUE) && -+ (arg->flags & WSM_TX_STATUS_REQUEUE)) { -+ /* "Requeue" means "implicit suspend" */ -+ struct wsm_suspend_resume suspend = { -+ .link_id = arg->link_id, -+ .stop = 1, -+ .multicast = !arg->link_id, -+ .if_id = arg->if_id, -+ }; -+ xradio_suspend_resume(priv, &suspend); -+ txrx_printk(XRADIO_DBG_WARN, "Requeue for link_id %d (try %d)." -+ " STAs asleep: 0x%.8X\n", -+ arg->link_id, -+ xradio_queue_get_generation(arg->packetID) + 1, -+ priv->sta_asleep_mask); -+ -+ WARN_ON(xradio_queue_requeue(queue, -+ arg->packetID, true)); -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ if (!arg->link_id) { -+ priv->buffered_multicasts = true; -+ if (priv->sta_asleep_mask) { -+ queue_work(hw_priv->workqueue, -+ &priv->multicast_start_work); -+ } -+ } -+ spin_unlock_bh(&priv->ps_state_lock); -+ spin_unlock(&priv->vif_lock); -+ } else if (!WARN_ON(xradio_queue_get_skb( -+ queue, arg->packetID, &skb, &txpriv))) { -+ struct ieee80211_tx_info *tx = IEEE80211_SKB_CB(skb); -+ struct ieee80211_hdr *frame = (struct ieee80211_hdr *)&skb->data[txpriv->offset]; -+ int tx_count = arg->ackFailures; -+ u8 ht_flags = 0; -+ int i; -+ -+ //yangfh add to reset if_0 in firmware when STA-unjoined, -+ //fix the errors when switch APs in combo mode. -+ if (unlikely(ieee80211_is_disassoc(frame->frame_control) || -+ ieee80211_is_deauth(frame->frame_control))) { -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ wms_send_deauth_to_self(hw_priv, priv); -+ /* Shedule unjoin work */ -+ txrx_printk(XRADIO_DBG_WARN, "Issue unjoin command(TX) by self.\n"); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->unjoin_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+ -+ if (priv->association_mode.greenfieldMode) -+ ht_flags |= IEEE80211_TX_RC_GREEN_FIELD; -+ -+ //bss loss confirm. -+ if (unlikely(priv->bss_loss_status == XRADIO_BSS_LOSS_CONFIRMING && -+ priv->bss_loss_confirm_id == arg->packetID)) { -+ spin_lock(&priv->bss_loss_lock); -+ priv->bss_loss_status = arg->status? -+ XRADIO_BSS_LOSS_CONFIRMED : XRADIO_BSS_LOSS_NONE; -+ spin_unlock(&priv->bss_loss_lock); -+ } -+ -+ if (likely(!arg->status)) { -+ tx->flags |= IEEE80211_TX_STAT_ACK; -+ priv->cqm_tx_failure_count = 0; -+ ++tx_count; -+ -+ if (arg->flags & WSM_TX_STATUS_AGGREGATION) { -+ /* Do not report aggregation to mac80211: -+ * it confuses minstrel a lot. */ -+ /* tx->flags |= IEEE80211_TX_STAT_AMPDU; */ -+ } -+ } else { -+ /* TODO: Update TX failure counters */ -+ if (unlikely(priv->cqm_tx_failure_thold && -+ (++priv->cqm_tx_failure_count > -+ priv->cqm_tx_failure_thold))) { -+ priv->cqm_tx_failure_thold = 0; -+ queue_work(hw_priv->workqueue, -+ &priv->tx_failure_work); -+ } -+ if (tx_count) -+ ++tx_count; -+ } -+ spin_unlock(&priv->vif_lock); -+ -+ tx->status.ampdu_len = 1; -+ tx->status.ampdu_ack_len = 1; -+ -+ txrx_printk(XRADIO_DBG_NIY,"feedback:%08x, %08x, %08x.\n", -+ arg->rate_try[2], arg->rate_try[1], arg->rate_try[0]); -+ if(txpriv->use_bg_rate) { //bg rates -+ tx->status.rates[0].count = arg->ackFailures+1; -+ tx->status.rates[0].idx = 0; -+ tx->status.rates[1].idx = -1; -+ tx->status.rates[2].idx = -1; -+ tx->status.rates[3].idx = -1; -+ } else { -+ int j; -+ s8 txed_idx; -+ register u8 rate_num=0, shift=0, retries=0; -+ u8 flag = tx->status.rates[0].flags; -+ -+ //get retry rate idx. -+ for(i=2; i>=0;i--) { -+ if(arg->rate_try[i]) { -+ for(j=7; j>=0;j--) { -+ shift = j<<2; -+ retries = (arg->rate_try[i]>>shift)&0xf; -+ if(retries) { -+ feedback_retry += retries; -+ txed_idx = xradio_get_rate_idx(hw_priv,flag,((i<<3)+j)); -+ txrx_printk(XRADIO_DBG_NIY, "rate_num=%d, hw=%d, idx=%d, " -+ "retries=%d, flag=%d", rate_num, ((i<<3)+j), -+ txed_idx, retries, flag); -+ if(likely(txed_idx>=0)) { -+ tx->status.rates[rate_num].idx = txed_idx; -+ tx->status.rates[rate_num].count = retries; -+ if (tx->status.rates[rate_num].flags & IEEE80211_TX_RC_MCS) -+ tx->status.rates[rate_num].flags |= ht_flags; -+ rate_num++; -+ if(rate_num>=IEEE80211_TX_MAX_RATES) { -+ i = -1; -+ break; -+ } -+ } -+ } -+ } -+ } -+ } -+ //clear other rate. -+ for (i=rate_num; i < IEEE80211_TX_MAX_RATES; ++i) { -+ tx->status.rates[i].count = 0; -+ tx->status.rates[i].idx = -1; -+ } -+ //get successful rate idx. -+ if(!arg->status) { -+ txed_idx = xradio_get_rate_idx(hw_priv, flag, arg->txedRate); -+ if(rate_num == 0) { -+ tx->status.rates[0].idx = txed_idx; -+ tx->status.rates[0].count = 1; -+ } else if(rate_num <= IEEE80211_TX_MAX_RATES){ -+ --rate_num; -+ if(txed_idx == tx->status.rates[rate_num].idx) { -+ tx->status.rates[rate_num].count += 1; -+ } else if(rate_num<(IEEE80211_TX_MAX_RATES-1)){ -+ ++rate_num; -+ tx->status.rates[rate_num].idx = txed_idx; -+ tx->status.rates[rate_num].count = 1; -+ } else if(txed_idx >=0) { -+ tx->status.rates[rate_num].idx = txed_idx; -+ tx->status.rates[rate_num].count = 1; -+ } -+ } -+ } -+ } -+ -+ dev_dbg(hw_priv->pdev, "[TX policy] Ack: " \ -+ "%d:%d, %d:%d, %d:%d, %d:%d\n", -+ tx->status.rates[0].idx, tx->status.rates[0].count, -+ tx->status.rates[1].idx, tx->status.rates[1].count, -+ tx->status.rates[2].idx, tx->status.rates[2].count, -+ tx->status.rates[3].idx, tx->status.rates[3].count); -+ -+ -+ xradio_queue_remove(queue, arg->packetID); -+ } -+} -+ -+static void xradio_notify_buffered_tx(struct xradio_vif *priv, -+ struct sk_buff *skb, int link_id, int tid) -+{ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ struct ieee80211_sta *sta; -+ struct ieee80211_hdr *hdr; -+ u8 *buffered; -+ u8 still_buffered = 0; -+ -+ -+ if (link_id && tid < XRADIO_MAX_TID) { -+ buffered = priv->link_id_db -+ [link_id - 1].buffered; -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ if (!WARN_ON(!buffered[tid])) -+ still_buffered = --buffered[tid]; -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+ if (!still_buffered && tid < XRADIO_MAX_TID) { -+ hdr = (struct ieee80211_hdr *) skb->data; -+ rcu_read_lock(); -+ sta = ieee80211_find_sta(priv->vif, hdr->addr1); -+ if (sta) -+ ieee80211_sta_set_buffered(sta, tid, false); -+ rcu_read_unlock(); -+ } -+ } -+#endif /* CONFIG_XRADIO_USE_EXTENSIONS */ -+} -+ -+void xradio_skb_dtor(struct xradio_common *hw_priv, -+ struct sk_buff *skb, -+ const struct xradio_txpriv *txpriv) -+{ -+ struct xradio_vif *priv = -+ __xrwl_hwpriv_to_vifpriv(hw_priv, txpriv->if_id); -+ -+ -+ skb_pull(skb, txpriv->offset); -+ if (priv && txpriv->rate_id != XRADIO_INVALID_RATE_ID) { -+ xradio_notify_buffered_tx(priv, skb, -+ txpriv->raw_link_id, txpriv->tid); -+ tx_policy_put(hw_priv, txpriv->rate_id); -+ } -+ ieee80211_tx_status(hw_priv->hw, skb); -+} -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+/* Workaround for WFD test case 6.1.10 */ -+void xradio_link_id_reset(struct work_struct *work) -+{ -+ struct xradio_vif *priv = -+ container_of(work, struct xradio_vif, linkid_reset_work); -+ struct xradio_common *hw_priv = priv->hw_priv; -+ int temp_linkid; -+ -+ -+ if (!priv->action_linkid) { -+ /* In GO mode we can receive ACTION frames without a linkID */ -+ temp_linkid = xradio_alloc_link_id(priv, -+ &priv->action_frame_sa[0]); -+ WARN_ON(!temp_linkid); -+ if (temp_linkid) { -+ /* Make sure we execute the WQ */ -+ flush_workqueue(hw_priv->workqueue); -+ /* Release the link ID */ -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->link_id_db[temp_linkid - 1].prev_status = -+ priv->link_id_db[temp_linkid - 1].status; -+ priv->link_id_db[temp_linkid - 1].status = -+ XRADIO_LINK_RESET; -+ spin_unlock_bh(&priv->ps_state_lock); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, -+ &priv->link_id_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+ } else { -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->link_id_db[priv->action_linkid - 1].prev_status = -+ priv->link_id_db[priv->action_linkid - 1].status; -+ priv->link_id_db[priv->action_linkid - 1].status = -+ XRADIO_LINK_RESET_REMAP; -+ spin_unlock_bh(&priv->ps_state_lock); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->link_id_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ flush_workqueue(hw_priv->workqueue); -+ } -+} -+#endif -diff --git a/drivers/net/wireless/xradio/tx.h b/drivers/net/wireless/xradio/tx.h -new file mode 100644 -index 0000000..e08bb71 ---- /dev/null -+++ b/drivers/net/wireless/xradio/tx.h -@@ -0,0 +1,86 @@ -+/* -+ * txrx interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_TXRX_H -+#define XRADIO_TXRX_H -+ -+#include -+ -+/* extern */ struct ieee80211_hw; -+/* extern */ struct sk_buff; -+/* extern */ struct wsm_tx; -+/* extern */ struct wsm_rx; -+/* extern */ struct wsm_tx_confirm; -+/* extern */ struct xradio_txpriv; -+/* extern */ struct xradio_vif; -+ -+struct tx_policy { -+ union { -+ __le32 tbl[3]; -+ u8 raw[12]; -+ }; -+ u8 defined; /* TODO: u32 or u8, profile and select best */ -+ u8 usage_count; /* --// -- */ -+ u8 retry_count; /* --// -- */ -+ u8 uploaded; -+}; -+ -+struct tx_policy_cache_entry { -+ struct tx_policy policy; -+ struct list_head link; -+}; -+ -+#define TX_POLICY_CACHE_SIZE (8) -+struct tx_policy_cache { -+ struct tx_policy_cache_entry cache[TX_POLICY_CACHE_SIZE]; -+ struct list_head used; -+ struct list_head free; -+ spinlock_t lock; -+}; -+ -+/* ******************************************************************** */ -+/* TX policy cache */ -+/* Intention of TX policy cache is an overcomplicated WSM API. -+ * Device does not accept per-PDU tx retry sequence. -+ * It uses "tx retry policy id" instead, so driver code has to sync -+ * linux tx retry sequences with a retry policy table in the device. -+ */ -+void tx_policy_init(struct xradio_common *hw_priv); -+void tx_policy_upload_work(struct work_struct *work); -+ -+/* ******************************************************************** */ -+/* TX implementation */ -+ -+u32 xradio_rate_mask_to_wsm(struct xradio_common *hw_priv, -+ u32 rates); -+void xradio_tx(struct ieee80211_hw *dev, struct ieee80211_tx_control *control, struct sk_buff *skb); -+void xradio_skb_dtor(struct xradio_common *hw_priv, -+ struct sk_buff *skb, -+ const struct xradio_txpriv *txpriv); -+ -+/* ******************************************************************** */ -+/* WSM callbacks */ -+ -+void xradio_tx_confirm_cb(struct xradio_common *hw_priv, -+ struct wsm_tx_confirm *arg); -+ -+/* ******************************************************************** */ -+/* Timeout */ -+ -+void xradio_tx_timeout(struct work_struct *work); -+ -+/* ******************************************************************** */ -+/* Workaround for WFD test case 6.1.10 */ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+void xradio_link_id_reset(struct work_struct *work); -+#endif -+ -+#endif /* XRADIO_TXRX_H */ -diff --git a/drivers/net/wireless/xradio/wsm.c b/drivers/net/wireless/xradio/wsm.c -new file mode 100644 -index 0000000..3842116 ---- /dev/null -+++ b/drivers/net/wireless/xradio/wsm.c -@@ -0,0 +1,3004 @@ -+/* -+ * WSM host interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xradio.h" -+#include "wsm.h" -+#include "bh.h" -+#include "ap.h" -+#include "sta.h" -+#include "rx.h" -+ -+#define WSM_CMD_TIMEOUT (2 * HZ) /* With respect to interrupt loss */ -+#define WSM_CMD_JOIN_TIMEOUT (7 * HZ) /* Join timeout is 5 sec. in FW */ -+#define WSM_CMD_START_TIMEOUT (7 * HZ) -+#define WSM_CMD_RESET_TIMEOUT (3 * HZ) /* 2 sec. timeout was observed. */ -+#define WSM_CMD_DEFAULT_TIMEOUT (3 * HZ) -+#define WSM_SKIP(buf, size) \ -+ do { \ -+ if (unlikely((buf)->data + size > (buf)->end)) \ -+ goto underflow; \ -+ (buf)->data += size; \ -+ } while (0) -+ -+#define WSM_GET(buf, ptr, size) \ -+ do { \ -+ if (unlikely((buf)->data + size > (buf)->end)) \ -+ goto underflow; \ -+ memcpy(ptr, (buf)->data, size); \ -+ (buf)->data += size; \ -+ } while (0) -+ -+#define __WSM_GET(buf, type, cvt) \ -+ ({ \ -+ type val; \ -+ if (unlikely((buf)->data + sizeof(type) > (buf)->end)) \ -+ goto underflow; \ -+ val = cvt(*(type *)(buf)->data); \ -+ (buf)->data += sizeof(type); \ -+ val; \ -+ }) -+ -+#define WSM_GET8(buf) __WSM_GET(buf, u8, (u8)) -+#define WSM_GET16(buf) __WSM_GET(buf, u16, __le16_to_cpu) -+#define WSM_GET32(buf) __WSM_GET(buf, u32, __le32_to_cpu) -+ -+#define WSM_PUT(buf, ptr, size) \ -+ do { \ -+ if (unlikely((buf)->data + size > (buf)->end)) \ -+ if (unlikely(wsm_buf_reserve((buf), size))) \ -+ goto nomem; \ -+ memcpy((buf)->data, ptr, size); \ -+ (buf)->data += size; \ -+ } while (0) -+ -+#define __WSM_PUT(buf, val, type, cvt) \ -+ do { \ -+ if (unlikely((buf)->data + sizeof(type) > (buf)->end)) \ -+ if (unlikely(wsm_buf_reserve((buf), sizeof(type)))) \ -+ goto nomem; \ -+ *(type *)(buf)->data = cvt(val); \ -+ (buf)->data += sizeof(type); \ -+ } while (0) -+ -+#define WSM_PUT8(buf, val) __WSM_PUT(buf, val, u8, (u8)) -+#define WSM_PUT16(buf, val) __WSM_PUT(buf, val, u16, __cpu_to_le16) -+#define WSM_PUT32(buf, val) __WSM_PUT(buf, val, u32, __cpu_to_le32) -+ -+static void wsm_buf_reset(struct wsm_buf *buf); -+static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size); -+static int get_interface_id_scanning(struct xradio_common *hw_priv); -+ -+static int wsm_cmd_send(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, -+ void *arg, u16 cmd, long tmo, int if_id); -+ -+static struct xradio_vif -+ *wsm_get_interface_for_tx(struct xradio_common *hw_priv); -+ -+static inline void wsm_cmd_lock(struct xradio_common *hw_priv) -+{ -+ mutex_lock(&hw_priv->wsm_cmd_mux); -+} -+ -+static inline void wsm_cmd_unlock(struct xradio_common *hw_priv) -+{ -+ mutex_unlock(&hw_priv->wsm_cmd_mux); -+} -+ -+static inline void wsm_oper_lock(struct xradio_common *hw_priv) -+{ -+ mutex_lock(&hw_priv->wsm_oper_lock); -+} -+ -+static inline void wsm_oper_unlock(struct xradio_common *hw_priv) -+{ -+ mutex_unlock(&hw_priv->wsm_oper_lock); -+} -+ -+/* ******************************************************************** */ -+/* WSM API implementation */ -+ -+static int wsm_generic_confirm(struct xradio_common *hw_priv, -+ void *arg, -+ struct wsm_buf *buf) -+{ -+ u32 status = WSM_GET32(buf); -+ if (status != WSM_STATUS_SUCCESS) -+ return -EINVAL; -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+#ifdef XR_RRM//RadioResourceMeasurement -+static int wsm_start_measure_requset(struct xradio_common *hw_priv, -+ MEASUREMENT_PARAMETERS *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT(buf, arg, sizeof(*arg)); -+ ret = wsm_cmd_send(hw_priv, buf, arg, 0x000E, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+ nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+ -+} -+ -+int wsm_11k_measure_requset(struct xradio_common *hw_priv, -+ u8 measure_type, -+ u16 ChannelNum, -+ u16 Duration) -+{ -+ int ret; -+ u8 type, sub_type; -+ MEASUREMENT_PARAMETERS rrm_paras; -+ LMAC_MEAS_REQUEST *rrm_req = &rrm_paras.MeasurementRequest; -+// LMAC_MEAS_CHANNEL_LOAD_PARAMS *rrm_req = &rrm_paras.MeasurementRequest; -+ rrm_paras.TxPowerLevel = 0x11; -+ rrm_paras.DurationMandatory = 0x22; -+ rrm_paras.MeasurementRequestLength = 0x33; -+ -+ type = (measure_type&0xf0)>>4; -+ sub_type = measure_type&0xf; -+ rrm_paras.MeasurementType = type; -+// if (measure_type == ChannelLoadMeasurement) { -+ if (type == ChannelLoadMeasurement) { -+ rrm_req->ChannelLoadParams.Reserved = 0; -+ rrm_req->ChannelLoadParams.ChannelLoadCCA = sub_type; -+ rrm_req->ChannelLoadParams.ChannelNum = ChannelNum; -+ //valid when channelload measure, interval bettween request&start -+ rrm_req->ChannelLoadParams.RandomInterval = 0; -+ //unit:1TU=1024us -+ rrm_req->ChannelLoadParams.MeasurementDuration = Duration; -+ rrm_req->ChannelLoadParams.MeasurementStartTimel = 0; -+ rrm_req->ChannelLoadParams.MeasurementStartTimeh = 0; -+ } else if (type == NoiseHistrogramMeasurement) { -+ rrm_req->NoisHistogramParams.Reserved = 0; -+ rrm_req->NoisHistogramParams.IpiRpi = sub_type; -+ rrm_req->NoisHistogramParams.ChannelNum = ChannelNum; -+ rrm_req->NoisHistogramParams.RandomInterval = 0; -+ rrm_req->NoisHistogramParams.MeasurementDuration = Duration; -+ rrm_req->NoisHistogramParams.MeasurementStartTimel = 0; -+ rrm_req->NoisHistogramParams.MeasurementStartTimeh = 0; -+ } -+ ret = wsm_start_measure_requset(hw_priv, &rrm_paras, 0); -+ -+ return ret; -+} -+ -+ -+#endif//RadioResourceMeasurement -+int wsm_configuration(struct xradio_common *hw_priv, -+ struct wsm_configuration *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT32(buf, arg->dot11MaxTransmitMsduLifeTime); -+ WSM_PUT32(buf, arg->dot11MaxReceiveLifeTime); -+ WSM_PUT32(buf, arg->dot11RtsThreshold); -+ -+ /* DPD block. */ -+ WSM_PUT16(buf, arg->dpdData_size + 12); -+ WSM_PUT16(buf, 1); /* DPD version */ -+ WSM_PUT(buf, arg->dot11StationId, ETH_ALEN); -+ WSM_PUT16(buf, 5); /* DPD flags */ -+ WSM_PUT(buf, arg->dpdData, arg->dpdData_size); -+ -+ ret = wsm_cmd_send(hw_priv, buf, arg, 0x0009, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+static int wsm_configuration_confirm(struct xradio_common *hw_priv, -+ struct wsm_configuration *arg, -+ struct wsm_buf *buf) -+{ -+ int i; -+ int status; -+ -+ status = WSM_GET32(buf); -+ if (WARN_ON(status != WSM_STATUS_SUCCESS)) -+ return -EINVAL; -+ -+ WSM_GET(buf, arg->dot11StationId, ETH_ALEN); -+ arg->dot11FrequencyBandsSupported = WSM_GET8(buf); -+ WSM_SKIP(buf, 1); -+ arg->supportedRateMask = WSM_GET32(buf); -+ for (i = 0; i < 2; ++i) { -+ arg->txPowerRange[i].min_power_level = WSM_GET32(buf); -+ arg->txPowerRange[i].max_power_level = WSM_GET32(buf); -+ arg->txPowerRange[i].stepping = WSM_GET32(buf); -+ } -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+void wsm_query_work(struct work_struct *work) -+{ -+ struct xradio_common *hw_priv = -+ container_of(work, struct xradio_common, query_work); -+ u8 ret[100] = {0}; -+ -+ -+ *(u32*)&ret[0] = hw_priv->query_packetID; -+ wsm_read_mib(hw_priv, WSM_MIB_ID_REQ_PKT_STATUS, (void*)&ret[0], sizeof(ret), 4); -+ if(!ret[4]) { -+ wsm_printk(XRADIO_DBG_ERROR,"QuerypktID=0x%08x, status=0x%x, retry=%d, flags=0x%x, PktDebug=0x%x\n" \ -+ "pktqueue=0x%x, ext1=%d, ext2=%d, ext3=%d, ext4=0x%x, ext5=0x%x\n", -+ *(u32*)&ret[0], ret[6], ret[7], *(u32*)&ret[8], *(u32*)&ret[12], -+ ret[44], ret[45], ret[46], ret[47], ret[48], ret[49]); -+ wsm_printk(XRADIO_DBG_ERROR,"interdebug=0x%x, 0x%x, 0x%x, Soure=0x%x, 0x%x, 0x%x\n" \ -+ "interuse=%d, external=%d, TxOutstanding=%d, QueueStatus=0x%x, BA0=0x%x, BA1=0x%x\n" \ -+ "ScanStatus=0x%x, scanNULL=0x%x, wr_state=0x%x,0x%x,0x%x,0x%x," \ -+ "wr_cnt=%d, %d, %d, %d\n", -+ *(u32*)&ret[16], *(u32*)&ret[20], *(u32*)&ret[24], ret[28], ret[29], ret[30], -+ ret[32], ret[33], ret[34], ret[35], *(u32*)&ret[36], *(u32*)&ret[40], -+ ret[50], ret[51], ret[52], ret[53], ret[54], ret[55], -+ *(u16*)&ret[56], *(u16*)&ret[58], *(u16*)&ret[60], *(u16*)&ret[62]); -+ } else { -+ ret[5] = 0; -+ wsm_printk(XRADIO_DBG_ERROR,"No req packid=0x%08x!\n", *(u32*)&ret[0]); -+ } -+ //hardware error occurs, try to restart wifi. -+ if(ret[5] & 0x4) { -+ wsm_printk(XRADIO_DBG_ERROR,"Hardware need to reset 0x%x.\n", ret[5]); -+ hw_priv->bh_error = 1; -+ wake_up(&hw_priv->bh_wq); -+ } -+ hw_priv->query_packetID = 0; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_reset(struct xradio_common *hw_priv, const struct wsm_reset *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ u16 cmd = 0x000A | WSM_TX_LINK_ID(arg->link_id); -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT32(buf, arg->reset_statistics ? 0 : 1); -+ ret = wsm_cmd_send(hw_priv, buf, NULL, cmd, WSM_CMD_RESET_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+struct wsm_mib { -+ u16 mibId; -+ void *buf; -+ size_t buf_size; -+}; -+ -+int wsm_read_mib(struct xradio_common *hw_priv, u16 mibId, void *_buf, -+ size_t buf_size, size_t arg_size) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ struct wsm_mib mib_buf = { -+ .mibId = mibId, -+ .buf = _buf, -+ .buf_size = buf_size, -+ }; -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT16(buf, mibId); -+ WSM_PUT16(buf, arg_size); -+ WSM_PUT(buf, _buf, arg_size); -+ -+ ret = wsm_cmd_send(hw_priv, buf, &mib_buf, 0x0005, WSM_CMD_TIMEOUT, -1); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+static int wsm_read_mib_confirm(struct xradio_common *hw_priv, -+ struct wsm_mib *arg, -+ struct wsm_buf *buf) -+{ -+ u16 size; -+ if (WARN_ON(WSM_GET32(buf) != WSM_STATUS_SUCCESS)) -+ return -EINVAL; -+ -+ if (WARN_ON(WSM_GET16(buf) != arg->mibId)) -+ return -EINVAL; -+ -+ size = WSM_GET16(buf); -+ if (size > arg->buf_size) -+ size = arg->buf_size; -+ -+ WSM_GET(buf, arg->buf, size); -+ arg->buf_size = size; -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_write_mib(struct xradio_common *hw_priv, u16 mibId, void *_buf, -+ size_t buf_size, int if_id) -+{ -+ int ret = 0; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ struct wsm_mib mib_buf = { -+ .mibId = mibId, -+ .buf = _buf, -+ .buf_size = buf_size, -+ }; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT16(buf, mibId); -+ WSM_PUT16(buf, buf_size); -+ WSM_PUT(buf, _buf, buf_size); -+ -+ ret = wsm_cmd_send(hw_priv, buf, &mib_buf, 0x0006, WSM_CMD_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+static int wsm_write_mib_confirm(struct xradio_common *hw_priv, -+ struct wsm_mib *arg, -+ struct wsm_buf *buf, -+ int interface_link_id) -+{ -+ int ret; -+ int i; -+ struct xradio_vif *priv; -+ ret = wsm_generic_confirm(hw_priv, arg, buf); -+ if (ret) -+ return ret; -+ -+ /*wsm_set_operational_mode confirm.*/ -+ if (arg->mibId == 0x1006) { -+ const char *p = arg->buf; -+ bool powersave_enabled = (p[0] & 0x0F) ? true : false; -+ -+ /* update vif PM status. */ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, interface_link_id); -+ if (priv) { -+ xradio_enable_powersave(priv, powersave_enabled); -+ spin_unlock(&priv->vif_lock); -+ } -+ -+ /* HW powersave base on vif except for generic vif. */ -+ spin_lock(&hw_priv->vif_list_lock); -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ powersave_enabled &= !!priv->powersave_enabled; -+ } -+ hw_priv->powersave_enabled = powersave_enabled; -+ spin_unlock(&hw_priv->vif_list_lock); -+ -+ } -+ return 0; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_scan(struct xradio_common *hw_priv, const struct wsm_scan *arg, -+ int if_id) -+{ -+ int i; -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ if (unlikely(arg->numOfChannels > 48)) -+ return -EINVAL; -+ -+ if (unlikely(arg->numOfSSIDs > WSM_SCAN_MAX_NUM_OF_SSIDS)) -+ return -EINVAL; -+ -+ if (unlikely(arg->band > 1)) -+ return -EINVAL; -+ -+ wsm_oper_lock(hw_priv); -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->band); -+ WSM_PUT8(buf, arg->scanType); -+ WSM_PUT8(buf, arg->scanFlags); -+ WSM_PUT8(buf, arg->maxTransmitRate); -+ WSM_PUT32(buf, arg->autoScanInterval); -+ WSM_PUT8(buf, arg->numOfProbeRequests); -+ WSM_PUT8(buf, arg->numOfChannels); -+ WSM_PUT8(buf, arg->numOfSSIDs); -+ WSM_PUT8(buf, arg->probeDelay); -+ -+ for (i = 0; i < arg->numOfChannels; ++i) { -+ WSM_PUT16(buf, arg->ch[i].number); -+ WSM_PUT16(buf, 0); -+ WSM_PUT32(buf, arg->ch[i].minChannelTime); -+ WSM_PUT32(buf, arg->ch[i].maxChannelTime); -+ WSM_PUT32(buf, 0); -+ } -+ -+ for (i = 0; i < arg->numOfSSIDs; ++i) { -+ WSM_PUT32(buf, arg->ssids[i].length); -+ WSM_PUT(buf, &arg->ssids[i].ssid[0], -+ sizeof(arg->ssids[i].ssid)); -+ } -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0007, WSM_CMD_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ if (ret) -+ wsm_oper_unlock(hw_priv); -+ -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ wsm_oper_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_stop_scan(struct xradio_common *hw_priv, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ wsm_cmd_lock(hw_priv); -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0008, WSM_CMD_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+} -+ -+ -+static int wsm_tx_confirm(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, -+ int interface_link_id) -+{ -+ struct wsm_tx_confirm tx_confirm; -+ -+ tx_confirm.packetID = WSM_GET32(buf); -+ tx_confirm.status = WSM_GET32(buf); -+ tx_confirm.txedRate = WSM_GET8(buf); -+ tx_confirm.ackFailures = WSM_GET8(buf); -+ tx_confirm.flags = WSM_GET16(buf); -+ tx_confirm.rate_try[0] = WSM_GET32(buf); -+ tx_confirm.rate_try[1] = WSM_GET32(buf); -+ tx_confirm.rate_try[2] = WSM_GET32(buf); -+ tx_confirm.mediaDelay = WSM_GET32(buf); -+ tx_confirm.txQueueDelay = WSM_GET32(buf); -+ -+ if (is_hardware_xradio(hw_priv)) { -+ /* TODO:COMBO:linkID will be stored in packetID*/ -+ /* TODO:COMBO: Extract traffic resumption map */ -+ tx_confirm.if_id = xradio_queue_get_if_id(tx_confirm.packetID); -+ tx_confirm.link_id = xradio_queue_get_link_id( -+ tx_confirm.packetID); -+ } else { -+ tx_confirm.link_id = interface_link_id; -+ tx_confirm.if_id = 0; -+ } -+ -+ wsm_release_vif_tx_buffer(hw_priv, tx_confirm.if_id, 1); -+ -+ xradio_tx_confirm_cb(hw_priv, &tx_confirm); -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+static int wsm_multi_tx_confirm(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, int interface_link_id) -+{ -+ struct xradio_vif *priv; -+ int ret; -+ int count; -+ int i; -+ -+ count = WSM_GET32(buf); -+ if (WARN_ON(count <= 0)) -+ return -EINVAL; -+ else if (count > 1) { -+ ret = wsm_release_tx_buffer(hw_priv, count - 1); -+ if (ret < 0) -+ return ret; -+ else if (ret > 0) -+ xradio_bh_wakeup(hw_priv); -+ } -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, interface_link_id); -+ if (priv) { -+ spin_unlock(&priv->vif_lock); -+ } -+ for (i = 0; i < count; ++i) { -+ ret = wsm_tx_confirm(hw_priv, buf, interface_link_id); -+ if (ret) -+ return ret; -+ } -+ return ret; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+/* ******************************************************************** */ -+ -+static int wsm_join_confirm(struct xradio_common *hw_priv, -+ struct wsm_join *arg, -+ struct wsm_buf *buf) -+{ -+ if (WSM_GET32(buf) != WSM_STATUS_SUCCESS) -+ return -EINVAL; -+ arg->minPowerLevel = WSM_GET32(buf); -+ arg->maxPowerLevel = WSM_GET32(buf); -+ -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+int wsm_join(struct xradio_common *hw_priv, struct wsm_join *arg, -+ int if_id) -+/*TODO: combo: make it work per vif.*/ -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_oper_lock(hw_priv); -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->mode); -+ WSM_PUT8(buf, arg->band); -+ WSM_PUT16(buf, arg->channelNumber); -+ WSM_PUT(buf, &arg->bssid[0], sizeof(arg->bssid)); -+ WSM_PUT16(buf, arg->atimWindow); -+ WSM_PUT8(buf, arg->preambleType); -+ WSM_PUT8(buf, arg->probeForJoin); -+ WSM_PUT8(buf, arg->dtimPeriod); -+ WSM_PUT8(buf, arg->flags); -+ WSM_PUT32(buf, arg->ssidLength); -+ WSM_PUT(buf, &arg->ssid[0], sizeof(arg->ssid)); -+ WSM_PUT32(buf, arg->beaconInterval); -+ WSM_PUT32(buf, arg->basicRateSet); -+ -+ hw_priv->tx_burst_idx = -1; -+ ret = wsm_cmd_send(hw_priv, buf, arg, 0x000B, WSM_CMD_JOIN_TIMEOUT, -+ if_id); -+ wsm_cmd_unlock(hw_priv); -+ wsm_oper_unlock(hw_priv); /*confirm, not indcation.*/ -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ wsm_oper_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_set_bss_params(struct xradio_common *hw_priv, -+ const struct wsm_set_bss_params *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, 0); -+ WSM_PUT8(buf, arg->beaconLostCount); -+ WSM_PUT16(buf, arg->aid); -+ WSM_PUT32(buf, arg->operationalRateSet); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0011, WSM_CMD_TIMEOUT, -+ if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_add_key(struct xradio_common *hw_priv, const struct wsm_add_key *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT(buf, arg, sizeof(*arg)); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x000C, WSM_CMD_TIMEOUT, -+ if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_remove_key(struct xradio_common *hw_priv, -+ const struct wsm_remove_key *arg, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->entryIndex); -+ WSM_PUT8(buf, 0); -+ WSM_PUT16(buf, 0); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x000D, WSM_CMD_TIMEOUT, -+ if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_set_tx_queue_params(struct xradio_common *hw_priv, -+ const struct wsm_set_tx_queue_params *arg, -+ u8 id, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ u8 queue_id_to_wmm_aci[] = {3, 2, 0, 1}; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, queue_id_to_wmm_aci[id]); -+ WSM_PUT8(buf, 0); -+ WSM_PUT8(buf, arg->ackPolicy); -+ WSM_PUT8(buf, 0); -+ WSM_PUT32(buf, arg->maxTransmitLifetime); -+ WSM_PUT16(buf, arg->allowedMediumTime); -+ WSM_PUT16(buf, 0); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0012, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_set_edca_params(struct xradio_common *hw_priv, -+ const struct wsm_edca_params *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ /* Implemented according to specification. */ -+ -+ WSM_PUT16(buf, arg->params[3].cwMin); -+ WSM_PUT16(buf, arg->params[2].cwMin); -+ WSM_PUT16(buf, arg->params[1].cwMin); -+ WSM_PUT16(buf, arg->params[0].cwMin); -+ -+ WSM_PUT16(buf, arg->params[3].cwMax); -+ WSM_PUT16(buf, arg->params[2].cwMax); -+ WSM_PUT16(buf, arg->params[1].cwMax); -+ WSM_PUT16(buf, arg->params[0].cwMax); -+ -+ WSM_PUT8(buf, arg->params[3].aifns); -+ WSM_PUT8(buf, arg->params[2].aifns); -+ WSM_PUT8(buf, arg->params[1].aifns); -+ WSM_PUT8(buf, arg->params[0].aifns); -+ -+ WSM_PUT16(buf, arg->params[3].txOpLimit); -+ WSM_PUT16(buf, arg->params[2].txOpLimit); -+ WSM_PUT16(buf, arg->params[1].txOpLimit); -+ WSM_PUT16(buf, arg->params[0].txOpLimit); -+ -+ WSM_PUT32(buf, arg->params[3].maxReceiveLifetime); -+ WSM_PUT32(buf, arg->params[2].maxReceiveLifetime); -+ WSM_PUT32(buf, arg->params[1].maxReceiveLifetime); -+ WSM_PUT32(buf, arg->params[0].maxReceiveLifetime); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0013, WSM_CMD_TIMEOUT, if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_switch_channel(struct xradio_common *hw_priv, -+ const struct wsm_switch_channel *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_lock_tx(hw_priv); -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->channelMode); -+ WSM_PUT8(buf, arg->channelSwitchCount); -+ WSM_PUT16(buf, arg->newChannelNumber); -+ -+ hw_priv->channel_switch_in_progress = 1; -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0016, WSM_CMD_TIMEOUT, if_id); -+ wsm_cmd_unlock(hw_priv); -+ if (ret) { -+ wsm_unlock_tx(hw_priv); -+ hw_priv->channel_switch_in_progress = 0; -+ } -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ wsm_unlock_tx(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_set_pm(struct xradio_common *hw_priv, const struct wsm_set_pm *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_oper_lock(hw_priv); -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->pmMode); -+ WSM_PUT8(buf, arg->fastPsmIdlePeriod); -+ WSM_PUT8(buf, arg->apPsmChangePeriod); -+ WSM_PUT8(buf, arg->minAutoPsPollPeriod); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0010, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ if (ret) -+ wsm_oper_unlock(hw_priv); -+ -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ wsm_oper_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_start(struct xradio_common *hw_priv, const struct wsm_start *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT8(buf, arg->mode); -+ WSM_PUT8(buf, arg->band); -+ WSM_PUT16(buf, arg->channelNumber); -+ WSM_PUT32(buf, arg->CTWindow); -+ WSM_PUT32(buf, arg->beaconInterval); -+ WSM_PUT8(buf, arg->DTIMPeriod); -+ WSM_PUT8(buf, arg->preambleType); -+ WSM_PUT8(buf, arg->probeDelay); -+ WSM_PUT8(buf, arg->ssidLength); -+ WSM_PUT(buf, arg->ssid, sizeof(arg->ssid)); -+ WSM_PUT32(buf, arg->basicRateSet); -+ -+ hw_priv->tx_burst_idx = -1; -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0017, WSM_CMD_START_TIMEOUT, -+ if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+#if 0 -+/* This API is no longer present in WSC */ -+/* ******************************************************************** */ -+ -+int wsm_beacon_transmit(struct xradio_common *hw_priv, -+ const struct wsm_beacon_transmit *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT32(buf, arg->enableBeaconing ? 1 : 0); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0018, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+#endif -+ -+/* ******************************************************************** */ -+ -+int wsm_start_find(struct xradio_common *hw_priv, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x0019, WSM_CMD_TIMEOUT, if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_stop_find(struct xradio_common *hw_priv, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x001A, WSM_CMD_TIMEOUT, if_id); -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_map_link(struct xradio_common *hw_priv, const struct wsm_map_link *arg, -+ int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ u16 cmd = 0x001C; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT(buf, &arg->mac_addr[0], sizeof(arg->mac_addr)); -+ -+ if (is_hardware_xradio(hw_priv)) { -+ WSM_PUT8(buf, arg->unmap); -+ WSM_PUT8(buf, arg->link_id); -+ } else { -+ cmd |= WSM_TX_LINK_ID(arg->link_id); -+ WSM_PUT16(buf, 0); -+ } -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, cmd, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+} -+ -+/* ******************************************************************** */ -+ -+int wsm_update_ie(struct xradio_common *hw_priv, -+ const struct wsm_update_ie *arg, int if_id) -+{ -+ int ret; -+ struct wsm_buf *buf = &hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(hw_priv); -+ -+ WSM_PUT16(buf, arg->what); -+ WSM_PUT16(buf, arg->count); -+ WSM_PUT(buf, arg->ies, arg->length); -+ -+ ret = wsm_cmd_send(hw_priv, buf, NULL, 0x001B, WSM_CMD_TIMEOUT, if_id); -+ -+ wsm_cmd_unlock(hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(hw_priv); -+ return -ENOMEM; -+ -+} -+/* ******************************************************************** */ -+#ifdef MCAST_FWDING -+/* 3.66 */ -+static int wsm_give_buffer_confirm(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ wsm_printk(XRADIO_DBG_MSG, "HW Buf count %d\n", hw_priv->hw_bufs_used); -+ if (!hw_priv->hw_bufs_used) -+ wake_up(&hw_priv->bh_evt_wq); -+ -+ return 0; -+} -+ -+/* 3.65 */ -+int wsm_init_release_buffer_request(struct xradio_common *hw_priv, u8 index) -+{ -+ struct wsm_buf *buf = &hw_priv->wsm_release_buf[index]; -+ u16 cmd = 0x0022; /* Buffer Request */ -+ u8 flags; -+ size_t buf_len; -+ -+ wsm_buf_init(buf); -+ -+ flags = index ? 0: 0x1; -+ -+ WSM_PUT8(buf, flags); -+ WSM_PUT8(buf, 0); -+ WSM_PUT16(buf, 0); -+ -+ buf_len = buf->data - buf->begin; -+ -+ /* Fill HI message header */ -+ ((__le16 *)buf->begin)[0] = __cpu_to_le16(buf_len); -+ ((__le16 *)buf->begin)[1] = __cpu_to_le16(cmd); -+ -+ return 0; -+nomem: -+ return -ENOMEM; -+} -+ -+/* 3.65 fixed memory leakage by yangfh*/ -+int wsm_deinit_release_buffer(struct xradio_common *hw_priv) -+{ -+ struct wsm_buf *buf = NULL; -+ int i, err = 0; -+ -+ for (i = 0; i < WSM_MAX_BUF; i++) { -+ buf = &hw_priv->wsm_release_buf[i]; -+ if(likely(buf)) { -+ if(likely(buf->begin)) -+ kfree(buf->begin); -+ buf->begin = buf->data = buf->end = NULL; -+ } else { -+ err++; -+ } -+ } -+ if(err) wsm_printk(XRADIO_DBG_ERROR, "%s, NULL buf=%d!\n", __func__, err); -+ return 0; -+} -+ -+/* 3.68 */ -+static int wsm_request_buffer_confirm(struct xradio_vif *priv, -+ u8 *arg, -+ struct wsm_buf *buf) -+{ -+ u8 count; -+ u32 sta_asleep_mask = 0; -+ int i; -+ u32 mask = 0; -+ u32 change_mask = 0; -+ struct xradio_common *hw_priv = priv->hw_priv; -+ -+ /* There is no status field in this message */ -+ sta_asleep_mask = WSM_GET32(buf); -+ count = WSM_GET8(buf); -+ count -= 1; /* Current workaround for FW issue */ -+ -+ spin_lock_bh(&priv->ps_state_lock); -+ change_mask = (priv->sta_asleep_mask ^ sta_asleep_mask); -+ wsm_printk(XRADIO_DBG_MSG, "CM %x, HM %x, FWM %x\n", change_mask,priv->sta_asleep_mask, sta_asleep_mask); -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+ if (change_mask) { -+ struct ieee80211_sta *sta; -+ int ret = 0; -+ -+ -+ for (i = 0; i < MAX_STA_IN_AP_MODE ; ++i) { -+ -+ if(XRADIO_LINK_HARD != priv->link_id_db[i].status) -+ continue; -+ -+ mask = BIT(i + 1); -+ -+ /* If FW state and host state for this link are different then notify OMAC */ -+ if(change_mask & mask) { -+ wsm_printk(XRADIO_DBG_MSG, "PS State Changed %d for sta %pM\n", (sta_asleep_mask & mask) ? 1:0, priv->link_id_db[i].mac); -+ rcu_read_lock(); -+ sta = ieee80211_find_sta(priv->vif, priv->link_id_db[i].mac); -+ if (!sta) { -+ wsm_printk(XRADIO_DBG_MSG, "WRBC - could not find sta %pM\n", -+ priv->link_id_db[i].mac); -+ } else { -+ ret = ieee80211_sta_ps_transition_ni(sta, (sta_asleep_mask & mask) ? true: false); -+ wsm_printk(XRADIO_DBG_MSG, "PS State NOTIFIED %d\n", ret); -+ WARN_ON(ret); -+ } -+ rcu_read_unlock(); -+ } -+ } -+ /* Replace STA mask with one reported by FW */ -+ spin_lock_bh(&priv->ps_state_lock); -+ priv->sta_asleep_mask = sta_asleep_mask; -+ spin_unlock_bh(&priv->ps_state_lock); -+ } -+ -+ wsm_printk(XRADIO_DBG_MSG, "WRBC - HW Buf count %d SleepMask %d\n", -+ hw_priv->hw_bufs_used, sta_asleep_mask); -+ hw_priv->buf_released = 0; -+ WARN_ON(count != (hw_priv->wsm_caps.numInpChBufs - 1)); -+ -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+/* 3.67 */ -+int wsm_request_buffer_request(struct xradio_vif *priv, -+ u8 *arg) -+{ -+ int ret; -+ struct wsm_buf *buf = &priv->hw_priv->wsm_cmd_buf; -+ -+ wsm_cmd_lock(priv->hw_priv); -+ -+ WSM_PUT8(buf, (*arg)); -+ WSM_PUT8(buf, 0); -+ WSM_PUT16(buf, 0); -+ -+ ret = wsm_cmd_send(priv->hw_priv, buf, arg, 0x0023, WSM_CMD_JOIN_TIMEOUT,priv->if_id); -+ -+ wsm_cmd_unlock(priv->hw_priv); -+ return ret; -+ -+nomem: -+ wsm_cmd_unlock(priv->hw_priv); -+ return -ENOMEM; -+} -+ -+#endif -+ -+int wsm_set_keepalive_filter(struct xradio_vif *priv, bool enable) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ priv->rx_filter.keepalive = enable; -+ return wsm_set_rx_filter(hw_priv, &priv->rx_filter, priv->if_id); -+} -+ -+int wsm_set_probe_responder(struct xradio_vif *priv, bool enable) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ -+ priv->rx_filter.probeResponder = enable; -+ return wsm_set_rx_filter(hw_priv, &priv->rx_filter, priv->if_id); -+} -+/* ******************************************************************** */ -+/* WSM indication events implementation */ -+ -+static int wsm_startup_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ u16 status; -+ static const char * const fw_types[] = { -+ "ETF", -+ "WFM", -+ "WSM", -+ "HI test", -+ "Platform test" -+ }; -+ -+ hw_priv->wsm_caps.numInpChBufs = WSM_GET16(buf); -+ hw_priv->wsm_caps.sizeInpChBuf = WSM_GET16(buf); -+ hw_priv->wsm_caps.hardwareId = WSM_GET16(buf); -+ hw_priv->wsm_caps.hardwareSubId = WSM_GET16(buf); -+ status = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareCap = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareType = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareApiVer = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareBuildNumber = WSM_GET16(buf); -+ hw_priv->wsm_caps.firmwareVersion = WSM_GET16(buf); -+ WSM_GET(buf, &hw_priv->wsm_caps.fw_label[0], WSM_FW_LABEL); -+ hw_priv->wsm_caps.fw_label[WSM_FW_LABEL+1] = 0; /* Do not trust FW too much. */ -+ -+ if (WARN_ON(status)) -+ return -EINVAL; -+ -+ if (WARN_ON(hw_priv->wsm_caps.firmwareType > 4)) -+ return -EINVAL; -+ -+ dev_info(hw_priv->pdev, -+ " Input buffers: %d x %d bytes\n" -+ " Hardware: %d.%d\n" -+ " %s firmware ver: %d, build: %d," -+ " api: %d, cap: 0x%.4X\n", -+ hw_priv->wsm_caps.numInpChBufs, -+ hw_priv->wsm_caps.sizeInpChBuf, -+ hw_priv->wsm_caps.hardwareId, -+ hw_priv->wsm_caps.hardwareSubId, -+ fw_types[hw_priv->wsm_caps.firmwareType], -+ hw_priv->wsm_caps.firmwareVersion, -+ hw_priv->wsm_caps.firmwareBuildNumber, -+ hw_priv->wsm_caps.firmwareApiVer, -+ hw_priv->wsm_caps.firmwareCap); -+ -+ dev_info(hw_priv->pdev, "Firmware Label:%s\n", &hw_priv->wsm_caps.fw_label[0]); -+ -+ hw_priv->wsm_caps.firmwareReady = 1; -+ -+ wake_up(&hw_priv->wsm_startup_done); -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+//add by yangfh 2014-10-31 16:58:53 -+void wms_send_deauth_to_self(struct xradio_common *hw_priv, struct xradio_vif *priv) -+{ -+ struct sk_buff *skb = NULL; -+ struct ieee80211_mgmt *deauth = NULL; -+ -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ int i = 0; -+ wsm_printk(XRADIO_DBG_WARN, "AP mode, send_deauth_to_self\n"); -+ for (i = 0; ilink_id_db[i].status == XRADIO_LINK_HARD) { -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ return; -+ skb_reserve(skb, 64); -+ deauth = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ if(!deauth) { -+ WARN_ON(1); -+ return; -+ } -+ deauth->frame_control = -+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); -+ deauth->duration = 0; -+ memcpy(deauth->da, priv->vif->addr, ETH_ALEN); -+ memcpy(deauth->sa, priv->link_id_db[i].mac, ETH_ALEN); -+ memcpy(deauth->bssid, priv->vif->addr, ETH_ALEN); -+ deauth->seq_ctrl = 0; -+ deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+ } -+ } else if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ wsm_printk(XRADIO_DBG_WARN, "STA mode, send_deauth_to_self\n"); -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ return; -+ skb_reserve(skb, 64); -+ deauth = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ if(!deauth) { -+ WARN_ON(1); -+ return; -+ } -+ deauth->frame_control = -+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); -+ deauth->duration = 0; -+ memcpy(deauth->da, priv->vif->addr, ETH_ALEN); -+ memcpy(deauth->sa, priv->join_bssid, ETH_ALEN); -+ memcpy(deauth->bssid, priv->join_bssid, ETH_ALEN); -+ deauth->seq_ctrl = 0; -+ deauth->u.deauth.reason_code = WLAN_REASON_DEAUTH_LEAVING; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+} -+ -+void wms_send_disassoc_to_self(struct xradio_common *hw_priv, struct xradio_vif *priv) -+{ -+ struct sk_buff *skb = NULL; -+ struct ieee80211_mgmt *disassoc = NULL; -+ if (priv->join_status == XRADIO_JOIN_STATUS_AP) { -+ int i = 0; -+ wsm_printk(XRADIO_DBG_WARN, "AP mode, wms_send_disassoc_to_self\n"); -+ for (i = 0; ilink_id_db[i].status == XRADIO_LINK_HARD) { -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ return; -+ skb_reserve(skb, 64); -+ disassoc = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ if(!disassoc) { -+ WARN_ON(1); -+ return; -+ } -+ disassoc->frame_control = -+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DISASSOC); -+ disassoc->duration = 0; -+ memcpy(disassoc->da, priv->vif->addr, ETH_ALEN); -+ memcpy(disassoc->sa, priv->link_id_db[i].mac, ETH_ALEN); -+ memcpy(disassoc->bssid, priv->vif->addr, ETH_ALEN); -+ disassoc->seq_ctrl = 0; -+ disassoc->u.disassoc.reason_code = WLAN_REASON_DISASSOC_STA_HAS_LEFT; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+ } -+ } else if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ wsm_printk(XRADIO_DBG_WARN, "STA mode, wms_send_disassoc_to_self\n"); -+ skb = dev_alloc_skb(sizeof(struct ieee80211_mgmt) + 64); -+ if (!skb) -+ return; -+ skb_reserve(skb, 64); -+ disassoc = (struct ieee80211_mgmt *)skb_put(skb, sizeof(struct ieee80211_mgmt)); -+ if(!disassoc) { -+ WARN_ON(1); -+ return; -+ } -+ disassoc->frame_control = -+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DISASSOC); -+ disassoc->duration = 0; -+ memcpy(disassoc->da, priv->vif->addr, ETH_ALEN); -+ memcpy(disassoc->sa, priv->join_bssid, ETH_ALEN); -+ memcpy(disassoc->bssid, priv->join_bssid, ETH_ALEN); -+ disassoc->seq_ctrl = 0; -+ disassoc->u.disassoc.reason_code = WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY; -+ ieee80211_rx_irqsafe(priv->hw, skb); -+ } -+} -+ -+static int wsm_receive_indication(struct xradio_common *hw_priv, -+ int interface_link_id, -+ struct wsm_buf *buf, -+ struct sk_buff **skb_p) -+{ -+ struct xradio_vif *priv; -+ struct wsm_rx rx; -+ struct ieee80211_hdr *hdr; -+ size_t hdr_len; -+ -+ hw_priv->rx_timestamp = jiffies; -+ -+ rx.status = WSM_GET32(buf); -+ rx.channelNumber = WSM_GET16(buf); -+ rx.rxedRate = WSM_GET8(buf); -+ rx.rcpiRssi = WSM_GET8(buf); -+ rx.flags = WSM_GET32(buf); -+ -+ /* TODO:COMBO: Frames received from scanning are received -+ * with interface ID == 2 */ -+ if (is_hardware_xradio(hw_priv)) { -+ if (interface_link_id == XRWL_GENERIC_IF_ID) { -+ /* Frames received in response to SCAN -+ * Request */ -+ interface_link_id = -+ get_interface_id_scanning(hw_priv); -+ if (interface_link_id == -1) { -+ interface_link_id = hw_priv->roc_if_id; -+ } -+#ifdef ROAM_OFFLOAD -+ if (hw_priv->auto_scanning) { -+ interface_link_id = hw_priv->scan.if_id; -+ } -+#endif/*ROAM_OFFLOAD*/ -+ } -+ /* linkid (peer sta id is encoded in bit 25-28 of -+ flags field */ -+ rx.link_id = ((rx.flags & (0xf << 25)) >> 25); -+ rx.if_id = interface_link_id; -+ } else { -+ rx.link_id = interface_link_id; -+ rx.if_id = 0; -+ } -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, rx.if_id); -+ if (!priv) { -+ dev_dbg(hw_priv->pdev, "got frame on a vif we don't have, dropped\n"); -+ return 0; -+ } -+ //remove wsm hdr of skb -+ hdr_len = buf->data - buf->begin; -+ skb_pull(*skb_p, hdr_len); -+ -+ /* FW Workaround: Drop probe resp or -+ beacon when RSSI is 0 */ -+ hdr = (struct ieee80211_hdr *) (*skb_p)->data; -+ -+ if (!rx.rcpiRssi && -+ (ieee80211_is_probe_resp(hdr->frame_control) || -+ ieee80211_is_beacon(hdr->frame_control))) { -+ spin_unlock(&priv->vif_lock); -+ return 0; -+ } -+ -+ /* If no RSSI subscription has been made, -+ * convert RCPI to RSSI here */ -+ if (!priv->cqm_use_rssi) -+ rx.rcpiRssi = rx.rcpiRssi / 2 - 110; -+ -+ if (!rx.status && unlikely(ieee80211_is_deauth(hdr->frame_control))) { -+ if (priv->join_status == XRADIO_JOIN_STATUS_STA) { -+ /* Shedule unjoin work */ -+ dev_dbg(hw_priv->pdev, -+ "Issue unjoin command (RX).\n"); -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, -+ &priv->unjoin_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+ xradio_rx_cb(priv, &rx, skb_p); -+ if (*skb_p) -+ skb_push(*skb_p, hdr_len); -+ spin_unlock(&priv->vif_lock); -+ -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+ -+static int wsm_event_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, -+ int interface_link_id) -+{ -+ int first; -+ struct xradio_wsm_event *event = NULL; -+ struct xradio_vif *priv; -+ -+ if (!is_hardware_xradio(hw_priv)) -+ interface_link_id = 0; -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, interface_link_id); -+ -+ if (unlikely(!priv)) { -+ dev_warn(hw_priv->pdev, "Event: %d(%d) for removed " -+ "interface, ignoring\n", __le32_to_cpu(WSM_GET32(buf)), -+ __le32_to_cpu(WSM_GET32(buf))); -+ return 0; -+ } -+ -+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { -+ /* STA is stopped. */ -+ return 0; -+ } -+ spin_unlock(&priv->vif_lock); -+ -+ event = kzalloc(sizeof(struct xradio_wsm_event), GFP_KERNEL); -+ if (event == NULL) { -+ dev_err(hw_priv->pdev, "xr_kzalloc failed!"); -+ return -EINVAL; -+ } -+ -+ event->evt.eventId = __le32_to_cpu(WSM_GET32(buf)); -+ event->evt.eventData = __le32_to_cpu(WSM_GET32(buf)); -+ event->if_id = interface_link_id; -+ -+ dev_dbg(hw_priv->pdev, "Event: %d(%d)\n", -+ event->evt.eventId, event->evt.eventData); -+ -+ spin_lock(&hw_priv->event_queue_lock); -+ first = list_empty(&hw_priv->event_queue); -+ list_add_tail(&event->link, &hw_priv->event_queue); -+ spin_unlock(&hw_priv->event_queue_lock); -+ -+ if (first) -+ queue_work(hw_priv->workqueue, &hw_priv->event_handler); -+ -+ return 0; -+ -+underflow: -+ kfree(event); -+ return -EINVAL; -+} -+ -+#define PRINT_11K_MEASRURE 1 -+static int wsm_measure_cmpl_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ MEASUREMENT_COMPLETE measure_cmpl; -+ u8 cca_chanload; -+ u32 buf_len = 0; -+ u32 *data; -+ -+ LMAC_MEAS_CHANNEL_LOAD_RESULTS *chanload_res; -+ LMAC_MEAS_NOISE_HISTOGRAM_RESULTS *noise_res; -+ WSM_GET(buf, &measure_cmpl, 12); -+ -+ switch (measure_cmpl.MeasurementType) { -+ case ChannelLoadMeasurement: -+ buf_len = sizeof(LMAC_MEAS_CHANNEL_LOAD_RESULTS); -+ break; -+ case NoiseHistrogramMeasurement: -+ buf_len = sizeof(LMAC_MEAS_NOISE_HISTOGRAM_RESULTS); -+ break; -+ case BeaconReport: -+ buf_len = sizeof(LMAC_MEAS_BEACON_RESULTS); -+ break; -+ case STAstatisticsReport: -+ buf_len = sizeof(LMAC_MEAS_STA_STATS_RESULTS); -+ break; -+ case LinkMeasurement: -+ buf_len = sizeof(LMAC_MEAS_LINK_MEASUREMENT_RESULTS); -+ break; -+ } -+ wsm_printk(XRADIO_DBG_ERROR, "[11K]buf_len = %d\n", buf_len); -+ WSM_GET(buf, &measure_cmpl.MeasurementReport, buf_len); -+ -+ data = (u32 *)(&measure_cmpl); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[0]=%08x\n", data[0]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[1]=%08x\n", data[1]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[2]=%08x\n", data[2]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[3]=%08x\n", data[3]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[4]=%08x\n", data[4]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[5]=%08x\n", data[5]); -+// wsm_printk(XRADIO_DBG_ERROR, "[***HL***]data[6]=%08x\n", data[6]); -+ wsm_printk(XRADIO_DBG_ERROR, "[***HL***]MeasurementType=%0d\n", measure_cmpl.MeasurementType); -+ -+ if (measure_cmpl.Status == WSM_STATUS_SUCCESS){ -+ switch (measure_cmpl.MeasurementType) { -+ case ChannelLoadMeasurement: -+ chanload_res = &measure_cmpl.MeasurementReport.ChannelLoadResults; -+ cca_chanload = (chanload_res->ChannelLoadCCA == MEAS_CCA) ? -+ chanload_res->CCAbusyFraction : -+ chanload_res->ChannelLoad; -+ #ifdef PRINT_11K_MEASRURE -+ wsm_printk(XRADIO_DBG_ERROR, "[11K] ChannelLoadMeasurement Result:\n"\ -+ "ChannelLoadCCA = %d\n"\ -+ "ChannelNum = %d\n"\ -+ "Duration = %d\n"\ -+ "Fraction = %d\n", \ -+ chanload_res->ChannelLoadCCA,\ -+ chanload_res->ChannelNum,\ -+ chanload_res->MeasurementDuration,\ -+ cca_chanload -+ ); -+ #endif -+ break; -+ case NoiseHistrogramMeasurement: -+ noise_res = &measure_cmpl.MeasurementReport.NoiseHistogramResults; -+// IpiRpi = (noise_res->IpiRpi == MEAS_RPI) ? -+// chanload_res->CCAbusyFraction : -+// chanload_res->ChannelLoad; -+ #ifdef PRINT_11K_MEASRURE -+ wsm_printk(XRADIO_DBG_ERROR, "[11K] NoiseHistogramResults:\n"\ -+ "IpiRpi = %d\n"\ -+ "ChannelNum = %d\n"\ -+ "PI_0__Density = %d\n"\ -+ "PI_1__Density = %d\n"\ -+ "PI_2__Density = %d\n"\ -+ "PI_3__Density = %d\n"\ -+ "PI_4__Density = %d\n"\ -+ "PI_5__Density = %d\n"\ -+ "PI_6__Density = %d\n"\ -+ "PI_7__Density = %d\n"\ -+ "PI_8__Density = %d\n"\ -+ "PI_9__Density = %d\n"\ -+ "PI_10_Density = %d\n", \ -+ noise_res->IpiRpi,\ -+ noise_res->ChannelNum,\ -+ noise_res->PI_0_Density,\ -+ noise_res->PI_1_Density,\ -+ noise_res->PI_2_Density,\ -+ noise_res->PI_3_Density,\ -+ noise_res->PI_4_Density,\ -+ noise_res->PI_5_Density,\ -+ noise_res->PI_6_Density,\ -+ noise_res->PI_7_Density,\ -+ noise_res->PI_8_Density,\ -+ noise_res->PI_9_Density,\ -+ noise_res->PI_10_Density -+ ); -+ #endif -+ break; -+ case BeaconReport: -+ break; -+ case STAstatisticsReport: -+ break; -+ case LinkMeasurement: -+ break; -+ } -+ } else { -+ wsm_printk(XRADIO_DBG_ERROR, "11K Measure(type=%d) Fail\n", measure_cmpl.MeasurementType); -+ } -+ -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+/* TODO:COMBO:Make this perVIFF once mac80211 support is available */ -+static int wsm_channel_switch_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ wsm_unlock_tx(hw_priv); /* Re-enable datapath */ -+ WARN_ON(WSM_GET32(buf)); -+ -+ hw_priv->channel_switch_in_progress = 0; -+ wake_up(&hw_priv->channel_switch_done); -+ -+ -+ xradio_channel_switch_cb(hw_priv); -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+ -+static int wsm_set_pm_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ wsm_oper_unlock(hw_priv); -+ return 0; -+} -+ -+static int wsm_scan_complete_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ struct wsm_scan_complete arg; -+#ifdef ROAM_OFFLOAD -+ if(hw_priv->auto_scanning == 0) -+ wsm_oper_unlock(hw_priv); -+#else -+ wsm_oper_unlock(hw_priv); -+#endif /*ROAM_OFFLOAD*/ -+ -+ arg.status = WSM_GET32(buf); -+ arg.psm = WSM_GET8(buf); -+ arg.numChannels = WSM_GET8(buf); -+ xradio_scan_complete_cb(hw_priv, &arg); -+ -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+ -+static int wsm_find_complete_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ /* TODO: Implement me. */ -+ //STUB(); -+ return 0; -+} -+ -+static int wsm_suspend_resume_indication(struct xradio_common *hw_priv, -+ int interface_link_id, -+ struct wsm_buf *buf) -+{ -+ u32 flags; -+ struct wsm_suspend_resume arg; -+ struct xradio_vif *priv; -+ -+ if (is_hardware_xradio(hw_priv)) { -+ int i; -+ arg.if_id = interface_link_id; -+ /* TODO:COMBO: Extract bitmap from suspend-resume -+ * TX indication */ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ if (priv->join_status == -+ XRADIO_JOIN_STATUS_AP) { -+ arg.if_id = priv->if_id; -+ break; -+ } -+ arg.link_id = 0; -+ } -+ } else { -+ arg.if_id = 0; -+ arg.link_id = interface_link_id; -+ } -+ -+ flags = WSM_GET32(buf); -+ arg.stop = !(flags & 1); -+ arg.multicast = !!(flags & 8); -+ arg.queue = (flags >> 1) & 3; -+ -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, arg.if_id); -+ if (unlikely(!priv)) { -+ wsm_printk(XRADIO_DBG_MSG, "suspend-resume indication" -+ " for removed interface!\n"); -+ return 0; -+ } -+ xradio_suspend_resume(priv, &arg); -+ spin_unlock(&priv->vif_lock); -+ -+ return 0; -+ -+underflow: -+ return -EINVAL; -+} -+ -+ -+/* ******************************************************************** */ -+/* WSM TX */ -+ -+int wsm_cmd_send(struct xradio_common *hw_priv, -+ struct wsm_buf *buf, -+ void *arg, u16 cmd, long tmo, int if_id) -+{ -+ size_t buf_len = buf->data - buf->begin; -+ int ret; -+ -+ if (cmd == 0x0006 || cmd == 0x0005) /* Write/Read MIB */ -+ wsm_printk(XRADIO_DBG_MSG, ">>> 0x%.4X [MIB: 0x%.4X] (%d)\n", -+ cmd, __le16_to_cpu(((__le16 *)buf->begin)[2]), -+ buf_len); -+ else -+ wsm_printk(XRADIO_DBG_MSG, ">>> 0x%.4X (%d)\n", cmd, buf_len); -+ -+ if (unlikely(hw_priv->bh_error)) { -+ wsm_buf_reset(buf); -+ wsm_printk(XRADIO_DBG_ERROR, "bh error!>>> 0x%.4X (%d)\n", cmd, buf_len); -+ return -ETIMEDOUT; -+ } -+ -+ /* Fill HI message header */ -+ /* BH will add sequence number */ -+ -+ /* TODO:COMBO: Add if_id from to the WSM header */ -+ /* if_id == -1 indicates that command is HW specific, -+ * eg. wsm_configuration which is called during driver initialzation -+ * (mac80211 .start callback called when first ifce is created. )*/ -+ -+ /* send hw specific commands on if 0 */ -+ if (if_id == -1) -+ if_id = 0; -+ -+ ((__le16 *)buf->begin)[0] = __cpu_to_le16(buf_len); -+ ((__le16 *)buf->begin)[1] = __cpu_to_le16(cmd | -+ ((is_hardware_xradio(hw_priv)) ? (if_id << 6) : 0)); -+ -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ BUG_ON(hw_priv->wsm_cmd.ptr); -+ hw_priv->wsm_cmd.done = 0; -+ hw_priv->wsm_cmd.ptr = buf->begin; -+ hw_priv->wsm_cmd.len = buf_len; -+ hw_priv->wsm_cmd.arg = arg; -+ hw_priv->wsm_cmd.cmd = cmd; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ -+ xradio_bh_wakeup(hw_priv); -+ -+ if (unlikely(hw_priv->bh_error)) { -+ /* Do not wait for timeout if BH is dead. Exit immediately. */ -+ ret = 0; -+ } else { -+ unsigned long wsm_cmd_max_tmo; -+ -+ /* Give start cmd a little more time */ -+ if (unlikely(tmo == WSM_CMD_START_TIMEOUT)) -+ wsm_cmd_max_tmo = WSM_CMD_START_TIMEOUT; -+ else -+ wsm_cmd_max_tmo = WSM_CMD_DEFAULT_TIMEOUT; -+ -+ /*Set max timeout.*/ -+ wsm_cmd_max_tmo = jiffies + wsm_cmd_max_tmo; -+ -+ /* Firmware prioritizes data traffic over control confirm. -+ * Loop below checks if data was RXed and increases timeout -+ * accordingly. */ -+ do { -+ /* It's safe to use unprotected access to wsm_cmd.done here */ -+ ret = wait_event_timeout(hw_priv->wsm_cmd_wq, hw_priv->wsm_cmd.done, tmo); -+ -+ /* check time since last rxed and max timeout.*/ -+ } while (!ret && -+ time_before_eq(jiffies, hw_priv->rx_timestamp+tmo) && -+ time_before(jiffies, wsm_cmd_max_tmo)); -+ -+ } -+ -+ if (unlikely(ret == 0)) { -+ u16 raceCheck; -+ -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ raceCheck = hw_priv->wsm_cmd.cmd; -+ hw_priv->wsm_cmd.arg = NULL; -+ hw_priv->wsm_cmd.ptr = NULL; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ -+ dev_err(hw_priv->pdev, "***CMD timeout!>>> 0x%.4X (%d), buf_use=%d, bh_state=%d\n", -+ cmd, buf_len, hw_priv->hw_bufs_used, hw_priv->bh_error); -+ /* Race condition check to make sure _confirm is not called -+ * after exit of _send */ -+ if (raceCheck == 0xFFFF) { -+ /* If wsm_handle_rx got stuck in _confirm we will hang -+ * system there. It's better than silently currupt -+ * stack or heap, isn't it? */ -+ BUG_ON(wait_event_timeout( -+ hw_priv->wsm_cmd_wq, -+ hw_priv->wsm_cmd.done, -+ WSM_CMD_LAST_CHANCE_TIMEOUT) <= 0); -+ } -+ -+ /* Kill BH thread to report the error to the top layer. */ -+ hw_priv->bh_error = 1; -+#ifdef BH_USE_SEMAPHORE -+ up(&hw_priv->bh_sem); -+#else -+ wake_up(&hw_priv->bh_wq); -+#endif -+ ret = -ETIMEDOUT; -+ } else { -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ BUG_ON(!hw_priv->wsm_cmd.done); -+ ret = hw_priv->wsm_cmd.ret; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ } -+ wsm_buf_reset(buf); -+ return ret; -+} -+ -+/* ******************************************************************** */ -+/* WSM TX port control */ -+ -+void wsm_lock_tx(struct xradio_common *hw_priv) -+{ -+ down(&hw_priv->tx_lock_sem); -+ atomic_add(1, &hw_priv->tx_lock); -+ /* always check event if wsm_vif_lock_tx.*/ -+ if (wsm_flush_tx(hw_priv)) -+ wsm_printk(XRADIO_DBG_MSG, "TX is locked.\n"); -+ up(&hw_priv->tx_lock_sem); -+} -+ -+void wsm_vif_lock_tx(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ down(&hw_priv->tx_lock_sem); -+ if (atomic_add_return(1, &hw_priv->tx_lock) == 1) { -+ if (wsm_vif_flush_tx(priv)) -+ wsm_printk(XRADIO_DBG_MSG, "TX is locked for" -+ " if_id %d.\n", priv->if_id); -+ } -+ up(&hw_priv->tx_lock_sem); -+} -+ -+void wsm_lock_tx_async(struct xradio_common *hw_priv) -+{ -+ if (atomic_add_return(1, &hw_priv->tx_lock) == 1) -+ wsm_printk(XRADIO_DBG_MSG, "TX is locked (async).\n"); -+} -+ -+bool wsm_flush_tx(struct xradio_common *hw_priv) -+{ -+ long timeout = WSM_CMD_LAST_CHANCE_TIMEOUT; -+ -+ /* Flush must be called with TX lock held. */ -+ BUG_ON(!atomic_read(&hw_priv->tx_lock)); -+ -+ /* First check if we really need to do something. -+ * It is safe to use unprotected access, as hw_bufs_used -+ * can only decrements. */ -+ if (!hw_priv->hw_bufs_used) -+ return true; -+ -+ if (hw_priv->bh_error) { -+ /* In case of failure do not wait for magic. */ -+ wsm_printk(XRADIO_DBG_ERROR, "Fatal error occured, " -+ "will not flush TX.\n"); -+ return false; -+ } else { -+ /* Get "oldest" frame, if any frames stuck in firmware, -+ query all of them until max timeout. */ -+ int num = hw_priv->hw_bufs_used + 1; -+ while (xradio_query_txpkt_timeout(hw_priv, XRWL_ALL_IFS, -+ 0xffffffff, &timeout)) { -+ if (timeout < 0 || !num) { -+ /* Hmmm... Not good. Frame had stuck in firmware. */ -+ wsm_printk(XRADIO_DBG_ERROR, -+ "%s:hw_bufs_used=%d, num=%d, timeout=%ld\n", -+ __func__, hw_priv->hw_bufs_used, num, timeout); -+ hw_priv->bh_error = 1; -+#ifdef BH_USE_SEMAPHORE -+ up(&hw_priv->bh_sem); -+#else -+ wake_up(&hw_priv->bh_wq); -+#endif -+ return false; -+ } else if (wait_event_timeout(hw_priv->bh_evt_wq, -+ !hw_priv->hw_bufs_used, timeout) > 0) { -+ return true; -+ } -+ --num; -+ } -+ if (hw_priv->hw_bufs_used) -+ wsm_printk(XRADIO_DBG_ERROR, "%s:No pengding, but hw_bufs_used=%d\n", -+ __func__, hw_priv->hw_bufs_used); -+ /* Ok, everything is flushed. */ -+ return true; -+ } -+} -+ -+bool wsm_vif_flush_tx(struct xradio_vif *priv) -+{ -+ struct xradio_common *hw_priv = priv->hw_priv; -+ long timeout = WSM_CMD_LAST_CHANCE_TIMEOUT; -+ int if_id = priv->if_id; -+ -+ /* Flush must be called with TX lock held. */ -+ BUG_ON(!atomic_read(&hw_priv->tx_lock)); -+ -+ /* First check if we really need to do something. -+ * It is safe to use unprotected access, as hw_bufs_used -+ * can only decrements. */ -+ if (!hw_priv->hw_bufs_used_vif[if_id]) -+ return true; -+ -+ if (hw_priv->bh_error) { -+ /* In case of failure do not wait for magic. */ -+ wsm_printk(XRADIO_DBG_ERROR, "Fatal error occured, " -+ "will not flush TX.\n"); -+ return false; -+ } else { -+ /* Get "oldest" frame, if any frames stuck in firmware, -+ query all of them until max timeout. */ -+ int num = hw_priv->hw_bufs_used_vif[if_id] + 1; -+ while (xradio_query_txpkt_timeout(hw_priv, if_id, 0xffffffff, &timeout)) { -+ if (timeout < 0 || !num) { -+ /* Hmmm... Not good. Frame had stuck in firmware. */ -+ wsm_printk(XRADIO_DBG_ERROR, "%s: if_id=%d, hw_bufs_used_vif=%d, num=%d\n", -+ __func__, if_id, hw_priv->hw_bufs_used_vif[priv->if_id], -+ num); -+ hw_priv->bh_error = 1; -+ #ifdef BH_USE_SEMAPHORE -+ up(&hw_priv->bh_sem); -+ #else -+ wake_up(&hw_priv->bh_wq); -+ #endif -+ return false; -+ } else if (wait_event_timeout(hw_priv->bh_evt_wq, -+ !hw_priv->hw_bufs_used_vif[if_id], timeout) > 0) { -+ return true; -+ } -+ --num; -+ } -+ if (hw_priv->hw_bufs_used_vif[if_id]) -+ wsm_printk(XRADIO_DBG_ERROR, "%s:No pengding, but hw_bufs_used_vif=%d\n", -+ __func__, hw_priv->hw_bufs_used_vif[priv->if_id]); -+ /* Ok, everything is flushed. */ -+ return true; -+ } -+} -+ -+ -+void wsm_unlock_tx(struct xradio_common *hw_priv) -+{ -+ int tx_lock; -+ if (hw_priv->bh_error) -+ wsm_printk(XRADIO_DBG_ERROR, "bh_error=%d, wsm_unlock_tx is unsafe\n", -+ hw_priv->bh_error); -+ else { -+ tx_lock = atomic_sub_return(1, &hw_priv->tx_lock); -+ if (tx_lock < 0) { -+ BUG_ON(1); -+ } else if (tx_lock == 0) { -+ xradio_bh_wakeup(hw_priv); -+ wsm_printk(XRADIO_DBG_MSG, "TX is unlocked.\n"); -+ } -+ } -+} -+ -+/* ******************************************************************** */ -+/* WSM RX */ -+ -+int wsm_handle_exception(struct xradio_common *hw_priv, u8 *data, size_t len) -+{ -+ struct wsm_buf buf; -+ u32 reason; -+ u32 reg[18]; -+ char fname[48]; -+ int i = 0; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ struct xradio_vif *priv = NULL; -+#endif -+ -+ static const char * const reason_str[] = { -+ "undefined instruction", -+ "prefetch abort", -+ "data abort", -+ "unknown error", -+ }; -+ -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ /* Send the event upwards on the FW exception */ -+ xradio_pm_stay_awake(&hw_priv->pm_state, 3*HZ); -+ -+ spin_lock(&hw_priv->vif_list_lock); -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (!priv) -+ continue; -+ //ieee80211_driver_hang_notify(priv->vif, GFP_KERNEL); -+ } -+ spin_unlock(&hw_priv->vif_list_lock); -+#endif -+ -+ buf.begin = buf.data = data; -+ buf.end = &buf.begin[len]; -+ -+ reason = WSM_GET32(&buf); -+ for (i = 0; i < ARRAY_SIZE(reg); ++i) -+ reg[i] = WSM_GET32(&buf); -+ WSM_GET(&buf, fname, sizeof(fname)); -+ -+ if (reason < 4) { -+ dev_err(hw_priv->pdev, "Firmware exception: %s.\n", -+ reason_str[reason]); -+ } else { -+ dev_err(hw_priv->pdev, "Firmware assert at %.*s, line %d, reason=0x%x\n", -+ sizeof(fname), fname, reg[1], reg[2]); -+ } -+ -+ for (i = 0; i < 12; i += 4) { -+ dev_err(hw_priv->pdev, "Firmware:" \ -+ "R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X, R%d: 0x%.8X,\n", -+ i + 0, reg[i + 0], i + 1, reg[i + 1], -+ i + 2, reg[i + 2], i + 3, reg[i + 3]); -+ } -+ dev_err(hw_priv->pdev, "Firmware:" \ -+ "R12: 0x%.8X, SP: 0x%.8X, LR: 0x%.8X, PC: 0x%.8X,\n", -+ reg[i + 0], reg[i + 1], reg[i + 2], reg[i + 3]); -+ i += 4; -+ dev_err(hw_priv->pdev, "Firmware:CPSR: 0x%.8X, SPSR: 0x%.8X\n", -+ reg[i + 0], reg[i + 1]); -+ -+ return 0; -+ -+underflow: -+ dev_err(hw_priv->pdev, "Firmware exception.\n"); -+ print_hex_dump_bytes("Exception: ", DUMP_PREFIX_NONE, data, len); -+ return -EINVAL; -+} -+ -+static int wsm_debug_indication(struct xradio_common *hw_priv, -+ struct wsm_buf *buf) -+{ -+ //for only one debug item. -+ u32 dbg_id, buf_data=0; -+ u16 dbg_buf_len; -+ u8 dbg_len; -+ u8 *dbg_buf; -+ dbg_id = WSM_GET32(buf); -+ -+ dbg_buf_len = buf->end - buf->data; -+ -+ if (dbg_id == 5) { -+ do { -+ dbg_buf_len = buf->end - buf->data; -+ dbg_len = WSM_GET8(buf); -+ if (dbg_len > dbg_buf_len - sizeof(dbg_len)) { -+ wsm_printk(XRADIO_DBG_ERROR, "[FW]dbg_len = %d\n", dbg_len); -+ wsm_printk(XRADIO_DBG_ERROR, "[FW]dbg_buf_len = %d\n", dbg_buf_len); -+ wsm_printk(XRADIO_DBG_ERROR, "[FW]debug ind err\n"); -+ //ret = -EINVAL; -+ //return ret; -+ -+ -+ break; -+ } -+ -+ dbg_buf = buf->data; -+ //print it; -+ wsm_printk(XRADIO_DBG_ALWY, "[FW-LOG] %s", dbg_buf); -+ // -+ buf->data += dbg_len; -+ -+ } while (buf->data < buf->end); -+ } else { -+ if (dbg_buf_len >= 4) { -+ buf_data = WSM_GET32(buf); -+ wsm_printk(XRADIO_DBG_ALWY, "[FW-DEBUG] DbgId = %d, data = %d", dbg_id, buf_data); -+ } else { -+ wsm_printk(XRADIO_DBG_ALWY, "[FW-DEBUG] DbgId = %d", dbg_id); -+ } -+ } -+ -+ return 0; -+ -+underflow: -+ WARN_ON(1); -+ return -EINVAL; -+} -+ -+int wsm_handle_rx(struct xradio_common *hw_priv, int id, -+ struct wsm_hdr *wsm, struct sk_buff **skb_p) -+{ -+ int ret = 0; -+ struct wsm_buf wsm_buf; -+ /* struct xradio_vif *priv = NULL; MRK: unused variable, see if 0 below */ -+ /* int i = 0; MRK: unused variable, see if 0 below */ -+ int interface_link_id = (id >> 6) & 0x0F; -+#ifdef ROAM_OFFLOAD -+#if 0 -+ struct xradio_vif *priv; -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, interface_link_id); -+ if (unlikely(!priv)) { -+ WARN_ON(1); -+ return 0; -+ } -+ spin_unlock(&priv->vif_lock); -+#endif -+#endif/*ROAM_OFFLOAD*/ -+ -+ /* Strip link id. */ -+ id &= ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); -+ -+ wsm_buf.begin = (u8 *)&wsm[0]; -+ wsm_buf.data = (u8 *)&wsm[1]; -+ wsm_buf.end = &wsm_buf.begin[__le32_to_cpu(wsm->len)]; -+ -+ wsm_printk(XRADIO_DBG_MSG, "<<< 0x%.4X (%d)\n", id, -+ wsm_buf.end - wsm_buf.begin); -+ -+#if defined(DGB_XRADIO_HWT) -+/***************************for HWT ********************************/ -+ if (id == 0x0424) { -+ u16 TestID = *(u16 *)(wsm_buf.data); -+ if (TestID == 1) //test frame confirm. -+ wsm_hwt_tx_confirm(hw_priv, &wsm_buf); -+ else { -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ hw_priv->wsm_cmd.ret = *((u16 *)(wsm_buf.data) + 1); -+ hw_priv->wsm_cmd.done = 1; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ wake_up(&hw_priv->wsm_cmd_wq); -+ wsm_printk(XRADIO_DBG_ALWY, "HWT TestID=0x%x Confirm ret=%d\n", -+ *(u16 *)(wsm_buf.data), hw_priv->wsm_cmd.ret); -+ } -+ return 0; -+ } else if (id == 0x0824) { -+ u16 TestID = *(u16 *)(wsm_buf.data); -+ switch (TestID) { -+ case 2: //recieve a test frame. -+ wsm_hwt_rx_frames(hw_priv, &wsm_buf); -+ break; -+ case 3: //enc test result. -+ wsm_hwt_enc_results(hw_priv, &wsm_buf); -+ break; -+ case 4: //mic test result. -+ wsm_hwt_mic_results(hw_priv, &wsm_buf); -+ break; -+ default: -+ wsm_printk(XRADIO_DBG_ERROR, "HWT ERROR Indication TestID=0x%x\n", TestID); -+ break; -+ } -+ return 0; -+ } -+/***************************for HWT ********************************/ -+#endif //DGB_XRADIO_HWT -+ -+ if (id == 0x404) { -+ ret = wsm_tx_confirm(hw_priv, &wsm_buf, interface_link_id); -+#ifdef MCAST_FWDING -+#if 1 -+ } else if (id == 0x422) { -+ ret = wsm_give_buffer_confirm(hw_priv, &wsm_buf); -+#endif -+#endif -+ -+ } else if (id == 0x41E) { -+ ret = wsm_multi_tx_confirm(hw_priv, &wsm_buf, -+ interface_link_id); -+ } else if (id & 0x0400) { -+ void *wsm_arg; -+ u16 wsm_cmd; -+ -+ /* Do not trust FW too much. Protection against repeated -+ * response and race condition removal (see above). */ -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ wsm_arg = hw_priv->wsm_cmd.arg; -+ wsm_cmd = hw_priv->wsm_cmd.cmd & -+ ~WSM_TX_LINK_ID(WSM_TX_LINK_ID_MAX); -+ hw_priv->wsm_cmd.cmd = 0xFFFF; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ -+ if (WARN_ON((id & ~0x0400) != wsm_cmd)) { -+ /* Note that any non-zero is a fatal retcode. */ -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ switch (id) { -+ case 0x0409: -+ /* Note that wsm_arg can be NULL in case of timeout in -+ * wsm_cmd_send(). */ -+ if (likely(wsm_arg)) -+ ret = wsm_configuration_confirm(hw_priv, -+ wsm_arg, -+ &wsm_buf); -+ break; -+ case 0x0405: -+ if (likely(wsm_arg)) -+ ret = wsm_read_mib_confirm(hw_priv, wsm_arg, -+ &wsm_buf); -+ break; -+ case 0x0406: -+ if (likely(wsm_arg)) -+ ret = wsm_write_mib_confirm(hw_priv, wsm_arg, -+ &wsm_buf, -+ interface_link_id); -+ break; -+ case 0x040B: -+ if (likely(wsm_arg)) -+ ret = wsm_join_confirm(hw_priv, wsm_arg, &wsm_buf); -+ if (ret) -+ wsm_printk(XRADIO_DBG_WARN, "Join confirm Failed!\n"); -+ break; -+ case 0x040E: /* 11K measure*/ -+ if (likely(wsm_arg)) -+ ret = wsm_generic_confirm(hw_priv, wsm_arg, &wsm_buf); -+ if (ret) -+ wsm_printk(XRADIO_DBG_ERROR, "[***HL***]11K Confirm Error\n"); -+ -+ break; -+ -+#ifdef MCAST_FWDING -+ case 0x0423: /* req buffer cfm*/ -+ if (likely(wsm_arg)){ -+ xradio_for_each_vif(hw_priv, priv, i) { -+ if (priv && (priv->join_status == XRADIO_JOIN_STATUS_AP)) -+ ret = wsm_request_buffer_confirm(priv, -+ wsm_arg, &wsm_buf); -+ } -+ } -+ break; -+#endif -+ case 0x0407: /* start-scan */ -+#ifdef ROAM_OFFLOAD -+ if (hw_priv->auto_scanning) { -+ if (atomic_read(&hw_priv->scan.in_progress)) { -+ hw_priv->auto_scanning = 0; -+ } -+ else { -+ wsm_oper_unlock(hw_priv); -+ up(&hw_priv->scan.lock); -+ } -+ } -+#endif /*ROAM_OFFLOAD*/ -+ case 0x0408: /* stop-scan */ -+ case 0x040A: /* wsm_reset */ -+ case 0x040C: /* add_key */ -+ case 0x040D: /* remove_key */ -+ case 0x0410: /* wsm_set_pm */ -+ case 0x0411: /* set_bss_params */ -+ case 0x0412: /* set_tx_queue_params */ -+ case 0x0413: /* set_edca_params */ -+ case 0x0416: /* switch_channel */ -+ case 0x0417: /* start */ -+ case 0x0418: /* beacon_transmit */ -+ case 0x0419: /* start_find */ -+ case 0x041A: /* stop_find */ -+ case 0x041B: /* update_ie */ -+ case 0x041C: /* map_link */ -+ WARN_ON(wsm_arg != NULL); -+ ret = wsm_generic_confirm(hw_priv, wsm_arg, &wsm_buf); -+ if (ret) -+ wsm_printk(XRADIO_DBG_ERROR, -+ "wsm_generic_confirm " -+ "failed for request 0x%.4X.\n", -+ id & ~0x0400); -+ break; -+ default: -+ BUG_ON(1); -+ } -+ -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ hw_priv->wsm_cmd.ret = ret; -+ hw_priv->wsm_cmd.done = 1; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ ret = 0; /* Error response from device should ne stop BH. */ -+ -+ wake_up(&hw_priv->wsm_cmd_wq); -+ } else if (id & 0x0800) { -+ switch (id) { -+ case 0x0801: -+ ret = wsm_startup_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x0804: -+ ret = wsm_receive_indication(hw_priv, interface_link_id, -+ &wsm_buf, skb_p); -+ break; -+ case 0x0805: -+ ret = wsm_event_indication(hw_priv, &wsm_buf, -+ interface_link_id); -+ break; -+ case 0x0807: -+ wsm_printk(XRADIO_DBG_ERROR, "[11K]wsm_measure_cmpl_indication\n"); -+// wsm_printk(XRADIO_DBG_ERROR, "[11K]wsm->len = %d\n",wsm->len); -+ -+ ret = wsm_measure_cmpl_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x080A: -+ ret = wsm_channel_switch_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x0809: -+ ret = wsm_set_pm_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x0806: -+#ifdef ROAM_OFFLOAD -+ if(hw_priv->auto_scanning && hw_priv->frame_rcvd) { -+ struct xradio_vif *priv; -+ hw_priv->frame_rcvd = 0; -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); -+ if (unlikely(!priv)) { -+ WARN_ON(1); -+ return 0; -+ } -+ spin_unlock(&priv->vif_lock); -+ if (hw_priv->beacon) { -+ struct wsm_scan_complete *scan_cmpl = \ -+ (struct wsm_scan_complete *) \ -+ ((u8 *)wsm + sizeof(struct wsm_hdr)); -+ struct ieee80211_rx_status *rhdr = \ -+ IEEE80211_SKB_RXCB(hw_priv->beacon); -+ rhdr->signal = (s8)scan_cmpl->reserved; -+ if (!priv->cqm_use_rssi) { -+ rhdr->signal = rhdr->signal / 2 - 110; -+ } -+ if (!hw_priv->beacon_bkp) -+ hw_priv->beacon_bkp = \ -+ skb_copy(hw_priv->beacon, GFP_ATOMIC); -+ ieee80211_rx_irqsafe(hw_priv->hw, hw_priv->beacon); -+ hw_priv->beacon = hw_priv->beacon_bkp; -+ -+ hw_priv->beacon_bkp = NULL; -+ } -+ wsm_printk(XRADIO_DBG_MSG, \ -+ "Send Testmode Event.\n"); -+ xradio_testmode_event(priv->hw->wiphy, -+ NL80211_CMD_NEW_SCAN_RESULTS, 0, -+ 0, GFP_KERNEL); -+ -+ } -+#endif /*ROAM_OFFLOAD*/ -+ ret = wsm_scan_complete_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x080B: -+ ret = wsm_find_complete_indication(hw_priv, &wsm_buf); -+ break; -+ case 0x080C: -+ ret = wsm_suspend_resume_indication(hw_priv, -+ interface_link_id, &wsm_buf); -+ break; -+ case 0x080E: -+ wsm_printk(XRADIO_DBG_MSG, "wsm_debug_indication"); -+ ret = wsm_debug_indication(hw_priv, &wsm_buf); -+ break; -+ -+ default: -+ wsm_printk(XRADIO_DBG_ERROR, "unknown Indmsg ID=0x%04x,len=%d\n", -+ wsm->id, wsm->len); -+ break; -+ } -+ } else { -+ WARN_ON(1); -+ ret = -EINVAL; -+ } -+out: -+ return ret; -+} -+ -+static bool wsm_handle_tx_data(struct xradio_vif *priv, -+ const struct wsm_tx *wsm, -+ const struct ieee80211_tx_info *tx_info, -+ struct xradio_txpriv *txpriv, -+ struct xradio_queue *queue) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ bool handled = false; -+ const struct ieee80211_hdr *frame = -+ (struct ieee80211_hdr *) &((u8 *)wsm)[txpriv->offset]; -+ __le16 fctl = frame->frame_control; -+ enum { -+ doProbe, -+ doDrop, -+ doJoin, -+ doOffchannel, -+ doWep, -+ doTx, -+ } action = doTx; -+ -+ hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ frame = (struct ieee80211_hdr *) &((u8 *)wsm)[txpriv->offset]; -+ fctl = frame->frame_control; -+ -+ switch (priv->mode) { -+ case NL80211_IFTYPE_STATION: -+ if (unlikely(priv->bss_loss_status == XRADIO_BSS_LOSS_CHECKING && -+ priv->join_status == XRADIO_JOIN_STATUS_STA) && -+ ieee80211_is_data(fctl)) { -+ spin_lock(&priv->bss_loss_lock); -+ priv->bss_loss_confirm_id = wsm->packetID; -+ priv->bss_loss_status = XRADIO_BSS_LOSS_CONFIRMING; -+ spin_unlock(&priv->bss_loss_lock); -+ } else if (unlikely((priv->join_status <= XRADIO_JOIN_STATUS_MONITOR) || -+ memcmp(frame->addr1, priv->join_bssid,sizeof(priv->join_bssid)))) { -+ if (ieee80211_is_auth(fctl)) -+ action = doJoin; -+ else if ((ieee80211_is_deauth(fctl) || ieee80211_is_disassoc(fctl))&& -+ priv->join_status < XRADIO_JOIN_STATUS_MONITOR) -+ action = doDrop; //no need to send deauth when STA-unjoined, yangfh 2014-10-31 16:32:16. -+ else if (ieee80211_is_probe_req(fctl)) -+ action = doTx; -+ else if (memcmp(frame->addr1, priv->join_bssid, -+ sizeof(priv->join_bssid)) && -+ (priv->join_status == -+ XRADIO_JOIN_STATUS_STA) && -+ (ieee80211_is_data(fctl))) { -+ action = doDrop; -+ } -+ else if (priv->join_status >= -+ XRADIO_JOIN_STATUS_MONITOR) -+ action = doTx; -+ else if (get_interface_id_scanning(hw_priv) != -1) { -+ wsm_printk(XRADIO_DBG_WARN, "Scan ONGOING dropping" -+ " offchannel eligible frame.\n"); -+ action = doDrop; -+ } else { -+ if (ieee80211_is_probe_resp(fctl)) -+ action = doDrop; -+ else -+ action = doOffchannel; -+ wsm_printk(XRADIO_DBG_WARN, "Offchannel fctl=0x%04x", fctl); -+ } -+ } -+ break; -+ case NL80211_IFTYPE_AP: -+ if (unlikely(!priv->join_status)) -+ action = doDrop; -+ else if (unlikely(!(BIT(txpriv->raw_link_id) & -+ (BIT(0) | priv->link_id_map)))) { -+ wsm_printk(XRADIO_DBG_WARN, -+ "A frame with expired link id " -+ "is dropped.\n"); -+ action = doDrop; -+ } -+ if (xradio_queue_get_generation(wsm->packetID) > -+ XRADIO_MAX_REQUEUE_ATTEMPTS) { -+ /* HACK!!! WSM324 firmware has tendency to requeue -+ * multicast frames in a loop, causing performance -+ * drop and high power consumption of the driver. -+ * In this situation it is better just to drop -+ * the problematic frame. */ -+ wsm_printk(XRADIO_DBG_WARN, -+ "Too many attempts " -+ "to requeue a frame. " -+ "Frame is dropped, fctl=0x%04x.\n", fctl); -+ action = doDrop; -+ } -+ break; -+ case NL80211_IFTYPE_ADHOC: -+ case NL80211_IFTYPE_MESH_POINT: -+ //STUB(); -+ case NL80211_IFTYPE_MONITOR: -+ default: -+ action = doDrop; -+ break; -+ } -+ -+ if (action == doTx) { -+ if (unlikely(ieee80211_is_probe_req(fctl))) { -+ action = doProbe; -+ } else if ((fctl & __cpu_to_le32(IEEE80211_FCTL_PROTECTED)) && -+ tx_info->control.hw_key && -+ unlikely(tx_info->control.hw_key->keyidx != -+ priv->wep_default_key_id) && -+ (tx_info->control.hw_key->cipher == -+ WLAN_CIPHER_SUITE_WEP40 || -+ tx_info->control.hw_key->cipher == -+ WLAN_CIPHER_SUITE_WEP104)) { -+ action = doWep; -+ } -+ } -+ -+ switch (action) { -+ case doProbe: -+ { -+ /* An interesting FW "feature". Device filters -+ * probe responses. -+ * The easiest way to get it back is to convert -+ * probe request into WSM start_scan command. */ -+ wsm_printk(XRADIO_DBG_MSG, \ -+ "Convert probe request to scan.\n"); -+ wsm_lock_tx_async(hw_priv); -+ hw_priv->pending_frame_id = __le32_to_cpu(wsm->packetID); -+ queue_delayed_work(hw_priv->workqueue, -+ &hw_priv->scan.probe_work, 0); -+ handled = true; -+ } -+ break; -+ case doDrop: -+ { -+ /* See detailed description of "join" below. -+ * We are dropping everything except AUTH in non-joined mode. */ -+ wsm_printk(XRADIO_DBG_MSG, "Drop frame (0x%.4X).\n", fctl); -+ BUG_ON(xradio_queue_remove(queue, -+ __le32_to_cpu(wsm->packetID))); -+ handled = true; -+ } -+ break; -+ case doJoin: -+ { -+ /* p2p should disconnect when sta try to join a different channel AP, -+ * because no good performance in this case. -+ */ -+ struct xradio_vif *p2p_tmp_vif = __xrwl_hwpriv_to_vifpriv(hw_priv, 1); -+ if (priv->if_id == 0 && p2p_tmp_vif) { -+ if (p2p_tmp_vif->join_status >= XRADIO_JOIN_STATUS_STA && -+ hw_priv->channel_changed) { -+ wsm_printk(XRADIO_DBG_WARN, "combo with different channels, p2p disconnect.\n"); -+ wms_send_disassoc_to_self(hw_priv, p2p_tmp_vif); -+ } -+ } -+ -+ /* There is one more interesting "feature" -+ * in FW: it can't do RX/TX before "join". -+ * "Join" here is not an association, -+ * but just a syncronization between AP and STA. -+ * priv->join_status is used only in bh thread and does -+ * not require protection */ -+ wsm_printk(XRADIO_DBG_NIY, "Issue join command.\n"); -+ wsm_lock_tx_async(hw_priv); -+ hw_priv->pending_frame_id = __le32_to_cpu(wsm->packetID); -+ if (queue_work(hw_priv->workqueue, &priv->join_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ handled = true; -+ } -+ break; -+ case doOffchannel: -+ { -+ wsm_printk(XRADIO_DBG_MSG, "Offchannel TX request.\n"); -+ wsm_lock_tx_async(hw_priv); -+ hw_priv->pending_frame_id = __le32_to_cpu(wsm->packetID); -+ if (queue_work(hw_priv->workqueue, &priv->offchannel_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ handled = true; -+ } -+ break; -+ case doWep: -+ { -+ wsm_printk(XRADIO_DBG_MSG, "Issue set_default_wep_key.\n"); -+ wsm_lock_tx_async(hw_priv); -+ priv->wep_default_key_id = tx_info->control.hw_key->keyidx; -+ hw_priv->pending_frame_id = __le32_to_cpu(wsm->packetID); -+ if (queue_work(hw_priv->workqueue, &priv->wep_key_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ handled = true; -+ } -+ break; -+ case doTx: -+ { -+#if 0 -+ /* Kept for history. If you want to implement wsm->more, -+ * make sure you are able to send a frame after that. */ -+ wsm->more = (count > 1) ? 1 : 0; -+ if (wsm->more) { -+ /* HACK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -+ * It's undocumented in WSM spec, but XRADIO hangs -+ * if 'more' is set and no TX is performed due to TX -+ * buffers limitation. */ -+ if (priv->hw_bufs_used + 1 == -+ priv->wsm_caps.numInpChBufs) -+ wsm->more = 0; -+ } -+ -+ /* BUG!!! FIXME: we can't use 'more' at all: we don't know -+ * future. It could be a request from upper layer with TX lock -+ * requirements (scan, for example). If "more" is set device -+ * will not send data and wsm_tx_lock() will fail... -+ * It's not obvious how to fix this deadlock. Any ideas? -+ * As a workaround more is set to 0. */ -+ wsm->more = 0; -+#endif /* 0 */ -+ -+ if (ieee80211_is_deauth(fctl) && -+ priv->mode != NL80211_IFTYPE_AP) { -+ /* Shedule unjoin work */ -+ wsm_printk(XRADIO_DBG_WARN, "Issue unjoin command(TX).\n"); -+#if 0 -+ wsm->more = 0; -+#endif /* 0 */ -+ wsm_lock_tx_async(hw_priv); -+ if (queue_work(hw_priv->workqueue, &priv->unjoin_work) <= 0) -+ wsm_unlock_tx(hw_priv); -+ } -+ } -+ break; -+ } -+ return handled; -+} -+ -+static int xradio_get_prio_queue(struct xradio_vif *priv, -+ u32 link_id_map, int *total) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ static u32 urgent; -+ struct wsm_edca_queue_params *edca; -+ unsigned score, best = -1; -+ int winner = -1; -+ int queued; -+ int i; -+ urgent = BIT(priv->link_id_after_dtim) | BIT(priv->link_id_uapsd); -+ -+ /* search for a winner using edca params */ -+ for (i = 0; i < 4; ++i) { -+ queued = xradio_queue_get_num_queued(priv, -+ &hw_priv->tx_queue[i], -+ link_id_map); -+ if (!queued) -+ continue; -+ *total += queued; -+ edca = &priv->edca.params[i]; -+ score = ((edca->aifns + edca->cwMin) << 16) + -+ (edca->cwMax - edca->cwMin) * -+ (prandom_u32() & 0xFFFF); -+ if (score < best && (winner < 0 || i != 3)) { -+ best = score; -+ winner = i; -+ } -+ } -+ -+ /* override winner if bursting */ -+ if (winner >= 0 && hw_priv->tx_burst_idx >= 0 && -+ winner != hw_priv->tx_burst_idx && -+ !xradio_queue_get_num_queued(priv, -+ &hw_priv->tx_queue[winner], -+ link_id_map & urgent) && -+ xradio_queue_get_num_queued(priv, -+ &hw_priv->tx_queue[hw_priv->tx_burst_idx], -+ link_id_map)) -+ winner = hw_priv->tx_burst_idx; -+ -+ return winner; -+} -+ -+static int wsm_get_tx_queue_and_mask(struct xradio_vif *priv, -+ struct xradio_queue **queue_p, -+ u32 *tx_allowed_mask_p, -+ bool *more) -+{ -+ struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); -+ int idx; -+ u32 tx_allowed_mask; -+ int total = 0; -+ -+ /* Search for a queue with multicast frames buffered */ -+ if (priv->tx_multicast) { -+ tx_allowed_mask = BIT(priv->link_id_after_dtim); -+ idx = xradio_get_prio_queue(priv, -+ tx_allowed_mask, &total); -+ if (idx >= 0) { -+ *more = total > 1; -+ goto found; -+ } -+ } -+ -+ /* Search for unicast traffic */ -+ tx_allowed_mask = ~priv->sta_asleep_mask; -+ tx_allowed_mask |= BIT(priv->link_id_uapsd); -+ if (priv->sta_asleep_mask) { -+ tx_allowed_mask |= priv->pspoll_mask; -+ tx_allowed_mask &= ~BIT(priv->link_id_after_dtim); -+ } else { -+ tx_allowed_mask |= BIT(priv->link_id_after_dtim); -+ } -+ idx = xradio_get_prio_queue(priv, -+ tx_allowed_mask, &total); -+ if (idx < 0) -+ return -ENOENT; -+ -+found: -+ *queue_p = &hw_priv->tx_queue[idx]; -+ *tx_allowed_mask_p = tx_allowed_mask; -+ return 0; -+} -+ -+int wsm_get_tx(struct xradio_common *hw_priv, u8 **data, -+ size_t *tx_len, int *burst, int *vif_selected) -+{ -+ struct wsm_tx *wsm = NULL; -+ struct ieee80211_tx_info *tx_info; -+ struct xradio_queue *queue = NULL; -+ int queue_num; -+ u32 tx_allowed_mask = 0; -+ struct xradio_txpriv *txpriv = NULL; -+ /* -+ * Count was intended as an input for wsm->more flag. -+ * During implementation it was found that wsm->more -+ * is not usable, see details above. It is kept just -+ * in case you would like to try to implement it again. -+ */ -+ int count = 0; -+ int if_pending = 1; -+ -+ /* More is used only for broadcasts. */ -+ bool more = false; -+ -+ if (hw_priv->wsm_cmd.ptr) { -+ ++count; -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ BUG_ON(!hw_priv->wsm_cmd.ptr); -+ *data = hw_priv->wsm_cmd.ptr; -+ *tx_len = hw_priv->wsm_cmd.len; -+ *burst = 1; -+ *vif_selected = -1; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ } else { -+ for (;;) { -+ int ret; -+ struct xradio_vif *priv; -+#if 0 -+ int num_pending_vif0, num_pending_vif1; -+#endif -+ if (atomic_add_return(0, &hw_priv->tx_lock)) -+ break; -+ /* Keep one buffer reserved for commands. Note -+ that, hw_bufs_used has already been incremented -+ before reaching here. */ -+ if (hw_priv->hw_bufs_used >= -+ hw_priv->wsm_caps.numInpChBufs) -+ break; -+ priv = wsm_get_interface_for_tx(hw_priv); -+ /* go to next interface ID to select next packet */ -+ hw_priv->if_id_selected ^= 1; -+ -+ /* There might be no interface before add_interface -+ * call */ -+ if (!priv) { -+ if (if_pending) { -+ if_pending = 0; -+ continue; -+ } -+ break; -+ } -+ -+#if 0 -+ if (((priv->if_id == 0) && -+ (hw_priv->hw_bufs_used_vif[0] >= -+ XRWL_FW_VIF0_THROTTLE)) || -+ ((priv->if_id == 1) && -+ (hw_priv->hw_bufs_used_vif[1] >= -+ XRWL_FW_VIF1_THROTTLE))) { -+ spin_unlock(&priv->vif_lock); -+ if (if_pending) { -+ if_pending = 0; -+ continue; -+ } -+ break; -+ } -+#endif -+ -+ /* This can be removed probably: xradio_vif will not -+ * be in hw_priv->vif_list (as returned from -+ * wsm_get_interface_for_tx) until it's fully -+ * enabled, so statement above will take case of that*/ -+ if (!atomic_read(&priv->enabled)) { -+ spin_unlock(&priv->vif_lock); -+ break; -+ } -+ -+ /* TODO:COMBO: Find the next interface for which -+ * packet needs to be found */ -+ spin_lock_bh(&priv->ps_state_lock); -+ ret = wsm_get_tx_queue_and_mask(priv, &queue, -+ &tx_allowed_mask, &more); -+ queue_num = queue - hw_priv->tx_queue; -+ -+ if (priv->buffered_multicasts && -+ (ret || !more) && -+ (priv->tx_multicast || -+ !priv->sta_asleep_mask)) { -+ priv->buffered_multicasts = false; -+ if (priv->tx_multicast) { -+ priv->tx_multicast = false; -+ queue_work(hw_priv->workqueue, -+ &priv->multicast_stop_work); -+ } -+ } -+ -+ spin_unlock_bh(&priv->ps_state_lock); -+ -+ if (ret) { -+ spin_unlock(&priv->vif_lock); -+ if (if_pending == 1) { -+ if_pending = 0; -+ continue; -+ } -+ break; -+ } -+ -+ if (xradio_queue_get(queue, -+ priv->if_id, -+ tx_allowed_mask, -+ &wsm, &tx_info, &txpriv)) { -+ spin_unlock(&priv->vif_lock); -+ if_pending = 0; -+ continue; -+ } -+ -+// #ifdef ROC_DEBUG -+// { -+// struct ieee80211_hdr *hdr = -+// (struct ieee80211_hdr *) -+// &((u8 *)wsm)[txpriv->offset]; -+// -+// wsm_printk(XRADIO_DBG_ERROR, "QGET-1 %x, off_id %d," -+// " if_id %d\n", -+// hdr->frame_control, -+// txpriv->offchannel_if_id, -+// priv->if_id); -+// } -+// #else -+// { -+// struct ieee80211_hdr *hdr = -+// (struct ieee80211_hdr *) -+// &((u8 *)wsm)[txpriv->offset]; -+// -+// wsm_printk(XRADIO_DBG_ERROR, "QGET-1 %x, off_id %d," -+// " if_id %d\n", -+// hdr->frame_control, -+// txpriv->raw_if_id, -+// priv->if_id); -+// } -+// #endif -+ -+ if (wsm_handle_tx_data(priv, wsm, -+ tx_info, txpriv, queue)) { -+ spin_unlock(&priv->vif_lock); -+ if_pending = 0; -+ continue; /* Handled by WSM */ -+ } -+ -+ wsm->hdr.id &= __cpu_to_le16( -+ ~WSM_TX_IF_ID(WSM_TX_IF_ID_MAX)); -+ if (txpriv->offchannel_if_id) -+ wsm->hdr.id |= cpu_to_le16( -+ WSM_TX_IF_ID(txpriv->offchannel_if_id)); -+ else -+ wsm->hdr.id |= cpu_to_le16( -+ WSM_TX_IF_ID(priv->if_id)); -+ -+ *vif_selected = priv->if_id; -+// #ifdef ROC_DEBUG -+// /* remand the roc debug. */ -+// { -+// struct ieee80211_hdr *hdr = -+// (struct ieee80211_hdr *) -+// &((u8 *)wsm)[txpriv->offset]; -+// -+// wsm_printk(XRADIO_DBG_ERROR, "QGET-2 %x, off_id %d," -+// " if_id %d\n", -+// hdr->frame_control, -+// txpriv->offchannel_if_id, -+// priv->if_id); -+// } -+// #else -+// { -+// struct ieee80211_hdr *hdr = -+// (struct ieee80211_hdr *) -+// &((u8 *)wsm)[txpriv->offset]; -+// -+// wsm_printk(XRADIO_DBG_ERROR, "QGET-2 %x, off_id %d," -+// " if_id %d\n", -+// hdr->frame_control, -+// txpriv->raw_if_id, -+// priv->if_id); -+// } -+// #endif -+ -+ priv->pspoll_mask &= ~BIT(txpriv->raw_link_id); -+ -+ *data = (u8 *)wsm; -+ *tx_len = __le16_to_cpu(wsm->hdr.len); -+ -+ /* allow bursting if txop is set */ -+ if (priv->edca.params[queue_num].txOpLimit) -+ *burst = min(*burst, -+ (int)xradio_queue_get_num_queued(priv, -+ queue, tx_allowed_mask) + 1); -+ else -+ *burst = 1; -+ -+ /* store index of bursting queue */ -+ if (*burst > 1) -+ hw_priv->tx_burst_idx = queue_num; -+ else -+ hw_priv->tx_burst_idx = -1; -+ -+ if (more) { -+ struct ieee80211_hdr *hdr = -+ (struct ieee80211_hdr *) -+ &((u8 *)wsm)[txpriv->offset]; -+ if(strstr(&priv->ssid[0], "6.1.12")) { -+ if(hdr->addr1[0] & 0x01 ) { -+ hdr->frame_control |= -+ cpu_to_le16(IEEE80211_FCTL_MOREDATA); -+ } -+ } -+ else { -+ /* more buffered multicast/broadcast frames -+ * ==> set MoreData flag in IEEE 802.11 header -+ * to inform PS STAs */ -+ hdr->frame_control |= -+ cpu_to_le16(IEEE80211_FCTL_MOREDATA); -+ } -+ } -+ wsm_printk(XRADIO_DBG_MSG, ">>> 0x%.4X (%d) %p %c\n", -+ 0x0004, *tx_len, *data, -+ wsm->more ? 'M' : ' '); -+ ++count; -+ spin_unlock(&priv->vif_lock); -+ break; -+ } -+ } -+ -+ return count; -+} -+ -+void wsm_txed(struct xradio_common *hw_priv, u8 *data) -+{ -+ if (data == hw_priv->wsm_cmd.ptr) { -+ spin_lock(&hw_priv->wsm_cmd.lock); -+ hw_priv->wsm_cmd.ptr = NULL; -+ spin_unlock(&hw_priv->wsm_cmd.lock); -+ } -+} -+ -+/* ******************************************************************** */ -+/* WSM buffer */ -+ -+void wsm_buf_init(struct wsm_buf *buf) -+{ -+ int size = (SDIO_BLOCK_SIZE<<1); //for sdd file big than SDIO_BLOCK_SIZE -+ BUG_ON(buf->begin); -+ buf->begin = kmalloc(size, GFP_KERNEL); -+ buf->end = buf->begin ? &buf->begin[size] : buf->begin; -+ wsm_buf_reset(buf); -+} -+ -+void wsm_buf_deinit(struct wsm_buf *buf) -+{ -+ if(buf->begin) -+ kfree(buf->begin); -+ buf->begin = buf->data = buf->end = NULL; -+} -+ -+static void wsm_buf_reset(struct wsm_buf *buf) -+{ -+ if (buf->begin) { -+ buf->data = &buf->begin[4]; -+ *(u32 *)buf->begin = 0; -+ } else -+ buf->data = buf->begin; -+} -+ -+static int wsm_buf_reserve(struct wsm_buf *buf, size_t extra_size) -+{ -+ size_t pos = buf->data - buf->begin; -+ size_t size = pos + extra_size; -+ -+ -+ if (size & (SDIO_BLOCK_SIZE - 1)) { -+ size &= SDIO_BLOCK_SIZE; -+ size += SDIO_BLOCK_SIZE; -+ } -+ -+ buf->begin = krealloc(buf->begin, size, GFP_KERNEL); -+ if (buf->begin) { -+ buf->data = &buf->begin[pos]; -+ buf->end = &buf->begin[size]; -+ return 0; -+ } else { -+ buf->end = buf->data = buf->begin; -+ return -ENOMEM; -+ } -+} -+ -+static struct xradio_vif -+ *wsm_get_interface_for_tx(struct xradio_common *hw_priv) -+{ -+ struct xradio_vif *priv = NULL, *i_priv; -+ int i = hw_priv->if_id_selected; -+ -+ if ( 1 /*TODO:COMBO*/) { -+ spin_lock(&hw_priv->vif_list_lock); -+ i_priv = hw_priv->vif_list[i] ? -+ xrwl_get_vif_from_ieee80211(hw_priv->vif_list[i]) : NULL; -+ if (i_priv) { -+ priv = i_priv; -+ spin_lock(&priv->vif_lock); -+ } -+ /* TODO:COMBO: -+ * Find next interface based on TX bitmap announced by the FW -+ * Find next interface based on load balancing */ -+ spin_unlock(&hw_priv->vif_list_lock); -+ } else { -+ priv = xrwl_hwpriv_to_vifpriv(hw_priv, 0); -+ } -+ -+ return priv; -+} -+ -+static inline int get_interface_id_scanning(struct xradio_common *hw_priv) -+{ -+ if (hw_priv->scan.req || hw_priv->scan.direct_probe) -+ return hw_priv->scan.if_id; -+ else -+ return -1; -+} -diff --git a/drivers/net/wireless/xradio/wsm.h b/drivers/net/wireless/xradio/wsm.h -new file mode 100644 -index 0000000..8056abc ---- /dev/null -+++ b/drivers/net/wireless/xradio/wsm.h -@@ -0,0 +1,2354 @@ -+/* -+ * wsm interfaces for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_WSM_H_INCLUDED -+#define XRADIO_WSM_H_INCLUDED -+ -+#include -+ -+struct xradio_common; -+ -+/* Bands */ -+/* Radio band 2.412 -2.484 GHz. */ -+#define WSM_PHY_BAND_2_4G (0) -+ -+/* Radio band 4.9375-5.8250 GHz. */ -+#define WSM_PHY_BAND_5G (1) -+ -+/* Transmit rates */ -+/* 1 Mbps ERP-DSSS */ -+#define WSM_TRANSMIT_RATE_1 (0) -+ -+/* 2 Mbps ERP-DSSS */ -+#define WSM_TRANSMIT_RATE_2 (1) -+ -+/* 5.5 Mbps ERP-CCK, ERP-PBCC (Not supported) */ -+/* #define WSM_TRANSMIT_RATE_5 (2) */ -+ -+/* 11 Mbps ERP-CCK, ERP-PBCC (Not supported) */ -+/* #define WSM_TRANSMIT_RATE_11 (3) */ -+ -+/* 22 Mbps ERP-PBCC (Not supported) */ -+/* #define WSM_TRANSMIT_RATE_22 (4) */ -+ -+/* 33 Mbps ERP-PBCC (Not supported) */ -+/* #define WSM_TRANSMIT_RATE_33 (5) */ -+ -+/* 6 Mbps (3 Mbps) ERP-OFDM, BPSK coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_6 (6) -+ -+/* 9 Mbps (4.5 Mbps) ERP-OFDM, BPSK coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_9 (7) -+ -+/* 12 Mbps (6 Mbps) ERP-OFDM, QPSK coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_12 (8) -+ -+/* 18 Mbps (9 Mbps) ERP-OFDM, QPSK coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_18 (9) -+ -+/* 24 Mbps (12 Mbps) ERP-OFDM, 16QAM coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_24 (10) -+ -+/* 36 Mbps (18 Mbps) ERP-OFDM, 16QAM coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_36 (11) -+ -+/* 48 Mbps (24 Mbps) ERP-OFDM, 64QAM coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_48 (12) -+ -+/* 54 Mbps (27 Mbps) ERP-OFDM, 64QAM coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_54 (13) -+ -+/* 6.5 Mbps HT-OFDM, BPSK coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_HT_6 (14) -+ -+/* 13 Mbps HT-OFDM, QPSK coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_HT_13 (15) -+ -+/* 19.5 Mbps HT-OFDM, QPSK coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_HT_19 (16) -+ -+/* 26 Mbps HT-OFDM, 16QAM coding rate 1/2 */ -+#define WSM_TRANSMIT_RATE_HT_26 (17) -+ -+/* 39 Mbps HT-OFDM, 16QAM coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_HT_39 (18) -+ -+/* 52 Mbps HT-OFDM, 64QAM coding rate 2/3 */ -+#define WSM_TRANSMIT_RATE_HT_52 (19) -+ -+/* 58.5 Mbps HT-OFDM, 64QAM coding rate 3/4 */ -+#define WSM_TRANSMIT_RATE_HT_58 (20) -+ -+/* 65 Mbps HT-OFDM, 64QAM coding rate 5/6 */ -+#define WSM_TRANSMIT_RATE_HT_65 (21) -+ -+/* Scan types */ -+/* Foreground scan */ -+#define WSM_SCAN_TYPE_FOREGROUND (0) -+ -+/* Background scan */ -+#define WSM_SCAN_TYPE_BACKGROUND (1) -+ -+/* Auto scan */ -+#define WSM_SCAN_TYPE_AUTO (2) -+ -+/* Scan flags */ -+/* Forced background scan means if the station cannot */ -+/* enter the power-save mode, it shall force to perform a */ -+/* background scan. Only valid when ScanType is */ -+/* background scan. */ -+#define WSM_SCAN_FLAG_FORCE_BACKGROUND (BIT(0)) -+ -+/* The WLAN device scans one channel at a time so */ -+/* that disturbance to the data traffic is minimized. */ -+#define WSM_SCAN_FLAG_SPLIT_METHOD (BIT(1)) -+ -+/* Preamble Type. Long if not set. */ -+#define WSM_SCAN_FLAG_SHORT_PREAMBLE (BIT(2)) -+ -+/* 11n Tx Mode. Mixed if not set. */ -+#define WSM_SCAN_FLAG_11N_GREENFIELD (BIT(3)) -+ -+#define WSM_FLAG_MAC_INSTANCE_1 (BIT(4)) -+ -+#define WSM_FLAG_MAC_INSTANCE_0 (~(BIT(4))) -+ -+/* Scan constraints */ -+/* Maximum number of channels to be scanned. */ -+#define WSM_SCAN_MAX_NUM_OF_CHANNELS (48) -+ -+/* The maximum number of SSIDs that the device can scan for. */ -+#define WSM_SCAN_MAX_NUM_OF_SSIDS (2) -+ -+/* Power management modes */ -+/* 802.11 Active mode */ -+#define WSM_PSM_ACTIVE (0) -+ -+/* 802.11 PS mode */ -+#define WSM_PSM_PS BIT(0) -+ -+/* Fast Power Save bit */ -+#define WSM_PSM_FAST_PS_FLAG BIT(7) -+ -+/* Dynamic aka Fast power save */ -+#define WSM_PSM_FAST_PS (BIT(0) | BIT(7)) -+ -+/* Undetermined */ -+/* Note : Undetermined status is reported when the */ -+/* NULL data frame used to advertise the PM mode to */ -+/* the AP at Pre or Post Background Scan is not Acknowledged */ -+#define WSM_PSM_UNKNOWN BIT(1) -+ -+/* Queue IDs */ -+/* best effort/legacy */ -+#define WSM_QUEUE_BEST_EFFORT (0) -+ -+/* background */ -+#define WSM_QUEUE_BACKGROUND (1) -+ -+/* video */ -+#define WSM_QUEUE_VIDEO (2) -+ -+/* voice */ -+#define WSM_QUEUE_VOICE (3) -+ -+/* HT TX parameters */ -+/* Non-HT */ -+#define WSM_HT_TX_NON_HT (0) -+ -+/* Mixed format */ -+#define WSM_HT_TX_MIXED (1) -+ -+/* Greenfield format */ -+#define WSM_HT_TX_GREENFIELD (2) -+ -+/* STBC allowed */ -+#define WSM_HT_TX_STBC (BIT(7)) -+ -+/* EPTA prioirty flags for BT Coex */ -+/* default epta priority */ -+#define WSM_EPTA_PRIORITY_DEFAULT 4 -+/* use for normal data */ -+#define WSM_EPTA_PRIORITY_DATA 4 -+/* use for connect/disconnect/roaming*/ -+#define WSM_EPTA_PRIORITY_MGT 5 -+/* use for action frames */ -+#define WSM_EPTA_PRIORITY_ACTION 5 -+/* use for AC_VI data */ -+#define WSM_EPTA_PRIORITY_VIDEO 5 -+/* use for AC_VO data */ -+#define WSM_EPTA_PRIORITY_VOICE 6 -+/* use for EAPOL exchange */ -+#define WSM_EPTA_PRIORITY_EAPOL 7 -+ -+/* TX status */ -+/* Frame was sent aggregated */ -+/* Only valid for WSM_SUCCESS status. */ -+#define WSM_TX_STATUS_AGGREGATION (BIT(0)) -+ -+/* Host should requeue this frame later. */ -+/* Valid only when status is WSM_REQUEUE. */ -+#define WSM_TX_STATUS_REQUEUE (BIT(1)) -+ -+/* Normal Ack */ -+#define WSM_TX_STATUS_NORMAL_ACK (0<<2) -+ -+/* No Ack */ -+#define WSM_TX_STATUS_NO_ACK (1<<2) -+ -+/* No explicit acknowledgement */ -+#define WSM_TX_STATUS_NO_EXPLICIT_ACK (2<<2) -+ -+/* Block Ack */ -+/* Only valid for WSM_SUCCESS status. */ -+#define WSM_TX_STATUS_BLOCK_ACK (3<<2) -+ -+/* RX status */ -+/* Unencrypted */ -+#define WSM_RX_STATUS_UNENCRYPTED (0<<0) -+ -+/* WEP */ -+#define WSM_RX_STATUS_WEP (1<<0) -+ -+/* TKIP */ -+#define WSM_RX_STATUS_TKIP (2<<0) -+ -+/* AES */ -+#define WSM_RX_STATUS_AES (3<<0) -+ -+/* WAPI */ -+#define WSM_RX_STATUS_WAPI (4<<0) -+ -+/* Macro to fetch encryption subfield. */ -+#define WSM_RX_STATUS_ENCRYPTION(status) ((status) & 0x07) -+ -+/* Frame was part of an aggregation */ -+#define WSM_RX_STATUS_AGGREGATE (BIT(3)) -+ -+/* Frame was first in the aggregation */ -+#define WSM_RX_STATUS_AGGREGATE_FIRST (BIT(4)) -+ -+/* Frame was last in the aggregation */ -+#define WSM_RX_STATUS_AGGREGATE_LAST (BIT(5)) -+ -+/* Indicates a defragmented frame */ -+#define WSM_RX_STATUS_DEFRAGMENTED (BIT(6)) -+ -+/* Indicates a Beacon frame */ -+#define WSM_RX_STATUS_BEACON (BIT(7)) -+ -+/* Indicates STA bit beacon TIM field */ -+#define WSM_RX_STATUS_TIM (BIT(8)) -+ -+/* Indicates Beacon frame's virtual bitmap contains multicast bit */ -+#define WSM_RX_STATUS_MULTICAST (BIT(9)) -+ -+/* Indicates frame contains a matching SSID */ -+#define WSM_RX_STATUS_MATCHING_SSID (BIT(10)) -+ -+/* Indicates frame contains a matching BSSI */ -+#define WSM_RX_STATUS_MATCHING_BSSI (BIT(11)) -+ -+/* Indicates More bit set in Framectl field */ -+#define WSM_RX_STATUS_MORE_DATA (BIT(12)) -+ -+/* Indicates frame received during a measurement process */ -+#define WSM_RX_STATUS_MEASUREMENT (BIT(13)) -+ -+/* Indicates frame received as an HT packet */ -+#define WSM_RX_STATUS_HT (BIT(14)) -+ -+/* Indicates frame received with STBC */ -+#define WSM_RX_STATUS_STBC (BIT(15)) -+ -+/* Indicates Address 1 field matches dot11StationId */ -+#define WSM_RX_STATUS_ADDRESS1 (BIT(16)) -+ -+/* Indicates Group address present in the Address 1 field */ -+#define WSM_RX_STATUS_GROUP (BIT(17)) -+ -+/* Indicates Broadcast address present in the Address 1 field */ -+#define WSM_RX_STATUS_BROADCAST (BIT(18)) -+ -+/* Indicates group key used with encrypted frames */ -+#define WSM_RX_STATUS_GROUP_KEY (BIT(19)) -+ -+/* Macro to fetch encryption key index. */ -+#define WSM_RX_STATUS_KEY_IDX(status) (((status >> 20)) & 0x0F) -+ -+/* Frame Control field starts at Frame offset + 2 */ -+#define WSM_TX_2BYTES_SHIFT (BIT(7)) -+ -+/* Join mode */ -+/* IBSS */ -+#define WSM_JOIN_MODE_IBSS (0) -+ -+/* BSS */ -+#define WSM_JOIN_MODE_BSS (1) -+ -+/* PLCP preamble type */ -+/* For long preamble */ -+#define WSM_JOIN_PREAMBLE_LONG (0) -+ -+/* For short preamble (Long for 1Mbps) */ -+#define WSM_JOIN_PREAMBLE_SHORT (1) -+ -+/* For short preamble (Long for 1 and 2Mbps) */ -+#define WSM_JOIN_PREAMBLE_SHORT_2 (2) -+ -+/* Join flags */ -+/* Unsynchronized */ -+#define WSM_JOIN_FLAGS_UNSYNCRONIZED BIT(0) -+/* The BSS owner is a P2P GO */ -+#define WSM_JOIN_FLAGS_P2P_GO BIT(1) -+/* Force to join BSS with the BSSID and the -+ * SSID specified without waiting for beacons. The -+ * ProbeForJoin parameter is ignored. */ -+#define WSM_JOIN_FLAGS_FORCE BIT(2) -+/* Give probe request/response higher -+ * priority over the BT traffic */ -+#define WSM_JOIN_FLAGS_PRIO BIT(3) -+ -+/* Key types */ -+#define WSM_KEY_TYPE_WEP_DEFAULT (0) -+#define WSM_KEY_TYPE_WEP_PAIRWISE (1) -+#define WSM_KEY_TYPE_TKIP_GROUP (2) -+#define WSM_KEY_TYPE_TKIP_PAIRWISE (3) -+#define WSM_KEY_TYPE_AES_GROUP (4) -+#define WSM_KEY_TYPE_AES_PAIRWISE (5) -+#define WSM_KEY_TYPE_WAPI_GROUP (6) -+#define WSM_KEY_TYPE_WAPI_PAIRWISE (7) -+ -+/* Key indexes */ -+#define WSM_KEY_MAX_INDEX (10) -+ -+/* ACK policy */ -+#define WSM_ACK_POLICY_NORMAL (0) -+#define WSM_ACK_POLICY_NO_ACK (1) -+ -+/* Start modes */ -+#define WSM_START_MODE_AP (0) /* Mini AP */ -+#define WSM_START_MODE_P2P_GO (1) /* P2P GO */ -+#define WSM_START_MODE_P2P_DEV (2) /* P2P device */ -+ -+/* SetAssociationMode MIB flags */ -+#define WSM_ASSOCIATION_MODE_USE_PREAMBLE_TYPE (BIT(0)) -+#define WSM_ASSOCIATION_MODE_USE_HT_MODE (BIT(1)) -+#define WSM_ASSOCIATION_MODE_USE_BASIC_RATE_SET (BIT(2)) -+#define WSM_ASSOCIATION_MODE_USE_MPDU_START_SPACING (BIT(3)) -+#define WSM_ASSOCIATION_MODE_SNOOP_ASSOC_FRAMES (BIT(4)) -+ -+/* RcpiRssiThreshold MIB flags */ -+#define WSM_RCPI_RSSI_THRESHOLD_ENABLE (BIT(0)) -+#define WSM_RCPI_RSSI_USE_RSSI (BIT(1)) -+#define WSM_RCPI_RSSI_DONT_USE_UPPER (BIT(2)) -+#define WSM_RCPI_RSSI_DONT_USE_LOWER (BIT(3)) -+ -+/* Update-ie constants */ -+#define WSM_UPDATE_IE_BEACON (BIT(0)) -+#define WSM_UPDATE_IE_PROBE_RESP (BIT(1)) -+#define WSM_UPDATE_IE_PROBE_REQ (BIT(2)) -+ -+/* WSM events */ -+/* Error */ -+#define WSM_EVENT_ERROR (0) -+ -+/* BSS lost */ -+#define WSM_EVENT_BSS_LOST (1) -+ -+/* BSS regained */ -+#define WSM_EVENT_BSS_REGAINED (2) -+ -+/* Radar detected */ -+#define WSM_EVENT_RADAR_DETECTED (3) -+ -+/* RCPI or RSSI threshold triggered */ -+#define WSM_EVENT_RCPI_RSSI (4) -+ -+/* BT inactive */ -+#define WSM_EVENT_BT_INACTIVE (5) -+ -+/* BT active */ -+#define WSM_EVENT_BT_ACTIVE (6) -+ -+#define WSM_EVENT_PS_MODE_ERROR (7) -+ -+#define WSM_EVENT_INACTIVITY (9) -+ -+/* MAC Addr Filter */ -+#define WSM_MIB_ID_MAC_ADDR_FILTER 0x1030 -+ -+/* MIB IDs */ -+/* 4.1 dot11StationId */ -+#define WSM_MIB_ID_DOT11_STATION_ID 0x0000 -+ -+/* 4.2 dot11MaxtransmitMsduLifeTime */ -+#define WSM_MIB_ID_DOT11_MAX_TRANSMIT_LIFTIME 0x0001 -+ -+/* 4.3 dot11MaxReceiveLifeTime */ -+#define WSM_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME 0x0002 -+ -+/* 4.4 dot11SlotTime */ -+#define WSM_MIB_ID_DOT11_SLOT_TIME 0x0003 -+ -+/* 4.5 dot11GroupAddressesTable */ -+#define WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE 0x0004 -+#define WSM_MAX_GRP_ADDRTABLE_ENTRIES 8 -+ -+/* 4.6 dot11WepDefaultKeyId */ -+#define WSM_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID 0x0005 -+ -+/* 4.7 dot11CurrentTxPowerLevel */ -+#define WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL 0x0006 -+ -+/* 4.8 dot11RTSThreshold */ -+#define WSM_MIB_ID_DOT11_RTS_THRESHOLD 0x0007 -+ -+/* Huanglu add for firmware debug control */ -+#define WSM_MIB_ID_FW_DEBUG_CONTROL 0x0008 -+ -+/* yangfh add for read/write registers from firmware*/ -+#define WSM_MIB_ID_RW_FW_REG 0x0009 -+ -+/* yangfh add for Set max number of mpdus in a-mpdu*/ -+#define WSM_MIB_ID_SET_AMPDU_NUM 0x000a -+ -+/* Huanglu add for tx-ampdu-len-adaption */ -+#define WSM_MIB_ID_SET_TALA_PARA 0x000b -+ -+/* yangfh add for set TPA param */ -+#define WSM_MIB_ID_SET_TPA_PARAM 0x000c -+ -+/* 4.9 NonErpProtection */ -+#define WSM_MIB_ID_NON_ERP_PROTECTION 0x1000 -+ -+/* 4.10 ArpIpAddressesTable */ -+#define WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE 0x1001 -+#define WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES 1 -+ -+/* 4.11 TemplateFrame */ -+#define WSM_MIB_ID_TEMPLATE_FRAME 0x1002 -+ -+/* 4.12 RxFilter */ -+#define WSM_MIB_ID_RX_FILTER 0x1003 -+ -+/* 4.13 BeaconFilterTable */ -+#define WSM_MIB_ID_BEACON_FILTER_TABLE 0x1004 -+ -+/* 4.14 BeaconFilterEnable */ -+#define WSM_MIB_ID_BEACON_FILTER_ENABLE 0x1005 -+ -+/* 4.15 OperationalPowerMode */ -+#define WSM_MIB_ID_OPERATIONAL_POWER_MODE 0x1006 -+ -+/* 4.16 BeaconWakeUpPeriod */ -+#define WSM_MIB_ID_BEACON_WAKEUP_PERIOD 0x1007 -+ -+/* 4.17 RcpiRssiThreshold */ -+#define WSM_MIB_ID_RCPI_RSSI_THRESHOLD 0x1009 -+ -+/* 4.18 StatisticsTable */ -+#define WSM_MIB_ID_STATISTICS_TABLE 0x100A -+ -+/* 4.19 IbssPsConfig */ -+#define WSM_MIB_ID_IBSS_PS_CONFIG 0x100B -+ -+/* 4.20 CountersTable */ -+#define WSM_MIB_ID_COUNTERS_TABLE 0x100C -+#define WSM_MIB_ID_AMPDUCOUNTERS_TABLE 0x1036 -+#define WSM_MIB_ID_TXPIPE_TABLE 0x1037 -+#define WSM_MIB_ID_BACKOFF_DBG 0x1038 -+#define WSM_MIB_ID_BACKOFF_CTRL 0x1039 -+ -+//add yangfh for requery packet status -+#define WSM_MIB_ID_REQ_PKT_STATUS 0x1040 -+ -+//add yangfh for TPA debug informations -+#define WSM_MIB_ID_TPA_DEBUG_INFO 0x1041 -+ -+//add yangfh for tx power informations -+#define WSM_MIB_ID_TX_POWER_INFO 0x1042 -+ -+//add yangfh for some hardware information -+#define WSM_MIB_ID_HW_INFO 0x1043 -+ -+/* 4.21 BlockAckPolicy */ -+#define WSM_MIB_ID_BLOCK_ACK_POLICY 0x100E -+ -+/* 4.22 OverrideInternalTxRate */ -+#define WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE 0x100F -+ -+/* 4.23 SetAssociationMode */ -+#define WSM_MIB_ID_SET_ASSOCIATION_MODE 0x1010 -+ -+/* 4.24 UpdateEptaConfigData */ -+#define WSM_MIB_ID_UPDATE_EPTA_CONFIG_DATA 0x1011 -+ -+/* 4.25 SelectCcaMethod */ -+#define WSM_MIB_ID_SELECT_CCA_METHOD 0x1012 -+ -+/* 4.26 SetUpasdInformation */ -+#define WSM_MIB_ID_SET_UAPSD_INFORMATION 0x1013 -+ -+/* 4.27 SetAutoCalibrationMode WBF00004073 */ -+#define WSM_MIB_ID_SET_AUTO_CALIBRATION_MODE 0x1015 -+ -+/* 4.28 SetTxRateRetryPolicy */ -+#define WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY 0x1016 -+ -+/* 4.29 SetHostMessageTypeFilter */ -+#define WSM_MIB_ID_SET_HOST_MSG_TYPE_FILTER 0x1017 -+ -+/* 4.30 P2PFindInfo */ -+#define WSM_MIB_ID_P2P_FIND_INFO 0x1018 -+ -+/* 4.31 P2PPsModeInfo */ -+#define WSM_MIB_ID_P2P_PS_MODE_INFO 0x1019 -+ -+/* 4.32 SetEtherTypeDataFrameFilter */ -+#define WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER 0x101A -+ -+/* 4.33 SetUDPPortDataFrameFilter */ -+#define WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER 0x101B -+ -+/* 4.34 SetMagicDataFrameFilter */ -+#define WSM_MIB_ID_SET_MAGIC_DATAFRAME_FILTER 0x101C -+#define WSM_MIB_ID_SET_HOST_SLEEP 0x1050 -+ -+/* This is the end of specification. */ -+ -+/* 4.35 P2PDeviceInfo */ -+#define WSM_MIB_ID_P2P_DEVICE_INFO 0x101D -+ -+/* 4.36 SetWCDMABand */ -+#define WSM_MIB_ID_SET_WCDMA_BAND 0x101E -+ -+/* 4.37 GroupTxSequenceCounter */ -+#define WSM_MIB_ID_GRP_SEQ_COUNTER 0x101F -+ -+/* 4.38 ProtectedMgmtPolicy */ -+#define WSM_MIB_ID_PROTECTED_MGMT_POLICY 0x1020 -+ -+/* 4.39 SetHtProtection */ -+#define WSM_MID_ID_SET_HT_PROTECTION 0x1021 -+ -+/* 4.40 GPIO Command */ -+#define WSM_MIB_ID_GPIO_COMMAND 0x1022 -+ -+/* 4.41 TSF Counter Value */ -+#define WSM_MIB_ID_TSF_COUNTER 0x1023 -+ -+/* Test Purposes Only */ -+#define WSM_MIB_ID_BLOCK_ACK_INFO 0x100D -+ -+/* 4.42 UseMultiTxConfMessage */ -+#define WSM_MIB_USE_MULTI_TX_CONF 0x1024 -+ -+/* 4.43 Keep-alive period */ -+#define WSM_MIB_ID_KEEP_ALIVE_PERIOD 0x1025 -+ -+/* 4.44 Disable BSSID filter */ -+#define WSM_MIB_ID_DISABLE_BSSID_FILTER 0x1026 -+ -+/* Inactivity */ -+#define WSM_MIB_ID_SET_INACTIVITY 0x1035 -+ -+/* MAC Addr Filter */ -+#define WSM_MIB_ID_MAC_ADDR_FILTER 0x1030 -+ -+#ifdef MCAST_FWDING -+/* 4.51 Set Forwarding Offload */ -+#define WSM_MIB_ID_FORWARDING_OFFLOAD 0x1033 -+#endif -+ -+/* Frame template types */ -+#define WSM_FRAME_TYPE_PROBE_REQUEST (0) -+#define WSM_FRAME_TYPE_BEACON (1) -+#define WSM_FRAME_TYPE_NULL (2) -+#define WSM_FRAME_TYPE_QOS_NULL (3) -+#define WSM_FRAME_TYPE_PS_POLL (4) -+#define WSM_FRAME_TYPE_PROBE_RESPONSE (5) -+#define WSM_FRAME_TYPE_ARP_REPLY (6) -+ -+#define WSM_FRAME_GREENFIELD (0x80) /* See 4.11 */ -+ -+/* Status */ -+/* The WSM firmware has completed a request */ -+/* successfully. */ -+#define WSM_STATUS_SUCCESS (0) -+ -+/* This is a generic failure code if other error codes do */ -+/* not apply. */ -+#define WSM_STATUS_FAILURE (1) -+ -+/* A request contains one or more invalid parameters. */ -+#define WSM_INVALID_PARAMETER (2) -+ -+/* The request cannot perform because the device is in */ -+/* an inappropriate mode. */ -+#define WSM_ACCESS_DENIED (3) -+ -+/* The frame received includes a decryption error. */ -+#define WSM_STATUS_DECRYPTFAILURE (4) -+ -+/* A MIC failure is detected in the received packets. */ -+#define WSM_STATUS_MICFAILURE (5) -+ -+/* The transmit request failed due to retry limit being */ -+/* exceeded. */ -+#define WSM_STATUS_RETRY_EXCEEDED (6) -+ -+/* The transmit request failed due to MSDU life time */ -+/* being exceeded. */ -+#define WSM_STATUS_TX_LIFETIME_EXCEEDED (7) -+ -+/* The link to the AP is lost. */ -+#define WSM_STATUS_LINK_LOST (8) -+ -+/* No key was found for the encrypted frame */ -+#define WSM_STATUS_NO_KEY_FOUND (9) -+ -+/* Jammer was detected when transmitting this frame */ -+#define WSM_STATUS_JAMMER_DETECTED (10) -+ -+/* The message should be requeued later. */ -+/* This is applicable only to Transmit */ -+#define WSM_REQUEUE (11) -+ -+/* Advanced filtering options */ -+#define WSM_MAX_FILTER_ELEMENTS (4) -+ -+#define WSM_FILTER_ACTION_IGNORE (0) -+#define WSM_FILTER_ACTION_FILTER_IN (1) -+#define WSM_FILTER_ACTION_FILTER_OUT (2) -+ -+#define WSM_FILTER_PORT_TYPE_DST (0) -+#define WSM_FILTER_PORT_TYPE_SRC (1) -+ -+ -+ -+struct wsm_hdr { -+ __le16 len; -+ __le16 id; -+}; -+ -+#define WSM_TX_SEQ_MAX (7) -+#define WSM_TX_SEQ(seq) \ -+ ((seq & WSM_TX_SEQ_MAX) << 13) -+#define WSM_TX_LINK_ID_MAX (0x0F) -+#define WSM_TX_LINK_ID(link_id) \ -+ ((link_id & WSM_TX_LINK_ID_MAX) << 6) -+ -+#define WSM_TX_IF_ID_MAX (0x0F) -+#define WSM_TX_IF_ID(if_id) \ -+ ((if_id & WSM_TX_IF_ID_MAX) << 6) -+ -+#define MAX_BEACON_SKIP_TIME_MS 1000 -+ -+#ifdef FPGA_SETUP -+#define WSM_CMD_LAST_CHANCE_TIMEOUT (HZ * 9 / 2) -+#else -+#define WSM_CMD_LAST_CHANCE_TIMEOUT (HZ * 20 / 2) -+#endif -+#define WSM_CMD_EXTENDED_TIMEOUT (HZ * 20 / 2) -+ -+#define WSM_RI_GET_PEER_ID_FROM_FLAGS(_f) (((_f)&(0xF<<25)>>25)) -+ -+ -+/* ******************************************************************** */ -+/* WSM capcbility */ -+#define WSM_FW_LABEL 128 -+struct wsm_caps { -+ u16 numInpChBufs; -+ u16 sizeInpChBuf; -+ u16 hardwareId; -+ u16 hardwareSubId; -+ u16 firmwareCap; -+ u16 firmwareType; -+ u16 firmwareApiVer; -+ u16 firmwareBuildNumber; -+ u16 firmwareVersion; -+ char fw_label[WSM_FW_LABEL+2]; -+ int firmwareReady; -+}; -+ -+/* ******************************************************************** */ -+/* WSM commands */ -+ -+struct wsm_tx_power_range { -+ int min_power_level; -+ int max_power_level; -+ u32 stepping; -+}; -+ -+/* 3.1 */ -+struct wsm_configuration { -+ /* [in] */ u32 dot11MaxTransmitMsduLifeTime; -+ /* [in] */ u32 dot11MaxReceiveLifeTime; -+ /* [in] */ u32 dot11RtsThreshold; -+ /* [in, out] */ u8 *dot11StationId; -+ /* [in] */ const void *dpdData; -+ /* [in] */ size_t dpdData_size; -+ /* [out] */ u8 dot11FrequencyBandsSupported; -+ /* [out] */ u32 supportedRateMask; -+ /* [out] */ struct wsm_tx_power_range txPowerRange[2]; -+}; -+ -+int wsm_configuration(struct xradio_common *hw_priv, -+ struct wsm_configuration *arg, -+ int if_id); -+ -+/* 3.3 */ -+struct wsm_reset { -+ /* [in] */ int link_id; -+ /* [in] */ bool reset_statistics; -+}; -+ -+int wsm_reset(struct xradio_common *hw_priv, const struct wsm_reset *arg, -+ int if_id); -+ -+//add by yangfh -+void wsm_query_work(struct work_struct *work); -+ -+/* 3.5 */ -+int wsm_read_mib(struct xradio_common *hw_priv, u16 mibId, void *buf, -+ size_t buf_size, size_t arg_size); -+ -+/* 3.7 */ -+int wsm_write_mib(struct xradio_common *hw_priv, u16 mibId, void *buf, -+ size_t buf_size, int if_id); -+ -+/* 3.9 */ -+struct wsm_ssid { -+ u8 ssid[32]; -+ u32 length; -+}; -+ -+struct wsm_scan_ch { -+ u16 number; -+ u32 minChannelTime; -+ u32 maxChannelTime; -+ u32 txPowerLevel; -+}; -+ -+/* 3.13 */ -+struct wsm_scan_complete { -+ /* WSM_STATUS_... */ -+ u32 status; -+ -+ /* WSM_PSM_... */ -+ u8 psm; -+ -+ /* Number of channels that the scan operation completed. */ -+ u8 numChannels; -+#ifdef ROAM_OFFLOAD -+ u16 reserved; -+#endif /*ROAM_OFFLOAD*/ -+}; -+ -+/* 3.9 */ -+struct wsm_scan { -+ /* WSM_PHY_BAND_... */ -+ /* [in] */ u8 band; -+ -+ /* WSM_SCAN_TYPE_... */ -+ /* [in] */ u8 scanType; -+ -+ /* WSM_SCAN_FLAG_... */ -+ /* [in] */ u8 scanFlags; -+ -+ /* WSM_TRANSMIT_RATE_... */ -+ /* [in] */ u8 maxTransmitRate; -+ -+ /* Interval period in TUs that the device shall the re- */ -+ /* execute the requested scan. Max value supported by the device */ -+ /* is 256s. */ -+ /* [in] */ u32 autoScanInterval; -+ -+ /* Number of probe requests (per SSID) sent to one (1) */ -+ /* channel. Zero (0) means that none is send, which */ -+ /* means that a passive scan is to be done. Value */ -+ /* greater than zero (0) means that an active scan is to */ -+ /* be done. */ -+ /* [in] */ u32 numOfProbeRequests; -+ -+ /* Number of channels to be scanned. */ -+ /* Maximum value is WSM_SCAN_MAX_NUM_OF_CHANNELS. */ -+ /* [in] */ u8 numOfChannels; -+ -+ /* Number of SSID provided in the scan command (this */ -+ /* is zero (0) in broadcast scan) */ -+ /* The maximum number of SSIDs is WSM_SCAN_MAX_NUM_OF_SSIDS. */ -+ /* [in] */ u8 numOfSSIDs; -+ -+ /* The delay time (in microseconds) period */ -+ /* before sending a probe-request. */ -+ /* [in] */ u8 probeDelay; -+ -+ /* SSIDs to be scanned [numOfSSIDs]; */ -+ /* [in] */ struct wsm_ssid *ssids; -+ -+ /* Channels to be scanned [numOfChannels]; */ -+ /* [in] */ struct wsm_scan_ch *ch; -+}; -+ -+int wsm_scan(struct xradio_common *hw_priv, const struct wsm_scan *arg, -+ int if_id); -+ -+/* 3.11 */ -+int wsm_stop_scan(struct xradio_common *hw_priv, int if_id); -+ -+/* 3.14 */ -+struct wsm_tx_confirm { -+ /* Packet identifier used in wsm_tx. */ -+ /* [out] */ u32 packetID; -+ -+ /* WSM_STATUS_... */ -+ /* [out] */ u32 status; -+ -+ /* WSM_TRANSMIT_RATE_... */ -+ /* [out] */ u8 txedRate; -+ -+ /* The number of times the frame was transmitted */ -+ /* without receiving an acknowledgement. */ -+ /* [out] */ u8 ackFailures; -+ -+ /* WSM_TX_STATUS_... */ -+ /* [out] */ u16 flags; -+ -+ //rate feed back, add by yangfh -+ /* [out] */ u32 rate_try[3]; -+ -+ /* The total time in microseconds that the frame spent in */ -+ /* the WLAN device before transmission as completed. */ -+ /* [out] */ u32 mediaDelay; -+ -+ /* The total time in microseconds that the frame spent in */ -+ /* the WLAN device before transmission was started. */ -+ /* [out] */ u32 txQueueDelay; -+ -+ /* [out]*/ u32 link_id; -+ -+ /*[out]*/ int if_id; -+}; -+ -+/* 3.15 */ -+ -+/* Note that ideology of wsm_tx struct is different against the rest of -+ * WSM API. wsm_hdr is /not/ a caller-adapted struct to be used as an input -+ * argument for WSM call, but a prepared bytestream to be sent to firmware. -+ * It is filled partly in xradio_tx, partly in low-level WSM code. -+ * Please pay attention once again: ideology is different. -+ * -+ * Legend: -+ * - [in]: xradio_tx must fill this field. -+ * - [wsm]: the field is filled by low-level WSM. -+ */ -+struct wsm_tx { -+ /* common WSM header */ -+ /* [in/wsm] */ struct wsm_hdr hdr; -+ -+ /* Packet identifier that meant to be used in completion. */ -+ /* [in] */ __le32 packetID; -+ -+ /* WSM_TRANSMIT_RATE_... */ -+ /* [in] */ u8 maxTxRate; -+ -+ /* WSM_QUEUE_... */ -+ /* [in] */ u8 queueId; -+ -+ /* True: another packet is pending on the host for transmission. */ -+ /* [wsm] */ u8 more; -+ -+ /* Bit 0 = 0 - Start expiry time from first Tx attempt (default) */ -+ /* Bit 0 = 1 - Start expiry time from receipt of Tx Request */ -+ /* Bits 3:1 - PTA Priority */ -+ /* Bits 6:4 - Tx Rate Retry Policy */ -+ /* Bit 7 - Reserved */ -+ /* [in] */ u8 flags; -+ -+ /* Should be 0. */ -+ /* [in] */ __le32 reserved; -+ -+ /* The elapsed time in TUs, after the initial transmission */ -+ /* of an MSDU, after which further attempts to transmit */ -+ /* the MSDU shall be terminated. Overrides the global */ -+ /* dot11MaxTransmitMsduLifeTime setting [optional] */ -+ /* Device will set the default value if this is 0. */ -+ /* [wsm] */ __le32 expireTime; -+ -+ /* WSM_HT_TX_... */ -+ /* [in] */ __le32 htTxParameters; -+}; -+ -+/* = sizeof(generic hi hdr) + sizeof(wsm hdr) + sizeof(alignment) */ -+#define WSM_TX_EXTRA_HEADROOM (28) -+ -+/* 3.16 */ -+struct wsm_rx { -+ /* WSM_STATUS_... */ -+ /* [out] */ u32 status; -+ -+ /* Specifies the channel of the received packet. */ -+ /* [out] */ u16 channelNumber; -+ -+ /* WSM_TRANSMIT_RATE_... */ -+ /* [out] */ u8 rxedRate; -+ -+ /* This value is expressed in signed Q8.0 format for */ -+ /* RSSI and unsigned Q7.1 format for RCPI. */ -+ /* [out] */ u8 rcpiRssi; -+ -+ /* WSM_RX_STATUS_... */ -+ /* [out] */ u32 flags; -+ -+ /* An 802.11 frame. */ -+ /* [out] */ void *frame; -+ -+ /* Size of the frame */ -+ /* [out] */ size_t frame_size; -+ -+ /* Link ID */ -+ /* [out] */ int link_id; -+ /* [out] */ int if_id; -+}; -+ -+/* = sizeof(generic hi hdr) + sizeof(wsm hdr) */ -+#define WSM_RX_EXTRA_HEADROOM (16) -+ -+/* 3.17 */ -+struct wsm_event { -+ /* WSM_STATUS_... */ -+ /* [out] */ u32 eventId; -+ -+ /* Indication parameters. */ -+ /* For error indication, this shall be a 32-bit WSM status. */ -+ /* For RCPI or RSSI indication, this should be an 8-bit */ -+ /* RCPI or RSSI value. */ -+ /* [out] */ u32 eventData; -+}; -+ -+struct xradio_wsm_event { -+ struct list_head link; -+ struct wsm_event evt; -+ u8 if_id; -+}; -+ -+/* 3.18 - 3.22 */ -+/* Measurement. Skipped for now. Irrelevent. */ -+ -+ -+/* 3.23 */ -+struct wsm_join { -+ /* WSM_JOIN_MODE_... */ -+ /* [in] */ u8 mode; -+ -+ /* WSM_PHY_BAND_... */ -+ /* [in] */ u8 band; -+ -+ /* Specifies the channel number to join. The channel */ -+ /* number will be mapped to an actual frequency */ -+ /* according to the band */ -+ /* [in] */ u16 channelNumber; -+ -+ /* Specifies the BSSID of the BSS or IBSS to be joined */ -+ /* or the IBSS to be started. */ -+ /* [in] */ u8 bssid[6]; -+ -+ /* ATIM window of IBSS */ -+ /* When ATIM window is zero the initiated IBSS does */ -+ /* not support power saving. */ -+ /* [in] */ u16 atimWindow; -+ -+ /* WSM_JOIN_PREAMBLE_... */ -+ /* [in] */ u8 preambleType; -+ -+ /* Specifies if a probe request should be send with the */ -+ /* specified SSID when joining to the network. */ -+ /* [in] */ u8 probeForJoin; -+ -+ /* DTIM Period (In multiples of beacon interval) */ -+ /* [in] */ u8 dtimPeriod; -+ -+ /* WSM_JOIN_FLAGS_... */ -+ /* [in] */ u8 flags; -+ -+ /* Length of the SSID */ -+ /* [in] */ u32 ssidLength; -+ -+ /* Specifies the SSID of the IBSS to join or start */ -+ /* [in] */ u8 ssid[32]; -+ -+ /* Specifies the time between TBTTs in TUs */ -+ /* [in] */ u32 beaconInterval; -+ -+ /* A bit mask that defines the BSS basic rate set. */ -+ /* [in] */ u32 basicRateSet; -+ -+ /* Minimum transmission power level in units of 0.1dBm */ -+ /* [out] */ int minPowerLevel; -+ -+ /* Maximum transmission power level in units of 0.1dBm */ -+ /* [out] */ int maxPowerLevel; -+}; -+ -+int wsm_join(struct xradio_common *hw_priv, struct wsm_join *arg, int if_id); -+ -+/* 3.25 */ -+struct wsm_set_pm { -+ /* WSM_PSM_... */ -+ /* [in] */ u8 pmMode; -+ -+ /* in unit of 500us; 0 to use default */ -+ /* [in] */ u8 fastPsmIdlePeriod; -+ -+ /* in unit of 500us; 0 to use default */ -+ /* [in] */ u8 apPsmChangePeriod; -+ -+ /* in unit of 500us; 0 to disable auto-pspoll */ -+ /* [in] */ u8 minAutoPsPollPeriod; -+}; -+ -+int wsm_set_pm(struct xradio_common *hw_priv, const struct wsm_set_pm *arg, -+ int if_id); -+ -+/* 3.27 */ -+struct wsm_set_pm_complete { -+ u8 psm; /* WSM_PSM_... */ -+}; -+ -+/* 3.28 */ -+struct wsm_set_bss_params { -+ /* The number of lost consecutive beacons after which */ -+ /* the WLAN device should indicate the BSS-Lost event */ -+ /* to the WLAN host driver. */ -+ u8 beaconLostCount; -+ -+ /* The AID received during the association process. */ -+ u16 aid; -+ -+ /* The operational rate set mask */ -+ u32 operationalRateSet; -+}; -+ -+int wsm_set_bss_params(struct xradio_common *hw_priv, -+ const struct wsm_set_bss_params *arg, int if_id); -+ -+/* 3.30 */ -+struct wsm_add_key { -+ u8 type; /* WSM_KEY_TYPE_... */ -+ u8 entryIndex; /* Key entry index: 0 -- WSM_KEY_MAX_INDEX */ -+ u16 reserved; -+ union { -+ struct { -+ u8 peerAddress[6]; /* MAC address of the -+ * peer station */ -+ u8 reserved; -+ u8 keyLength; /* Key length in bytes */ -+ u8 keyData[16]; /* Key data */ -+ } __packed wepPairwiseKey; -+ struct { -+ u8 keyId; /* Unique per key identifier -+ * (0..3) */ -+ u8 keyLength; /* Key length in bytes */ -+ u16 reserved; -+ u8 keyData[16]; /* Key data */ -+ } __packed wepGroupKey; -+ struct { -+ u8 peerAddress[6]; /* MAC address of the -+ * peer station */ -+ u8 reserved[2]; -+ u8 tkipKeyData[16]; /* TKIP key data */ -+ u8 rxMicKey[8]; /* Rx MIC key */ -+ u8 txMicKey[8]; /* Tx MIC key */ -+ } __packed tkipPairwiseKey; -+ struct { -+ u8 tkipKeyData[16]; /* TKIP key data */ -+ u8 rxMicKey[8]; /* Rx MIC key */ -+ u8 keyId; /* Key ID */ -+ u8 reserved[3]; -+ u8 rxSeqCounter[8]; /* Receive Sequence Counter */ -+ } __packed tkipGroupKey; -+ struct { -+ u8 peerAddress[6]; /* MAC address of the -+ * peer station */ -+ u16 reserved; -+ u8 aesKeyData[16]; /* AES key data */ -+ } __packed aesPairwiseKey; -+ struct { -+ u8 aesKeyData[16]; /* AES key data */ -+ u8 keyId; /* Key ID */ -+ u8 reserved[3]; -+ u8 rxSeqCounter[8]; /* Receive Sequence Counter */ -+ } __packed aesGroupKey; -+ struct { -+ u8 peerAddress[6]; /* MAC address of the -+ * peer station */ -+ u8 keyId; /* Key ID */ -+ u8 reserved; -+ u8 wapiKeyData[16]; /* WAPI key data */ -+ u8 micKeyData[16]; /* MIC key data */ -+ } __packed wapiPairwiseKey; -+ struct { -+ u8 wapiKeyData[16]; /* WAPI key data */ -+ u8 micKeyData[16]; /* MIC key data */ -+ u8 keyId; /* Key ID */ -+ u8 reserved[3]; -+ } __packed wapiGroupKey; -+ } __packed; -+} __packed; -+ -+int wsm_add_key(struct xradio_common *hw_priv, const struct wsm_add_key *arg, -+ int if_id); -+ -+/* 3.32 */ -+struct wsm_remove_key { -+ /* Key entry index : 0-10 */ -+ u8 entryIndex; -+}; -+ -+int wsm_remove_key(struct xradio_common *hw_priv, -+ const struct wsm_remove_key *arg, int if_id); -+ -+/* 3.34 */ -+struct wsm_set_tx_queue_params { -+ /* WSM_ACK_POLICY_... */ -+ u8 ackPolicy; -+ -+ /* Medium Time of TSPEC (in 32us units) allowed per */ -+ /* One Second Averaging Period for this queue. */ -+ u16 allowedMediumTime; -+ -+ /* dot11MaxTransmitMsduLifetime to be used for the */ -+ /* specified queue. */ -+ u32 maxTransmitLifetime; -+}; -+ -+struct wsm_tx_queue_params { -+ /* NOTE: index is a linux queue id. */ -+ struct wsm_set_tx_queue_params params[4]; -+}; -+ -+#define WSM_TX_QUEUE_SET(queue_params, queue, ack_policy, allowed_time, \ -+ max_life_time) \ -+do { \ -+ struct wsm_set_tx_queue_params *p = &(queue_params)->params[queue]; \ -+ p->ackPolicy = (ack_policy); \ -+ p->allowedMediumTime = (allowed_time); \ -+ p->maxTransmitLifetime = (max_life_time); \ -+} while (0) -+ -+int wsm_set_tx_queue_params(struct xradio_common *hw_priv, -+ const struct wsm_set_tx_queue_params *arg, -+ u8 id, int if_id); -+ -+/* 3.36 */ -+struct wsm_edca_queue_params { -+ /* CWmin (in slots) for the access class. */ -+ /* [in] */ u16 cwMin; -+ -+ /* CWmax (in slots) for the access class. */ -+ /* [in] */ u16 cwMax; -+ -+ /* AIFS (in slots) for the access class. */ -+ /* [in] */ u8 aifns; -+ -+ /* TX OP Limit (in microseconds) for the access class. */ -+ /* [in] */ u16 txOpLimit; -+ -+ /* dot11MaxReceiveLifetime to be used for the specified */ -+ /* the access class. Overrides the global */ -+ /* dot11MaxReceiveLifetime value */ -+ /* [in] */ u32 maxReceiveLifetime; -+ -+ /* UAPSD trigger support for the access class. */ -+ /* [in] */ bool uapsdEnable; -+}; -+ -+struct wsm_edca_params { -+ /* NOTE: index is a linux queue id. */ -+ struct wsm_edca_queue_params params[4]; -+}; -+ -+#define TXOP_UNIT 32 -+#define WSM_EDCA_SET(edca, queue, aifs, cw_min, cw_max, txop, life_time,\ -+ uapsd) \ -+ do { \ -+ struct wsm_edca_queue_params *p = &(edca)->params[queue]; \ -+ p->cwMin = (cw_min); \ -+ p->cwMax = (cw_max); \ -+ p->aifns = (aifs); \ -+ p->txOpLimit = ((txop) * TXOP_UNIT); \ -+ p->maxReceiveLifetime = (life_time); \ -+ p->uapsdEnable = (uapsd); \ -+ } while (0) -+ -+int wsm_set_edca_params(struct xradio_common *hw_priv, -+ const struct wsm_edca_params *arg, int if_id); -+ -+int wsm_set_uapsd_param(struct xradio_common *hw_priv, -+ const struct wsm_edca_params *arg); -+ -+/* 3.38 */ -+/* Set-System info. Skipped for now. Irrelevent. */ -+ -+/* 3.40 */ -+struct wsm_switch_channel { -+ /* 1 - means the STA shall not transmit any further */ -+ /* frames until the channel switch has completed */ -+ /* [in] */ u8 channelMode; -+ -+ /* Number of TBTTs until channel switch occurs. */ -+ /* 0 - indicates switch shall occur at any time */ -+ /* 1 - occurs immediately before the next TBTT */ -+ /* [in] */ u8 channelSwitchCount; -+ -+ /* The new channel number to switch to. */ -+ /* Note this is defined as per section 2.7. */ -+ /* [in] */ u16 newChannelNumber; -+}; -+ -+int wsm_switch_channel(struct xradio_common *hw_priv, -+ const struct wsm_switch_channel *arg, int if_id); -+ -+struct wsm_start { -+ /* WSM_START_MODE_... */ -+ /* [in] */ u8 mode; -+ -+ /* WSM_PHY_BAND_... */ -+ /* [in] */ u8 band; -+ -+ /* Channel number */ -+ /* [in] */ u16 channelNumber; -+ -+ /* Client Traffic window in units of TU */ -+ /* Valid only when mode == ..._P2P */ -+ /* [in] */ u32 CTWindow; -+ -+ /* Interval between two consecutive */ -+ /* beacon transmissions in TU. */ -+ /* [in] */ u32 beaconInterval; -+ -+ /* DTIM period in terms of beacon intervals */ -+ /* [in] */ u8 DTIMPeriod; -+ -+ /* WSM_JOIN_PREAMBLE_... */ -+ /* [in] */ u8 preambleType; -+ -+ /* The delay time (in microseconds) period */ -+ /* before sending a probe-request. */ -+ /* [in] */ u8 probeDelay; -+ -+ /* Length of the SSID */ -+ /* [in] */ u8 ssidLength; -+ -+ /* SSID of the BSS or P2P_GO to be started now. */ -+ /* [in] */ u8 ssid[32]; -+ -+ /* The basic supported rates for the MiniAP. */ -+ /* [in] */ u32 basicRateSet; -+}; -+ -+int wsm_start(struct xradio_common *hw_priv, const struct wsm_start *arg, -+ int if_id); -+ -+#if 0 -+struct wsm_beacon_transmit { -+ /* 1: enable; 0: disable */ -+ /* [in] */ u8 enableBeaconing; -+}; -+ -+int wsm_beacon_transmit(struct xradio_common *hw_priv, -+ const struct wsm_beacon_transmit *arg, -+ int if_id); -+#endif -+ -+int wsm_start_find(struct xradio_common *hw_priv, int if_id); -+ -+int wsm_stop_find(struct xradio_common *hw_priv, int if_id); -+ -+struct wsm_suspend_resume { -+ /* See 3.52 */ -+ /* Link ID */ -+ /* [out] */ int link_id; -+ /* Stop sending further Tx requests down to device for this link */ -+ /* [out] */ bool stop; -+ /* Transmit multicast Frames */ -+ /* [out] */ bool multicast; -+ /* The AC on which Tx to be suspended /resumed. */ -+ /* This is applicable only for U-APSD */ -+ /* WSM_QUEUE_... */ -+ /* [out] */ int queue; -+ /* [out] */ int if_id; -+}; -+ -+/* 3.54 Update-IE request. */ -+struct wsm_update_ie { -+ /* WSM_UPDATE_IE_... */ -+ /* [in] */ u16 what; -+ /* [in] */ u16 count; -+ /* [in] */ u8 *ies; -+ /* [in] */ size_t length; -+}; -+ -+int wsm_update_ie(struct xradio_common *hw_priv, -+ const struct wsm_update_ie *arg, int if_id); -+ -+/* 3.56 */ -+struct wsm_map_link { -+ /* MAC address of the remote device */ -+ /* [in] */ u8 mac_addr[6]; -+ /* [in] */ u8 unmap; -+ /* [in] */ u8 link_id; -+}; -+ -+int wsm_map_link(struct xradio_common *hw_priv, const struct wsm_map_link *arg, -+ int if_id); -+ -+#ifdef MCAST_FWDING -+ -+/* 3.65 Give Buffer Request */ -+int wsm_init_release_buffer_request(struct xradio_common *priv, u8 index); -+ -+/* 3.65 fixed memory leakage by yangfh*/ -+int wsm_deinit_release_buffer(struct xradio_common *hw_priv); -+ -+/* 3.67 Request Buffer Request */ -+int wsm_request_buffer_request(struct xradio_vif *priv, -+ u8 *arg); -+#endif -+/* ******************************************************************** */ -+/* MIB shortcats */ -+#define XR_RRM 1 -+#ifdef XR_RRM//RadioResourceMeasurement -+/* RadioResourceMeasurement Request*/ -+#define MEAS_CCA 0 -+#define MEAS_CHANNELLOAD 1 -+typedef struct LMAC_MEAS_CHANNEL_LOAD_PARAMS_S -+{ -+ u8 Reserved; -+ u8 ChannelLoadCCA; -+ u16 ChannelNum; -+ u16 RandomInterval; -+ u16 MeasurementDuration; -+ u32 MeasurementStartTimel; -+ u32 MeasurementStartTimeh; -+}LMAC_MEAS_CHANNEL_LOAD_PARAMS; -+ -+#define MEAS_RPI 0 -+#define MEAS_IPI 1 -+ -+typedef struct LMAC_MEAS_NOISE_HISTOGRAM_PARAMS_S -+{ -+ u8 Reserved; -+ u8 IpiRpi; -+ u16 ChannelNum; -+ u16 RandomInterval; -+ u16 MeasurementDuration; -+ u32 MeasurementStartTimel; -+ u32 MeasurementStartTimeh; -+}LMAC_MEAS_NOISE_HISTOGRAM_PARAMS; -+ -+#define LMAC_MAX_SSIDS 16 -+#define LMAC_MAX_SSID_LENGTH 32 -+typedef struct LMAC_CHANNELS_S -+{ -+ u32 ChannelNum; -+ u32 MinChannelTime; -+ u32 MaxChannelTime; -+ s32 TxPowerLevel; -+}LMAC_CHANNELS; -+ -+typedef struct LMAC_SSIDS_S -+{ -+ u32 SSIDLength; -+ u8 SSID[LMAC_MAX_SSID_LENGTH]; -+}LMAC_SSIDS; -+ -+typedef struct LMAC_MEAS_BEACON_PARAMS_S -+{ -+ //u8 RegulatoryClass; -+ //u8 MeasurementMode; -+ //u16 ChannelNum; -+ u16 RandomInterval; -+ //u16 MeasurementDuration; -+ //u8 Bssid[6]; -+ u16 Reserved; -+ //SCAN_PARAMETERS ScanParameters; -+ u8 Band; -+ u8 ScanType; -+ u8 ScanFlags; -+ u8 MaxTransmitRate; -+ u32 AutoScanInterval; -+ u8 NumOfProbeRequests; -+ u8 NumOfChannels; -+ u8 NumOfSSIDs; -+ u8 ProbeDelay; -+ LMAC_CHANNELS Channels; -+ LMAC_SSIDS Ssids; // here for SCAN_PARAMETER sizing purposes -+}LMAC_MEAS_BEACON_PARAMS; -+ -+typedef struct LMAC_MEAS_STA_STATS_PARAMS_S -+{ -+ u8 PeerMacAddress[6]; -+ u16 RandomInterval; -+ u16 MeasurementDuration; -+ u8 GroupId; -+ u8 Reserved; -+}LMAC_MEAS_STA_STATS_PARAMS; -+ -+typedef struct LMAC_MEAS_LINK_MEASUREMENT_PARAMS_S -+{ -+ u8 Reserved[4]; -+}LMAC_MEAS_LINK_MEASUREMENT_PARAMS; -+ -+typedef union LMAC_MEAS_REQUEST_U -+{ -+ LMAC_MEAS_CHANNEL_LOAD_PARAMS ChannelLoadParams; -+ LMAC_MEAS_NOISE_HISTOGRAM_PARAMS NoisHistogramParams; -+ LMAC_MEAS_BEACON_PARAMS BeaconParams; -+ LMAC_MEAS_STA_STATS_PARAMS StaStatsParams; -+ LMAC_MEAS_LINK_MEASUREMENT_PARAMS LinkMeasurementParams; -+} LMAC_MEAS_REQUEST; -+ -+// This struct is a copy of WSM_HI_START_MEASUREMENT_REQ, except that MsgLen and MsgId is not included -+typedef struct MEASUREMENT_PARAMETERS_S -+{ -+// u16 MsgLen; -+// u16 MsgId; -+ s32 TxPowerLevel; -+ u8 DurationMandatory; -+ u8 MeasurementType; -+ u8 MeasurementRequestLength; -+ u8 Reserved[5]; -+ LMAC_MEAS_REQUEST MeasurementRequest; -+}MEASUREMENT_PARAMETERS; -+ -+/* RadioResourceMeasurement Result*/ -+ typedef struct LMAC_MEAS_CHANNEL_LOAD_RESULTS_S -+{ -+ u8 Reserved; -+ u8 ChannelLoadCCA; -+ u16 ChannelNum; -+ u32 ActualMeasurementStartTimel; -+ u32 ActualMeasurementStartTimeh; -+ u16 MeasurementDuration; -+ u8 CCAbusyFraction; -+ u8 ChannelLoad; -+}LMAC_MEAS_CHANNEL_LOAD_RESULTS; -+ -+typedef struct LMAC_MEAS_NOISE_HISTOGRAM_RESULTS_S -+{ -+ u16 Reserved; -+ u16 ChannelNum; -+ u32 ActualMeasurementStartTimel; -+ u32 ActualMeasurementStartTimeh; -+ u16 MeasurementDuration; -+ u8 AntennaID; -+ u8 IpiRpi; -+ u8 PI_0_Density; -+ u8 PI_1_Density; -+ u8 PI_2_Density; -+ u8 PI_3_Density; -+ u8 PI_4_Density; -+ u8 PI_5_Density; -+ u8 PI_6_Density; -+ u8 PI_7_Density; -+ u8 PI_8_Density; -+ u8 PI_9_Density; -+ u8 PI_10_Density; -+ u8 Reserved2; -+}LMAC_MEAS_NOISE_HISTOGRAM_RESULTS; -+ -+typedef struct LMAC_MEAS_BEACON_RESULTS_S -+{ -+ u16 MeasurementDuration; -+ u16 Reserved; -+ u32 StartTsfl; -+ u32 StartTsfh; -+ u32 Durationl; -+ u32 Durationh; -+ //SCAN_PARAMETERS ScanParameters; -+ u8 Band; -+ u8 ScanType; -+ u8 ScanFlags; -+ u8 MaxTransmitRate; -+ u32 AutoScanInterval; -+ u8 NumOfProbeRequests; -+ u8 NumOfChannels; -+ u8 NumOfSSIDs; -+ u8 ProbeDelay; -+ LMAC_CHANNELS Channels; -+ LMAC_SSIDS Ssids; -+}LMAC_MEAS_BEACON_RESULTS; -+ -+typedef struct LMAC_MEAS_STA_STATS_RESULTS_S -+{ -+ u16 MeasurementDuration; -+ u8 GroupId; -+ u8 StatisticsGroupDataLength; -+ u8 StatisticsGroupData[52]; -+}LMAC_MEAS_STA_STATS_RESULTS; -+ -+typedef struct LMAC_MEAS_LINK_MEASUREMENT_RESULTS_S -+{ -+ s16 TransmitPower; -+ u8 RxAntennaID; -+ u8 TxAntennaID; -+ s32 NoiseLeveldBm; -+ s8 LatestRssi; -+ u8 Reserved1; -+ u8 Reserved2; -+ u8 Reserved3; -+}LMAC_MEAS_LINK_MEASUREMENT_RESULTS; -+ -+typedef union LMAC_MEAS_REPORT_U -+{ -+ LMAC_MEAS_CHANNEL_LOAD_RESULTS ChannelLoadResults; -+ LMAC_MEAS_NOISE_HISTOGRAM_RESULTS NoiseHistogramResults; -+ LMAC_MEAS_BEACON_RESULTS BeaconResults; -+ LMAC_MEAS_STA_STATS_RESULTS StaStatsResults; -+ LMAC_MEAS_LINK_MEASUREMENT_RESULTS LinkMeasurementResults; -+}LMAC_MEAS_REPORT; -+ -+// Note: eMeasurementTypes MUST match the #define WSM_MEASURE_TYPE_XXX from wsm_api.h -+typedef enum { -+ ChannelLoadMeasurement=0, -+ NoiseHistrogramMeasurement, -+ BeaconReport, -+ STAstatisticsReport, -+ LinkMeasurement -+}eMeasurementTypes; -+ -+typedef struct MEASUREMENT_COMPLETE_S -+{ -+// u16 RandomInterval; -+// u16 Reserved0; -+ u8 Dot11PowerMgmtMode; // From here WSM_HI_MEASURE_CMPL_IND and MEASUREMENT_COMPLETE_S must be identical -+ u8 MeasurementType; -+ u16 MoreInd; // Set to 1 if more indications are to follow for this measurement, otherwise 0; -+ u32 Status; -+ u8 MeasurementReportLength; -+ u8 Reserved2[3]; -+ LMAC_MEAS_REPORT MeasurementReport; -+}MEASUREMENT_COMPLETE; // Note: must be 32 bit aligned -+ -+#endif -+int wsm_11k_measure_requset(struct xradio_common *hw_priv, -+ u8 measure_type, -+ u16 ChannelNum, -+ u16 Duration); -+ -+ -+static inline int wsm_set_fw_debug_control(struct xradio_common *hw_priv, -+ int debug_control, int if_id) -+{ -+ __le32 val = __cpu_to_le32(debug_control); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_FW_DEBUG_CONTROL, -+ &val, sizeof(val), if_id); -+} -+ -+static inline int wsm_set_host_sleep(struct xradio_common *hw_priv, -+ u8 host_sleep, int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_HOST_SLEEP, -+ &host_sleep, sizeof(host_sleep), if_id); -+} -+ -+static inline int wsm_set_output_power(struct xradio_common *hw_priv, -+ int power_level, int if_id) -+{ -+ __le32 val = __cpu_to_le32(power_level); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_CURRENT_TX_POWER_LEVEL, -+ &val, sizeof(val), if_id); -+} -+ -+static inline int wsm_set_beacon_wakeup_period(struct xradio_common *hw_priv, -+ unsigned dtim_interval, -+ unsigned listen_interval, -+ int if_id) -+{ -+ struct { -+ u8 numBeaconPeriods; -+ u8 reserved; -+ __le16 listenInterval; -+ } val = { -+ dtim_interval, 0, __cpu_to_le16(listen_interval)}; -+ if (dtim_interval > 0xFF || listen_interval > 0xFFFF) -+ return -EINVAL; -+ else -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_WAKEUP_PERIOD, -+ &val, sizeof(val), if_id); -+} -+ -+struct wsm_rcpi_rssi_threshold { -+ u8 rssiRcpiMode; /* WSM_RCPI_RSSI_... */ -+ u8 lowerThreshold; -+ u8 upperThreshold; -+ u8 rollingAverageCount; -+}; -+ -+static inline int wsm_set_rcpi_rssi_threshold(struct xradio_common *hw_priv, -+ struct wsm_rcpi_rssi_threshold *arg, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_RCPI_RSSI_THRESHOLD, arg, -+ sizeof(*arg), if_id); -+} -+ -+struct wsm_counters_table { -+ __le32 countPlcpErrors; -+ __le32 countFcsErrors; -+ __le32 countTxPackets; -+ __le32 countRxPackets; -+ __le32 countRxPacketErrors; -+ __le32 countRtsSuccess; -+ __le32 countRtsFailures; -+ __le32 countRxFramesSuccess; -+ __le32 countRxDecryptionFailures; -+ __le32 countRxMicFailures; -+ __le32 countRxNoKeyFailures; -+ __le32 countTxMulticastFrames; -+ __le32 countTxFramesSuccess; -+ __le32 countTxFrameFailures; -+ __le32 countTxFramesRetried; -+ __le32 countTxFramesMultiRetried; -+ __le32 countRxFrameDuplicates; -+ __le32 countAckFailures; -+ __le32 countRxMulticastFrames; -+ __le32 countRxCMACICVErrors; -+ __le32 countRxCMACReplays; -+ __le32 countRxMgmtCCMPReplays; -+ __le32 countRxBIPMICErrors; -+}; -+ -+ -+struct wsm_ampducounters_table { -+ u32 countTxAMPDUs; -+ u32 countTxMPDUsInAMPDUs; -+ u32 countTxOctetsInAMPDUs_l32; -+ u32 countTxOctetsInAMPDUs_h32; -+ u32 countRxAMPDUs; -+ u32 countRxMPDUsInAMPDUs; -+ u32 countRxOctetsInAMPDUs_l32; -+ u32 countRxOctetsInAMPDUs_h32; -+ u32 countRxDelimeterCRCErrorCount; -+ u32 countImplictBARFailures; -+ u32 countExplictBARFailures; -+}; -+ -+struct wsm_txpipe_counter { -+ u32 count1; -+ u32 count2; -+ u32 count3; -+ u32 count4; -+ u32 count5; -+ u32 count6; -+ u32 count7; -+ u32 count8; -+ u32 count9; -+ u32 counta; -+}; -+ -+struct wsm_backoff_counter { -+ u32 count0; -+ u32 count1; -+ u32 count2; -+ u32 count3; -+ u32 count4; -+ u32 count5; -+ u32 count6; -+ u32 count7; -+ u32 count8; -+ u32 count9; -+}; -+//add by yangfh for read/write fw registers -+#define WSM_REG_RW_F BIT(0) //0:read, 1:write -+#define WSM_REG_RET_F BIT(1) //results is valid. -+#define WSM_REG_BK_F BIT(4) //operate in block mode. -+ -+struct reg_data { -+ u32 reg_addr; -+ u32 reg_val; -+}; -+ -+typedef struct tag_wsm_reg_w { -+ u16 flag; -+ u16 data_size; -+ struct reg_data arg[16]; -+} WSM_REG_W; -+ -+typedef struct tag_wsm_reg_r { -+ u16 flag; -+ u16 data_size; -+ u32 arg[16]; -+} WSM_REG_R; -+ -+struct wsm_backoff_ctrl { -+ u32 enable; -+ u32 min; -+ u32 max; -+}; -+struct wsm_tala_para { -+ u32 para; -+ u32 thresh; -+}; -+static inline int wsm_get_counters_table(struct xradio_common *hw_priv, -+ struct wsm_counters_table *arg) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_COUNTERS_TABLE, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_get_ampducounters_table(struct xradio_common *hw_priv, -+ struct wsm_ampducounters_table *arg) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_AMPDUCOUNTERS_TABLE, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_get_txpipe_table(struct xradio_common *hw_priv, -+ struct wsm_txpipe_counter *arg) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_TXPIPE_TABLE, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_get_backoff_dbg(struct xradio_common *hw_priv, -+ struct wsm_backoff_counter *arg) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_BACKOFF_DBG, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_set_backoff_ctrl(struct xradio_common *hw_priv, -+ struct wsm_backoff_ctrl *arg) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BACKOFF_CTRL, -+ arg, sizeof(*arg), 0); -+} -+ -+static inline int wsm_set_tala(struct xradio_common *hw_priv, -+ struct wsm_tala_para *arg) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_TALA_PARA, -+ arg, sizeof(*arg), 0); -+} -+static inline int wsm_get_station_id(struct xradio_common *hw_priv, u8 *mac) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_DOT11_STATION_ID, mac, -+ ETH_ALEN, 0); -+} -+ -+struct wsm_rx_filter { -+ bool promiscuous; -+ bool bssid; -+ bool fcs; -+ bool probeResponder; -+ bool keepalive; -+}; -+ -+static inline int wsm_set_rx_filter(struct xradio_common *hw_priv, -+ const struct wsm_rx_filter *arg, -+ int if_id) -+{ -+ __le32 val = 0; -+ if (arg->promiscuous) -+ val |= __cpu_to_le32(BIT(0)); -+ if (arg->bssid) -+ val |= __cpu_to_le32(BIT(1)); -+ if (arg->fcs) -+ val |= __cpu_to_le32(BIT(2)); -+ if (arg->probeResponder) -+ val |= __cpu_to_le32(BIT(3)); -+ if (arg->keepalive) -+ val |= __cpu_to_le32(BIT(4)); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_RX_FILTER, &val, sizeof(val), -+ if_id); -+} -+ -+int wsm_set_probe_responder(struct xradio_vif *priv, bool enable); -+int wsm_set_keepalive_filter(struct xradio_vif *priv, bool enable); -+ -+#define WSM_BEACON_FILTER_IE_HAS_CHANGED BIT(0) -+#define WSM_BEACON_FILTER_IE_NO_LONGER_PRESENT BIT(1) -+#define WSM_BEACON_FILTER_IE_HAS_APPEARED BIT(2) -+ -+struct wsm_beacon_filter_table_entry { -+ u8 ieId; -+ u8 actionFlags; -+ u8 oui[3]; -+ u8 matchData[3]; -+} __packed; -+ -+struct wsm_beacon_filter_table { -+ __le32 numOfIEs; -+ struct wsm_beacon_filter_table_entry entry[10]; -+} __packed; -+ -+static inline int wsm_set_beacon_filter_table(struct xradio_common *hw_priv, -+ struct wsm_beacon_filter_table *ft, -+ int if_id) -+{ -+ size_t size = __le32_to_cpu(ft->numOfIEs) * -+ sizeof(struct wsm_beacon_filter_table_entry) + -+ sizeof(__le32); -+ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_FILTER_TABLE, ft, size, -+ if_id); -+} -+ -+#define WSM_BEACON_FILTER_ENABLE BIT(0) /* Enable/disable beacon filtering */ -+#define WSM_BEACON_FILTER_AUTO_ERP BIT(1) /* If 1 FW will handle ERP IE changes internally */ -+ -+struct wsm_beacon_filter_control { -+ int enabled; -+ int bcn_count; -+}; -+ -+static inline int wsm_beacon_filter_control(struct xradio_common *hw_priv, -+ struct wsm_beacon_filter_control *arg, -+ int if_id) -+{ -+ struct { -+ __le32 enabled; -+ __le32 bcn_count; -+ } val; -+ val.enabled = __cpu_to_le32(arg->enabled); -+ val.bcn_count = __cpu_to_le32(arg->bcn_count); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BEACON_FILTER_ENABLE, &val, -+ sizeof(val), if_id); -+} -+ -+enum wsm_power_mode { -+ wsm_power_mode_active = 0, -+ wsm_power_mode_doze = 1, -+ wsm_power_mode_quiescent = 2, -+}; -+ -+struct wsm_operational_mode { -+ enum wsm_power_mode power_mode; -+ int disableMoreFlagUsage; -+ int performAntDiversity; -+}; -+ -+static const struct wsm_operational_mode defaultoperationalmode = { -+ .power_mode = wsm_power_mode_active, -+ .disableMoreFlagUsage = true, -+}; -+ -+static inline int wsm_set_operational_mode(struct xradio_common *hw_priv, -+ const struct wsm_operational_mode *arg, -+ int if_id) -+{ -+ u32 val = arg->power_mode; -+ -+ if (arg->disableMoreFlagUsage) -+ val |= BIT(4); -+ if (arg->performAntDiversity) -+ val |= BIT(5); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_OPERATIONAL_POWER_MODE, &val, -+ sizeof(val), if_id); -+} -+ -+struct wsm_inactivity { -+ u8 max_inactivity; -+ u8 min_inactivity; -+}; -+ -+static inline int wsm_set_inactivity(struct xradio_common *hw_priv, -+ const struct wsm_inactivity *arg, -+ int if_id) -+{ -+ struct { -+ u8 min_inactive; -+ u8 max_inactive; -+ u16 reserved; -+ } val; -+ -+ val.max_inactive = arg->max_inactivity; -+ val.min_inactive = arg->min_inactivity; -+ val.reserved = 0; -+ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_INACTIVITY, &val, -+ sizeof(val), if_id); -+} -+ -+struct wsm_template_frame { -+ u8 frame_type; -+ u8 rate; -+ bool disable; -+ struct sk_buff *skb; -+}; -+ -+static inline int wsm_set_template_frame(struct xradio_common *hw_priv, -+ struct wsm_template_frame *arg, -+ int if_id) -+{ -+ int ret; -+ u8 *p = skb_push(arg->skb, 4); -+ p[0] = arg->frame_type; -+ p[1] = arg->rate; -+ if (arg->disable) -+ ((u16 *) p)[1] = 0; -+ else -+ ((u16 *) p)[1] = __cpu_to_le16(arg->skb->len - 4); -+ ret = wsm_write_mib(hw_priv, WSM_MIB_ID_TEMPLATE_FRAME, p, -+ arg->skb->len, if_id); -+ skb_pull(arg->skb, 4); -+ return ret; -+} -+ -+ -+struct wsm_protected_mgmt_policy { -+ bool protectedMgmtEnable; -+ bool unprotectedMgmtFramesAllowed; -+ bool encryptionForAuthFrame; -+}; -+ -+static inline int -+wsm_set_protected_mgmt_policy(struct xradio_common *hw_priv, -+ struct wsm_protected_mgmt_policy *arg, -+ int if_id) -+{ -+ __le32 val = 0; -+ int ret; -+ if (arg->protectedMgmtEnable) -+ val |= __cpu_to_le32(BIT(0)); -+ if (arg->unprotectedMgmtFramesAllowed) -+ val |= __cpu_to_le32(BIT(1)); -+ if (arg->encryptionForAuthFrame) -+ val |= __cpu_to_le32(BIT(2)); -+ ret = wsm_write_mib(hw_priv, WSM_MIB_ID_PROTECTED_MGMT_POLICY, &val, -+ sizeof(val), if_id); -+ return ret; -+} -+ -+static inline int wsm_set_block_ack_policy(struct xradio_common *hw_priv, -+ u8 blockAckTxTidPolicy, -+ u8 blockAckRxTidPolicy, -+ int if_id) -+{ -+ struct { -+ u8 blockAckTxTidPolicy; -+ u8 reserved1; -+ u8 blockAckRxTidPolicy; -+ u8 reserved2; -+ } val = { -+ .blockAckTxTidPolicy = blockAckTxTidPolicy, -+ .blockAckRxTidPolicy = blockAckRxTidPolicy, -+ }; -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_BLOCK_ACK_POLICY, &val, -+ sizeof(val), if_id); -+} -+ -+struct wsm_association_mode { -+ u8 flags; /* WSM_ASSOCIATION_MODE_... */ -+ u8 preambleType; /* WSM_JOIN_PREAMBLE_... */ -+ u8 greenfieldMode; /* 1 for greenfield */ -+ u8 mpduStartSpacing; -+ __le32 basicRateSet; -+}; -+ -+static inline int wsm_set_association_mode(struct xradio_common *hw_priv, -+ struct wsm_association_mode *arg, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_ASSOCIATION_MODE, arg, -+ sizeof(*arg), if_id); -+} -+ -+struct wsm_set_tx_rate_retry_policy_header { -+ u8 numTxRatePolicies; -+ u8 reserved[3]; -+} __packed; -+ -+struct wsm_set_tx_rate_retry_policy_policy { -+ u8 policyIndex; -+ u8 shortRetryCount; -+ u8 longRetryCount; -+ u8 policyFlags; -+ u8 rateRecoveryCount; -+ u8 reserved[3]; -+ __le32 rateCountIndices[3]; -+} __packed; -+ -+struct wsm_set_tx_rate_retry_policy { -+ struct wsm_set_tx_rate_retry_policy_header hdr; -+ struct wsm_set_tx_rate_retry_policy_policy tbl[8]; -+} __packed; -+ -+static inline int wsm_set_tx_rate_retry_policy(struct xradio_common *hw_priv, -+ struct wsm_set_tx_rate_retry_policy *arg, -+ int if_id) -+{ -+ size_t size = sizeof(struct wsm_set_tx_rate_retry_policy_header) + -+ arg->hdr.numTxRatePolicies * -+ sizeof(struct wsm_set_tx_rate_retry_policy_policy); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, -+ size, if_id); -+} -+ -+/* 4.32 SetEtherTypeDataFrameFilter */ -+struct wsm_ether_type_filter_hdr { -+ u8 nrFilters; /* Up to WSM_MAX_FILTER_ELEMENTS */ -+ u8 reserved[3]; -+} __packed; -+ -+struct wsm_ether_type_filter { -+ u8 filterAction; /* WSM_FILTER_ACTION_XXX */ -+ u8 reserved; -+ __le16 etherType; /* Type of ethernet frame */ -+} __packed; -+ -+static inline int wsm_set_ether_type_filter(struct xradio_common *hw_priv, -+ struct wsm_ether_type_filter_hdr *arg, -+ int if_id) -+{ -+ size_t size = sizeof(struct wsm_ether_type_filter_hdr) + -+ arg->nrFilters * sizeof(struct wsm_ether_type_filter); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_ETHERTYPE_DATAFRAME_FILTER, -+ arg, size, if_id); -+} -+ -+ -+/* 4.33 SetUDPPortDataFrameFilter */ -+struct wsm_udp_port_filter_hdr { -+ u8 nrFilters; /* Up to WSM_MAX_FILTER_ELEMENTS */ -+ u8 reserved[3]; -+} __packed; -+ -+struct wsm_udp_port_filter { -+ u8 filterAction; /* WSM_FILTER_ACTION_XXX */ -+ u8 portType; /* WSM_FILTER_PORT_TYPE_XXX */ -+ __le16 udpPort; /* Port number */ -+} __packed; -+ -+static inline int wsm_set_udp_port_filter(struct xradio_common *hw_priv, -+ struct wsm_udp_port_filter_hdr *arg, -+ int if_id) -+{ -+ size_t size = sizeof(struct wsm_udp_port_filter_hdr) + -+ arg->nrFilters * sizeof(struct wsm_udp_port_filter); -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_UDPPORT_DATAFRAME_FILTER, -+ arg, size, if_id); -+} -+ -+/* Undocumented MIBs: */ -+/* 4.35 P2PDeviceInfo */ -+#define D11_MAX_SSID_LEN (32) -+ -+struct wsm_p2p_device_type { -+ __le16 categoryId; -+ u8 oui[4]; -+ __le16 subCategoryId; -+} __packed; -+ -+struct wsm_p2p_device_info { -+ struct wsm_p2p_device_type primaryDevice; -+ u8 reserved1[3]; -+ u8 devNameSize; -+ u8 localDevName[D11_MAX_SSID_LEN]; -+ u8 reserved2[3]; -+ u8 numSecDevSupported; -+ struct wsm_p2p_device_type secondaryDevices[0]; -+} __packed; -+ -+/* 4.36 SetWCDMABand - WO */ -+struct wsm_cdma_band { -+ u8 WCDMA_Band; -+ u8 reserved[3]; -+} __packed; -+ -+/* 4.37 GroupTxSequenceCounter - RO */ -+struct wsm_group_tx_seq { -+ __le32 bits_47_16; -+ __le16 bits_15_00; -+ __le16 reserved; -+} __packed; -+ -+/* 4.39 SetHtProtection - WO */ -+#define WSM_DUAL_CTS_PROT_ENB (1 << 0) -+#define WSM_NON_GREENFIELD_STA PRESENT(1 << 1) -+#define WSM_HT_PROT_MODE__NO_PROT (0 << 2) -+#define WSM_HT_PROT_MODE__NON_MEMBER (1 << 2) -+#define WSM_HT_PROT_MODE__20_MHZ (2 << 2) -+#define WSM_HT_PROT_MODE__NON_HT_MIXED (3 << 2) -+#define WSM_LSIG_TXOP_PROT_FULL (1 << 4) -+#define WSM_LARGE_L_LENGTH_PROT (1 << 5) -+ -+struct wsm_ht_protection { -+ __le32 flags; -+} __packed; -+ -+/* 4.40 GPIO Command - R/W */ -+#define WSM_GPIO_COMMAND_SETUP 0 -+#define WSM_GPIO_COMMAND_READ 1 -+#define WSM_GPIO_COMMAND_WRITE 2 -+#define WSM_GPIO_COMMAND_RESET 3 -+#define WSM_GPIO_ALL_PINS 0xFF -+ -+struct wsm_gpio_command { -+ u8 GPIO_Command; -+ u8 pin; -+ __le16 config; -+} __packed; -+ -+/* 4.41 TSFCounter - RO */ -+struct wsm_tsf_counter { -+ __le64 TSF_Counter; -+} __packed; -+ -+/* 4.43 Keep alive period */ -+struct wsm_keep_alive_period { -+ __le16 keepAlivePeriod; -+ u8 reserved[2]; -+} __packed; -+ -+static inline int wsm_keep_alive_period(struct xradio_common *hw_priv, -+ int period, int if_id) -+{ -+ struct wsm_keep_alive_period arg = { -+ .keepAlivePeriod = __cpu_to_le16(period), -+ }; -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_KEEP_ALIVE_PERIOD, -+ &arg, sizeof(arg), if_id); -+}; -+ -+/* BSSID filtering */ -+struct wsm_set_bssid_filtering { -+ u8 filter; -+ u8 reserved[3]; -+} __packed; -+ -+static inline int wsm_set_bssid_filtering(struct xradio_common *hw_priv, -+ bool enabled, int if_id) -+{ -+ struct wsm_set_bssid_filtering arg = { -+ .filter = !enabled, -+ }; -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_DISABLE_BSSID_FILTER, -+ &arg, sizeof(arg), if_id); -+} -+ -+/* Multicat filtering - 4.5 */ -+struct wsm_multicast_filter { -+ __le32 enable; -+ __le32 numOfAddresses; -+ u8 macAddress[WSM_MAX_GRP_ADDRTABLE_ENTRIES][ETH_ALEN]; -+} __packed; -+ -+/* Mac Addr Filter Info */ -+struct wsm_mac_addr_info { -+ u8 filter_mode; -+ u8 address_mode; -+ u8 MacAddr[6]; -+} __packed; -+ -+/* Mac Addr Filter */ -+struct wsm_mac_addr_filter { -+ u8 numfilter; -+ u8 action_mode; -+ u8 Reserved[2]; -+ struct wsm_mac_addr_info macaddrfilter[0]; -+} __packed; -+ -+/* Broadcast Addr Filter */ -+struct wsm_broadcast_addr_filter { -+ u8 action_mode; -+ u8 nummacaddr; -+ u8 filter_mode; -+ u8 address_mode; -+ u8 MacAddr[6]; -+} __packed; -+ -+static inline int wsm_set_multicast_filter(struct xradio_common *hw_priv, -+ struct wsm_multicast_filter *fp, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_DOT11_GROUP_ADDRESSES_TABLE, -+ fp, sizeof(*fp), if_id); -+} -+ -+/* ARP IPv4 filtering - 4.10 */ -+struct wsm_arp_ipv4_filter { -+ __le32 enable; -+ __be32 ipv4Address[WSM_MAX_ARP_IP_ADDRTABLE_ENTRIES]; -+} __packed; -+ -+ -+static inline int wsm_set_arp_ipv4_filter(struct xradio_common *hw_priv, -+ struct wsm_arp_ipv4_filter *fp, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_ARP_IP_ADDRESSES_TABLE, -+ fp, sizeof(*fp), if_id); -+} -+ -+/* P2P Power Save Mode Info - 4.31 */ -+struct wsm_p2p_ps_modeinfo { -+ u8 oppPsCTWindow; -+ u8 count; -+ u8 reserved; -+ u8 dtimCount; -+ __le32 duration; -+ __le32 interval; -+ __le32 startTime; -+} __packed; -+ -+static inline int wsm_set_p2p_ps_modeinfo(struct xradio_common *hw_priv, -+ struct wsm_p2p_ps_modeinfo *mi, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_P2P_PS_MODE_INFO, -+ mi, sizeof(*mi), if_id); -+} -+ -+static inline int wsm_get_p2p_ps_modeinfo(struct xradio_common *hw_priv, -+ struct wsm_p2p_ps_modeinfo *mi) -+{ -+ return wsm_read_mib(hw_priv, WSM_MIB_ID_P2P_PS_MODE_INFO, -+ mi, sizeof(*mi), 0); -+} -+ -+/* UseMultiTxConfMessage */ -+ -+static inline int wsm_use_multi_tx_conf(struct xradio_common *hw_priv, -+ bool enabled, int if_id) -+{ -+ __le32 arg = enabled ? __cpu_to_le32(1) : 0; -+ -+ return wsm_write_mib(hw_priv, WSM_MIB_USE_MULTI_TX_CONF, -+ &arg, sizeof(arg), if_id); -+} -+ -+ -+/* 4.26 SetUpasdInformation */ -+struct wsm_uapsd_info { -+ __le16 uapsdFlags; -+ __le16 minAutoTriggerInterval; -+ __le16 maxAutoTriggerInterval; -+ __le16 autoTriggerStep; -+}; -+ -+static inline int wsm_set_uapsd_info(struct xradio_common *hw_priv, -+ struct wsm_uapsd_info *arg, -+ int if_id) -+{ -+ /* TODO:COMBO:UAPSD will be supported only on one interface */ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_SET_UAPSD_INFORMATION, -+ arg, sizeof(*arg), if_id); -+} -+ -+/* 4.22 OverrideInternalTxRate */ -+struct wsm_override_internal_txrate { -+ u8 internalTxRate; -+ u8 nonErpInternalTxRate; -+ u8 reserved[2]; -+} __packed; -+ -+static inline int -+wsm_set_override_internal_txrate(struct xradio_common *hw_priv, -+ struct wsm_override_internal_txrate *arg, -+ int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_OVERRIDE_INTERNAL_TX_RATE, -+ arg, sizeof(*arg), if_id); -+} -+#ifdef MCAST_FWDING -+/* 4.51 SetForwardingOffload */ -+struct wsm_forwarding_offload { -+ u8 fwenable; -+ u8 flags; -+ u8 reserved[2]; -+} __packed; -+ -+static inline int wsm_set_forwarding_offlad(struct xradio_common *hw_priv, -+ struct wsm_forwarding_offload *arg,int if_id) -+{ -+ return wsm_write_mib(hw_priv, WSM_MIB_ID_FORWARDING_OFFLOAD, -+ arg, sizeof(*arg),if_id); -+} -+ -+#endif -+/* ******************************************************************** */ -+/* WSM TX port control */ -+ -+void wsm_lock_tx(struct xradio_common *hw_priv); -+void wsm_vif_lock_tx(struct xradio_vif *priv); -+void wsm_lock_tx_async(struct xradio_common *hw_priv); -+bool wsm_flush_tx(struct xradio_common *hw_priv); -+bool wsm_vif_flush_tx(struct xradio_vif *priv); -+void wsm_unlock_tx(struct xradio_common *hw_priv); -+ -+/* ******************************************************************** */ -+/* WSM / BH API */ -+ -+int wsm_handle_exception(struct xradio_common *hw_priv, u8 * data, size_t len); -+int wsm_handle_rx(struct xradio_common *hw_priv, int id, struct wsm_hdr *wsm, -+ struct sk_buff **skb_p); -+void wms_send_deauth_to_self(struct xradio_common *hw_priv, struct xradio_vif *priv); -+void wms_send_disassoc_to_self(struct xradio_common *hw_priv, struct xradio_vif *priv); -+ -+/* ******************************************************************** */ -+/* wsm_buf API */ -+ -+struct wsm_buf { -+ u8 *begin; -+ u8 *data; -+ u8 *end; -+}; -+ -+void wsm_buf_init(struct wsm_buf *buf); -+void wsm_buf_deinit(struct wsm_buf *buf); -+ -+/* ******************************************************************** */ -+/* wsm_cmd API */ -+ -+struct wsm_cmd { -+ spinlock_t lock; -+ int done; -+ u8 *ptr; -+ size_t len; -+ void *arg; -+ int ret; -+ u16 cmd; -+}; -+ -+/* ******************************************************************** */ -+/* WSM TX buffer access */ -+ -+int wsm_get_tx(struct xradio_common *hw_priv, u8 **data, -+ size_t *tx_len, int *burst, int *vif_selected); -+void wsm_txed(struct xradio_common *hw_priv, u8 *data); -+ -+/* ******************************************************************** */ -+/* Queue mapping: WSM <---> linux */ -+/* Linux: VO VI BE BK */ -+/* WSM: BE BK VI VO */ -+ -+static inline u8 wsm_queue_id_to_linux(u8 queueId) -+{ -+ static const u8 queue_mapping[] = { -+ 2, 3, 1, 0 -+ }; -+ return queue_mapping[queueId]; -+} -+ -+static inline u8 wsm_queue_id_to_wsm(u8 queueId) -+{ -+ static const u8 queue_mapping[] = { -+ 3, 2, 0, 1 -+ }; -+ return queue_mapping[queueId]; -+} -+ -+#endif /* XRADIO_HWIO_H_INCLUDED */ -diff --git a/drivers/net/wireless/xradio/xradio.h b/drivers/net/wireless/xradio/xradio.h -new file mode 100644 -index 0000000..d565db0 ---- /dev/null -+++ b/drivers/net/wireless/xradio/xradio.h -@@ -0,0 +1,577 @@ -+/* -+ * Common define of private data for XRadio drivers -+ * -+ * Copyright (c) 2013, XRadio -+ * Author: XRadio -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#ifndef XRADIO_H -+#define XRADIO_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+//Macroses for Driver parameters. -+#define XRWL_MAX_QUEUE_SZ (128) -+#define AC_QUEUE_NUM 4 -+ -+#define XRWL_MAX_VIFS (2) -+#define XRWL_GENERIC_IF_ID (2) -+#define XRWL_HOST_VIF0_11N_THROTTLE (58) //(XRWL_MAX_QUEUE_SZ/(XRWL_MAX_VIFS-1))*0.9 -+#define XRWL_HOST_VIF1_11N_THROTTLE (58) //(XRWL_MAX_QUEUE_SZ/(XRWL_MAX_VIFS-1))*0.9 -+#define XRWL_HOST_VIF0_11BG_THROTTLE (35) //XRWL_HOST_VIF0_11N_THROTTLE*0.6 = 35 -+#define XRWL_HOST_VIF1_11BG_THROTTLE (35) //XRWL_HOST_VIF0_11N_THROTTLE*0.6 = 35 -+#if 0 -+#define XRWL_FW_VIF0_THROTTLE (15) -+#define XRWL_FW_VIF1_THROTTLE (15) -+#endif -+ -+#define IEEE80211_FCTL_WEP 0x4000 -+#define IEEE80211_QOS_DATAGRP 0x0080 -+#define WSM_KEY_MAX_IDX 20 -+ -+#include "queue.h" -+#include "wsm.h" -+#include "scan.h" -+#include "tx.h" -+#include "ht.h" -+#include "pm.h" -+#include "fwio.h" -+ -+/* #define ROC_DEBUG */ -+/* hidden ssid is only supported when separate probe resp IE -+ configuration is supported */ -+#ifdef PROBE_RESP_EXTRA_IE -+#define HIDDEN_SSID 1 -+#endif -+ -+#define XRADIO_MAX_CTRL_FRAME_LEN (0x1000) -+ -+#define MAX_STA_IN_AP_MODE (14) -+#define WLAN_LINK_ID_MAX (MAX_STA_IN_AP_MODE + 3) -+ -+#define XRADIO_MAX_STA_IN_AP_MODE (5) -+#define XRADIO_MAX_REQUEUE_ATTEMPTS (5) -+#define XRADIO_LINK_ID_UNMAPPED (15) -+#define XRADIO_MAX_TID (8) -+ -+#define XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID (0x3F) -+#define XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID (0x3F) -+#define XRADIO_RX_BLOCK_ACK_ENABLED_FOR_BE_TID \ -+ (XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID & 0x01) -+#define XRADIO_TX_BLOCK_ACK_DISABLED_FOR_ALL_TID (0) -+#define XRADIO_RX_BLOCK_ACK_DISABLED_FOR_ALL_TID (0) -+ -+#define XRADIO_BLOCK_ACK_CNT (30) -+#define XRADIO_BLOCK_ACK_THLD (800) -+#define XRADIO_BLOCK_ACK_HIST (3) -+#define XRADIO_BLOCK_ACK_INTERVAL (1 * HZ / XRADIO_BLOCK_ACK_HIST) -+#define XRWL_ALL_IFS (-1) -+ -+#ifdef ROAM_OFFLOAD -+#define XRADIO_SCAN_TYPE_ACTIVE 0x1000 -+#define XRADIO_SCAN_BAND_5G 0x2000 -+#endif /*ROAM_OFFLOAD*/ -+ -+#define IEEE80211_FCTL_WEP 0x4000 -+#define IEEE80211_QOS_DATAGRP 0x0080 -+ -+#ifdef MCAST_FWDING -+#define WSM_MAX_BUF 30 -+#endif -+ -+#define MAX_RATES_STAGE 8 // -+#define MAX_RATES_RETRY 15 -+ -+#define XRADIO_WORKQUEUE "xradio_wq" -+#define WIFI_CONF_PATH "/data/xr_wifi.conf" -+ -+/* extern */ struct task_struct; -+/* extern */ struct xradio_debug_priv; -+/* extern */ struct xradio_debug_common; -+/* extern */ struct firmware; -+ -+/* Please keep order */ -+enum xradio_join_status { -+ XRADIO_JOIN_STATUS_PASSIVE = 0, -+ XRADIO_JOIN_STATUS_MONITOR, -+ XRADIO_JOIN_STATUS_STA, -+ XRADIO_JOIN_STATUS_AP, -+}; -+ -+enum xradio_link_status { -+ XRADIO_LINK_OFF, -+ XRADIO_LINK_RESERVE, -+ XRADIO_LINK_SOFT, -+ XRADIO_LINK_HARD, -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ XRADIO_LINK_RESET, -+ XRADIO_LINK_RESET_REMAP, -+#endif -+}; -+ -+enum xradio_bss_loss_status { -+ XRADIO_BSS_LOSS_NONE, -+ XRADIO_BSS_LOSS_CHECKING, -+ XRADIO_BSS_LOSS_CONFIRMING, -+ XRADIO_BSS_LOSS_CONFIRMED, -+}; -+ -+struct xradio_link_entry { -+ unsigned long timestamp; -+ enum xradio_link_status status; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ enum xradio_link_status prev_status; -+#endif -+ u8 mac[ETH_ALEN]; -+ u8 buffered[XRADIO_MAX_TID]; -+ struct sk_buff_head rx_queue; -+}; -+ -+#if defined(ROAM_OFFLOAD) -+struct xradio_testframe { -+ u8 len; -+ u8 *data; -+}; -+#endif -+ -+struct xradio_common { -+ struct xradio_debug_common *debug; -+ struct xradio_queue tx_queue[AC_QUEUE_NUM]; -+ struct xradio_queue_stats tx_queue_stats; -+ -+ struct ieee80211_hw *hw; -+ struct mac_address addresses[XRWL_MAX_VIFS]; -+ -+ /*Will be a pointer to a list of VIFs - Dynamically allocated */ -+ struct ieee80211_vif *vif_list[XRWL_MAX_VIFS]; -+ atomic_t num_vifs; -+ spinlock_t vif_list_lock; -+ u32 if_id_slot; -+ struct device *pdev; -+ struct workqueue_struct *workqueue; -+ -+ struct mutex conf_mutex; -+ -+ struct sdio_func *sdio_func; -+ int driver_ready; -+ -+ /* HW/FW type (HIF_...) */ -+ int hw_type; -+ int hw_revision; -+ int fw_revision; -+ -+ /* firmware/hardware info */ -+ unsigned int tx_hdr_len; -+ -+ /* Radio data */ -+ int output_power; -+ int noise; -+ -+ /* calibration, output power limit and rssi<->dBm conversation data */ -+ -+ /* BBP/MAC state */ -+ const struct firmware *sdd; -+ struct ieee80211_rate *rates; -+ struct ieee80211_rate *mcs_rates; -+ u8 mac_addr[ETH_ALEN]; -+ /*TODO:COMBO: To be made per VIFF after mac80211 support */ -+ struct ieee80211_channel *channel; -+ int channel_switch_in_progress; -+ wait_queue_head_t channel_switch_done; -+ u8 channel_changed; //add by yangfh 2015-5-15 16:57:38. -+ u8 long_frame_max_tx_count; -+ u8 short_frame_max_tx_count; -+ /* TODO:COMBO: According to Hong aggregation will happen per VIFF. -+ * Keeping in common structure for the time being. Will be moved to VIFF -+ * after the mechanism is clear */ -+ u8 ba_tid_mask; -+ int ba_acc; /*TODO: Same as above */ -+ int ba_cnt; /*TODO: Same as above */ -+ int ba_cnt_rx; /*TODO: Same as above */ -+ int ba_acc_rx; /*TODO: Same as above */ -+ int ba_hist; /*TODO: Same as above */ -+ struct timer_list ba_timer;/*TODO: Same as above */ -+ spinlock_t ba_lock; /*TODO: Same as above */ -+ bool ba_ena; /*TODO: Same as above */ -+ struct work_struct ba_work; /*TODO: Same as above */ -+ struct xradio_pm_state pm_state; -+ bool is_BT_Present; -+ bool is_go_thru_go_neg; -+ u8 conf_listen_interval; -+ -+ /* BH */ -+ atomic_t bh_tx; -+ atomic_t bh_term; -+ atomic_t bh_suspend; -+ struct task_struct *bh_thread; -+ int bh_error; -+ wait_queue_head_t bh_wq; -+ wait_queue_head_t bh_evt_wq; -+ -+ -+ int buf_id_tx; /* byte */ -+ int buf_id_rx; /* byte */ -+ int wsm_rx_seq; /* byte */ -+ int wsm_tx_seq; /* byte */ -+ int hw_bufs_used; -+ int hw_bufs_used_vif[XRWL_MAX_VIFS]; -+ struct sk_buff *skb_cache; -+ struct sk_buff *skb_reserved; -+ int skb_resv_len; -+ bool powersave_enabled; -+ bool device_can_sleep; -+ /* Keep xradio awake (WUP = 1) 1 second after each scan to avoid -+ * FW issue with sleeping/waking up. */ -+ atomic_t recent_scan; -+ long connet_time[XRWL_MAX_VIFS]; -+#ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF -+ atomic_t suspend_state; -+#endif -+ -+ /* WSM */ -+ struct wsm_caps wsm_caps; -+ struct mutex wsm_cmd_mux; -+ struct wsm_buf wsm_cmd_buf; -+ struct wsm_cmd wsm_cmd; -+ wait_queue_head_t wsm_cmd_wq; -+ wait_queue_head_t wsm_startup_done; -+ struct semaphore tx_lock_sem; -+ atomic_t tx_lock; -+ u32 pending_frame_id; -+ -+ /* WSM debug */ -+ u32 query_packetID; -+ atomic_t query_cnt; -+ struct work_struct query_work; /* for query packet */ -+ -+ /* Scan status */ -+ struct xradio_scan scan; -+ -+ /* TX/RX */ -+ unsigned long rx_timestamp; -+ -+ /* WSM events */ -+ spinlock_t event_queue_lock; -+ struct list_head event_queue; -+ struct work_struct event_handler; -+ -+ /* TX rate policy cache */ -+ struct tx_policy_cache tx_policy_cache; -+ struct work_struct tx_policy_upload_work; -+ atomic_t upload_count; -+ -+ /* cryptographic engine information */ -+ -+ /* bit field of glowing LEDs */ -+ u16 softled_state; -+ -+ /* statistics */ -+ struct ieee80211_low_level_stats stats; -+ -+ struct xradio_ht_oper ht_oper; -+ int tx_burst_idx; -+ -+ struct ieee80211_iface_limit if_limits1[2]; -+ struct ieee80211_iface_limit if_limits2[2]; -+ struct ieee80211_iface_limit if_limits3[2]; -+ struct ieee80211_iface_combination if_combs[3]; -+ -+ struct mutex wsm_oper_lock; -+ struct delayed_work rem_chan_timeout; -+ atomic_t remain_on_channel; -+ int roc_if_id; -+ u64 roc_cookie; -+ wait_queue_head_t offchannel_wq; -+ u16 offchannel_done; -+ u16 prev_channel; -+ int if_id_selected; -+ u32 key_map; -+ struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1]; -+#ifdef MCAST_FWDING -+ struct wsm_buf wsm_release_buf[WSM_MAX_BUF]; -+ u8 buf_released; -+#endif -+#ifdef ROAM_OFFLOAD -+ u8 auto_scanning; -+ u8 frame_rcvd; -+ u8 num_scanchannels; -+ u8 num_2g_channels; -+ u8 num_5g_channels; -+ struct wsm_scan_ch scan_channels[48]; -+ struct sk_buff *beacon; -+ struct sk_buff *beacon_bkp; -+ struct xradio_testframe testframe; -+#endif /*ROAM_OFFLOAD*/ -+ -+ u8 connected_sta_cnt; -+ u16 vif0_throttle; -+ u16 vif1_throttle; -+}; -+ -+/* Virtual Interface State. One copy per VIF */ -+struct xradio_vif { -+ atomic_t enabled; -+ spinlock_t vif_lock; -+ int if_id; -+ /*TODO: Split into Common and VIF parts */ -+ struct xradio_debug_priv *debug; -+ /* BBP/MAC state */ -+ u8 bssid[ETH_ALEN]; -+ struct wsm_edca_params edca; -+ struct wsm_tx_queue_params tx_queue_params; -+ struct wsm_association_mode association_mode; -+ struct wsm_set_bss_params bss_params; -+ struct wsm_set_pm powersave_mode; -+ struct wsm_set_pm firmware_ps_mode; -+ int power_set_true; -+ int user_power_set_true; -+ u8 user_pm_mode; -+ int cqm_rssi_thold; -+ unsigned cqm_rssi_hyst; -+ unsigned cqm_tx_failure_thold; -+ unsigned cqm_tx_failure_count; -+ bool cqm_use_rssi; -+ int cqm_link_loss_count; -+ int cqm_beacon_loss_count; -+ int mode; -+ bool enable_beacon; -+ int beacon_int; -+ size_t ssid_length; -+ u8 ssid[IEEE80211_MAX_SSID_LEN]; -+#ifdef HIDDEN_SSID -+ bool hidden_ssid; -+#endif -+ bool listening; -+ struct wsm_rx_filter rx_filter; -+ struct wsm_beacon_filter_table bf_table; -+ struct wsm_beacon_filter_control bf_control; -+ struct wsm_multicast_filter multicast_filter; -+ bool has_multicast_subscription; -+ struct wsm_broadcast_addr_filter broadcast_filter; -+ bool disable_beacon_filter; -+ struct wsm_arp_ipv4_filter filter4; -+ struct work_struct update_filtering_work; -+ struct work_struct set_beacon_wakeup_period_work; -+ struct xradio_pm_state_vif pm_state_vif; -+ /*TODO: Add support in mac80211 for psmode info per VIF */ -+ struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo; -+ struct wsm_uapsd_info uapsd_info; -+ bool setbssparams_done; -+ u32 listen_interval; -+ u32 erp_info; -+ bool powersave_enabled; -+ -+ /* WSM Join */ -+ enum xradio_join_status join_status; -+ u8 join_bssid[ETH_ALEN]; -+ struct work_struct join_work; -+ struct delayed_work join_timeout; -+ struct work_struct unjoin_work; -+ struct work_struct offchannel_work; -+ int join_dtim_period; -+ atomic_t delayed_unjoin; -+ -+ /* Security */ -+ s8 wep_default_key_id; -+ struct work_struct wep_key_work; -+ unsigned long rx_timestamp; -+ u32 cipherType; -+ -+ -+ /* AP powersave */ -+ u32 link_id_map; -+ u32 max_sta_ap_mode; -+ u32 link_id_after_dtim; -+ u32 link_id_uapsd; -+ u32 link_id_max; -+ u32 wsm_key_max_idx; -+ struct xradio_link_entry link_id_db[MAX_STA_IN_AP_MODE]; -+ struct work_struct link_id_work; -+ struct delayed_work link_id_gc_work; -+ u32 sta_asleep_mask; -+ u32 pspoll_mask; -+ bool aid0_bit_set; -+ spinlock_t ps_state_lock; -+ bool buffered_multicasts; -+ bool tx_multicast; -+ u8 last_tim[8]; //for softap dtim, add by yangfh -+ struct work_struct set_tim_work; -+ struct delayed_work set_cts_work; -+ struct work_struct multicast_start_work; -+ struct work_struct multicast_stop_work; -+ struct timer_list mcast_timeout; -+ -+ /* CQM Implementation */ -+ struct delayed_work bss_loss_work; -+ struct delayed_work connection_loss_work; -+ struct work_struct tx_failure_work; -+ int delayed_link_loss; -+ spinlock_t bss_loss_lock; -+ int bss_loss_status; -+ int bss_loss_confirm_id; -+ -+ struct ieee80211_vif *vif; -+ struct xradio_common *hw_priv; -+ struct ieee80211_hw *hw; -+ -+ /* ROC implementation */ -+ struct delayed_work pending_offchanneltx_work; -+#if defined(CONFIG_XRADIO_USE_EXTENSIONS) -+ /* Workaround for WFD testcase 6.1.10*/ -+ struct work_struct linkid_reset_work; -+ u8 action_frame_sa[ETH_ALEN]; -+ u8 action_linkid; -+#endif -+ bool htcap; -+#ifdef AP_HT_CAP_UPDATE -+ u16 ht_oper; -+ struct work_struct ht_oper_update_work; -+#endif -+ -+#ifdef AP_HT_COMPAT_FIX -+ u16 ht_compat_cnt; -+ u16 ht_compat_det; -+#endif -+}; -+struct xradio_sta_priv { -+ int link_id; -+ struct xradio_vif *priv; -+}; -+enum xradio_data_filterid { -+ IPV4ADDR_FILTER_ID = 0, -+}; -+ -+/* Datastructure for LLC-SNAP HDR */ -+#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; -+ -+ -+#ifdef TES_P2P_0002_ROC_RESTART -+extern s32 TES_P2P_0002_roc_dur; -+extern s32 TES_P2P_0002_roc_sec; -+extern s32 TES_P2P_0002_roc_usec; -+extern u32 TES_P2P_0002_packet_id; -+extern u32 TES_P2P_0002_state; -+ -+#define TES_P2P_0002_STATE_IDLE 0x00 -+#define TES_P2P_0002_STATE_SEND_RESP 0x01 -+#define TES_P2P_0002_STATE_GET_PKTID 0x02 -+#endif -+ -+/* debug.h must be here because refer to struct xradio_vif and -+ struct xradio_common.*/ -+#include "debug.h" -+ -+/******************************************************* -+ interfaces for operations of vif. -+********************************************************/ -+static inline -+struct xradio_common *xrwl_vifpriv_to_hwpriv(struct xradio_vif *priv) -+{ -+ return priv->hw_priv; -+} -+static inline -+struct xradio_vif *xrwl_get_vif_from_ieee80211(struct ieee80211_vif *vif) -+{ -+ return (struct xradio_vif *)vif->drv_priv; -+} -+ -+static inline -+struct xradio_vif *xrwl_hwpriv_to_vifpriv(struct xradio_common *hw_priv, -+ int if_id) -+{ -+ struct xradio_vif *vif; -+ -+ if (WARN_ON((-1 == if_id) || (if_id > XRWL_MAX_VIFS))) -+ return NULL; -+ /* TODO:COMBO: During scanning frames can be received -+ * on interface ID 3 */ -+ spin_lock(&hw_priv->vif_list_lock); -+ if (!hw_priv->vif_list[if_id]) { -+ spin_unlock(&hw_priv->vif_list_lock); -+ return NULL; -+ } -+ -+ vif = xrwl_get_vif_from_ieee80211(hw_priv->vif_list[if_id]); -+ WARN_ON(!vif); -+ if (vif) -+ spin_lock(&vif->vif_lock); -+ spin_unlock(&hw_priv->vif_list_lock); -+ return vif; -+} -+ -+static inline -+struct xradio_vif *__xrwl_hwpriv_to_vifpriv(struct xradio_common *hw_priv, -+ int if_id) -+{ -+ WARN_ON((-1 == if_id) || (if_id > XRWL_MAX_VIFS)); -+ /* TODO:COMBO: During scanning frames can be received -+ * on interface ID 3 */ -+ if (!hw_priv->vif_list[if_id]) { -+ return NULL; -+ } -+ -+ return xrwl_get_vif_from_ieee80211(hw_priv->vif_list[if_id]); -+} -+ -+static inline -+struct xradio_vif *xrwl_get_activevif(struct xradio_common *hw_priv) -+{ -+ return xrwl_hwpriv_to_vifpriv(hw_priv, ffs(hw_priv->if_id_slot)-1); -+} -+ -+static inline bool is_hardware_xradio(struct xradio_common *hw_priv) -+{ -+ return (hw_priv->hw_revision == XR819_HW_REV0); -+} -+ -+static inline int xrwl_get_nr_hw_ifaces(struct xradio_common *hw_priv) -+{ -+ switch(hw_priv->hw_revision) { -+ case XR819_HW_REV0: -+ default: -+ return 1; -+ } -+} -+ -+#define xradio_for_each_vif(_hw_priv, _priv, _i) \ -+ for( \ -+ _i = 0; \ -+ (_i < XRWL_MAX_VIFS) \ -+ && ((_priv = _hw_priv->vif_list[_i] ? \ -+ xrwl_get_vif_from_ieee80211(_hw_priv->vif_list[_i]) : NULL),1); \ -+ _i++ \ -+ ) -+ -+/******************************************************* -+ interfaces for operations of queue. -+********************************************************/ -+static inline void xradio_tx_queues_lock(struct xradio_common *hw_priv) -+{ -+ int i; -+ for (i = 0; i < 4; ++i) -+ xradio_queue_lock(&hw_priv->tx_queue[i]); -+} -+ -+static inline void xradio_tx_queues_unlock(struct xradio_common *hw_priv) -+{ -+ int i; -+ for (i = 0; i < 4; ++i) -+ xradio_queue_unlock(&hw_priv->tx_queue[i]); -+} -+ -+#endif /* XRADIO_H */ diff --git a/patch/kernel/sunxi-legacy/xxx-0001-network-audio-orangepiwin-dts.patch b/patch/kernel/sunxi-legacy/xxx-0001-network-audio-orangepiwin-dts.patch.disabled similarity index 100% rename from patch/kernel/sunxi-legacy/xxx-0001-network-audio-orangepiwin-dts.patch rename to patch/kernel/sunxi-legacy/xxx-0001-network-audio-orangepiwin-dts.patch.disabled diff --git a/patch/kernel/sunxi-legacy/xxx-opi-win-bluetooth.patch b/patch/kernel/sunxi-legacy/xxx-opi-win-bluetooth.patch deleted file mode 100644 index a77db4f07..000000000 --- a/patch/kernel/sunxi-legacy/xxx-opi-win-bluetooth.patch +++ /dev/null @@ -1,56 +0,0 @@ -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts -index b4ce2e056..63b9e7433 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts -@@ -94,6 +94,8 @@ - wifi_pwrseq: wifi_pwrseq { - compatible = "mmc-pwrseq-simple"; - reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>; /* PL8 */ -+ clocks = <&rtc 1>; -+ clock-names = "ext_clock"; - }; - - hdmi-connector { -@@ -191,6 +193,14 @@ - bus-width = <4>; - non-removable; - status = "okay"; -+ -+ brcmf: wifi@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ interrupt-parent = <&r_pio>; -+ interrupts = <0 7 IRQ_TYPE_LEVEL_LOW>; /* PL7 */ -+ interrupt-names = "host-wake"; -+ }; - }; - - &ohci0 { -@@ -363,7 +373,20 @@ - &uart1 { - pinctrl-names = "default"; - pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; -+ uart-has-rtscts; - status = "okay"; -+ -+ bluetooth { -+ compatible = "brcm,bcm43438-bt"; -+ max-speed = <1500000>; -+ clocks = <&rtc 1>; -+ clock-names = "lpo"; -+ vbat-supply = <®_dldo2>; -+ vddio-supply = <®_dldo4>; -+ device-wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6 */ -+ host-wakeup-gpios = <&r_pio 0 5 GPIO_ACTIVE_HIGH>; /* PL5 */ -+ shutdown-gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */ -+ }; - }; - - &usb_otg { -@@ -375,4 +398,4 @@ - usb0_id_det-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */ - usb1_vbus-supply = <®_usb1_vbus>; - status = "okay"; --}; -\ No newline at end of file -+};